@unbrained/pm-cli 2026.3.12 → 2026.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/.agents/pm/extensions/.managed-extensions.json +42 -0
  2. package/.agents/pm/extensions/beads/index.js +109 -0
  3. package/.agents/pm/extensions/beads/manifest.json +7 -0
  4. package/{dist/cli/commands/beads.js → .agents/pm/extensions/beads/runtime.js} +31 -21
  5. package/.agents/pm/extensions/beads/runtime.ts +702 -0
  6. package/.agents/pm/extensions/todos/index.js +126 -0
  7. package/.agents/pm/extensions/todos/manifest.json +7 -0
  8. package/{dist/extensions/builtins/todos/import-export.js → .agents/pm/extensions/todos/runtime.js} +39 -29
  9. package/.agents/pm/extensions/todos/runtime.ts +568 -0
  10. package/AGENTS.md +196 -92
  11. package/CHANGELOG.md +399 -0
  12. package/CODE_OF_CONDUCT.md +42 -0
  13. package/CONTRIBUTING.md +144 -0
  14. package/PRD.md +512 -164
  15. package/README.md +1053 -2
  16. package/SECURITY.md +51 -0
  17. package/dist/cli/commands/activity.d.ts +5 -0
  18. package/dist/cli/commands/activity.js +66 -3
  19. package/dist/cli/commands/activity.js.map +1 -1
  20. package/dist/cli/commands/aggregate.d.ts +54 -0
  21. package/dist/cli/commands/aggregate.js +181 -0
  22. package/dist/cli/commands/aggregate.js.map +1 -0
  23. package/dist/cli/commands/append.js +4 -1
  24. package/dist/cli/commands/append.js.map +1 -1
  25. package/dist/cli/commands/calendar.d.ts +109 -0
  26. package/dist/cli/commands/calendar.js +797 -0
  27. package/dist/cli/commands/calendar.js.map +1 -0
  28. package/dist/cli/commands/claim.d.ts +5 -1
  29. package/dist/cli/commands/claim.js +42 -21
  30. package/dist/cli/commands/claim.js.map +1 -1
  31. package/dist/cli/commands/close.d.ts +1 -0
  32. package/dist/cli/commands/close.js +54 -5
  33. package/dist/cli/commands/close.js.map +1 -1
  34. package/dist/cli/commands/comments-audit.d.ts +91 -0
  35. package/dist/cli/commands/comments-audit.js +195 -0
  36. package/dist/cli/commands/comments-audit.js.map +1 -0
  37. package/dist/cli/commands/comments.d.ts +1 -0
  38. package/dist/cli/commands/comments.js +70 -21
  39. package/dist/cli/commands/comments.js.map +1 -1
  40. package/dist/cli/commands/completion.d.ts +10 -4
  41. package/dist/cli/commands/completion.js +1184 -137
  42. package/dist/cli/commands/completion.js.map +1 -1
  43. package/dist/cli/commands/config.d.ts +35 -3
  44. package/dist/cli/commands/config.js +968 -13
  45. package/dist/cli/commands/config.js.map +1 -1
  46. package/dist/cli/commands/context.d.ts +86 -0
  47. package/dist/cli/commands/context.js +299 -0
  48. package/dist/cli/commands/context.js.map +1 -0
  49. package/dist/cli/commands/contracts.d.ts +78 -0
  50. package/dist/cli/commands/contracts.js +920 -0
  51. package/dist/cli/commands/contracts.js.map +1 -0
  52. package/dist/cli/commands/create.d.ts +48 -14
  53. package/dist/cli/commands/create.js +1331 -160
  54. package/dist/cli/commands/create.js.map +1 -1
  55. package/dist/cli/commands/dedupe-audit.d.ts +81 -0
  56. package/dist/cli/commands/dedupe-audit.js +330 -0
  57. package/dist/cli/commands/dedupe-audit.js.map +1 -0
  58. package/dist/cli/commands/deps.d.ts +52 -0
  59. package/dist/cli/commands/deps.js +204 -0
  60. package/dist/cli/commands/deps.js.map +1 -0
  61. package/dist/cli/commands/docs.d.ts +19 -0
  62. package/dist/cli/commands/docs.js +212 -13
  63. package/dist/cli/commands/docs.js.map +1 -1
  64. package/dist/cli/commands/extension.d.ts +122 -0
  65. package/dist/cli/commands/extension.js +1850 -0
  66. package/dist/cli/commands/extension.js.map +1 -0
  67. package/dist/cli/commands/files.d.ts +52 -1
  68. package/dist/cli/commands/files.js +443 -13
  69. package/dist/cli/commands/files.js.map +1 -1
  70. package/dist/cli/commands/gc.d.ts +11 -1
  71. package/dist/cli/commands/gc.js +89 -11
  72. package/dist/cli/commands/gc.js.map +1 -1
  73. package/dist/cli/commands/get.d.ts +13 -0
  74. package/dist/cli/commands/get.js +35 -3
  75. package/dist/cli/commands/get.js.map +1 -1
  76. package/dist/cli/commands/health.d.ts +10 -2
  77. package/dist/cli/commands/health.js +774 -23
  78. package/dist/cli/commands/health.js.map +1 -1
  79. package/dist/cli/commands/history.d.ts +20 -0
  80. package/dist/cli/commands/history.js +152 -6
  81. package/dist/cli/commands/history.js.map +1 -1
  82. package/dist/cli/commands/index.d.ts +16 -3
  83. package/dist/cli/commands/index.js +16 -3
  84. package/dist/cli/commands/index.js.map +1 -1
  85. package/dist/cli/commands/init.d.ts +7 -2
  86. package/dist/cli/commands/init.js +137 -5
  87. package/dist/cli/commands/init.js.map +1 -1
  88. package/dist/cli/commands/learnings.d.ts +17 -0
  89. package/dist/cli/commands/learnings.js +129 -0
  90. package/dist/cli/commands/learnings.js.map +1 -0
  91. package/dist/cli/commands/list.d.ts +29 -1
  92. package/dist/cli/commands/list.js +289 -53
  93. package/dist/cli/commands/list.js.map +1 -1
  94. package/dist/cli/commands/normalize.d.ts +51 -0
  95. package/dist/cli/commands/normalize.js +298 -0
  96. package/dist/cli/commands/normalize.js.map +1 -0
  97. package/dist/cli/commands/notes.d.ts +17 -0
  98. package/dist/cli/commands/notes.js +129 -0
  99. package/dist/cli/commands/notes.js.map +1 -0
  100. package/dist/cli/commands/reindex.d.ts +1 -0
  101. package/dist/cli/commands/reindex.js +208 -32
  102. package/dist/cli/commands/reindex.js.map +1 -1
  103. package/dist/cli/commands/restore.js +164 -30
  104. package/dist/cli/commands/restore.js.map +1 -1
  105. package/dist/cli/commands/search.d.ts +14 -1
  106. package/dist/cli/commands/search.js +475 -81
  107. package/dist/cli/commands/search.js.map +1 -1
  108. package/dist/cli/commands/stats.js +26 -10
  109. package/dist/cli/commands/stats.js.map +1 -1
  110. package/dist/cli/commands/templates.d.ts +26 -0
  111. package/dist/cli/commands/templates.js +179 -0
  112. package/dist/cli/commands/templates.js.map +1 -0
  113. package/dist/cli/commands/test-all.d.ts +19 -1
  114. package/dist/cli/commands/test-all.js +161 -13
  115. package/dist/cli/commands/test-all.js.map +1 -1
  116. package/dist/cli/commands/test-runs.d.ts +63 -0
  117. package/dist/cli/commands/test-runs.js +179 -0
  118. package/dist/cli/commands/test-runs.js.map +1 -0
  119. package/dist/cli/commands/test.d.ts +75 -1
  120. package/dist/cli/commands/test.js +1360 -41
  121. package/dist/cli/commands/test.js.map +1 -1
  122. package/dist/cli/commands/update-many.d.ts +57 -0
  123. package/dist/cli/commands/update-many.js +631 -0
  124. package/dist/cli/commands/update-many.js.map +1 -0
  125. package/dist/cli/commands/update.d.ts +30 -0
  126. package/dist/cli/commands/update.js +1393 -84
  127. package/dist/cli/commands/update.js.map +1 -1
  128. package/dist/cli/commands/validate.d.ts +30 -0
  129. package/dist/cli/commands/validate.js +1140 -0
  130. package/dist/cli/commands/validate.js.map +1 -0
  131. package/dist/cli/error-guidance.d.ts +33 -0
  132. package/dist/cli/error-guidance.js +337 -0
  133. package/dist/cli/error-guidance.js.map +1 -0
  134. package/dist/cli/extension-command-options.d.ts +1 -0
  135. package/dist/cli/extension-command-options.js +92 -0
  136. package/dist/cli/extension-command-options.js.map +1 -1
  137. package/dist/cli/help-content.d.ts +20 -0
  138. package/dist/cli/help-content.js +543 -0
  139. package/dist/cli/help-content.js.map +1 -0
  140. package/dist/cli/main.js +3625 -445
  141. package/dist/cli/main.js.map +1 -1
  142. package/dist/core/extensions/index.d.ts +13 -1
  143. package/dist/core/extensions/index.js +108 -1
  144. package/dist/core/extensions/index.js.map +1 -1
  145. package/dist/core/extensions/item-fields.d.ts +2 -0
  146. package/dist/core/extensions/item-fields.js +79 -0
  147. package/dist/core/extensions/item-fields.js.map +1 -0
  148. package/dist/core/extensions/loader.d.ts +322 -9
  149. package/dist/core/extensions/loader.js +911 -20
  150. package/dist/core/extensions/loader.js.map +1 -1
  151. package/dist/core/extensions/runtime-registrations.d.ts +5 -0
  152. package/dist/core/extensions/runtime-registrations.js +51 -0
  153. package/dist/core/extensions/runtime-registrations.js.map +1 -0
  154. package/dist/core/history/history-stream-policy.d.ts +20 -0
  155. package/dist/core/history/history-stream-policy.js +53 -0
  156. package/dist/core/history/history-stream-policy.js.map +1 -0
  157. package/dist/core/history/history.js +90 -1
  158. package/dist/core/history/history.js.map +1 -1
  159. package/dist/core/item/id.js +4 -1
  160. package/dist/core/item/id.js.map +1 -1
  161. package/dist/core/item/index.d.ts +1 -0
  162. package/dist/core/item/index.js +1 -0
  163. package/dist/core/item/index.js.map +1 -1
  164. package/dist/core/item/item-format.d.ts +11 -5
  165. package/dist/core/item/item-format.js +507 -24
  166. package/dist/core/item/item-format.js.map +1 -1
  167. package/dist/core/item/parent-reference-policy.d.ts +6 -0
  168. package/dist/core/item/parent-reference-policy.js +32 -0
  169. package/dist/core/item/parent-reference-policy.js.map +1 -0
  170. package/dist/core/item/parse.d.ts +5 -0
  171. package/dist/core/item/parse.js +216 -19
  172. package/dist/core/item/parse.js.map +1 -1
  173. package/dist/core/item/sprint-release-format.d.ts +6 -0
  174. package/dist/core/item/sprint-release-format.js +33 -0
  175. package/dist/core/item/sprint-release-format.js.map +1 -0
  176. package/dist/core/item/status.d.ts +3 -0
  177. package/dist/core/item/status.js +24 -0
  178. package/dist/core/item/status.js.map +1 -0
  179. package/dist/core/item/type-registry.d.ts +37 -0
  180. package/dist/core/item/type-registry.js +706 -0
  181. package/dist/core/item/type-registry.js.map +1 -0
  182. package/dist/core/lock/lock.d.ts +1 -1
  183. package/dist/core/lock/lock.js +101 -12
  184. package/dist/core/lock/lock.js.map +1 -1
  185. package/dist/core/output/command-aware.d.ts +1 -0
  186. package/dist/core/output/command-aware.js +394 -0
  187. package/dist/core/output/command-aware.js.map +1 -0
  188. package/dist/core/output/output.d.ts +3 -0
  189. package/dist/core/output/output.js +124 -6
  190. package/dist/core/output/output.js.map +1 -1
  191. package/dist/core/schema/runtime-field-filters.d.ts +3 -0
  192. package/dist/core/schema/runtime-field-filters.js +39 -0
  193. package/dist/core/schema/runtime-field-filters.js.map +1 -0
  194. package/dist/core/schema/runtime-field-values.d.ts +8 -0
  195. package/dist/core/schema/runtime-field-values.js +154 -0
  196. package/dist/core/schema/runtime-field-values.js.map +1 -0
  197. package/dist/core/schema/runtime-schema.d.ts +68 -0
  198. package/dist/core/schema/runtime-schema.js +554 -0
  199. package/dist/core/schema/runtime-schema.js.map +1 -0
  200. package/dist/core/search/cache.d.ts +13 -1
  201. package/dist/core/search/cache.js +123 -14
  202. package/dist/core/search/cache.js.map +1 -1
  203. package/dist/core/search/semantic-defaults.d.ts +6 -0
  204. package/dist/core/search/semantic-defaults.js +120 -0
  205. package/dist/core/search/semantic-defaults.js.map +1 -0
  206. package/dist/core/search/vector-stores.js +3 -1
  207. package/dist/core/search/vector-stores.js.map +1 -1
  208. package/dist/core/shared/command-types.d.ts +2 -0
  209. package/dist/core/shared/conflict-markers.d.ts +7 -0
  210. package/dist/core/shared/conflict-markers.js +27 -0
  211. package/dist/core/shared/conflict-markers.js.map +1 -0
  212. package/dist/core/shared/constants.d.ts +15 -4
  213. package/dist/core/shared/constants.js +141 -1
  214. package/dist/core/shared/constants.js.map +1 -1
  215. package/dist/core/shared/errors.d.ts +10 -1
  216. package/dist/core/shared/errors.js +3 -1
  217. package/dist/core/shared/errors.js.map +1 -1
  218. package/dist/core/shared/text-normalization.d.ts +4 -0
  219. package/dist/core/shared/text-normalization.js +33 -0
  220. package/dist/core/shared/text-normalization.js.map +1 -0
  221. package/dist/core/shared/time.d.ts +1 -2
  222. package/dist/core/shared/time.js +98 -11
  223. package/dist/core/shared/time.js.map +1 -1
  224. package/dist/core/store/index.d.ts +1 -0
  225. package/dist/core/store/index.js +1 -0
  226. package/dist/core/store/index.js.map +1 -1
  227. package/dist/core/store/item-format-migration.d.ts +9 -0
  228. package/dist/core/store/item-format-migration.js +87 -0
  229. package/dist/core/store/item-format-migration.js.map +1 -0
  230. package/dist/core/store/item-store.d.ts +13 -4
  231. package/dist/core/store/item-store.js +238 -51
  232. package/dist/core/store/item-store.js.map +1 -1
  233. package/dist/core/store/paths.d.ts +21 -3
  234. package/dist/core/store/paths.js +59 -4
  235. package/dist/core/store/paths.js.map +1 -1
  236. package/dist/core/store/settings.d.ts +14 -1
  237. package/dist/core/store/settings.js +463 -7
  238. package/dist/core/store/settings.js.map +1 -1
  239. package/dist/core/telemetry/consent.d.ts +2 -0
  240. package/dist/core/telemetry/consent.js +79 -0
  241. package/dist/core/telemetry/consent.js.map +1 -0
  242. package/dist/core/telemetry/runtime.d.ts +38 -0
  243. package/dist/core/telemetry/runtime.js +733 -0
  244. package/dist/core/telemetry/runtime.js.map +1 -0
  245. package/dist/core/test/background-runs.d.ts +117 -0
  246. package/dist/core/test/background-runs.js +760 -0
  247. package/dist/core/test/background-runs.js.map +1 -0
  248. package/dist/core/test/item-test-run-tracking.d.ts +9 -0
  249. package/dist/core/test/item-test-run-tracking.js +50 -0
  250. package/dist/core/test/item-test-run-tracking.js.map +1 -0
  251. package/dist/sdk/cli-contracts.d.ts +92 -0
  252. package/dist/sdk/cli-contracts.js +2357 -0
  253. package/dist/sdk/cli-contracts.js.map +1 -0
  254. package/dist/sdk/index.d.ts +34 -0
  255. package/dist/sdk/index.js +23 -0
  256. package/dist/sdk/index.js.map +1 -0
  257. package/dist/types.d.ts +197 -3
  258. package/dist/types.js +48 -1
  259. package/dist/types.js.map +1 -1
  260. package/docs/ARCHITECTURE.md +368 -39
  261. package/docs/EXTENSIONS.md +454 -49
  262. package/docs/RELEASING.md +68 -19
  263. package/docs/SDK.md +123 -0
  264. package/docs/examples/starter-extension/README.md +48 -0
  265. package/docs/examples/starter-extension/index.js +191 -0
  266. package/docs/examples/starter-extension/manifest.json +17 -0
  267. package/docs/examples/starter-extension/package.json +10 -0
  268. package/package.json +33 -6
  269. package/.pi/extensions/pm-cli/index.ts +0 -778
  270. package/dist/cli/commands/beads.d.ts +0 -16
  271. package/dist/cli/commands/beads.js.map +0 -1
  272. package/dist/cli/commands/install.d.ts +0 -18
  273. package/dist/cli/commands/install.js +0 -87
  274. package/dist/cli/commands/install.js.map +0 -1
  275. package/dist/core/extensions/builtins.d.ts +0 -3
  276. package/dist/core/extensions/builtins.js +0 -47
  277. package/dist/core/extensions/builtins.js.map +0 -1
  278. package/dist/extensions/builtins/beads/index.d.ts +0 -8
  279. package/dist/extensions/builtins/beads/index.js +0 -33
  280. package/dist/extensions/builtins/beads/index.js.map +0 -1
  281. package/dist/extensions/builtins/todos/import-export.d.ts +0 -26
  282. package/dist/extensions/builtins/todos/import-export.js.map +0 -1
  283. package/dist/extensions/builtins/todos/index.d.ts +0 -8
  284. package/dist/extensions/builtins/todos/index.js +0 -38
  285. package/dist/extensions/builtins/todos/index.js.map +0 -1
