From 530d3956aac2bb4f54047e9bf17f4672f2fb6f91 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 26 Jul 2026 08:20:04 +0200 Subject: [PATCH 1/3] feat(sdk): adopt pm-cli 2026.7.26 typed authoring contracts pm-cli 2026.7.26 splits the SDK into capability-tiered subpaths and adds a dedicated `sdk/authoring` entrypoint exposing the extension authoring contracts. That makes the forced-`any` shim this package carried unnecessary: import type { defineExtension as defineExtensionType } from "@unbrained/pm-cli/sdk"; const defineExtension: typeof defineExtensionType = ((extension: any) => extension) as any; Two `any`s existed only to bridge a missing type surface. The SDK's `defineExtension` is a pure identity function (`(module: T) => T`), so an equivalent local declaration constrained by the real `ExtensionModule` contract gives identical contract checking with no casts. It is declared locally rather than imported deliberately. This package's dependency on `@unbrained/pm-cli` is type-only, so every type import erases at build time and the published extension carries no runtime module edge to the CLI. Importing `defineExtension` as a value would have introduced one. `activate` is now typed with the real `ExtensionApi` instead of `any`, so every `api.register*` call is checked against the host contract. Dependency ranges move to pm-cli 2026.7.26 (the first release exposing `sdk/authoring`) and pm-changelog 2026.7.25. Refs: pm-github-zjxx Co-Authored-By: Claude Opus 5 (1M context) --- .agents/pm/history/pm-github-zjxx.jsonl | 2 ++ .agents/pm/tasks/pm-github-zjxx.toon | 12 ++++++++++++ index.ts | 15 ++++++++++++--- package-lock.json | 18 +++++++++--------- package.json | 6 +++--- 5 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 .agents/pm/history/pm-github-zjxx.jsonl create mode 100644 .agents/pm/tasks/pm-github-zjxx.toon diff --git a/.agents/pm/history/pm-github-zjxx.jsonl b/.agents/pm/history/pm-github-zjxx.jsonl new file mode 100644 index 00000000..b6ac1996 --- /dev/null +++ b/.agents/pm/history/pm-github-zjxx.jsonl @@ -0,0 +1,2 @@ +{"ts":"2026-07-26T06:18:58.086Z","author":"codex","author_source":"configured","agent_harness":"claude-code","op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-zjxx"},{"op":"add","path":"/metadata/title","value":"Adopt pm-cli 2026.7.26 typed authoring contracts and remove the any-cast defineExtension shim"},{"op":"add","path":"/metadata/description","value":"Replace the forced-any defineExtension shim with a locally declared identity helper constrained by the SDK ExtensionModule contract, and type activate with the real ExtensionApi. Keeps the package's dependency on @unbrained/pm-cli type-only so no runtime module edge is introduced."},{"op":"add","path":"/metadata/type","value":"Task"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-07-26T06:18:58.086Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-07-26T06:18:58.086Z"},{"op":"add","path":"/metadata/author","value":"codex"},{"op":"add","path":"/metadata/acceptance_criteria","value":"No any casts remain in the extension definition path; activate is typed with the real ExtensionApi; Dependency on @unbrained/pm-cli stays type-only at runtime; typecheck and the full test suite pass"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"145ff478899448b2d2209646e9a759d5c28a93d83d6f00465b8924dfe7500ec8","message":""} +{"ts":"2026-07-26T06:18:58.580Z","author":"codex","author_source":"configured","agent_harness":"claude-code","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-07-26T06:18:58.580Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"145ff478899448b2d2209646e9a759d5c28a93d83d6f00465b8924dfe7500ec8","after_hash":"9ba9c77e784e1a5c86f263207905455114cad0045f196768dc437af73b5ef3a9"} diff --git a/.agents/pm/tasks/pm-github-zjxx.toon b/.agents/pm/tasks/pm-github-zjxx.toon new file mode 100644 index 00000000..a25318fe --- /dev/null +++ b/.agents/pm/tasks/pm-github-zjxx.toon @@ -0,0 +1,12 @@ +id: pm-github-zjxx +title: Adopt pm-cli 2026.7.26 typed authoring contracts and remove the any-cast defineExtension shim +description: "Replace the forced-any defineExtension shim with a locally declared identity helper constrained by the SDK ExtensionModule contract, and type activate with the real ExtensionApi. Keeps the package's dependency on @unbrained/pm-cli type-only so no runtime module edge is introduced." +type: Task +status: in_progress +priority: 2 +tags: [] +created_at: "2026-07-26T06:18:58.086Z" +updated_at: "2026-07-26T06:18:58.580Z" +author: codex +acceptance_criteria: No any casts remain in the extension definition path; activate is typed with the real ExtensionApi; Dependency on @unbrained/pm-cli stays type-only at runtime; typecheck and the full test suite pass +body: "" diff --git a/index.ts b/index.ts index f1972bd2..226a4ba8 100644 --- a/index.ts +++ b/index.ts @@ -13,13 +13,13 @@ // Issues use the REST API; Projects v2 is GraphQL-only (see the Projects v2 // section below and the pure plan/mapping logic in ./projects.ts). +import type { ExtensionApi, ExtensionModule } from "@unbrained/pm-cli/sdk/authoring"; import https from "node:https"; import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { spawnSync } from "node:child_process"; -import type { defineExtension as defineExtensionType } from "@unbrained/pm-cli/sdk"; import type { BulkItemMutation, CommitItemMutationsOptions, @@ -63,7 +63,6 @@ import { projectItemTag, } from "./projects.js"; -const defineExtension: typeof defineExtensionType = ((extension: any) => extension) as any; // --------------------------------------------------------------------------- // Types @@ -3797,11 +3796,21 @@ const PROJECT_SYNC_FLAGS = [ { long: "--dry-run", description: "Preview only (always wins over --apply)" }, ]; +/** + * Local stand-in for the SDK's `defineExtension` identity helper. + * + * Declared here rather than imported so this package keeps a type-only + * dependency on `@unbrained/pm-cli` and adds no runtime module edge. The + * generic constraint is the SDK's own, so the extension object is contract- + * checked against {@link ExtensionModule} exactly as the imported helper would. + */ +const defineExtension = (module: TModule): TModule => module; + export default defineExtension({ name: "pm-github", version: "2026.7.26", - activate(api: any) { + activate(api: ExtensionApi) { // ----------------------------------------------------------------------- // schema — declare the GitHub provenance fields so the workspace knows them // ----------------------------------------------------------------------- diff --git a/package-lock.json b/package-lock.json index 441ac2fb..ffcb88ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,15 +10,15 @@ "license": "MIT", "devDependencies": { "@types/node": "^26.1.1", - "@unbrained/pm-cli": "^2026.7.25", - "pm-changelog": "^2026.7.24", + "@unbrained/pm-cli": "^2026.7.26", + "pm-changelog": "^2026.7.25", "typescript": "^7.0.2" }, "engines": { "node": ">=22.18.0" }, "peerDependencies": { - "@unbrained/pm-cli": ">=2026.7.20" + "@unbrained/pm-cli": ">=2026.7.26" } }, "node_modules/@apm-js-collab/code-transformer": { @@ -717,9 +717,9 @@ } }, "node_modules/@unbrained/pm-cli": { - "version": "2026.7.25", - "resolved": "https://registry.npmjs.org/@unbrained/pm-cli/-/pm-cli-2026.7.25.tgz", - "integrity": "sha512-GtApg/4F/uMU28T+lT2bE+ELooxyEMHCkFbByRANa7HbMiq1Pz1oAoF4Gt0Rxppi//me8re5Pa8CxILDraIKcA==", + "version": "2026.7.26", + "resolved": "https://registry.npmjs.org/@unbrained/pm-cli/-/pm-cli-2026.7.26.tgz", + "integrity": "sha512-Esbt0SE0PgYlZzdgCCu5MlGt6zxkAvy5V/Pj8MOC3E2zfe5mCuazwi3mN/z71C0Xyp2TzSivpratUTia2IlOdQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1055,9 +1055,9 @@ } }, "node_modules/pm-changelog": { - "version": "2026.7.24", - "resolved": "https://registry.npmjs.org/pm-changelog/-/pm-changelog-2026.7.24.tgz", - "integrity": "sha512-3ixc8HLx//s/0NEXE9/LB5yd7MaKajC5N88u9XQtV37UJQcUNxKiPRKdoEOcBLFe7gUXgP1IFWNywjukbXmQPQ==", + "version": "2026.7.25", + "resolved": "https://registry.npmjs.org/pm-changelog/-/pm-changelog-2026.7.25.tgz", + "integrity": "sha512-Y+9pxsI8zu75p9UOROeMsOSO75j14YshxPearrNZKagkRltTFtQfUzQ3f6r4h1AiXNLom648mS9VUsWFEqKwdw==", "dev": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index 8433b601..d265f57b 100644 --- a/package.json +++ b/package.json @@ -38,12 +38,12 @@ "merge:install": "pm merge install" }, "peerDependencies": { - "@unbrained/pm-cli": ">=2026.7.20" + "@unbrained/pm-cli": ">=2026.7.26" }, "devDependencies": { "@types/node": "^26.1.1", - "@unbrained/pm-cli": "^2026.7.25", - "pm-changelog": "^2026.7.24", + "@unbrained/pm-cli": "^2026.7.26", + "pm-changelog": "^2026.7.25", "typescript": "^7.0.2" }, "keywords": [ From 63a5d410da1e1d8bfc590a448bf28bd7367af3f0 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 26 Jul 2026 08:25:38 +0200 Subject: [PATCH 2/3] chore(pm): close the implementation record atomically in its own PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses CodeRabbit's review finding: the task documented successful verification but stayed open, and its JSONL history carried no close event. An implementation record left open in the PR that implements it breaks atomic changelog attribution — the work ships in one release while the tracker closes in a later one, so the entry lands under the wrong version. Closes the record with full closure metadata (resolution, expected result, actual result, close reason) under `--validate-close strict`, appends the matching history event, and regenerates CHANGELOG.md with the same `--mode replace --all-release-tags` invocation `changelog:check` uses so generation and verification cannot drift. Co-Authored-By: Claude Opus 5 (1M context) --- .agents/pm/history/pm-github-zjxx.jsonl | 1 + .agents/pm/tasks/pm-github-zjxx.toon | 9 +++++++-- CHANGELOG.md | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.agents/pm/history/pm-github-zjxx.jsonl b/.agents/pm/history/pm-github-zjxx.jsonl index b6ac1996..63ca51da 100644 --- a/.agents/pm/history/pm-github-zjxx.jsonl +++ b/.agents/pm/history/pm-github-zjxx.jsonl @@ -1,2 +1,3 @@ {"ts":"2026-07-26T06:18:58.086Z","author":"codex","author_source":"configured","agent_harness":"claude-code","op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-zjxx"},{"op":"add","path":"/metadata/title","value":"Adopt pm-cli 2026.7.26 typed authoring contracts and remove the any-cast defineExtension shim"},{"op":"add","path":"/metadata/description","value":"Replace the forced-any defineExtension shim with a locally declared identity helper constrained by the SDK ExtensionModule contract, and type activate with the real ExtensionApi. Keeps the package's dependency on @unbrained/pm-cli type-only so no runtime module edge is introduced."},{"op":"add","path":"/metadata/type","value":"Task"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-07-26T06:18:58.086Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-07-26T06:18:58.086Z"},{"op":"add","path":"/metadata/author","value":"codex"},{"op":"add","path":"/metadata/acceptance_criteria","value":"No any casts remain in the extension definition path; activate is typed with the real ExtensionApi; Dependency on @unbrained/pm-cli stays type-only at runtime; typecheck and the full test suite pass"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"145ff478899448b2d2209646e9a759d5c28a93d83d6f00465b8924dfe7500ec8","message":""} {"ts":"2026-07-26T06:18:58.580Z","author":"codex","author_source":"configured","agent_harness":"claude-code","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-07-26T06:18:58.580Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"145ff478899448b2d2209646e9a759d5c28a93d83d6f00465b8924dfe7500ec8","after_hash":"9ba9c77e784e1a5c86f263207905455114cad0045f196768dc437af73b5ef3a9"} +{"ts":"2026-07-26T06:24:29.387Z","author":"codex","author_source":"configured","agent_harness":"claude-code","op":"close","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-07-26T06:24:29.387Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-07-26T06:24:29.387Z"},{"op":"add","path":"/metadata/resolution","value":"Replaced the forced-any defineExtension shim with a locally declared identity helper constrained by the SDK ExtensionModule contract, and typed activate with the real ExtensionApi from @unbrained/pm-cli/sdk/authoring."},{"op":"add","path":"/metadata/expected_result","value":"No any casts in the extension definition path, activate checked against the host contract, and the dependency on @unbrained/pm-cli kept type-only so no runtime module edge is added."},{"op":"add","path":"/metadata/actual_result","value":"typecheck clean and the full test suite passes; type imports erase at build time so the published extension carries no runtime edge to the CLI."},{"op":"add","path":"/metadata/close_reason","value":"Implemented and verified in PR #17"}],"before_hash":"9ba9c77e784e1a5c86f263207905455114cad0045f196768dc437af73b5ef3a9","after_hash":"46504d505d355bb64d26b3b4df2fa9f331bf7e73db2e7368310d89659ea32e18"} diff --git a/.agents/pm/tasks/pm-github-zjxx.toon b/.agents/pm/tasks/pm-github-zjxx.toon index a25318fe..0e8b4b58 100644 --- a/.agents/pm/tasks/pm-github-zjxx.toon +++ b/.agents/pm/tasks/pm-github-zjxx.toon @@ -2,11 +2,16 @@ id: pm-github-zjxx title: Adopt pm-cli 2026.7.26 typed authoring contracts and remove the any-cast defineExtension shim description: "Replace the forced-any defineExtension shim with a locally declared identity helper constrained by the SDK ExtensionModule contract, and type activate with the real ExtensionApi. Keeps the package's dependency on @unbrained/pm-cli type-only so no runtime module edge is introduced." type: Task -status: in_progress +status: closed priority: 2 tags: [] created_at: "2026-07-26T06:18:58.086Z" -updated_at: "2026-07-26T06:18:58.580Z" +updated_at: "2026-07-26T06:24:29.387Z" +closed_at: "2026-07-26T06:24:29.387Z" author: codex acceptance_criteria: No any casts remain in the extension definition path; activate is typed with the real ExtensionApi; Dependency on @unbrained/pm-cli stays type-only at runtime; typecheck and the full test suite pass +resolution: "Replaced the forced-any defineExtension shim with a locally declared identity helper constrained by the SDK ExtensionModule contract, and typed activate with the real ExtensionApi from @unbrained/pm-cli/sdk/authoring." +expected_result: "No any casts in the extension definition path, activate checked against the host contract, and the dependency on @unbrained/pm-cli kept type-only so no runtime module edge is added." +actual_result: typecheck clean and the full test suite passes; type imports erase at build time so the published extension carries no runtime edge to the CLI. +close_reason: Implemented and verified in PR #17 body: "" diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e5c5bfb..66bb3154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## 2026.7.26 - 2026-07-26 +### Removed + +- Adopt pm-cli 2026.7.26 typed authoring contracts and remove the any-cast defineExtension shim ([pm-github-zjxx](https://github.com/unbraind/pm-github/blob/main/.agents/pm/tasks/pm-github-zjxx.toon)) + +## 2026.7.26 - 2026-07-26 + ### Fixed - Documented install command fails: pm install github.com/unbraind/pm-github cannot resolve an entry file ([pm-github-q6ql](https://github.com/unbraind/pm-github/blob/main/.agents/pm/issues/pm-github-q6ql.toon)) From b890133bf6451c9af6dbca9f91f676eb8bb50cab Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sun, 26 Jul 2026 08:28:30 +0200 Subject: [PATCH 3/3] chore(changelog): regenerate against the 2026.07.26 release tag Rebased onto main after Daily Release cut v2026.07.26. Regenerated with the same --mode replace --all-release-tags invocation changelog:check runs so the generated file matches what CI verifies. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66bb3154..e6f5f4a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 2026.7.26 - 2026-07-26 +## Unreleased ### Removed