@unbrained/pm-cli 2026.5.10 → 2026.5.12

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 (172) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/AGENTS.md +3 -116
  3. package/CHANGELOG.md +14 -0
  4. package/PRD.md +11 -11
  5. package/README.md +20 -2
  6. package/dist/cli/argv-utils.d.ts +5 -0
  7. package/dist/cli/argv-utils.js +34 -0
  8. package/dist/cli/argv-utils.js.map +1 -0
  9. package/dist/cli/bootstrap-args.d.ts +15 -0
  10. package/dist/cli/bootstrap-args.js +211 -0
  11. package/dist/cli/bootstrap-args.js.map +1 -1
  12. package/dist/cli/commander-usage.js +109 -3
  13. package/dist/cli/commander-usage.js.map +1 -1
  14. package/dist/cli/commands/completion.js +7 -3
  15. package/dist/cli/commands/completion.js.map +1 -1
  16. package/dist/cli/commands/contracts.d.ts +19 -0
  17. package/dist/cli/commands/contracts.js +40 -2
  18. package/dist/cli/commands/contracts.js.map +1 -1
  19. package/dist/cli/commands/create.js +112 -51
  20. package/dist/cli/commands/create.js.map +1 -1
  21. package/dist/cli/commands/docs.js +9 -2
  22. package/dist/cli/commands/docs.js.map +1 -1
  23. package/dist/cli/commands/extension.d.ts +12 -3
  24. package/dist/cli/commands/extension.js +421 -69
  25. package/dist/cli/commands/extension.js.map +1 -1
  26. package/dist/cli/commands/files.js +9 -2
  27. package/dist/cli/commands/files.js.map +1 -1
  28. package/dist/cli/commands/index.d.ts +1 -0
  29. package/dist/cli/commands/index.js +1 -0
  30. package/dist/cli/commands/index.js.map +1 -1
  31. package/dist/cli/commands/init.d.ts +2 -0
  32. package/dist/cli/commands/init.js +21 -1
  33. package/dist/cli/commands/init.js.map +1 -1
  34. package/dist/cli/commands/metadata-normalizers.d.ts +4 -0
  35. package/dist/cli/commands/metadata-normalizers.js +37 -0
  36. package/dist/cli/commands/metadata-normalizers.js.map +1 -0
  37. package/dist/cli/commands/reindex.js +173 -135
  38. package/dist/cli/commands/reindex.js.map +1 -1
  39. package/dist/cli/commands/search.js +16 -6
  40. package/dist/cli/commands/search.js.map +1 -1
  41. package/dist/cli/commands/test.js +23 -8
  42. package/dist/cli/commands/test.js.map +1 -1
  43. package/dist/cli/commands/update.js +70 -39
  44. package/dist/cli/commands/update.js.map +1 -1
  45. package/dist/cli/commands/upgrade.d.ts +63 -0
  46. package/dist/cli/commands/upgrade.js +260 -0
  47. package/dist/cli/commands/upgrade.js.map +1 -0
  48. package/dist/cli/error-guidance.d.ts +9 -1
  49. package/dist/cli/error-guidance.js +147 -6
  50. package/dist/cli/error-guidance.js.map +1 -1
  51. package/dist/cli/guide-topics.js +18 -16
  52. package/dist/cli/guide-topics.js.map +1 -1
  53. package/dist/cli/help-content.js +42 -2
  54. package/dist/cli/help-content.js.map +1 -1
  55. package/dist/cli/help-json-payload.js +11 -1
  56. package/dist/cli/help-json-payload.js.map +1 -1
  57. package/dist/cli/main.js +69 -6
  58. package/dist/cli/main.js.map +1 -1
  59. package/dist/cli/register-setup.js +174 -82
  60. package/dist/cli/register-setup.js.map +1 -1
  61. package/dist/cli/telemetry-flush.d.ts +2 -0
  62. package/dist/cli/telemetry-flush.js +4 -0
  63. package/dist/cli/telemetry-flush.js.map +1 -0
  64. package/dist/cli.js +1 -2
  65. package/dist/cli.js.map +1 -1
  66. package/dist/core/extensions/extension-types.d.ts +72 -0
  67. package/dist/core/extensions/extension-types.js +24 -0
  68. package/dist/core/extensions/extension-types.js.map +1 -1
  69. package/dist/core/extensions/loader.d.ts +1 -0
  70. package/dist/core/extensions/loader.js +766 -7
  71. package/dist/core/extensions/loader.js.map +1 -1
  72. package/dist/core/lock/lock.js +2 -0
  73. package/dist/core/lock/lock.js.map +1 -1
  74. package/dist/core/packages/manifest.d.ts +13 -0
  75. package/dist/core/packages/manifest.js +139 -0
  76. package/dist/core/packages/manifest.js.map +1 -0
  77. package/dist/core/sentry/instrument.d.ts +15 -0
  78. package/dist/core/sentry/instrument.js +35 -3
  79. package/dist/core/sentry/instrument.js.map +1 -1
  80. package/dist/core/shared/constants.js +20 -0
  81. package/dist/core/shared/constants.js.map +1 -1
  82. package/dist/core/shared/errors.d.ts +8 -0
  83. package/dist/core/shared/errors.js.map +1 -1
  84. package/dist/core/shared/levenshtein.d.ts +1 -0
  85. package/dist/core/shared/levenshtein.js +37 -0
  86. package/dist/core/shared/levenshtein.js.map +1 -0
  87. package/dist/core/store/paths.js +34 -1
  88. package/dist/core/store/paths.js.map +1 -1
  89. package/dist/core/store/settings.js +210 -1
  90. package/dist/core/store/settings.js.map +1 -1
  91. package/dist/core/telemetry/runtime.d.ts +1 -0
  92. package/dist/core/telemetry/runtime.js +102 -3
  93. package/dist/core/telemetry/runtime.js.map +1 -1
  94. package/dist/mcp/server.js +11 -2
  95. package/dist/mcp/server.js.map +1 -1
  96. package/dist/sdk/cli-contracts.d.ts +38 -17
  97. package/dist/sdk/cli-contracts.js +387 -35
  98. package/dist/sdk/cli-contracts.js.map +1 -1
  99. package/dist/sdk/index.d.ts +13 -1
  100. package/dist/sdk/index.js +9 -1
  101. package/dist/sdk/index.js.map +1 -1
  102. package/dist/types.d.ts +41 -0
  103. package/dist/types.js.map +1 -1
  104. package/docs/ARCHITECTURE.md +1 -1
  105. package/docs/CLAUDE_CODE_PLUGIN.md +39 -0
  106. package/docs/COMMANDS.md +14 -1
  107. package/docs/EXTENSIONS.md +782 -12
  108. package/docs/MIGRATION_CLI_SIMPLIFICATION.md +64 -0
  109. package/docs/QUICKSTART.md +10 -2
  110. package/docs/README.md +4 -6
  111. package/docs/SDK.md +445 -0
  112. package/docs/examples/ci/github-actions-pm-extension-gate.yml +53 -0
  113. package/docs/examples/ci/gitlab-ci-pm-extension-gate.yml +41 -0
  114. package/docs/examples/ci/jenkins-pm-extension-gate.Jenkinsfile +45 -0
  115. package/docs/examples/policy-restricted-extension/README.md +74 -0
  116. package/docs/examples/policy-restricted-extension/index.js +21 -0
  117. package/docs/examples/policy-restricted-extension/manifest.json +21 -0
  118. package/docs/examples/policy-restricted-extension/package.json +8 -0
  119. package/docs/examples/sdk-app-embedding/README.md +39 -0
  120. package/docs/examples/sdk-app-embedding/package.json +9 -0
  121. package/docs/examples/sdk-app-embedding/run-embedded-pm.mjs +61 -0
  122. package/docs/examples/sdk-contract-consumer/README.md +57 -0
  123. package/docs/examples/sdk-contract-consumer/inspect-contracts.mjs +47 -0
  124. package/docs/examples/sdk-contract-consumer/package.json +10 -0
  125. package/docs/examples/starter-extension/README.md +57 -42
  126. package/docs/examples/starter-extension/manifest.json +15 -0
  127. package/marketplace.json +3 -3
  128. package/package.json +5 -23
  129. package/packages/pm-beads/README.md +10 -0
  130. package/{.agents/pm → packages/pm-beads}/extensions/beads/index.js +24 -9
  131. package/packages/pm-beads/extensions/beads/index.ts +131 -0
  132. package/packages/pm-beads/package.json +17 -0
  133. package/packages/pm-todos/README.md +11 -0
  134. package/{.agents/pm → packages/pm-todos}/extensions/todos/index.js +24 -9
  135. package/packages/pm-todos/extensions/todos/index.ts +149 -0
  136. package/{.agents/pm → packages/pm-todos}/extensions/todos/runtime.js +1 -1
  137. package/{.agents/pm → packages/pm-todos}/extensions/todos/runtime.ts +1 -1
  138. package/packages/pm-todos/package.json +17 -0
  139. package/plugins/pm-cli-claude/.claude-plugin/plugin.json +2 -2
  140. package/plugins/pm-cli-claude/README.md +54 -14
  141. package/plugins/pm-cli-claude/agents/pm-delivery-chain.md +88 -0
  142. package/plugins/pm-cli-claude/agents/pm-triage-agent.md +83 -0
  143. package/plugins/pm-cli-claude/agents/pm-verification-agent.md +88 -0
  144. package/plugins/pm-cli-claude/hooks/session-start.mjs +35 -21
  145. package/.agents/pm/extensions/.managed-extensions.json +0 -42
  146. package/.agents/skills/HARNESS_COMPATIBILITY.md +0 -45
  147. package/.agents/skills/README.md +0 -21
  148. package/.agents/skills/pm-developer/SKILL.md +0 -73
  149. package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +0 -48
  150. package/.agents/skills/pm-developer/references/PROMPTS.md +0 -17
  151. package/.agents/skills/pm-extensions/SKILL.md +0 -57
  152. package/.agents/skills/pm-extensions/references/LIFECYCLE.md +0 -40
  153. package/.agents/skills/pm-extensions/references/TROUBLESHOOTING.md +0 -25
  154. package/.agents/skills/pm-sdk/SKILL.md +0 -50
  155. package/.agents/skills/pm-sdk/references/INTEGRATION_CHECKLIST.md +0 -31
  156. package/.agents/skills/pm-sdk/references/PROMPTS.md +0 -13
  157. package/.agents/skills/pm-user/SKILL.md +0 -59
  158. package/.agents/skills/pm-user/references/PROMPTS.md +0 -17
  159. package/.agents/skills/pm-user/references/WORKFLOWS.md +0 -35
  160. package/.pi/README.md +0 -26
  161. package/.pi/extensions/pm-cli/index.js +0 -147
  162. package/.pi/prompts/pm-workflow.md +0 -5
  163. package/.pi/skills/pm-native/SKILL.md +0 -40
  164. package/.pi/skills/pm-release/SKILL.md +0 -35
  165. package/dist/pi/native.d.ts +0 -5
  166. package/dist/pi/native.js +0 -183
  167. package/dist/pi/native.js.map +0 -1
  168. package/docs/PI_PACKAGE.md +0 -56
  169. /package/{.agents/pm → packages/pm-beads}/extensions/beads/manifest.json +0 -0
  170. /package/{.agents/pm → packages/pm-beads}/extensions/beads/runtime.js +0 -0
  171. /package/{.agents/pm → packages/pm-beads}/extensions/beads/runtime.ts +0 -0
  172. /package/{.agents/pm → packages/pm-todos}/extensions/todos/manifest.json +0 -0