package/docs/RELEASING.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Releasing `@unbrained/pm-cli`
2
2
 
3
- This repository uses a tag-driven GitHub Actions release pipeline that publishes to npm and creates a GitHub Release.
3
+ This repository uses a tag-driven GitHub Actions pipeline that publishes to npm and creates a GitHub Release. The pipeline uses standard GitHub Actions, repository or environment secrets, artifacts, and npm provenance; it does not require paid GitHub features or paid-only environment protection rules.
4
4
 
5
- ## Version policy
5
+ ## Version Policy
6
6
 
7
7
  `pm-cli` uses a calendar SemVer-compatible scheme:
8
8
 
@@ -14,24 +14,40 @@ Examples:
14
14
  - First release on 2026-03-09: `2026.3.9`
15
15
  - Second release on 2026-03-09: `2026.3.9-2`
16
16
 
17
- Use:
17
+ Use this to compute the next expected release version from the npm registry:
18
18
 
19
19
  ```bash
20
20
  pnpm version:next
21
21
  ```
22
22
 
23
- to compute the next expected release version from the npm registry.
23
+ The release workflow enforces the package version, tag name, calendar date, and npm registry sequencing before publishing.
24
24
 
25
- ## One-time GitHub setup
25
+ ## One-Time Setup
26
26
 
