@unbrained/pm-cli 2026.5.6 → 2026.5.11

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 (268) hide show
  1. package/.agents/pm/extensions/.managed-extensions.json +2 -2
  2. package/.agents/pm/extensions/beads/runtime.js +4 -4
  3. package/.agents/pm/extensions/beads/runtime.ts +5 -5
  4. package/.agents/pm/extensions/todos/runtime.js +7 -7
  5. package/.agents/pm/extensions/todos/runtime.ts +10 -10
  6. package/.agents/skills/HARNESS_COMPATIBILITY.md +45 -0
  7. package/.agents/skills/README.md +21 -0
  8. package/.agents/skills/pm-developer/SKILL.md +73 -0
  9. package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +48 -0
  10. package/.agents/skills/pm-developer/references/PROMPTS.md +17 -0
  11. package/.agents/skills/pm-extensions/SKILL.md +57 -0
  12. package/.agents/skills/pm-extensions/references/LIFECYCLE.md +40 -0
  13. package/.agents/skills/pm-extensions/references/TROUBLESHOOTING.md +25 -0
  14. package/.agents/skills/pm-sdk/SKILL.md +50 -0
  15. package/.agents/skills/pm-sdk/references/INTEGRATION_CHECKLIST.md +31 -0
  16. package/.agents/skills/pm-sdk/references/PROMPTS.md +13 -0
  17. package/.agents/skills/pm-user/SKILL.md +59 -0
  18. package/.agents/skills/pm-user/references/PROMPTS.md +17 -0
  19. package/.agents/skills/pm-user/references/WORKFLOWS.md +35 -0
  20. package/.claude-plugin/marketplace.json +38 -0
  21. package/.pi/README.md +35 -0
  22. package/.pi/agents/pm-triage-agent.md +19 -0
  23. package/.pi/agents/pm-verification-agent.md +21 -0
  24. package/.pi/chains/pm-native-delivery.chain.md +11 -0
  25. package/.pi/extensions/pm-cli/index.js +387 -0
  26. package/.pi/prompts/pm-workflow.md +5 -0
  27. package/.pi/skills/pm-native/SKILL.md +44 -0
  28. package/.pi/skills/pm-release/SKILL.md +35 -0
  29. package/AGENTS.md +1 -1
  30. package/CHANGELOG.md +13 -0
  31. package/PRD.md +16 -16
  32. package/README.md +30 -4
  33. package/dist/cli/argv-utils.d.ts +5 -0
  34. package/dist/cli/argv-utils.js +34 -0
  35. package/dist/cli/argv-utils.js.map +1 -0
  36. package/dist/cli/bootstrap-args.d.ts +15 -0
  37. package/dist/cli/bootstrap-args.js +211 -0
  38. package/dist/cli/bootstrap-args.js.map +1 -1
  39. package/dist/cli/commander-usage.js +109 -3
  40. package/dist/cli/commander-usage.js.map +1 -1
  41. package/dist/cli/commands/claim.js +6 -6
  42. package/dist/cli/commands/claim.js.map +1 -1
  43. package/dist/cli/commands/close.js +9 -9
  44. package/dist/cli/commands/close.js.map +1 -1
  45. package/dist/cli/commands/comments.d.ts +2 -0
  46. package/dist/cli/commands/comments.js +57 -8
  47. package/dist/cli/commands/comments.js.map +1 -1
  48. package/dist/cli/commands/completion.js +40 -7
  49. package/dist/cli/commands/completion.js.map +1 -1
  50. package/dist/cli/commands/config.js +6 -3
  51. package/dist/cli/commands/config.js.map +1 -1
  52. package/dist/cli/commands/contracts.d.ts +19 -0
  53. package/dist/cli/commands/contracts.js +36 -1
  54. package/dist/cli/commands/contracts.js.map +1 -1
  55. package/dist/cli/commands/create.d.ts +2 -2
  56. package/dist/cli/commands/create.js +116 -55
  57. package/dist/cli/commands/create.js.map +1 -1
  58. package/dist/cli/commands/docs.js +13 -6
  59. package/dist/cli/commands/docs.js.map +1 -1
  60. package/dist/cli/commands/extension.d.ts +3 -1
  61. package/dist/cli/commands/extension.js +174 -2
  62. package/dist/cli/commands/extension.js.map +1 -1
  63. package/dist/cli/commands/files.js +19 -12
  64. package/dist/cli/commands/files.js.map +1 -1
  65. package/dist/cli/commands/get.js +5 -5
  66. package/dist/cli/commands/get.js.map +1 -1
  67. package/dist/cli/commands/guide.d.ts +55 -0
  68. package/dist/cli/commands/guide.js +260 -0
  69. package/dist/cli/commands/guide.js.map +1 -0
  70. package/dist/cli/commands/health.js +1 -1
  71. package/dist/cli/commands/health.js.map +1 -1
  72. package/dist/cli/commands/history.js +30 -10
  73. package/dist/cli/commands/history.js.map +1 -1
  74. package/dist/cli/commands/index.d.ts +1 -0
  75. package/dist/cli/commands/index.js +1 -0
  76. package/dist/cli/commands/index.js.map +1 -1
  77. package/dist/cli/commands/init.d.ts +2 -0
  78. package/dist/cli/commands/init.js +21 -1
  79. package/dist/cli/commands/init.js.map +1 -1
  80. package/dist/cli/commands/learnings.js +3 -3
  81. package/dist/cli/commands/learnings.js.map +1 -1
  82. package/dist/cli/commands/metadata-normalizers.d.ts +4 -0
  83. package/dist/cli/commands/metadata-normalizers.js +37 -0
  84. package/dist/cli/commands/metadata-normalizers.js.map +1 -0
  85. package/dist/cli/commands/notes.js +3 -3
  86. package/dist/cli/commands/notes.js.map +1 -1
  87. package/dist/cli/commands/reindex.js +180 -156
  88. package/dist/cli/commands/reindex.js.map +1 -1
  89. package/dist/cli/commands/restore.d.ts +2 -2
  90. package/dist/cli/commands/restore.js +44 -24
  91. package/dist/cli/commands/restore.js.map +1 -1
  92. package/dist/cli/commands/search.d.ts +2 -0
  93. package/dist/cli/commands/search.js +45 -26
  94. package/dist/cli/commands/search.js.map +1 -1
  95. package/dist/cli/commands/test-all.d.ts +2 -0
  96. package/dist/cli/commands/test-all.js +2 -0
  97. package/dist/cli/commands/test-all.js.map +1 -1
  98. package/dist/cli/commands/test.d.ts +1 -0
  99. package/dist/cli/commands/test.js +13 -5
  100. package/dist/cli/commands/test.js.map +1 -1
  101. package/dist/cli/commands/update.js +188 -157
  102. package/dist/cli/commands/update.js.map +1 -1
  103. package/dist/cli/commands/validate.js +1 -1
  104. package/dist/cli/commands/validate.js.map +1 -1
  105. package/dist/cli/error-guidance.d.ts +9 -1
  106. package/dist/cli/error-guidance.js +147 -6
  107. package/dist/cli/error-guidance.js.map +1 -1
  108. package/dist/cli/guide-topics.d.ts +25 -0
  109. package/dist/cli/guide-topics.js +283 -0
  110. package/dist/cli/guide-topics.js.map +1 -0
  111. package/dist/cli/help-content.js +25 -1
  112. package/dist/cli/help-content.js.map +1 -1
  113. package/dist/cli/help-json-payload.js +11 -1
  114. package/dist/cli/help-json-payload.js.map +1 -1
  115. package/dist/cli/main.js +69 -6
  116. package/dist/cli/main.js.map +1 -1
  117. package/dist/cli/register-list-query.js +38 -1
  118. package/dist/cli/register-list-query.js.map +1 -1
  119. package/dist/cli/register-mutation.js +17 -4
  120. package/dist/cli/register-mutation.js.map +1 -1
  121. package/dist/cli/register-setup.js +15 -1
  122. package/dist/cli/register-setup.js.map +1 -1
  123. package/dist/cli/telemetry-flush.d.ts +2 -0
  124. package/dist/cli/telemetry-flush.js +4 -0
  125. package/dist/cli/telemetry-flush.js.map +1 -0
  126. package/dist/cli.js +1 -2
  127. package/dist/cli.js.map +1 -1
  128. package/dist/core/extensions/extension-types.d.ts +72 -0
  129. package/dist/core/extensions/extension-types.js +24 -0
  130. package/dist/core/extensions/extension-types.js.map +1 -1
  131. package/dist/core/extensions/loader.d.ts +1 -0
  132. package/dist/core/extensions/loader.js +766 -7
  133. package/dist/core/extensions/loader.js.map +1 -1
  134. package/dist/core/history/history.js +32 -11
  135. package/dist/core/history/history.js.map +1 -1
  136. package/dist/core/item/item-format.d.ts +2 -2
  137. package/dist/core/item/item-format.js +16 -16
  138. package/dist/core/item/item-format.js.map +1 -1
  139. package/dist/core/lock/lock.js +2 -0
  140. package/dist/core/lock/lock.js.map +1 -1
  141. package/dist/core/schema/runtime-field-filters.js +1 -1
  142. package/dist/core/schema/runtime-field-filters.js.map +1 -1
  143. package/dist/core/schema/runtime-field-values.js +2 -2
  144. package/dist/core/schema/runtime-field-values.js.map +1 -1
  145. package/dist/core/schema/runtime-schema.d.ts +1 -1
  146. package/dist/core/schema/runtime-schema.js +3 -3
  147. package/dist/core/schema/runtime-schema.js.map +1 -1
  148. package/dist/core/search/cache.js +7 -21
  149. package/dist/core/search/cache.js.map +1 -1
  150. package/dist/core/search/corpus.d.ts +13 -0
  151. package/dist/core/search/corpus.js +74 -0
  152. package/dist/core/search/corpus.js.map +1 -0
  153. package/dist/core/search/embedding-batches.js +90 -30
  154. package/dist/core/search/embedding-batches.js.map +1 -1
  155. package/dist/core/sentry/instrument.d.ts +18 -1
  156. package/dist/core/sentry/instrument.js +128 -12
  157. package/dist/core/sentry/instrument.js.map +1 -1
  158. package/dist/core/shared/constants.d.ts +1 -1
  159. package/dist/core/shared/constants.js +21 -1
  160. package/dist/core/shared/constants.js.map +1 -1
  161. package/dist/core/shared/errors.d.ts +8 -0
  162. package/dist/core/shared/errors.js.map +1 -1
  163. package/dist/core/shared/levenshtein.d.ts +1 -0
  164. package/dist/core/shared/levenshtein.js +37 -0
  165. package/dist/core/shared/levenshtein.js.map +1 -0
  166. package/dist/core/store/front-matter-cache.d.ts +1 -1
  167. package/dist/core/store/front-matter-cache.js +13 -13
  168. package/dist/core/store/front-matter-cache.js.map +1 -1
  169. package/dist/core/store/item-format-migration.js +5 -2
  170. package/dist/core/store/item-format-migration.js.map +1 -1
  171. package/dist/core/store/item-store.js +16 -15
  172. package/dist/core/store/item-store.js.map +1 -1
  173. package/dist/core/store/paths.js +35 -2
  174. package/dist/core/store/paths.js.map +1 -1
  175. package/dist/core/store/settings.js +216 -2
  176. package/dist/core/store/settings.js.map +1 -1
  177. package/dist/core/telemetry/runtime.d.ts +1 -0
  178. package/dist/core/telemetry/runtime.js +102 -3
  179. package/dist/core/telemetry/runtime.js.map +1 -1
  180. package/dist/core/test/item-test-run-tracking.js +2 -2
  181. package/dist/core/test/item-test-run-tracking.js.map +1 -1
  182. package/dist/mcp/server.d.ts +2 -0
  183. package/dist/mcp/server.js +407 -0
  184. package/dist/mcp/server.js.map +1 -0
  185. package/dist/pi/native.d.ts +5 -0
  186. package/dist/pi/native.js +236 -0
  187. package/dist/pi/native.js.map +1 -0
  188. package/dist/sdk/cli-contracts.d.ts +24 -2
  189. package/dist/sdk/cli-contracts.js +317 -2
  190. package/dist/sdk/cli-contracts.js.map +1 -1
  191. package/dist/sdk/index.d.ts +12 -1
  192. package/dist/sdk/index.js +8 -1
  193. package/dist/sdk/index.js.map +1 -1
  194. package/dist/types.d.ts +51 -2
  195. package/dist/types.js.map +1 -1
  196. package/docs/AGENT_GUIDE.md +15 -0
  197. package/docs/ARCHITECTURE.md +2 -2
  198. package/docs/CLAUDE_CODE_PLUGIN.md +225 -0
  199. package/docs/CODEX_PLUGIN.md +33 -0
  200. package/docs/COMMANDS.md +6 -2
  201. package/docs/CONFIGURATION.md +2 -8
  202. package/docs/EXTENSIONS.md +688 -0
  203. package/docs/MIGRATION_CLI_SIMPLIFICATION.md +64 -0
  204. package/docs/PI_PACKAGE.md +141 -0
  205. package/docs/QUICKSTART.md +1 -0
  206. package/docs/README.md +30 -1
  207. package/docs/RELEASING.md +4 -2
  208. package/docs/SDK.md +444 -2
  209. package/docs/examples/ci/github-actions-pm-extension-gate.yml +53 -0
  210. package/docs/examples/ci/gitlab-ci-pm-extension-gate.yml +41 -0
  211. package/docs/examples/ci/jenkins-pm-extension-gate.Jenkinsfile +45 -0
  212. package/docs/examples/policy-restricted-extension/README.md +74 -0
  213. package/docs/examples/policy-restricted-extension/index.js +21 -0
  214. package/docs/examples/policy-restricted-extension/manifest.json +21 -0
  215. package/docs/examples/policy-restricted-extension/package.json +8 -0
  216. package/docs/examples/sdk-app-embedding/README.md +39 -0
  217. package/docs/examples/sdk-app-embedding/package.json +9 -0
  218. package/docs/examples/sdk-app-embedding/run-embedded-pm.mjs +61 -0
  219. package/docs/examples/sdk-contract-consumer/README.md +57 -0
  220. package/docs/examples/sdk-contract-consumer/inspect-contracts.mjs +47 -0
  221. package/docs/examples/sdk-contract-consumer/package.json +10 -0
  222. package/docs/examples/starter-extension/README.md +57 -42
  223. package/docs/examples/starter-extension/manifest.json +15 -0
  224. package/marketplace.json +34 -0
  225. package/package.json +38 -4
  226. package/plugins/pm-cli-claude/.claude-plugin/plugin.json +23 -0
  227. package/plugins/pm-cli-claude/.mcp.json +12 -0
  228. package/plugins/pm-cli-claude/README.md +225 -0
  229. package/plugins/pm-cli-claude/agents/pm-coordinator.md +48 -0
  230. package/plugins/pm-cli-claude/agents/pm-delivery-chain.md +88 -0
  231. package/plugins/pm-cli-claude/agents/pm-triage-agent.md +83 -0
  232. package/plugins/pm-cli-claude/agents/pm-verification-agent.md +88 -0
  233. package/plugins/pm-cli-claude/commands/pm-audit.md +39 -0
  234. package/plugins/pm-cli-claude/commands/pm-calendar.md +41 -0
  235. package/plugins/pm-cli-claude/commands/pm-close-task.md +20 -0
  236. package/plugins/pm-cli-claude/commands/pm-developer.md +38 -0
  237. package/plugins/pm-cli-claude/commands/pm-init.md +44 -0
  238. package/plugins/pm-cli-claude/commands/pm-list.md +39 -0
  239. package/plugins/pm-cli-claude/commands/pm-new.md +36 -0
  240. package/plugins/pm-cli-claude/commands/pm-planner.md +51 -0
  241. package/plugins/pm-cli-claude/commands/pm-release.md +41 -0
  242. package/plugins/pm-cli-claude/commands/pm-search.md +21 -0
  243. package/plugins/pm-cli-claude/commands/pm-start-task.md +27 -0
  244. package/plugins/pm-cli-claude/commands/pm-status.md +15 -0
  245. package/plugins/pm-cli-claude/commands/pm-triage.md +35 -0
  246. package/plugins/pm-cli-claude/commands/pm-workflow.md +49 -0
  247. package/plugins/pm-cli-claude/hooks/hooks.json +17 -0
  248. package/plugins/pm-cli-claude/hooks/session-start.mjs +120 -0
  249. package/plugins/pm-cli-claude/scripts/pm-mcp-server.mjs +60 -0
  250. package/plugins/pm-cli-claude/skills/pm-audit/SKILL.md +88 -0
  251. package/plugins/pm-cli-claude/skills/pm-developer/SKILL.md +116 -0
  252. package/plugins/pm-cli-claude/skills/pm-planner/SKILL.md +118 -0
  253. package/plugins/pm-cli-claude/skills/pm-release/SKILL.md +83 -0
  254. package/plugins/pm-cli-claude/skills/pm-workflow/SKILL.md +148 -0
  255. package/plugins/pm-cli-codex/.codex-plugin/plugin.json +45 -0
  256. package/plugins/pm-cli-codex/.mcp.json +14 -0
  257. package/plugins/pm-cli-codex/README.md +30 -0
  258. package/plugins/pm-cli-codex/assets/pm-cli-small.svg +4 -0
  259. package/plugins/pm-cli-codex/commands/pm-audit.md +8 -0
  260. package/plugins/pm-cli-codex/commands/pm-close-task.md +9 -0
  261. package/plugins/pm-cli-codex/commands/pm-start-task.md +9 -0
  262. package/plugins/pm-cli-codex/scripts/pm-mcp-server.mjs +54 -0
  263. package/plugins/pm-cli-codex/skills/pm-auditor/SKILL.md +21 -0
  264. package/plugins/pm-cli-codex/skills/pm-auditor/agents/openai.yaml +6 -0
  265. package/plugins/pm-cli-codex/skills/pm-native/SKILL.md +57 -0
  266. package/plugins/pm-cli-codex/skills/pm-native/agents/openai.yaml +6 -0
  267. package/plugins/pm-cli-codex/skills/pm-release/SKILL.md +19 -0
  268. package/plugins/pm-cli-codex/skills/pm-release/agents/openai.yaml +6 -0
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: pm-user
3
+ description: Guides user- and operator-facing pm-cli workflows for planning, triage, prioritization, and task lifecycle management with minimal token usage. Use when routing requests into pm items without implementing code changes.
4
+ license: MIT
5
+ compatibility: Works in terminal-based agent harnesses that execute pm CLI commands.
6
+ metadata:
7
+ owner: unbrained
8
+ domain: pm-cli
9
+ scope: operator-workflow
10
+ ---
11
+
12
+ # pm User Skill
13
+
14
+ Use this skill for planning and coordination work where the main output is clean tracker state.
15
+
16
+ ## Quick Start
17
+
18
+ ```bash
19
+ pm guide quickstart
20
+ pm context --limit 10
21
+ pm search "<request keywords>" --limit 10
22
+ pm list-open --limit 20
23
+ pm list-in-progress --limit 20
24
+ ```
25
+
26
+ ## Primary Use Cases
27
+
28
+ - Intake a new request and decide whether an item already exists.
29
+ - Create parent lineage (`Epic` -> `Feature` -> `Task`) for net-new scope.
30
+ - Prioritize and schedule work with deterministic metadata.
31
+ - Maintain clear ownership and handoff notes.
32
+
33
+ ## Workflow Prompts
34
+
35
+ ### Prompt: New Request Triage
36
+
37
+ `Triage this request using pm only. Reuse an existing item if relevant; otherwise create canonical parent lineage and a scoped child item with duplicate-check evidence.`
38
+
39
+ ### Prompt: Prioritization Sweep
40
+
41
+ `Review open and in-progress items, normalize priority/status metadata, and leave append-only notes explaining why any prioritization changed.`
42
+
43
+ ### Prompt: Handoff Preparation
44
+
45
+ `Prepare handoff for <ID>: summarize state in comments, ensure linked files/tests/docs are complete, and release claim when ready.`
46
+
47
+ ## Deterministic Metadata Commands
48
+
49
+ ```bash
50
+ pm update <ID> --description "..." --ac "..." --estimate 60
51
+ pm update <ID> --deadline +2d --priority 1 --status open
52
+ pm comments <ID> "Decision log: <why this status/priority>"
53
+ pm notes <ID> --add "Context for next owner."
54
+ ```
55
+
56
+ ## Progressive Disclosure References
57
+
58
+ - [Triage and planning workflows](references/WORKFLOWS.md)
59
+ - [Operator prompt templates](references/PROMPTS.md)
@@ -0,0 +1,17 @@
1
+ # Operator Prompt Templates
2
+
3
+ ## Triage
4
+
5
+ `Find the canonical pm item for this request. Show duplicate-check commands, then either reuse and update the item or create parent lineage + child item with explicit rationale.`
6
+
7
+ ## Schedule
8
+
9
+ `Apply deterministic scheduling metadata (status, priority, estimate, deadline) to <ID> and leave a comment explaining the prioritization decision.`
10
+
11
+ ## Handoff
12
+
13
+ `Prepare <ID> for handoff: append current state, blockers, and next actions; release the claim when handoff is complete.`
14
+
15
+ ## Closure Readiness
16
+
17
+ `Validate whether <ID> is close-ready by checking acceptance criteria, linked files/tests/docs, and latest verification evidence.`
@@ -0,0 +1,35 @@
1
+ # User and Operator Workflows
2
+
3
+ ## Intake Workflow
4
+
5
+ 1. Query current context:
6
+
7
+ ```bash
8
+ pm context --limit 10
9
+ pm search "<keywords>" --limit 10
10
+ pm list-open --limit 20
11
+ pm list-in-progress --limit 20
12
+ ```
13
+
14
+ 2. If existing item matches, reuse and update it.
15
+ 3. If no match exists, create parent lineage then child item.
16
+ 4. Add duplicate-check evidence in comments at creation time.
17
+
18
+ ## Claim and Ownership Workflow
19
+
20
+ ```bash
21
+ pm claim <ID>
22
+ pm update <ID> --status in_progress --message "Start work"
23
+ pm comments <ID> "Owner update: <state>"
24
+ pm release <ID>
25
+ ```
26
+
27
+ ## Audit-Friendly Collaboration
28
+
29
+ For non-owner append-only collaboration:
30
+
31
+ ```bash
32
+ pm comments <ID> --add "audit comment" --allow-audit-comment
33
+ pm notes <ID> --add "audit note" --allow-audit-comment
34
+ pm update <ID> --dep "id=<id>,kind=related,author=<author>,created_at=now" --allow-audit-dep-update
35
+ ```
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "pm",
3
+ "owner": {
4
+ "name": "unbrained",
5
+ "url": "https://github.com/unbraind/pm-cli"
6
+ },
7
+ "metadata": {
8
+ "description": "Official marketplace for pm CLI — native git-based project management for Claude Code and AI coding agents.",
9
+ "version": "1.3.0"
10
+ },
11
+ "plugins": [
12
+ {
13
+ "name": "pm-cli",
14
+ "source": "./plugins/pm-cli-claude",
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
+ "author": {
18
+ "name": "unbrained",
19
+ "url": "https://github.com/unbraind/pm-cli"
20
+ },
21
+ "homepage": "https://github.com/unbraind/pm-cli",
22
+ "repository": "https://github.com/unbraind/pm-cli",
23
+ "license": "MIT",
24
+ "keywords": [
25
+ "pm-cli",
26
+ "project-management",
27
+ "mcp",
28
+ "tasks",
29
+ "agents",
30
+ "workflows",
31
+ "git-native",
32
+ "task-tracker",
33
+ "ai"
34
+ ],
35
+ "category": "productivity"
36
+ }
37
+ ]
38
+ }
package/.pi/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # pm CLI Pi Package
2
+
3
+ This directory is the installable Pi package payload for `@unbrained/pm-cli`.
4
+
5
+ Install from npm after publish:
6
+
7
+ ```bash
8
+ pi install npm:@unbrained/pm-cli
9
+ ```
10
+
11
+ For local development from a checkout:
12
+
13
+ ```bash
14
+ pnpm build
15
+ pi install -l .
16
+ # or one-shot
17
+ pi -e .
18
+ ```
19
+
20
+ Resources exposed by `package.json`:
21
+
22
+ - `.pi/extensions/pm-cli/index.js` — native Pi extension registering the `pm` tool, custom TUI renderers, autocomplete, status/widget UI, and slash commands.
23
+ - `.pi/skills/*` — Pi skills for native pm workflows and release validation.
24
+ - `.pi/prompts/*` — prompt templates for pm-tracked work.
25
+ - `.pi/agents/*` and `.pi/chains/*` — optional pi-subagents setup for pm triage and verification workflows in repositories that use subagents.
26
+
27
+ The extension imports the built package from `dist/`, so run `pnpm build` before local install or before publishing.
28
+
29
+ Interactive commands:
30
+
31
+ - `/pm-board [limit]` — dashboard panel for active pm context.
32
+ - `/pm-item <id>` and `/pm-history <id>` — item details/history panels.
33
+ - `/pm-actions` and `/pm-workflows` — native action list and workflow reminders.
34
+
35
+ The `pm` tool should be preferred over shelling out to `pm`; it calls pm command modules directly in-process.
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: pm-triage-agent
3
+ description: Native pm triage agent for Pi. Use to inspect context, search for duplicates, select or create tracker lineage, and hand off an implementation-ready pm item without shelling out to the pm CLI.
4
+ tools: pm,read,grep,find,ls
5
+ skills: pm-native,pm-user
6
+ ---
7
+
8
+ # pm Triage Agent
9
+
10
+ Use the native `pm` tool only for pm operations.
11
+
12
+ Workflow:
13
+ 1. Run `pm` action `context` with `limit: 10`.
14
+ 2. Run `pm` action `search` with the user's key terms.
15
+ 3. Run `pm` actions `list-open` and `list-in-progress`.
16
+ 4. If an item exists, recommend reusing it and claim/start only when asked.
17
+ 5. If no item exists, identify parent lineage and propose a create payload with duplicate-check evidence.
18
+
19
+ Output a concise handoff with item id, rationale, recommended next action, and exact native `pm` tool calls.
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: pm-verification-agent
3
+ description: Native pm verification agent for Pi. Use to inspect linked files/tests/docs, run sandbox-safe linked tests through pm, validate close readiness, and produce closure evidence.
4
+ tools: pm,bash,read,grep,find,ls
5
+ skills: pm-native,pm-release
6
+ ---
7
+
8
+ # pm Verification Agent
9
+
10
+ Use the native `pm` tool for pm mutations and linked-test orchestration.
11
+ Use bash only for non-pm project commands such as `pnpm build` or `gh run list`.
12
+
13
+ Workflow:
14
+ 1. Read the target item with `pm` action `get`.
15
+ 2. Check linked files/docs/tests and acceptance criteria.
16
+ 3. Run `pm` action `test` with `run: true` or equivalent linked-test options when available.
17
+ 4. Run targeted project validation requested by the parent.
18
+ 5. Add a `pm` comment summarizing evidence.
19
+ 6. Recommend close/release only if verification is clean.
20
+
21
+ Output failures with exact commands, item id, and next remediation step.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: pm-native-delivery
3
+ description: Triage, implement, and verify a pm-tracked change using native pm operations in Pi.
4
+ steps:
5
+ - agent: pm-triage-agent
6
+ task: "Triage the requested work and identify the canonical pm item for: {task}"
7
+ - agent: worker
8
+ task: "Implement the approved scope from the triage handoff. Use native pm for tracker operations, link changed files/tests/docs, and keep edits scoped. Original request: {task}\n\nTriage handoff:\n{previous}"
9
+ - agent: pm-verification-agent
10
+ task: "Verify the implementation and produce pm closure evidence. Original request: {task}\n\nImplementation handoff:\n{previous}"
11
+ ---
@@ -0,0 +1,387 @@
1
+ import { PM_PI_TOOL_PARAMETERS_SCHEMA, PM_TOOL_ACTIONS } from "../../../dist/sdk/cli-contracts.js";
2
+ import { runNativePmAction } from "../../../dist/pi/native.js";
3
+
4
+ const PM_PI_TOOL_PARAMETERS_SCHEMA_COMPAT = {
5
+ ...PM_PI_TOOL_PARAMETERS_SCHEMA,
6
+ additionalProperties: true,
7
+ };
8
+
9
+ function contentText(result) {
10
+ if (typeof result === "string") return result;
11
+ return JSON.stringify(result, null, 2);
12
+ }
13
+
14
+ function firstText(result) {
15
+ const entry = Array.isArray(result?.content) ? result.content.find((part) => part?.type === "text") : undefined;
16
+ return typeof entry?.text === "string" ? entry.text : "";
17
+ }
18
+
19
+ function truncatePlain(value, width) {
20
+ const text = String(value ?? "");
21
+ let visible = 0;
22
+ let output = "";
23
+ for (let index = 0; index < text.length; index += 1) {
24
+ const char = text[index];
25
+ if (char === "\u001b") {
26
+ const match = text.slice(index).match(/^\u001b\[[0-9;?]*[ -/]*[@-~]/);
27
+ if (match) {
28
+ output += match[0];
29
+ index += match[0].length - 1;
30
+ continue;
31
+ }
32
+ }
33
+ if (visible >= Math.max(0, width - 1)) return `${output}…`;
34
+ output += char;
35
+ visible += 1;
36
+ }
37
+ return output;
38
+ }
39
+
40
+ function statusIcon(status, theme) {
41
+ const normalized = String(status ?? "").toLowerCase();
42
+ if (normalized === "closed") return theme.fg("success", "✓");
43
+ if (normalized === "blocked") return theme.fg("warning", "!");
44
+ if (normalized === "in_progress") return theme.fg("accent", "▶");
45
+ if (normalized === "canceled") return theme.fg("dim", "×");
46
+ return theme.fg("dim", "○");
47
+ }
48
+
49
+ class PmPanelComponent {
50
+ constructor(title, lines, theme, onClose) {
51
+ this.title = title;
52
+ this.lines = lines;
53
+ this.theme = theme;
54
+ this.onClose = onClose;
55
+ this.cachedWidth = undefined;
56
+ this.cachedLines = undefined;
57
+ }
58
+
59
+ handleInput(data) {
60
+ if (data === "\u001b" || data === "\u0003" || data === "q" || data === "Q") {
61
+ this.onClose?.();
62
+ }
63
+ }
64
+
65
+ render(width) {
66
+ if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;
67
+ const theme = this.theme;
68
+ const usable = Math.max(20, width);
69
+ const border = theme.fg("borderMuted", "─".repeat(Math.max(0, usable)));
70
+ const rendered = [
71
+ border,
72
+ truncatePlain(`${theme.fg("accent", theme.bold(` pm ${this.title} `))}${theme.fg("dim", "q/esc closes")}`, usable),
73
+ border,
74
+ ...this.lines.map((line) => truncatePlain(line, usable)),
75
+ border,
76
+ ];
77
+ this.cachedWidth = width;
78
+ this.cachedLines = rendered;
79
+ return rendered;
80
+ }
81
+
82
+ invalidate() {
83
+ this.cachedWidth = undefined;
84
+ this.cachedLines = undefined;
85
+ }
86
+ }
87
+
88
+ function makeItemLine(item, theme) {
89
+ const id = theme.fg("accent", item.id ?? "unknown");
90
+ const type = theme.fg("muted", item.type ?? "Item");
91
+ const status = statusIcon(item.status, theme);
92
+ const priority = item.priority === undefined ? "" : theme.fg("dim", ` p${item.priority}`);
93
+ const owner = item.assignee ? theme.fg("dim", ` @${item.assignee}`) : "";
94
+ return `${status} ${id} ${type}${priority}${owner} ${item.title ?? "(untitled)"}`;
95
+ }
96
+
97
+ function contextLines(result, theme) {
98
+ const lines = [];
99
+ const summary = result?.summary;
100
+ if (summary) {
101
+ lines.push(
102
+ `${theme.fg("muted", "summary")} active=${summary.active_items ?? 0} open=${summary.open ?? 0} in_progress=${summary.in_progress ?? 0} blocked=${summary.blocked ?? 0}`,
103
+ );
104
+ }
105
+ const high = Array.isArray(result?.high_level) ? result.high_level : [];
106
+ const low = Array.isArray(result?.low_level) ? result.low_level : [];
107
+ if (high.length > 0) {
108
+ lines.push("", theme.fg("accent", "High level"));
109
+ lines.push(...high.map((item) => makeItemLine(item, theme)));
110
+ }
111
+ if (low.length > 0) {
112
+ lines.push("", theme.fg("accent", "Tasks"));
113
+ lines.push(...low.map((item) => makeItemLine(item, theme)));
114
+ }
115
+ if (lines.length === 0) lines.push(theme.fg("dim", "No pm context items found."));
116
+ return lines;
117
+ }
118
+
119
+ function listLines(result, theme) {
120
+ const items = Array.isArray(result?.items) ? result.items : Array.isArray(result) ? result : [];
121
+ if (items.length === 0) return [theme.fg("dim", "No items.")];
122
+ return items.map((entry) => makeItemLine(entry.item ?? entry, theme));
123
+ }
124
+
125
+ function historyLines(result, theme) {
126
+ const entries = Array.isArray(result?.history) ? result.history : Array.isArray(result?.entries) ? result.entries : [];
127
+ if (entries.length === 0) return [theme.fg("dim", "No history entries.")];
128
+ return entries.slice(0, 30).map((entry) => {
129
+ const at = entry.timestamp ?? entry.created_at ?? "";
130
+ const op = entry.op ?? entry.operation ?? entry.type ?? "history";
131
+ const author = entry.author ? ` ${theme.fg("dim", `@${entry.author}`)}` : "";
132
+ const message = entry.message ?? entry.text ?? entry.reason ?? "";
133
+ return `${theme.fg("muted", at)} ${theme.fg("accent", op)}${author} ${message}`;
134
+ });
135
+ }
136
+
137
+ function getItemLines(result, theme) {
138
+ const item = result?.item ?? result;
139
+ if (!item || typeof item !== "object") return [theme.fg("dim", "No item details.")];
140
+ const lines = [makeItemLine(item, theme)];
141
+ if (item.description) lines.push("", item.description);
142
+ if (item.acceptance_criteria) lines.push("", `${theme.fg("accent", "Acceptance")}: ${item.acceptance_criteria}`);
143
+ if (Array.isArray(item.comments) && item.comments.length > 0) {
144
+ lines.push("", theme.fg("accent", "Recent comments"));
145
+ for (const comment of item.comments.slice(-5)) {
146
+ lines.push(`${theme.fg("muted", comment.created_at ?? "")} ${comment.author ?? "unknown"}: ${comment.text ?? ""}`);
147
+ }
148
+ }
149
+ return lines;
150
+ }
151
+
152
+ function resultLines(details, theme) {
153
+ const action = details?.action;
154
+ const result = details?.result;
155
+ if (action === "context") return contextLines(result, theme);
156
+ if (String(action ?? "").startsWith("list") || action === "search") return listLines(result, theme);
157
+ if (action === "history" || action === "activity") return historyLines(result, theme);
158
+ if (action === "get") return getItemLines(result, theme);
159
+ const raw = contentText(result);
160
+ return raw.split("\n").slice(0, 40);
161
+ }
162
+
163
+ function errorDetails(error) {
164
+ return {
165
+ message: error instanceof Error ? error.message : String(error),
166
+ code: typeof error?.exitCode === "number" ? error.exitCode : 1,
167
+ };
168
+ }
169
+
170
+ function uiTheme(ctx) {
171
+ return ctx.ui?.theme ?? {
172
+ fg: (_name, text) => String(text),
173
+ bold: (text) => String(text),
174
+ };
175
+ }
176
+
177
+ async function showPanel(ctx, title, lines, overlay = true) {
178
+ if (!ctx.hasUI || typeof ctx.ui?.custom !== "function") {
179
+ ctx.ui.notify(lines.join("\n"), "info");
180
+ return;
181
+ }
182
+ await ctx.ui.custom((_tui, theme, _keybindings, done) => new PmPanelComponent(title, lines, theme, () => done(undefined)), {
183
+ overlay,
184
+ overlayOptions: { anchor: "right-center", width: "70%", minWidth: 60, maxHeight: "85%", margin: 1 },
185
+ });
186
+ }
187
+
188
+ async function runForCommand(ctx, params) {
189
+ return runNativePmAction({ cwd: ctx.cwd, ...params });
190
+ }
191
+
192
+ export function createPmToolDefinition() {
193
+ return {
194
+ name: "pm",
195
+ label: "pm",
196
+ description:
197
+ "Use pm natively from Pi without shelling out to the pm CLI. Supports pm project context, search, lifecycle mutations, links, tests, validation, extension management, templates, calendar, guide, audit, beads, todos, and managed test-run workflows.",
198
+ promptSnippet: "Run native pm project-management operations without bash or the pm CLI.",
199
+ promptGuidelines: [
200
+ "Use the pm tool instead of bash pm commands for project-management operations when this tool is available.",
201
+ "Use pm action=context/list-open/list-in-progress/search before creating new work items.",
202
+ "For mutations, set author explicitly and link changed files/tests/docs through pm actions before closing work.",
203
+ "Use pm action=contracts or guide when you need exact action/flag support instead of guessing parameters.",
204
+ ],
205
+ parameters: PM_PI_TOOL_PARAMETERS_SCHEMA_COMPAT,
206
+ async execute(_toolCallId, params, _signal, onUpdate, ctx) {
207
+ onUpdate?.({ content: [{ type: "text", text: `Running native pm action: ${params.action}` }] });
208
+ try {
209
+ const result = await runNativePmAction({ cwd: ctx?.cwd, ...params });
210
+ return {
211
+ content: [{ type: "text", text: contentText(result) }],
212
+ details: { ok: true, action: params.action, result, native: true },
213
+ };
214
+ } catch (error) {
215
+ const details = errorDetails(error);
216
+ throw new Error(`pm ${params.action ?? "action"} failed: ${details.message}`);
217
+ }
218
+ },
219
+ renderCall(args, theme) {
220
+ const action = args?.action ?? "action";
221
+ const target = args?.id ?? args?.query ?? args?.target ?? args?.title ?? "";
222
+ return new PmPanelComponent("tool", [`${theme.fg("toolTitle", theme.bold("pm"))} ${theme.fg("accent", action)} ${theme.fg("dim", target)}`], theme);
223
+ },
224
+ renderResult(result, { expanded, isPartial }, theme) {
225
+ if (isPartial) return new PmPanelComponent("running", [theme.fg("warning", "Running…")], theme);
226
+ const details = result?.details;
227
+ if (!details?.ok) return new PmPanelComponent("result", [firstText(result) || contentText(result)], theme);
228
+ const lines = resultLines(details, theme);
229
+ const visible = expanded ? lines : lines.slice(0, 12);
230
+ if (!expanded && lines.length > visible.length) visible.push(theme.fg("dim", `… ${lines.length - visible.length} more; expand tool output for details`));
231
+ return new PmPanelComponent(String(details.action ?? "result"), visible, theme);
232
+ },
233
+ };
234
+ }
235
+
236
+ export function registerPmCommands(pi) {
237
+ pi.registerCommand("pm-context", {
238
+ description: "Show pm context snapshot using the native pm integration",
239
+ handler: async (args, ctx) => {
240
+ const limit = args?.trim() || "10";
241
+ const result = await runForCommand(ctx, { action: "context", limit, json: true });
242
+ await showPanel(ctx, "context", contextLines(result, uiTheme(ctx)));
243
+ },
244
+ });
245
+
246
+ pi.registerCommand("pm-board", {
247
+ description: "Open an interactive pm dashboard panel: /pm-board [limit]",
248
+ handler: async (args, ctx) => {
249
+ const limit = args?.trim() || "12";
250
+ const result = await runForCommand(ctx, { action: "context", limit, depth: "standard", json: true });
251
+ await showPanel(ctx, "board", contextLines(result, uiTheme(ctx)));
252
+ },
253
+ });
254
+
255
+ pi.registerCommand("pm-item", {
256
+ description: "Open pm item details: /pm-item <id>",
257
+ getArgumentCompletions: () => null,
258
+ handler: async (args, ctx) => {
259
+ const id = args?.trim();
260
+ if (!id) return ctx.ui.notify("Usage: /pm-item <id>", "error");
261
+ const result = await runForCommand(ctx, { action: "get", id, json: true });
262
+ await showPanel(ctx, id, getItemLines(result, uiTheme(ctx)));
263
+ },
264
+ });
265
+
266
+ pi.registerCommand("pm-history", {
267
+ description: "Open pm item history/activity panel: /pm-history <id>",
268
+ handler: async (args, ctx) => {
269
+ const id = args?.trim();
270
+ if (!id) return ctx.ui.notify("Usage: /pm-history <id>", "error");
271
+ const result = await runForCommand(ctx, { action: "history", id, limit: 30, json: true });
272
+ await showPanel(ctx, `${id} history`, historyLines(result, uiTheme(ctx)));
273
+ },
274
+ });
275
+
276
+ pi.registerCommand("pm-start", {
277
+ description: "Start/claim a pm item: /pm-start <id>",
278
+ handler: async (args, ctx) => {
279
+ const id = args?.trim();
280
+ if (!id) return ctx.ui.notify("Usage: /pm-start <id>", "error");
281
+ const result = await runForCommand(ctx, { action: "start-task", id, author: "pi-agent" });
282
+ ctx.ui.notify(contentText(result), "success");
283
+ },
284
+ });
285
+
286
+ pi.registerCommand("pm-close", {
287
+ description: "Close and release a pm item: /pm-close <id> <reason>",
288
+ handler: async (args, ctx) => {
289
+ const [id, ...reasonParts] = (args ?? "").trim().split(/\s+/);
290
+ const reason = reasonParts.join(" ");
291
+ if (!id || !reason) return ctx.ui.notify("Usage: /pm-close <id> <reason>", "error");
292
+ const result = await runForCommand(ctx, { action: "close-task", id, text: reason, author: "pi-agent", validateClose: "warn" });
293
+ ctx.ui.notify(contentText(result), "success");
294
+ },
295
+ });
296
+
297
+ pi.registerCommand("pm-actions", {
298
+ description: "List native pm tool actions",
299
+ handler: async (_args, ctx) => {
300
+ await showPanel(ctx, "actions", PM_TOOL_ACTIONS.map((action) => `• ${action}`));
301
+ },
302
+ });
303
+
304
+ pi.registerCommand("pm-workflows", {
305
+ description: "Show native pm workflow shortcuts and bundled Pi resources",
306
+ handler: async (_args, ctx) => {
307
+ await showPanel(ctx, "workflows", [
308
+ "1. /pm-board to inspect focus/context items.",
309
+ "2. Use the pm tool action=search/list-open/list-in-progress before creating work.",
310
+ "3. /pm-start <id> or pm action=start-task to claim and move in_progress.",
311
+ "4. Use pm action=files/docs/test to link implementation evidence.",
312
+ "5. Run pm action=test/validate and close with pm action=close-task.",
313
+ "Bundled resources: pm-native and pm-release skills, pm-workflow prompt, pm subagent templates in .pi/agents.",
314
+ ]);
315
+ },
316
+ });
317
+ }
318
+
319
+ function patchPmToolParametersInProviderPayload(payload) {
320
+ if (!payload || typeof payload !== "object" || !Array.isArray(payload.tools)) {
321
+ return undefined;
322
+ }
323
+ let changed = false;
324
+ const tools = payload.tools.map((tool) => {
325
+ if (!tool || typeof tool !== "object") {
326
+ return tool;
327
+ }
328
+ if (tool.name === "pm") {
329
+ const parameters = tool.parameters;
330
+ if (!parameters || parameters.type !== "object") {
331
+ changed = true;
332
+ return { ...tool, parameters: PM_PI_TOOL_PARAMETERS_SCHEMA_COMPAT };
333
+ }
334
+ }
335
+ if (tool.function?.name === "pm") {
336
+ const parameters = tool.function.parameters;
337
+ if (!parameters || parameters.type !== "object") {
338
+ changed = true;
339
+ return { ...tool, function: { ...tool.function, parameters: PM_PI_TOOL_PARAMETERS_SCHEMA_COMPAT } };
340
+ }
341
+ }
342
+ return tool;
343
+ });
344
+ return changed ? { ...payload, tools } : undefined;
345
+ }
346
+
347
+ function installPmAutocomplete(ctx) {
348
+ if (typeof ctx.ui?.addAutocompleteProvider !== "function") return;
349
+ ctx.ui.addAutocompleteProvider((current) => ({
350
+ async getSuggestions(lines, line, col, options) {
351
+ const beforeCursor = (lines[line] ?? "").slice(0, col);
352
+ const match = beforeCursor.match(/(?:^|[\s(])@(pm-[a-z0-9-]*)$/i);
353
+ if (!match) return current.getSuggestions(lines, line, col, options);
354
+ try {
355
+ const result = await runNativePmAction({ cwd: ctx.cwd, action: "list-open", limit: 20, json: true });
356
+ const items = Array.isArray(result?.items) ? result.items : [];
357
+ return {
358
+ prefix: `@${match[1] ?? ""}`,
359
+ items: items.map((item) => ({ value: `@${item.id}`, label: item.id, description: item.title ?? item.status ?? "pm item" })),
360
+ };
361
+ } catch {
362
+ return current.getSuggestions(lines, line, col, options);
363
+ }
364
+ },
365
+ applyCompletion(lines, line, col, item, prefix) {
366
+ return current.applyCompletion(lines, line, col, item, prefix);
367
+ },
368
+ shouldTriggerFileCompletion(lines, line, col) {
369
+ return current.shouldTriggerFileCompletion?.(lines, line, col) ?? true;
370
+ },
371
+ }));
372
+ }
373
+
374
+ export default function pmCliPiExtension(pi) {
375
+ pi.registerTool(createPmToolDefinition());
376
+ pi.on("before_provider_request", (event) => patchPmToolParametersInProviderPayload(event.payload));
377
+ registerPmCommands(pi);
378
+ pi.on("session_start", async (_event, ctx) => {
379
+ ctx.ui.setStatus?.("pm", ctx.ui.theme?.fg ? ctx.ui.theme.fg("accent", "pm native") : "pm native");
380
+ ctx.ui.setWidget?.("pm-native", ["pm native ready • /pm-board • /pm-actions • @pm-id autocomplete"], { placement: "belowEditor" });
381
+ installPmAutocomplete(ctx);
382
+ });
383
+ pi.on("session_shutdown", async (_event, ctx) => {
384
+ ctx.ui.setStatus?.("pm", undefined);
385
+ ctx.ui.setWidget?.("pm-native", undefined);
386
+ });
387
+ }
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: Start a pm-tracked implementation workflow using the native pm Pi tool.
3
+ ---
4
+
5
+ Use the native `pm` tool to orient, find an existing relevant item, claim it, link evidence, verify, and close/release only after acceptance criteria are met. Do not run `pm` via bash when the native tool is available.