@@ -1,19 +1,19 @@
1
1
  {
2
- "name": "pm-cli",
2
+ "name": "pm",
3
3
  "owner": {
4
4
  "name": "unbrained",
5
5
  "url": "https://github.com/unbraind/pm-cli"
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Official marketplace for pm CLI — native git-based project management for Claude Code and AI coding agents.",
9
- "version": "1.0.0"
9
+ "version": "1.3.0"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "pm-cli",
14
14
  "source": "./plugins/pm-cli-claude",
15
- "description": "Native pm CLI integration for Claude Code — 18 MCP tools, workflow skills, slash commands, session context injection, and a coordination subagent for git-based project management without leaving Claude Code.",
16
- "version": "1.0.0",
15
+ "description": "Native pm CLI integration for Claude Code — 18 MCP tools, 5 workflow skills, 14 slash commands, 3 subagents, hybrid TUI task tracking, session context injection, and coordination subagents for git-based project management without leaving Claude Code.",
16
+ "version": "1.3.0",
17
17
  "author": {
18
18
  "name": "unbrained",
19
19
  "url": "https://github.com/unbraind/pm-cli"
package/AGENTS.md CHANGED
@@ -321,120 +321,7 @@ Recover previous state:
321
321
  pm restore pm-a1b2 2026-02-17T11:15:03.120Z
322
322
  ```
323
323
 
324
- ## 9) Pi Tool Wrapper Usage
325
-
326
- The built-in Pi wrapper exposes one tool: `pm`.
327
- Reference implementation source lives at `.pi/extensions/pm-cli/index.ts` as a Pi agent extension module.
328
- `pm install` has been removed; install bundled managed runtime extensions via `pm extension --install beads|todos` (or explicit `.agents/pm/extensions/<name>` paths) when needed.
329
- Load the Pi wrapper in Pi with `pi -e ./.pi/extensions/pm-cli/index.ts` (or copy it into your Pi extensions directory).
330
- Use `action: "completion"` with `shell: "bash"|"zsh"|"fish"` to forward to `pm completion <shell>`.
331
- Use `action: "calendar"` for date-centric event views (`view`, `date`, `from`, `to`, `past`, `fullPeriod`, `type`, `tag`, `priority`, `status`, `assignee`, `sprint`, `release`, `limit`, `format`).
332
- Use `action: "aggregate"` for grouped decomposition checks (`groupBy`, `count`, `includeUnparented`, list-style filters).
333
- Use `action: "dedupe-audit"` for duplicate corpus checks (`mode`, `threshold`, `limit`, list-style filters).
334
- Use `action: "normalize"` for lifecycle metadata hygiene scans (`dryRun`) and explicit apply mode (`apply`) with list-style filter targeting.
335
- Use `action: "validate"` with optional check toggles (`checkMetadata`, `checkResolution`, `checkFiles`, `checkHistoryDrift`) and optional `scanMode` (`default|tracked-all`) for standalone audit workflows.
336
- Use `action: "extension-doctor"` for consolidated extension diagnostics with optional `scope` and `detail` (`summary|deep`).
337
- For `list*` wrapper actions, use projection/sort controls (`compact`, `fields`, `sort`, `order`) plus `includeBody` when body projection is needed.
338
- For `comments-audit`, use governance filters (`parent`, `tag`, `sprint`, `release`, `priority`) in addition to status/type/assignee filters.
339
- For `health`, use vector refresh controls (`checkOnly`, `noRefresh`, `refreshVectors`) while keeping strict flags available (`strictDirectories`, `strictExit`, `failOnWarn`).
340
- For `create` and `update`, use camelCase wrapper parameters for the canonical CLI scalar fields such as `parent`, `reviewer`, `risk`, `confidence`, `sprint`, `release`, `blockedBy`, `blockedReason`, `unblockNote`, `definitionOfReady`, `order`, `goal`, `objective`, `value`, `impact`, `outcome`, `whyNow`, `reporter`, `severity`, `environment`, `reproSteps`, `resolution`, `expectedResult`, `actualResult`, `affectedVersion`, `fixedVersion`, `component`, `regression`, and `customerImpact`; use `createMode` (`strict|progressive`) when staged creation is needed, `appendStable` for minimal-diff file-link appends, `allowAuditUpdate` for ownership-safe metadata-only non-owner updates, `allowAuditDepUpdate` for ownership-safe dependency-only non-owner updates, `allowAuditComment` for additive non-owner comment writes, repeatable `reminder` values for persistent reminders (`at=<iso|relative>,text=<text>`), and repeatable `typeOption` values for custom type metadata.
341
- For `contracts`, use projection controls (`flagsOnly`, `availabilityOnly`) when you need narrow machine-readable payloads; with `command` selected, contract output is command-scoped by default.
342
- For `completion`, use `eagerTags` only when embedding static tags in generated scripts is required; default generated scripts resolve tags lazily at runtime.
343
- For `activity`, use `id`, `op`, `author`, `from`, `to`, `limit`, and `stream` (`rows|ndjson|jsonl` or boolean true) for deterministic timeline filtering/export.
344
- For `test` and `test-all`, prefer explicit runtime parity/strictness parameters when needed: `pmContext` (`schema|tracker|auto`), `checkContext`, `autoPmContext`, `failOnContextMismatch`, `failOnSkipped`, and `requireAssertionsForPm`.
345
- For `gc`, use `dryRun` and repeatable `gcScope` (`index`, `embeddings`, `runtime`) for no-side-effect previews and targeted cleanup.
346
-
347
- ### Example: list open tasks
348
-
349
- ```json
350
- {
351
- "action": "list-open",
352
- "limit": 10
353
- }
354
- ```
355
-
356
- ### Example: create item
357
-
358
- ```json
359
- {
360
- "action": "create",
361
- "title": "Implement extension loader",
362
- "description": "Load global and project extensions with precedence.",
363
- "type": "Feature",
364
- "status": "open",
365
- "priority": 1,
366
- "tags": "extensions,core",
367
- "body": "",
368
- "deadline": "+14d",
369
- "estimate": 120,
370
- "acceptanceCriteria": "Loader applies deterministic precedence for core global and project extensions.",
371
- "author": "maintainer-agent",
372
- "message": "Create extension loader task",
373
- "assignee": "maintainer-agent",
374
- "parent": "pm-epic01",
375
- "reviewer": "maintainer-reviewer",
376
- "risk": "medium",
377
- "confidence": "high",
378
- "sprint": "maintainer-loop",
379
- "release": "v0.1",
380
- "blockedBy": "pm-arch-review",
381
- "blockedReason": "Awaiting architecture sign-off",
382
- "unblockNote": "Resume implementation once review notes are resolved",
383
- "reporter": "maintainer-agent",
384
- "severity": "medium",
385
- "environment": "cli",
386
- "reproSteps": "Create conflicting extension registrations across project/global scopes",
387
- "resolution": "Apply deterministic precedence in extension loader bootstrap",
388
- "expectedResult": "Loader applies project-over-global precedence deterministically",
389
- "actualResult": "Registration order currently varies by load path",
390
- "affectedVersion": "v0.1",
391
- "fixedVersion": "v0.2",
392
- "component": "extension-host",
393
- "regression": "false",
394
- "customerImpact": "Unpredictable extension behavior increases operator overhead",
395
- "definitionOfReady": "Extension loading behavior is clarified in docs.",
396
- "order": 1,
397
- "goal": "Release-hardening",
398
- "objective": "Ship deterministic extension loading",
399
- "value": "Makes extension behavior predictable for agents and humans",
400
- "impact": "Reduces configuration and precedence drift",
401
- "outcome": "Extension loader applies deterministic precedence",
402
- "whyNow": "Extension loading is foundational for the remaining roadmap",
403
- "dep": ["id=pm-epic01,kind=parent,author=maintainer-agent,created_at=now"],
404
- "comment": ["author=maintainer-agent,created_at=now,text=Why this task exists align extension load precedence behavior."],
405
- "note": ["author=maintainer-agent,created_at=now,text=Initial implementation plan wire loader in runtime bootstrap."],
406
- "learning": [],
407
- "linkedFile": ["path=src/core/extensions/loader.ts,scope=project,note=planned implementation file"],
408
- "linkedTest": ["command=node scripts/run-tests.mjs test,scope=project,timeout_seconds=240,note=sandbox-safe regression"],
409
- "doc": ["path=docs/ARCHITECTURE.md,scope=project,note=implementation reference"]
410
- }
411
- ```
412
-
413
- ### Example: append body update
414
-
415
- ```json
416
- {
417
- "action": "append",
418
- "id": "pm-a1b2",
419
- "body": "Implemented lock TTL and stale lock override."
420
- }
421
- ```
422
-
423
- Expected wrapper return shape:
424
-
425
- ```json
426
- {
427
- "content": [
428
- { "type": "text", "text": "..." }
429
- ],
430
- "details": {
431
- "action": "create",
432
- "item": {}
433
- }
434
- }
435
- ```
436
-
437
- ## 10) Multi-Agent Etiquette
324
+ ## 9) Multi-Agent Etiquette
438
325
 
439
326
  - Claim before heavy edits.
440
327
  - Release when blocked or context-switching.
@@ -442,7 +329,7 @@ Expected wrapper return shape:
442
329
  - Avoid silent force-claim unless policy allows and conflict is stale.
443
330
  - Keep item descriptions stable; append details in body/notes/comments.
444
331
 
445
- ## 11) Troubleshooting for Agents
332
+ ## 10) Troubleshooting for Agents
446
333
 
447
334
  Lock conflict:
448
335
 
@@ -467,7 +354,7 @@ Extension issues:
467
354
  - when debugging runtime behavior changes, inspect parser/preflight/service override collisions in health/profile diagnostics (last registration wins)
468
355
  - use SDK contracts from `@unbrained/pm-cli/sdk` (not internal `src/core/...` imports) for extension authoring and examples
469
356
 
470
- ## 12) Dogfood Logging Protocol (Required)
357
+ ## 11) Dogfood Logging Protocol (Required)
471
358
 
472
359
  From now on in this repository, all implementation work must be tracked through `pm` items and `pm` mutations.
473
360
 
package/CHANGELOG.md CHANGED
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2026.5.12] - 2026-05-12
11
+
12
+ ### Changed
13
+ - Added `pm install '*'` / `pm install all` to install all bundled first-party pm packages, including shell-expanded `pm install *`, and added typechecking for TypeScript-authored package sources.
14
+ - Added `pm upgrade` for package-first maintenance, including dry-run planning, CLI/SDK npm self-upgrade, managed package refresh from recorded sources, SDK/MCP action contracts, and docs/help coverage.
15
+ - Moved the Beads and Todo import/export bridges out of active project extension state so they are sourced from the first-party `packages/pm-beads` and `packages/pm-todos` package roots and installed on demand.
16
+
17
+ ## [2026.5.11] - 2026-05-11
18
+
19
+ ### Added
20
+ - Claude Code plugin v1.3.0: added `pm-triage-agent`, `pm-verification-agent`, and `pm-delivery-chain` subagents for full end-to-end pm workflow orchestration without leaving Claude Code.
21
+ - Claude Code plugin: registered `pm` as the canonical marketplace ID so the plugin installs via `/plugin install pm-cli@pm` (both `pm` and `pm-cli` marketplace IDs resolve to the same plugin).
22
+ - Claude Code plugin: rewrote session-start hook to use native `dist/pi/native.js` modules when available (repo checkout), falling back to `npx @unbrained/pm-cli` — no global `pm` CLI required.
23
+
10
24
  ## [2026.5.10] - 2026-05-10
11
25
 
12
26
  ### Changed
package/PRD.md CHANGED
@@ -43,9 +43,9 @@ Existing trackers either rely on hosted backends, store state in non-diff-friend
43
43
  - Provide safe mutation under concurrent access (claim/release + lock + atomic writes).
44
44
  - Default stdout to TOON; support `--json` parity for every command.
45
45
  - Provide extension architecture for commands, schema, rendering, import/export, search adapters, and hooks.
46
- - Ship bundled managed extension sources:
47
- - Beads import (`beads` alias, installed via `pm extension --install`)
48
- - todos.ts import/export (`todos` alias, installed via `pm extension --install`)
46
+ - Ship first-party installable package sources:
47
+ - Beads import (`packages/pm-beads`, installed via `pm install`)
48
+ - todos.ts import/export (`packages/pm-todos`, installed via `pm install`)
49
49
  - Pi agent extension wrapper source module
50
50
  - Provide optional semantic search with provider + vector-store adapters.
51
51
 
@@ -1327,7 +1327,7 @@ export interface ExtensionApi {
1327
1327
  - Mandatory migration resolution is deterministic: `status` equal to `"applied"` (case-insensitive) is treated as resolved; any other/missing status is unresolved.
1328
1328
  - Force-capable write commands may bypass the guard with explicit `--force`; write commands without `--force` remain blocked until blockers resolve.
1329
1329
 
1330
- ## 15) Bundled Managed Extensions Required in v1
1330
+ ## 15) First-Party Installable Packages Required in v1
1331
1331
 
1332
1332
  ### A) Beads import
1333
1333
 
@@ -1337,8 +1337,8 @@ Command:
1337
1337
 
1338
1338
  Current baseline status (release-hardening):
1339
1339
 
1340
- - Command is packaged in bundled managed extension source (`.agents/pm/extensions/beads`) using `activate(api)` and `api.registerCommand({ name, run })` for `beads import`.
1341
- - Command path is available only after extension install/activation in selected scope (`pm extension --install beads` or explicit path install).
1340
+ - Command is packaged in the first-party package root (`packages/pm-beads`) using `activate(api)` and `api.registerCommand({ name, run })` for `beads import`.
1341
+ - Command path is available only after package install/activation in selected scope (`pm install packages/pm-beads`, package aliases, or explicit package source install).
1342
1342
 
1343
1343
  Behavior:
1344
1344
 
@@ -1359,8 +1359,8 @@ Commands:
1359
1359
 
1360
1360
  Current baseline status (release-hardening):
1361
1361
 
1362
- - Commands are packaged in bundled managed extension source (`.agents/pm/extensions/todos`) using `activate(api)` and `api.registerCommand({ name, run })` for `todos import` and `todos export`.
1363
- - Command paths are available only after extension install/activation in selected scope (`pm extension --install todos` or explicit path install).
1362
+ - Commands are packaged in the first-party package root (`packages/pm-todos`) using `activate(api)` and `api.registerCommand({ name, run })` for `todos import` and `todos export`.
1363
+ - Command paths are available only after package install/activation in selected scope (`pm install packages/pm-todos`, package aliases, or explicit package source install).
1364
1364
 
1365
1365
  Behavior:
1366
1366
 
@@ -1711,10 +1711,10 @@ Definition of Done:
1711
1711
  Checklist:
1712
1712
 
1713
1713
  - [x] extension manifest loader + sandboxed execution boundary (deterministic manifest discovery, precedence, failure-isolated runtime loading, realpath/symlink-resolved entry containment enforcement, command-handler context snapshot isolation for `args`/`options`/`global`, per-hook context snapshot isolation, and dynamic extension command loose-option parsing hardening (null-prototype option maps + prototype-pollution key rejection) are implemented; broader command sandbox API surface is post-v0.1 roadmap)
1714
- - [x] hook lifecycle (extension `activate(api)` baseline with deterministic hook registration is implemented; registration now validates hook handlers as functions at activation time, per-hook context snapshot isolation prevents mutation leakage across hook callbacks and caller state, and `beforeCommand`/`afterCommand` command-lifecycle execution plus baseline read/write/index call-site wiring for core item-store reads/writes, create/restore item and history writes, settings read/write operations, history/activity history-directory scans and history-stream reads, health history-directory scans plus history-stream path dispatch, search item/linked reads, reindex flows, stats/health/gc command file-system paths (including `pm gc` onIndex dispatch with mode `gc` and deterministic cache-target totals), lock file read/write/unlink operations, init directory bootstrap ensure-write dispatch, and bundled managed beads/todos import-export source/item/history file operations are implemented)
1714
+ - [x] hook lifecycle (extension `activate(api)` baseline with deterministic hook registration is implemented; registration now validates hook handlers as functions at activation time, per-hook context snapshot isolation prevents mutation leakage across hook callbacks and caller state, and `beforeCommand`/`afterCommand` command-lifecycle execution plus baseline read/write/index call-site wiring for core item-store reads/writes, create/restore item and history writes, settings read/write operations, history/activity history-directory scans and history-stream reads, health history-directory scans plus history-stream path dispatch, search item/linked reads, reindex flows, stats/health/gc command file-system paths (including `pm gc` onIndex dispatch with mode `gc` and deterministic cache-target totals), lock file read/write/unlink operations, init directory bootstrap ensure-write dispatch, and first-party Beads/Todos package source/item/history file operations are implemented)
1715
1715
  - [x] renderer and command extension points (deterministic core-command override + renderer override registration/dispatch is implemented with failure containment, extension command handlers for declared command paths including dynamically surfaced non-core paths are implemented, dynamic command help now surfaces `registerFlags` metadata deterministically, deep snapshot isolation for override/renderer result contexts is implemented, and override/renderer execution now includes cloned command `args`/`options`/`global` snapshots plus `pm_root` metadata for contextual deterministic extension output behavior)
1716
- - [x] bundled managed beads import extension (bundled source packaging in `.agents/pm/extensions/beads`, install-only command surfacing through `pm extension`, Beads JSONL field mapping, deterministic defaults, `op: "import"` history entries, and parity polish implemented)
1717
- - [x] bundled managed todos import/export extension (bundled source packaging in `.agents/pm/extensions/todos`, install-only command surfacing through `pm extension`, todos markdown round-trip, canonical optional metadata preservation including planning/workflow and issue fields, hierarchical ID preservation, and `med` alias normalization implemented)
1716
+ - [x] first-party Beads import package (`packages/pm-beads`) with install-only command surfacing through `pm install`, Beads JSONL field mapping, deterministic defaults, `op: "import"` history entries, and parity polish implemented)
1717
+ - [x] first-party Todos import/export package (`packages/pm-todos`) with install-only command surfacing through `pm install`, todos markdown round-trip, canonical optional metadata preservation including planning/workflow and issue fields, hierarchical ID preservation, and `med` alias normalization implemented)
1718
1718
  - [x] Pi tool wrapper extension source module (Pi agent extension module at `.pi/extensions/pm-cli/index.ts` with full v0.1 action dispatch parity, including `completion` + `shell` mapping, camelCase parameter surface for all canonical scalar metadata, explicit empty-string passthrough, numeric-flag stringification, claim/release parity, packaged CLI fallback, and distribution packaging polish implemented)
1719
1719
 
1720
1720
  Definition of Done:
package/README.md CHANGED
@@ -16,7 +16,7 @@
16
16
  | Command families and examples | [Command Reference](docs/COMMANDS.md) |
17
17
  | Settings, storage, search, and output | [Configuration](docs/CONFIGURATION.md) |
18
18
  | Safe test execution and linked tests | [Testing](docs/TESTING.md) |
19
- | Extension authoring | [Extensions](docs/EXTENSIONS.md) and [SDK](docs/SDK.md) |
19
+ | Package and extension authoring | [Packages and Extensions](docs/EXTENSIONS.md) and [SDK](docs/SDK.md) |
20
20
  | Pi native package | [Pi Package](docs/PI_PACKAGE.md) |
21
21
  | Codex native integration | [Codex Plugin](docs/CODEX_PLUGIN.md) |
22
22
  | Maintainer release process (daily auto-release + local parity) | [Releasing](docs/RELEASING.md) |
@@ -51,13 +51,31 @@ Project-local invocation also works:
51
51
  npx @unbrained/pm-cli --help
52
52
  ```
53
53
 
54
+ For Claude Code, install the native plugin (no `pm` CLI required):
55
+
56
+ ```
57
+ /plugin install pm-cli@pm
58
+ ```
59
+
60
+ This registers 18 MCP tools, 5 workflow skills, 14 slash commands, 3 subagents, hybrid TUI tracking, and a session-start context hook — all without shelling out to the `pm` CLI.
61
+
54
62
  For Pi, install the native package integration after publish:
55
63
 
56
64
  ```bash
57
65
  pi install npm:@unbrained/pm-cli
58
66
  ```
59
67
 
60
- This registers a native `pm` tool, Pi skills, and prompt templates without requiring Pi to run the `pm` shell command.
68
+ This registers a native `pm` tool, custom TUI panels/renderers (`/pm-board`, `/pm-item`, `/pm-history`), Pi skills, prompt templates, and optional pi-subagents setup without requiring Pi to run the `pm` shell command.
69
+
70
+ `pm` packages use the same package-first vocabulary:
71
+
72
+ ```bash
73
+ pm install ./my-package
74
+ pm package manage --project
75
+ pm package doctor --detail summary
76
+ ```
77
+
78
+ The legacy `pm extension ...` command remains available for existing automation.
61
79
 
62
80
  ## 60 Second Example
63
81
 
@@ -0,0 +1,5 @@
1
+ export declare function normalizeLongFlag(flag: string): string;
2
+ export declare function normalizeLongOptionFlag(token: string): string | undefined;
3
+ export declare function extractProvidedOptionFlags(argv: string[]): string[];
4
+ export declare function quoteCommandArg(arg: string): string;
5
+ export declare function renderPmCommand(argv: string[]): string;
@@ -0,0 +1,34 @@
1
+ export function normalizeLongFlag(flag) {
2
+ return `--${flag
3
+ .replace(/^--?/, "")
4
+ .replace(/_/g, "-")
5
+ .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
6
+ .toLowerCase()}`;
7
+ }
8
+ export function normalizeLongOptionFlag(token) {
9
+ if (!token.startsWith("--")) {
10
+ return undefined;
11
+ }
12
+ const key = token.includes("=") ? token.slice(0, token.indexOf("=")) : token;
13
+ return normalizeLongFlag(key);
14
+ }
15
+ export function extractProvidedOptionFlags(argv) {
16
+ const provided = new Set();
17
+ for (const token of argv) {
18
+ const normalized = normalizeLongOptionFlag(token);
19
+ if (normalized) {
20
+ provided.add(normalized);
21
+ }
22
+ }
23
+ return [...provided].sort((left, right) => left.localeCompare(right));
24
+ }
25
+ export function quoteCommandArg(arg) {
26
+ if (/^[A-Za-z0-9._:/@=-]+$/.test(arg)) {
27
+ return arg;
28
+ }
29
+ return `"${arg.replace(/(["\\$`])/g, "\\$1")}"`;
30
+ }
31
+ export function renderPmCommand(argv) {
32
+ return `pm ${argv.map((token) => quoteCommandArg(token)).join(" ")}`;
33
+ }
34
+ //# sourceMappingURL=argv-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"argv-utils.js","sourceRoot":"/","sources":["cli/argv-utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,KAAK,IAAI;SACb,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;SACnB,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;SAClB,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,WAAW,EAAE,EAAE,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACnD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7E,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,IAAc;IACvD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,UAAU,EAAE,CAAC;YACf,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACvE,CAAC","sourcesContent":["export function normalizeLongFlag(flag: string): string {\n return `--${flag\n .replace(/^--?/, \"\")\n .replace(/_/g, \"-\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .toLowerCase()}`;\n}\n\nexport function normalizeLongOptionFlag(token: string): string | undefined {\n if (!token.startsWith(\"--\")) {\n return undefined;\n }\n const key = token.includes(\"=\") ? token.slice(0, token.indexOf(\"=\")) : token;\n return normalizeLongFlag(key);\n}\n\nexport function extractProvidedOptionFlags(argv: string[]): string[] {\n const provided = new Set<string>();\n for (const token of argv) {\n const normalized = normalizeLongOptionFlag(token);\n if (normalized) {\n provided.add(normalized);\n }\n }\n return [...provided].sort((left, right) => left.localeCompare(right));\n}\n\nexport function quoteCommandArg(arg: string): string {\n if (/^[A-Za-z0-9._:/@=-]+$/.test(arg)) {\n return arg;\n }\n return `\"${arg.replace(/([\"\\\\$`])/g, \"\\\\$1\")}\"`;\n}\n\nexport function renderPmCommand(argv: string[]): string {\n return `pm ${argv.map((token) => quoteCommandArg(token)).join(\" \")}`;\n}\n"]}
@@ -15,4 +15,19 @@ export declare function parseBootstrapHelpRequest(argv: string[]): BootstrapHelp
15
15
  export declare function parseBootstrapCommandName(argv: string[]): string | undefined;