27
- - Create GitHub Environment `release`
28
- - Add environment secret `NPM_TOKEN` (npm automation token with publish rights for `@unbrained/pm-cli`)
27
+ - Add `NPM_TOKEN` as a GitHub Environment or repository secret named `NPM_TOKEN`.
28
+ - If using an Environment named `release`, keep it free-feature compatible: no paid-only reviewer or deployment-protection requirements.
29
+ - Ensure `GITHUB_TOKEN` has the default workflow permission needed by `permissions: contents: write` for GitHub Release creation.
30
+ - Keep npm two-factor settings compatible with automation tokens and provenance publishing.
31
+ - Keep `package.json` repository, homepage, and bugs URLs aligned with the canonical GitHub source repository (`https://github.com/unbraind/pm-cli`); npm provenance validation rejects mismatched repository metadata.
29
32
 
30
- ## Release checklist
33
+ ## Local Release Checklist
31
34
 
32
- 1) Update `package.json` version and `CHANGELOG.md`
35
+ 1. Confirm the next version:
33
36
 
34
- 2) Run release gates locally:
37
+ ```bash
38
+ pnpm version:next
39
+ ```
40
+
41
+ 2. Update `package.json`, `pnpm-lock.yaml`, and `CHANGELOG.md`.
42
+
43
+ 3. Generate release notes locally from changelog + pm tracker data:
44
+
45
+ ```bash
46
+ pnpm build
47
+ pnpm release:notes -- --version "$(node -p 'require("./package.json").version')" --output /tmp/pm-cli-release-notes.md
48
+ ```
49
+
50
+ 4. Run local release gates:
35
51
 
