Eliminate all 37 source any with real Projects V2 GraphQL types, and adopt pm-cli 2026.7.27 - #18
Conversation
… types, and adopt pm-cli 2026.7.27
index.ts carried 37 `any` usages in two groups. Both are gone; source and test
`any` are now 0 (was 37 / 52 — the two remaining grep hits are comments that
mention `as any`, not usages).
**Group A — untyped GitHub Projects V2 GraphQL responses.** `githubGraphQL<any>`
at every call site, plus untyped `.map()` callbacks over nodes, fields and
options. Replaced with 18 precise interfaces derived from the ACTUAL query
strings sitting next to each call site rather than guessed: project metadata,
item connections with `pageInfo`/`nodes`, field lists with their option sets, the
draft-issue and add-item mutation payloads, the owner-projects listing, and issue
node-id resolution.
GraphQL nullability is modelled honestly rather than optimistically — `nodes` is
`Array<T | null>` because connections may include nulls for redacted or
inaccessible items, which the callers already `.filter(Boolean)`. Nothing
unselected is declared. Verified field-for-field against a real query:
`fetchProjectItems` selects `pageInfo{ hasNextPage endCursor }` and
`nodes{ id fieldValueByName content }`, and the interfaces declare exactly that.
**Group B — untyped extension handler and hook contexts.** `runSync`,
`runExport`, `runValidate`, the four project commands, the seven registered `run`
handlers, `registerPreflight`, `registerImporter`, `registerExporter`,
`hooks.afterCommand`, and the search query path all now use the real SDK types
instead of `ctx: any`.
**pm-cli 2026.7.27 adoption.** peerDependency `>=2026.7.26` → `>=2026.7.27`,
devDependency `^2026.7.26` → `^2026.7.27`, lockfile refreshed. Package and
manifest versions were already 2026.7.27 from the daily release.
Behaviour is unchanged; this is a typing refactor plus a dependency bump.
Verified by production proof rather than the suite alone — the built extension
installed into a throwaway workspace with two seeded items:
- install ok, no warnings
- host commands unaffected: `pm list` renders items, `pm list --json` is valid
- all five subcommands register and resolve: export, import, project, sync, validate
- no host-owned global flag is declared anywhere in index.ts
- `pm health` reports `extensions=ok` with no warnings
Also audited the camelCase multi-word flag contract that caused three defects in
pm-ops this session. pm-github was already correct: index.ts:432 documents that
flags may arrive kebab-case or camelCase, and all eleven multi-word flags
(comments-mode, dry-run, include-comments, include-prs, label-map, link-deps,
no-add-missing, skip-drafts, status-map, with-comments) are read with BOTH forms
via `optionEnabled`. No change needed.
Gates: build, typecheck, check, 168 tests (0 failures), changelog:full +
changelog:check after `git fetch --tags --force`.
pm items:
- pm-github-1wka (Chore) — the 37 `any` elimination
- pm-github-iai5 (Chore) — pm-cli 2026.7.27 adoption
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Warning Review limit reached
Next review available in: 22 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (10)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Reviewer's GuideRefactors pm-github to eliminate all remaining Sequence diagram for typed listOwnerProjectsV2Nodes paginationsequenceDiagram
participant Caller
participant listOwnerProjectsV2Nodes
participant collectProjectsV2Pages
participant GraphQLTransport
participant githubGraphQL
Caller->>listOwnerProjectsV2Nodes: listOwnerProjectsV2Nodes(owner, graphQL)
activate listOwnerProjectsV2Nodes
listOwnerProjectsV2Nodes->>collectProjectsV2Pages: collectProjectsV2Pages(fetchPage)
activate collectProjectsV2Pages
loop pages
collectProjectsV2Pages->>listOwnerProjectsV2Nodes: fetchPage(cursor)
activate listOwnerProjectsV2Nodes
listOwnerProjectsV2Nodes->>GraphQLTransport: graphQL(query, variables)
activate GraphQLTransport
GraphQLTransport->>githubGraphQL: githubGraphQL<GraphqlListOwnerProjectsData>(token, query, variables)
activate githubGraphQL
githubGraphQL-->>GraphQLTransport: GraphqlListOwnerProjectsData
deactivate githubGraphQL
GraphQLTransport-->>listOwnerProjectsV2Nodes: GraphqlListOwnerProjectsData
deactivate GraphQLTransport
listOwnerProjectsV2Nodes-->>collectProjectsV2Pages: ProjectsV2Page
deactivate listOwnerProjectsV2Nodes
end
collectProjectsV2Pages-->>listOwnerProjectsV2Nodes: GraphqlProjectsV2Node[]
deactivate collectProjectsV2Pages
listOwnerProjectsV2Nodes-->>Caller: GraphqlProjectsV2Node[]
deactivate listOwnerProjectsV2Nodes
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Greptile SummaryThis PR replaces the remaining untyped GitHub integration surfaces with concrete types and adopts
Confidence Score: 5/5Safe to merge based on the reviewed changes. The changes are mainly type refinements and a dependency bump with focused tests. The previous raw Files Needing Attention: No files require special attention.
What T-Rex did
|
| Filename | Overview |
|---|---|
| index.ts | Replaces untyped GraphQL and handler surfaces with concrete response/context types, switches required SDK helpers to typed imports, and preserves the raw/wrapped search document guard. |
| test/smoke.test.ts | Updates smoke coverage for the real extension harness, typed Projects V2 pagination helpers, exporter output routing, and the fixed raw/wrapped search corpus mapping. |
| test/comments-sync.test.ts | Updates comments-sync tests to use typed factories and the real SDK comments() primitive without any casts. |
| test/import-lock.test.ts | Updates import-lock tests with typed fixtures while preserving lock contention and concurrent comment-sync coverage. |
| package.json | Raises @unbrained/pm-cli peer and dev dependency ranges to 2026.7.27. |
| package-lock.json | Refreshes the lockfile for the @unbrained/pm-cli 2026.7.27 dependency update. |
| CHANGELOG.md | Adds unreleased changelog entries for the pm-cli bump and the any removal refactor. |
| .agents/pm/chores/pm-github-1wka.toon | Adds a closed chore item documenting the type-refactor scope, acceptance criteria, production proof, and the resolved prior search-corpus regression. |
| .agents/pm/chores/pm-github-iai5.toon | Adds a closed chore item for adopting @unbrained/pm-cli 2026.7.27 and recording activation-proof criteria. |
| .agents/pm/history/pm-github-1wka.jsonl | Adds history entries for the type-refactor chore, including notes for the previous Greptile search-corpus fix and falsifiable regression test. |
| .agents/pm/history/pm-github-iai5.jsonl | Adds history entries for the pm-cli dependency-bump chore lifecycle. |
Sequence Diagram
sequenceDiagram
participant Host as pm-cli host
participant Ext as pm-github extension
participant SDK as pm-cli SDK
participant GH as GitHub API
participant Store as pm workspace
Host->>Ext: activate with typed authoring API
Ext->>Host: register commands/importer/exporter/search/hooks
Host->>Ext: invoke github command/provider with typed context
alt GitHub Projects V2 path
Ext->>GH: typed GraphQL query/mutation
GH-->>Ext: query-shaped response data
Ext->>Ext: normalize nullable nodes/options
else comments/dependency SDK path
Ext->>SDK: typed SDK primitives
SDK-->>Ext: comments/metadata/mutation results
else search provider path
Ext->>GH: REST search
GH-->>Ext: matched issue numbers
Ext->>Store: fallback read when documents absent
Ext->>Ext: resolve wrapped or raw documents to pm items
end
Ext-->>Host: structured result
Reviews (6): Last reviewed commit: "fix: restore the search-provider documen..." | Re-trigger Greptile
…ropped Found by Greptile's review on PR #18 and reproduced with T-Rex: a wrapped document produced a local hit while a RAW document threw a TypeError. The SDK declares `SearchProviderQueryContext.documents` as `ItemDocument[]` with a REQUIRED `metadata`, so the typing refactor replaced the pre-existing guard (`d?.metadata ? d.metadata : d`) with a bare `d.metadata`. But `SearchProviderQueryContext` carries an `[key: string]: unknown` index signature and the runtime hands raw pm items straight through on some paths — so trusting the declared type yielded `undefined` entries and crashed `indexByProvenance`. This is the classic typing-refactor hazard: the type asserts a field always exists, the runtime disagrees, and the guard that proved otherwise gets deleted in the name of the type. The guard is restored as a typed narrowing helper (`searchDocumentToItem`) that handles wrapped, raw, and neither — with no `any`. My first regression tests for this were NOT falsifiable: reverting the guard still passed 172/172, because they exercised the helper in isolation plus a hand-mirrored copy of the mapping rather than the code the provider runs. That is precisely the flaw this session kept finding elsewhere — the unit under test not being the unit that ships. Fixed by extracting the provider's real mapping into `resolveSearchCorpus` and testing that. The surrounding `query` handler performs network I/O before reaching the mapping, so an end-to-end test cannot get there without stubbing internals, and an inline expression would be untestable in practice. Falsification now verified: reverting the guard inside `resolveSearchCorpus` fails the test (171 pass / 1 fail); restoring passes 172. Gates: build, typecheck, check, 172 tests (0 failures), changelog:check up to date, zero `any`.
Bot feedback triage — all four read, voted, acted on@greptile-apps 👍 — the P1 was real and is fixed in Confirmed exactly as your T-Rex run described — wrapped document → local hit, raw document → This is the canonical typing-refactor hazard, and worth your model retaining as a pattern: when a Fixed as a typed narrowing helper ( My first fix attempt had a worse problem than the bugRecording this because it is the more useful lesson. My initial regression tests were not The real fix was structural: extract the provider's mapping into
@sourcery-ai 👍 — accurate walkthrough of the four typing groups. @coderabbitai 👎 — @gemini-code-assist 👎 — consumer Gemini Code Assist is sunset; all review activity has ceased. @coderabbitai review |
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
🐇🔎 ✏️ Learnings added
✅ Action performedReview finished.
|
Summary
Eliminates all 37
anyusages fromindex.tsand adopts pm-cli 2026.7.27. Source and testanyare now 0 (was 37 / 52 — the two remaining grep hits are comments that mentionas any,not usages). Behaviour is unchanged: this is a typing refactor plus a dependency bump.
Group A — untyped GitHub Projects V2 GraphQL responses
githubGraphQL<any>at every call site, plus untyped.map()callbacks over nodes, fields andoptions. Replaced with 18 interfaces derived from the actual query strings sitting next to each
call site, not guessed: project metadata, item connections with
pageInfo/nodes, field lists withtheir option sets, the draft-issue and add-item mutation payloads, the owner-projects listing, and
issue node-id resolution.
Nullability is modelled honestly rather than optimistically —
nodesisArray<T | null>becauseGraphQL connections may include nulls for redacted or inaccessible items, which the callers already
.filter(Boolean). Nothing unselected is declared.Verified field-for-field against a real query —
fetchProjectItems:Exactly the selected fields, and no more.
Group B — untyped extension handler and hook contexts
runSync,runExport,runValidate, the four project commands, the seven registeredrunhandlers,
registerPreflight,registerImporter,registerExporter,hooks.afterCommand, and thesearch query path all now use the real SDK types instead of
ctx: any.pm-cli 2026.7.27 adoption
>=2026.7.26→>=2026.7.27^2026.7.26→^2026.7.27An activation proof is mandatory for this bump, not optional: 2026.7.27 hardened host-owned
global flags, and a collision aborts command registration at the offending command — dropping it
and every later sibling, while
--helpstill exits 0 with a misleading arity error(pm-cli#772).
Production proof
Built extension installed into a throwaway workspace with two seeded items — not the dev runner:
Flag-contract audit (no change needed)
Three defects in pm-ops#27 this session came from
multi-word flags arriving camelCased from the host while the handler read only the hyphenated
key. I audited pm-github for the same class and it was already correct:
index.ts:432documents thatflags may arrive kebab-case or camelCase, and all eleven multi-word flags (
comments-mode,dry-run,include-comments,include-prs,label-map,link-deps,no-add-missing,skip-drafts,status-map,with-comments) are read with both forms viaoptionEnabled.Gates
build,typecheck,check, 168 tests (0 failures),changelog:full+changelog:checkafter
git fetch origin --tags --force.No mutating GitHub API calls were made against any real repo or project during verification.
pm items
pm-github-1wka— Chore: the 37anyeliminationpm-github-iai5— Chore: pm-cli 2026.7.27 adoptionSummary by Sourcery
Update pm-github’s GitHub Projects V2 integration and extension wiring to be fully typed and aligned with the latest pm-cli SDK, while strengthening activation and export/import tests against the real host runtime.
Enhancements:
Build:
Documentation:
Summary by cubic
Replaces all remaining untyped GraphQL and handler contexts with real types and adopts
@unbrained/pm-cli2026.7.27. Also fixes a search provider crash when the host passes raw pm items instead ofItemDocuments.Refactors
anyby adding precise Projects V2 GraphQL result types derived from each query (with honest nullability).githubGraphQL<any>and untyped.map()s with typed models for items, fields, options, and mutations.CommandHandlerContext,ImportExportContext,PreflightOverrideContext,AfterCommandHookContext,SearchProviderQueryContext).comments,commitItemMutations,listAllItemMetadata, andcollectNewOrderingCycleWarnings.@unbrained/pm-cli/sdk/testing) and typed factories; casts removed.Bug Fixes
searchDocumentToItemandresolveSearchCorpusto support wrapped and raw items, preventingindexByProvenanceTypeErrors.Written for commit dc83cdd. Summary will update on new commits.