16
16
  export declare function applyBootstrapPagerPolicy(argv: string[]): void;
17
17
  export declare function normalizeLegacyExtensionActionSyntax(argv: string[]): string[];
18
+ type BootstrapNormalizationReason = "legacy_extension_action" | "flag_alias" | "flag_typo" | "bare_key_value";
19
+ type BootstrapNormalizationConfidence = "high" | "medium";
20
+ export interface BootstrapNormalizationEvent {
21
+ from: string;
22
+ to: string[];
23
+ reason: BootstrapNormalizationReason;
24
+ confidence: BootstrapNormalizationConfidence;
25
+ }
26
+ export interface BootstrapInvocationNormalizationResult {
27
+ argv: string[];
28
+ commandName: string | undefined;
29
+ trace: BootstrapNormalizationEvent[];
30
+ }
31
+ export declare function normalizeBootstrapInvocation(argv: string[]): BootstrapInvocationNormalizationResult;
18
32
  export declare function parseBootstrapTypeValue(argv: string[]): string | undefined;
33
+ export {};
@@ -1,3 +1,5 @@
1
+ import { resolveSubcommandFlagContractsForCommand } from "../sdk/cli-contracts.js";
2
+ import { levenshteinDistanceWithinLimit } from "../core/shared/levenshtein.js";
1
3
  function parseBootstrapPathToken(token, next) {
2
4
  if (token === "--path") {
3
5
  if (typeof next === "string" && next.length > 0) {
@@ -220,6 +222,215 @@ export function normalizeLegacyExtensionActionSyntax(argv) {
220
222
  }
221
223
  return [...argv.slice(0, extensionIndex + 1), forcedActionFlag, ...argv.slice(extensionIndex + 2)];
222
224
  }
225
+ function normalizeFlagKeyToken(raw) {
226
+ const withoutPrefix = raw.replace(/^--?/, "");
227
+ return withoutPrefix
228
+ .replace(/_/g, "-")
229
+ .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
230
+ .toLowerCase();
231
+ }
232
+ function toComparableFlagKey(raw) {
233
+ return normalizeFlagKeyToken(raw).replace(/-/g, "");
234
+ }
235
+ function markUnambiguousFlag(map, key, canonicalFlag) {
236
+ const existing = map.get(key);
237
+ if (existing === undefined) {
238
+ map.set(key, canonicalFlag);
239
+ return;
240
+ }
241
+ if (existing !== canonicalFlag) {
242
+ map.set(key, null);
243
+ }
244
+ }
245
+ function collectLongFlagCandidates(contract) {
246
+ const candidates = [];
247
+ const pushLongFlag = (value) => {
248
+ if (typeof value !== "string") {
249
+ return;
250
+ }
251
+ if (!value.startsWith("--")) {
252
+ return;
253
+ }
254
+ candidates.push(value);
255
+ };
256
+ pushLongFlag(contract.flag);
257
+ for (const alias of contract.aliases ?? []) {
258
+ pushLongFlag(alias);
259
+ }
260
+ return candidates;
261
+ }
262
+ function buildFlagLookup(commandName) {
263
+ const contracts = resolveSubcommandFlagContractsForCommand(commandName);
264
+ const canonicalByNormalized = new Map();
265
+ const canonicalByCompact = new Map();
266
+ const canonicalComparablesMap = new Map();
267
+ for (const contract of contracts) {
268
+ const longCandidates = collectLongFlagCandidates(contract);
269
+ if (longCandidates.length === 0) {
270
+ continue;
271
+ }
272
+ const canonicalFlag = `--${normalizeFlagKeyToken(longCandidates[0])}`;
273
+ for (const candidate of longCandidates) {
274
+ markUnambiguousFlag(canonicalByNormalized, normalizeFlagKeyToken(candidate), canonicalFlag);
275
+ markUnambiguousFlag(canonicalByCompact, toComparableFlagKey(candidate), canonicalFlag);
276
+ }
277
+ const comparable = toComparableFlagKey(canonicalFlag);
278
+ if (!canonicalComparablesMap.has(canonicalFlag)) {
279
+ canonicalComparablesMap.set(canonicalFlag, comparable);
280
+ }
281
+ }
282
+ return {
283
+ canonicalByNormalized,
284
+ canonicalByCompact,
285
+ canonicalComparables: [...canonicalComparablesMap.entries()].map(([canonicalFlag, comparable]) => ({
286
+ canonicalFlag,
287
+ comparable,
288
+ })),
289
+ };
290
+ }
291
+ function resolveCanonicalFlag(rawKey, lookup) {
292
+ const normalizedKey = normalizeFlagKeyToken(rawKey);
293
+ const direct = lookup.canonicalByNormalized.get(normalizedKey);
294
+ if (typeof direct === "string") {
295
+ return {
296
+ flag: direct,
297
+ reason: "flag_alias",
298
+ confidence: "high",
299
+ };
300
+ }
301
+ const comparableKey = normalizedKey.replace(/-/g, "");
302
+ const compactMatch = lookup.canonicalByCompact.get(comparableKey);
303
+ if (typeof compactMatch === "string") {
304
+ return {
305
+ flag: compactMatch,
306
+ reason: "flag_alias",
307
+ confidence: "high",
308
+ };
309
+ }
310
+ const maxDistance = comparableKey.length >= 8 ? 2 : 1;
311
+ let bestDistance = Number.POSITIVE_INFINITY;
312
+ let bestFlag;
313
+ let tied = false;
314
+ for (const candidate of lookup.canonicalComparables) {
315
+ const distance = levenshteinDistanceWithinLimit(comparableKey, candidate.comparable, maxDistance);
316
+ if (distance === null) {
317
+ continue;
318
+ }
319
+ if (distance < bestDistance) {
320
+ bestDistance = distance;
321
+ bestFlag = candidate.canonicalFlag;
322
+ tied = false;
323
+ continue;
324
+ }
325
+ if (distance === bestDistance && bestFlag !== candidate.canonicalFlag) {
326
+ tied = true;
327
+ }
328
+ }
329
+ if (!bestFlag || tied || !Number.isFinite(bestDistance) || bestDistance <= 0) {
330
+ return null;
331
+ }
332
+ return {
333
+ flag: bestFlag,
334
+ reason: "flag_typo",
335
+ confidence: bestDistance >= 2 ? "medium" : "high",
336
+ };
337
+ }
338
+ function parseBareKeyValueToken(token) {
339
+ if (token.includes("://")) {
340
+ return null;
341
+ }
342
+ const match = token.match(/^([A-Za-z][A-Za-z0-9_-]{1,63})([:=])(.*)$/);
343
+ if (!match) {
344
+ return null;
345
+ }
346
+ const key = match[1];
347
+ const value = match[3];
348
+ if (value.length === 0) {
349
+ return null;
350
+ }
351
+ return {
352
+ key,
353
+ value,
354
+ };
355
+ }
356
+ function normalizeLongOptionToken(token, lookup) {
357
+ if (!token.startsWith("--")) {
358
+ return { tokens: [token] };
359
+ }
360
+ const equalsIndex = token.indexOf("=");
361
+ const key = equalsIndex >= 0 ? token.slice(0, equalsIndex) : token;
362
+ const inlineValue = equalsIndex >= 0 ? token.slice(equalsIndex + 1) : undefined;
363
+ const resolution = resolveCanonicalFlag(key, lookup);
364
+ if (!resolution) {
365
+ return { tokens: [token] };
366
+ }
367
+ const normalizedToken = inlineValue === undefined ? resolution.flag : `${resolution.flag}=${inlineValue}`;
368
+ if (normalizedToken === token) {
369
+ return { tokens: [token] };
370
+ }
371
+ return {
372
+ tokens: [normalizedToken],
373
+ event: {
374
+ from: token,
375
+ to: [normalizedToken],
376
+ reason: resolution.reason,
377
+ confidence: resolution.confidence,
378
+ },
379
+ };
380
+ }
381
+ export function normalizeBootstrapInvocation(argv) {
382
+ const trace = [];
383
+ const legacyNormalized = normalizeLegacyExtensionActionSyntax(argv);
384
+ if (legacyNormalized.length !== argv.length || legacyNormalized.some((token, index) => token !== argv[index])) {
385
+ trace.push({
386
+ from: argv.join(" "),
387
+ to: [...legacyNormalized],
388
+ reason: "legacy_extension_action",
389
+ confidence: "high",
390
+ });
391
+ }
392
+ const commandName = parseBootstrapCommandName(legacyNormalized);
393
+ const lookup = buildFlagLookup(commandName);
394
+ const normalizedArgv = [];
395
+ for (let index = 0; index < legacyNormalized.length; index += 1) {
396
+ const token = legacyNormalized[index];
397
+ if (token === "--") {
398
+ normalizedArgv.push(...legacyNormalized.slice(index));
399
+ break;
400
+ }
401
+ const previous = normalizedArgv[normalizedArgv.length - 1];
402
+ if (token.startsWith("--")) {
403
+ const normalizedToken = normalizeLongOptionToken(token, lookup);
404
+ normalizedArgv.push(...normalizedToken.tokens);
405
+ if (normalizedToken.event) {
406
+ trace.push(normalizedToken.event);
407
+ }
408
+ continue;
409
+ }
410
+ const bareKeyValue = parseBareKeyValueToken(token);
411
+ if (bareKeyValue &&
412
+ !(typeof previous === "string" && previous.startsWith("-"))) {
413
+ const resolution = resolveCanonicalFlag(bareKeyValue.key, lookup);
414
+ if (resolution) {
415
+ const replacement = [resolution.flag, bareKeyValue.value];
416
+ normalizedArgv.push(...replacement);
417
+ trace.push({
418
+ from: token,
419
+ to: replacement,
420
+ reason: "bare_key_value",
421
+ confidence: resolution.confidence,
422
+ });
423
+ continue;
424
+ }
425
+ }
426
+ normalizedArgv.push(token);
427
+ }
428
+ return {
429
+ argv: normalizedArgv,
430
+ commandName,
431
+ trace,
432
+ };
433
+ }
223
434
  export function parseBootstrapTypeValue(argv) {
224
435
  for (let index = 0; index < argv.length; index += 1) {
225
436
  const token = argv[index];