36
52
  ```bash
37
53
  pnpm install
@@ -39,27 +55,60 @@ pnpm build
39
55
  pnpm typecheck
40
56
  pnpm test
41
57
  pnpm test:coverage
58
+ node scripts/run-tests.mjs coverage
42
59
  pnpm version:check
43
60
  pnpm security:scan
44
61
  pnpm smoke:npx
45
62
  ```
46
63
 
47
- 3) Commit and tag:
64
+ 5. Verify previous-version tracker compatibility before tagging. Use a temporary project with the previously published package, create representative items, then run the current build against the same sandboxed `PM_PATH` and `PM_GLOBAL_PATH`. Confirm item count, fields, linked files/docs/tests, comments, close metadata, health, and history drift checks remain intact.
65
+
66
+ 6. Commit, push, tag, and push the tag:
48
67
 
49
68
  ```bash
50
- git tag v<version>
51
69
  git push origin main
70
+ git tag v<version>
52
71
  git push origin v<version>
53
72
  ```
54
73
 
55
- 4) Verify Actions:
74
+ ## Release Workflow
75
+
76
+ `.github/workflows/release.yml` runs on `v*.*.*` tags and performs:
77
+
78
+ - full-history checkout for previous-tag and release-note generation
79
+ - pnpm install with frozen lockfile
80
+ - version policy and tag guard
81
+ - secret leak scan
82
+ - build, typecheck, test coverage, and sandboxed pm coverage
83
+ - npm pack dry run and npx tarball smoke test
84
+ - generated release notes from `CHANGELOG.md` plus sanitized `pm` tracker metadata
85
+ - coverage and release-note artifact uploads
86
+ - `npm publish --access public --provenance`
87
+ - GitHub Release creation using the generated release-note body
88
+
89
+ Monitor with:
90
+
91
+ ```bash
92
+ gh run list --workflow Release --limit 5
93
+ gh run watch <run-id> --exit-status
94
+ ```
95
+
96
+ ## Post-Release Verification
97
+
98
+ After the workflow succeeds, verify all distribution paths:
99
+
100
+ ```bash
101
+ npm view @unbrained/pm-cli@<version> version dist.integrity dist.unpackedSize --json
102
+ npx --yes @unbrained/pm-cli@<version> --version
103
+ bunx @unbrained/pm-cli@<version> --version
104
+ gh release view v<version> --json tagName,name,isDraft,isPrerelease,url
105
+ ```
56
106
 
57
- - `CI` passes for commit
58
- - `Release` workflow passes for tag
59
- - npm package published at `@unbrained/pm-cli`
60
- - GitHub Release created with generated notes
107
+ The `pm` executable name remains unchanged even though the npm package is scoped.
61
108
 
62
- ## Notes
109
+ ## Failure Handling
63
110
 
64
111
  - Do not run manual `npm publish`; publishing is owned by `.github/workflows/release.yml`.
65
- - Release workflow enforces tag/version alignment and calendar version sequencing before publish.
112
+ - If local gates fail, fix the code/docs/tests and rerun the checklist before tagging.
113
+ - If the tag workflow fails before npm publish, fix the issue, move the tag only after confirming no package was published, and rerun the workflow.
114
+ - If npm publish succeeds but GitHub Release creation fails, rerun only the release creation after confirming the tag and package are correct.
package/docs/SDK.md ADDED
@@ -0,0 +1,123 @@
1
+ # pm SDK Guide
2
+
3
+ This guide documents the public SDK surface for extension authors.
4
+
5
+ Primary import:
6
+
7
+ ```ts
8
+ import { defineExtension } from "@unbrained/pm-cli/sdk";
9
+ ```
10
+
11
+ Use this document for SDK/API contracts. Use `docs/EXTENSIONS.md` for full runtime lifecycle behavior and `pm extension --init ./my-extension` for starter scaffold generation.
12
+
13
+ ## Import Surfaces
14
+
15
+ - `@unbrained/pm-cli/sdk`: stable extension authoring API and CLI contract exports.
16
+ - `@unbrained/pm-cli/cli`: runtime CLI module entrypoint. This path is for runtime module resolution, not a typed library API; its declaration file intentionally exports no symbols.
17
+
18
+ ## Public SDK Exports
19
+
20
+ Source of truth:
21
+
22
+ - `src/sdk/index.ts`
23
+ - `src/sdk/cli-contracts.ts`
24
+
25
+ ### Extension authoring values
26
+
27
+ - `defineExtension(...)`
28
+ - `EXTENSION_CAPABILITIES`
29
+ - `EXTENSION_CAPABILITY_CONTRACT`
30
+ - `EXTENSION_CAPABILITY_CONTRACT_VERSION`
31
+ - `EXTENSION_CAPABILITY_LEGACY_ALIASES`
32
+
33
+ ### CLI/action contract values
34
+
35
+ - `PM_CORE_COMMAND_NAMES`
36
+ - `PM_TOOL_ACTIONS`
37
+ - `PM_TOOL_PARAMETERS_SCHEMA`
38
+ - `PM_EXTENSION_CAPABILITY_CONTRACTS`
39
+ - `PM_EXTENSION_SERVICE_NAME_CONTRACTS`
40
+ - all exported `...FLAG_CONTRACTS`, `...OPTION_CONTRACTS`, and `...COMMANDER_*_CONTRACTS` arrays from `src/sdk/cli-contracts.ts`
41
+
42
+ ### CLI/action contract helpers
43
+
44
+ - `withFlagAliasMetadata(...)`
45
+ - `toCompletionFlagString(...)`
46
+ - `readFirstStringFromCommanderOptions(...)`
47
+ - `readStringArrayFromCommanderOptions(...)`
48
+
49
+ ### Key type exports
50
+
51
+ - extension capability/types: `ExtensionCapability`, `PmToolAction`, `PmExtensionCapabilityContract`, `PmExtensionServiceNameContract`
52
+ - command/flag/type helpers: `CommandDefinition`, `ExtensionCommandArgumentDefinition`, `FlagDefinition`, `SchemaFieldDefinition`, `SchemaItemTypeDefinition`
53
+ - runtime extension API types: `ExtensionApi`, `ExtensionManifest`, lifecycle hook context types, importer/exporter contexts, search provider types, vector adapter types
54
+ - shared command/settings types: `GlobalOptions`, `PmSettings`
55
+
56
+ ## Capability Requirements (Quick Reference)
57
+
58
+ Declare capabilities in `manifest.json`; runtime gating is strict.
59
+
60
+ - `registerCommand(...)`: requires `commands`
61
+ - `registerCommand({ flags: [...] })` and `registerFlags(...)`: require `schema`
62
+ - `registerItemFields(...)`, `registerItemTypes(...)`, `registerMigration(...)`: require `schema`
63
+ - `registerImporter(...)` and `registerExporter(...)`: require `importers`
64
+ - `registerParser(...)`: requires `parser`
65
+ - `registerPreflight(...)`: requires `preflight`
66
+ - `registerService(...)`: requires `services`
67
+ - `registerRenderer(...)`: requires `renderers`
68
+ - lifecycle hooks (`beforeCommand`, `afterCommand`, `onWrite`, `onRead`, `onIndex`): require `hooks`
69
+ - `registerSearchProvider(...)` and `registerVectorStoreAdapter(...)`: require `search`
70
+
71
+ ## Minimal Extension
72
+
73
+ `manifest.json`:
74
+
75
+ ```json
76
+ {
77
+ "name": "hello-extension",
78
+ "version": "0.1.0",
79
+ "entry": "./index.js",
80
+ "capabilities": ["commands"]
81
+ }
82
+ ```
83
+
84
+ `index.js`:
85
+
86
+ ```js
87
+ import { defineExtension } from "@unbrained/pm-cli/sdk";
88
+
89
+ export default defineExtension({
90
+ activate(api) {
91
+ api.registerCommand({
92
+ name: "hello",
93
+ run: async () => ({ ok: true, message: "hello from sdk extension" }),
94
+ });
95
+ },
96
+ });
97
+ ```
98
+
99
+ ## Typed Authoring Highlights
100
+
101
+ The SDK provides explicit interfaces for key surfaces including:
102
+
103
+ - `CommandDefinition` and `ExtensionCommandArgumentDefinition`
104
+ - `FlagDefinition`
105
+ - `SchemaFieldDefinition`, `SchemaItemTypeDefinition`, `SchemaMigrationDefinition`
106
+ - `ImportExportContext`
107
+ - `SearchProviderDefinition`, `SearchProviderQueryContext`, `SearchProviderHit`
108
+ - `VectorStoreAdapterDefinition`, `VectorStoreQueryContext`, `VectorStoreUpsertContext`
109
+
110
+ These interfaces intentionally allow additive metadata (`[key: string]: unknown`) where extension-defined metadata is expected.
111
+
112
+ ## Recommended Authoring Pattern
113
+
114
+ - keep command handlers deterministic and JSON-like
115
+ - keep renderer/service overrides narrow to specific command paths
116
+ - prefer additive hooks and schema fields over global behavior changes
117
+ - ship one extension folder with `manifest.json`, an entry module, and package metadata/dependencies
118
+
119
+ ## Related Docs
120
+
121
+ - full extension lifecycle/runtime reference: `docs/EXTENSIONS.md`
122
+ - architecture internals: `docs/ARCHITECTURE.md`
123
+ - complete starter scaffold: `docs/examples/starter-extension/`
@@ -0,0 +1,48 @@
1
+ # Starter Extension (All 9 Capabilities)
2
+
3
+ This example demonstrates a single extension that uses the public SDK only:
4
+ `@unbrained/pm-cli/sdk`.
5
+
6
+ It is intentionally small and "feature complete" as a reference scaffold.
7
+
8
+ ## Files
9
+
10
+ - `manifest.json` declares all 9 capabilities.
11
+ - `package.json` declares the SDK dependency.
12
+ - `index.js` registers one or more examples for each capability.
13
+
14
+ ## Capability Coverage
15
+
16
+ 1. `commands` - `api.registerCommand(...)` + `api.registerFlags(...)`
17
+ 2. `parser` - `api.registerParser(...)`
18
+ 3. `preflight` - `api.registerPreflight(...)`
19
+ 4. `services` - `api.registerService(...)`
20
+ 5. `renderers` - `api.registerRenderer(...)`
21
+ 6. `hooks` - `api.hooks.beforeCommand/afterCommand/onWrite/onRead/onIndex`
22
+ 7. `schema` - `api.registerItemFields/registerItemTypes/registerMigration`
23
+ 8. `importers` - `api.registerImporter/registerExporter`
24
+ 9. `search` - `api.registerSearchProvider/registerVectorStoreAdapter`
25
+
26
+ ## Quick Start
27
+
28
+ 1. Copy this folder into an extension root:
29
+ - project: `.agents/pm/extensions/starter-extension`
30
+ - global: `~/.pm-cli/extensions/starter-extension`
31
+ 2. Install dependencies in that copied folder:
32
+
33
+ ```bash
34
+ npm install
35
+ ```
36
+
37
+ 3. Activate and test:
38
+
39
+ ```bash
40
+ pm extension --activate --project starter-extension
41
+ pm starter ping --name "agent"
42
+ ```
43
+
44
+ ## Notes
45
+
46
+ - This starter is for learning and scaffolding, not production behavior.
47
+ - Keep service/renderer overrides narrowly scoped in real extensions.
48
+ - Prefer returning deterministic JSON-like objects from handlers.
@@ -0,0 +1,191 @@
1
+ import { defineExtension } from "@unbrained/pm-cli/sdk";
2
+
3
+ const runtimeState = {
4
+ beforeCommandCount: 0,
5
+ afterCommandCount: 0,
6
+ onWriteCount: 0,
7
+ onReadCount: 0,
8
+ onIndexCount: 0,
9
+ };
10
+
11
+ function asRecord(value) {
12
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
13
+ return value;
14
+ }
15
+ return {};
16
+ }
17
+
18
+ function asString(value, fallback = "") {
19
+ return typeof value === "string" ? value : fallback;
20
+ }
21
+
22
+ function stableJson(value) {
23
+ try {
24
+ return JSON.stringify(value, null, 2);
25
+ } catch {
26
+ return JSON.stringify({ error: "non_serializable_payload" }, null, 2);
27
+ }
28
+ }
29
+
30
+ export default defineExtension({
31
+ activate(api) {
32
+ // commands
33
+ api.registerCommand({
34
+ name: "starter ping",
35
+ description: "Return a deterministic starter-extension response.",
36
+ intent: "Verify extension activation and show SDK registration patterns.",
37
+ examples: ["pm starter ping --name agent --uppercase"],
38
+ run: async (context) => {
39
+ const options = asRecord(context.options);
40
+ const rawName = asString(options.name, "agent").trim();
41
+ return {
42
+ ok: true,
43
+ source: "starter-extension",
44
+ command: context.command,
45
+ hello: rawName.length > 0 ? rawName : "agent",
46
+ hook_counts: {
47
+ before: runtimeState.beforeCommandCount,
48
+ after: runtimeState.afterCommandCount,
49
+ write: runtimeState.onWriteCount,
50
+ read: runtimeState.onReadCount,
51
+ index: runtimeState.onIndexCount,
52
+ },
53
+ };
54
+ },
55
+ });
56
+
57
+ // schema (registerFlags currently routes through schema capability)
58
+ api.registerFlags("starter ping", [
59
+ { long: "--name", value_name: "text", description: "Name to include in the response." },
60
+ { long: "--uppercase", description: "Render hello in uppercase via output_format service override." },
61
+ ]);
62
+
63
+ // parser
64
+ api.registerParser("starter ping", async (context) => {
65
+ const options = { ...asRecord(context.options) };
66
+ if (typeof options.name === "string") {
67
+ options.name = options.name.trim();
68
+ }
69
+ return { options };
70
+ });
71
+
72
+ // preflight
73
+ api.registerPreflight((context) => {
74
+ if (context.command !== "starter ping") {
75
+ return {};
76
+ }
77
+ return {
78
+ run_extension_migrations: false,
79
+ };
80
+ });
81
+
82
+ // services
83
+ api.registerService("output_format", (context) => {
84
+ if (context.command !== "starter ping") {
85
+ return context.payload;
86
+ }
87
+ const payload = asRecord(context.payload);
88
+ const result = asRecord(payload.result);
89
+ const options = asRecord(context.options);
90
+ const uppercase = options.uppercase === true;
91
+ const helloRaw = asString(result.hello, "agent");
92
+ const hello = uppercase ? helloRaw.toUpperCase() : helloRaw;
93
+ return `starter_service_output hello=${hello} command=${asString(context.command, "")}`;
94
+ });
95
+
96
+ // renderers
97
+ api.registerRenderer("json", (context) => stableJson(context.result));
98
+ api.registerRenderer("toon", (context) => {
99
+ const result = asRecord(context.result);
100
+ const hooks = asRecord(result.hook_counts);
101
+ return [
102
+ "starter_ping",
103
+ `hello: ${asString(result.hello, "agent")}`,
104
+ `command: ${asString(result.command, "")}`,
105
+ `hooks.before: ${String(hooks.before ?? 0)}`,
106
+ `hooks.after: ${String(hooks.after ?? 0)}`,
107
+ ].join("\n");
108
+ });
109
+
110
+ // hooks
111
+ api.hooks.beforeCommand(() => {
112
+ runtimeState.beforeCommandCount += 1;
113
+ });
114
+ api.hooks.afterCommand(() => {
115
+ runtimeState.afterCommandCount += 1;
116
+ });
117
+ api.hooks.onWrite(() => {
118
+ runtimeState.onWriteCount += 1;
119
+ });
120
+ api.hooks.onRead(() => {
121
+ runtimeState.onReadCount += 1;
122
+ });
123
+ api.hooks.onIndex(() => {
124
+ runtimeState.onIndexCount += 1;
125
+ });
126
+
127
+ // schema
128
+ api.registerItemFields([
129
+ {
130
+ name: "starter_context",
131
+ type: "string",
132
+ optional: true,
133
+ },
134
+ ]);
135
+ api.registerItemTypes([
136
+ {
137
+ name: "Experiment",
138
+ folder: "experiments",
139
+ aliases: ["exp"],
140
+ required_create_fields: ["description"],
141
+ },
142
+ ]);
143
+ api.registerMigration({
144
+ id: "starter-extension-noop-migration",
145
+ description: "No-op migration to demonstrate schema migration registration.",
146
+ status: "applied",
147
+ mandatory: false,
148
+ run: async () => ({ applied: true }),
149
+ });
150
+
151
+ // importers
152
+ api.registerImporter("starter-json", async (context) => ({
153
+ imported: true,
154
+ source: "starter-extension",
155
+ input: asRecord(context),
156
+ }));
157
+ api.registerExporter("starter-json", async (context) => ({
158
+ exported: true,
159
+ source: "starter-extension",
160
+ output: asRecord(context),
161
+ }));
162
+
163
+ // search
164
+ api.registerSearchProvider({
165
+ name: "starter-search",
166
+ kind: "example",
167
+ query: async (context) => {
168
+ const query = asString(asRecord(context).query, "").trim();
169
+ if (!query) {
170
+ return [];
171
+ }
172
+ return [
173
+ {
174
+ id: "starter-result-1",
175
+ score: 1,
176
+ title: "Starter Search Result",
177
+ snippet: `Echo match for: ${query}`,
178
+ source: "starter-extension",
179
+ },
180
+ ];
181
+ },
182
+ });
183
+ api.registerVectorStoreAdapter({
184
+ name: "starter-vector-adapter",
185
+ kind: "example",
186
+ upsert: async () => ({ upserted: 0 }),
187
+ query: async () => [],
188
+ delete: async () => ({ deleted: 0 }),
189
+ });
190
+ },
191
+ });
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "starter-extension",
3
+ "version": "0.1.0",
4
+ "description": "SDK-first starter extension demonstrating all pm extension capabilities.",
5
+ "entry": "./index.js",
6
+ "capabilities": [
7
+ "commands",
8
+ "parser",
9
+ "preflight",
10
+ "services",
11
+ "renderers",
12
+ "hooks",
13
+ "schema",
14
+ "importers",
15
+ "search"
16
+ ]
17
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@pm-cli/starter-extension",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "description": "Reference extension starter using @unbrained/pm-cli/sdk",
7
+ "dependencies": {
8
+ "@unbrained/pm-cli": "^2026.3.12"
9
+ }
10
+ }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@unbrained/pm-cli",
3
- "version": "2026.3.12",
3
+ "version": "2026.5.1",
4
4
  "description": "Git-native project management CLI for humans and agents.",
5
5
  "type": "module",
6
6
  "author": "unbrained",
7
7
  "homepage": "https://github.com/unbraind/pm-cli#readme",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "https://github.com/unbraind/pm-cli.git"
10
+ "url": "git+https://github.com/unbraind/pm-cli.git"
11
11
  },
12
12
  "bugs": {
13
13
  "url": "https://github.com/unbraind/pm-cli/issues"
@@ -15,14 +15,37 @@
15
15
  "bin": {
16
16
  "pm": "dist/cli.js"
17
17
  },
18
+ "types": "dist/sdk/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/sdk/index.d.ts",
22
+ "import": "./dist/sdk/index.js",
23
+ "default": "./dist/sdk/index.js"
24
+ },
25
+ "./sdk": {
26
+ "types": "./dist/sdk/index.d.ts",
27
+ "import": "./dist/sdk/index.js",
28
+ "default": "./dist/sdk/index.js"
29
+ },
30
+ "./cli": {
31
+ "types": "./dist/cli/main.d.ts",
32
+ "import": "./dist/cli/main.js",
33
+ "default": "./dist/cli/main.js"
34
+ },
35
+ "./package.json": "./package.json"
36
+ },
18
37
  "files": [
19
38
  "dist/**",
20
39
  "README.md",
40
+ "CHANGELOG.md",
41
+ "CONTRIBUTING.md",
42
+ "SECURITY.md",
43
+ "CODE_OF_CONDUCT.md",
21
44
  "LICENSE",
22
45
  "AGENTS.md",
23
46
  "PRD.md",
24
47
  "docs/**",
25
- ".pi/extensions/pm-cli/index.ts",
48
+ ".agents/pm/extensions/**",
26
49
  "scripts/install.sh",
27
50
  "scripts/install.ps1"
28
51
  ],
@@ -35,6 +58,7 @@
35
58
  "test:coverage": "pnpm build && vitest run --coverage",
36
59
  "version:check": "node scripts/release-version.mjs check",
37
60
  "version:next": "node scripts/release-version.mjs next",
61
+ "release:notes": "node scripts/generate-release-notes.mjs",
38
62
  "security:scan": "node scripts/check-secrets.mjs",
39
63
  "smoke:npx": "node scripts/smoke-npx-from-pack.mjs",
40
64
  "prepublishOnly": "pnpm build"
@@ -59,21 +83,24 @@
59
83
  "dependencies": {
60
84
  "@toon-format/toon": "latest",
61
85
  "commander": "latest",
86
+ "fast-glob": "^3.3.3",
62
87
  "fast-json-patch": "latest",
63
88
  "undici": "latest",
64
89
  "zod": "latest"
65
90
  },
66
91
  "devDependencies": {
67
92
  "@types/node": "latest",
68
- "@vitest/coverage-v8": "^4.0.18",
93
+ "@vitest/coverage-v8": "^4.1.5",
69
94
  "c8": "^11.0.0",
70
95
  "tsx": "latest",
71
96
  "typescript": "latest",
72
- "vitest": "^4.0.18"
97
+ "vitest": "^4.1.5"
73
98
  },
74
99
  "pnpm": {
75
100
  "overrides": {
76
- "rollup": ">=4.59.0"
101
+ "rollup": ">=4.59.0",
102
+ "brace-expansion": ">=5.0.5",
103
+ "vite": "7.3.2"
77
104
  }
78
105
  }
79
106
  }