@unbrained/pm-cli 2026.8.25 → 2026.8.27

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 (206) hide show
  1. package/.agents/skills/HARNESS_COMPATIBILITY.md +32 -0
  2. package/.agents/skills/README.md +47 -0
  3. package/.agents/skills/pm-developer/SKILL.md +117 -0
  4. package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +49 -0
  5. package/.agents/skills/pm-developer/references/GRAPH_AND_RELATIONSHIPS.md +91 -0
  6. package/.agents/skills/pm-developer/references/MULTI_AGENT_MERGE.md +72 -0
  7. package/.agents/skills/pm-developer/references/PROMPTS.md +17 -0
  8. package/.agents/skills/pm-developer/references/SCRIPTING_COMPOSITION.md +82 -0
  9. package/.agents/skills/pm-developer/references/TOKEN_BUDGETS.md +85 -0
  10. package/.agents/skills/pm-extensions/SKILL.md +106 -0
  11. package/.agents/skills/pm-extensions/references/AUTHORING.md +95 -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 +107 -0
  15. package/.agents/skills/pm-sdk/references/DOMAIN_MODELING.md +78 -0
  16. package/.agents/skills/pm-sdk/references/INTEGRATION_CHECKLIST.md +31 -0
  17. package/.agents/skills/pm-sdk/references/PROMPTS.md +13 -0
  18. package/.agents/skills/pm-sdk/references/SURFACE_MAP.md +82 -0
  19. package/.agents/skills/pm-user/SKILL.md +111 -0
  20. package/.agents/skills/pm-user/references/BACKLOG_SHAPING.md +105 -0
  21. package/.agents/skills/pm-user/references/PROMPTS.md +17 -0
  22. package/.agents/skills/pm-user/references/WORKFLOWS.md +35 -0
  23. package/.claude-plugin/marketplace.json +2 -2
  24. package/CHANGELOG.md +58 -3
  25. package/README.md +8 -5
  26. package/dist/cli/commander-usage.js +11 -7
  27. package/dist/cli/error-guidance.js +3 -3
  28. package/dist/cli/help-content.d.ts +2 -0
  29. package/dist/cli/help-content.js +53 -17
  30. package/dist/cli/help-json-payload.d.ts +8 -2
  31. package/dist/cli/help-json-payload.js +46 -12
  32. package/dist/cli/main.js +52 -74
  33. package/dist/cli/register-annotations.js +27 -21
  34. package/dist/cli/register-setup.js +98 -57
  35. package/dist/cli-bundle/bundle-manifest.json +156 -156
  36. package/dist/cli-bundle/chunks/chunk-3OO3W6FW.js +202 -0
  37. package/dist/cli-bundle/chunks/chunk-52EKTW6V.js +3 -0
  38. package/dist/cli-bundle/chunks/{chunk-QLUORNIB.js → chunk-CVBBGWW5.js} +62 -44
  39. package/dist/cli-bundle/chunks/chunk-MFNTKMTI.js +13 -0
  40. package/dist/cli-bundle/chunks/chunk-OS27HHBN.js +35 -0
  41. package/dist/cli-bundle/chunks/chunk-QTO7USTH.js +2 -0
  42. package/dist/cli-bundle/chunks/{chunk-5I5RWIJC.js → chunk-R4ETAOJC.js} +2 -2
  43. package/dist/cli-bundle/chunks/{chunk-OWHNAR2B.js → chunk-SH6P7FXI.js} +2 -2
  44. package/dist/cli-bundle/chunks/chunk-SHMDY36D.js +8 -0
  45. package/dist/cli-bundle/chunks/{chunk-244MI4GS.js → chunk-SKXLJIEK.js} +60 -60
  46. package/dist/cli-bundle/chunks/chunk-TNX6HC54.js +3 -0
  47. package/dist/cli-bundle/chunks/{register-list-query-XVN2ZLI7.js → register-list-query-EUWM6VII.js} +2 -2
  48. package/dist/cli-bundle/chunks/{register-mutation-QCKAEGIJ.js → register-mutation-FD4HSAVU.js} +4 -4
  49. package/dist/cli-bundle/chunks/{register-operations-SDEAXE7E.js → register-operations-HRMNFEC3.js} +2 -2
  50. package/dist/cli-bundle/chunks/register-setup-33GNICLX.js +2 -0
  51. package/dist/cli-bundle/focused-chunks/{chunk-IBZZZGK3.js → chunk-2AGZ5BRT.js} +2 -2
  52. package/dist/cli-bundle/focused-chunks/chunk-4BR5UU52.js +50 -0
  53. package/dist/cli-bundle/focused-chunks/{chunk-OHIHZ7HS.js → chunk-6GCRSLPG.js} +2 -2
  54. package/dist/cli-bundle/focused-chunks/{chunk-OVJL6NZE.js → chunk-AD6ULRAF.js} +4 -4
  55. package/dist/cli-bundle/focused-chunks/{chunk-7YCDTCBC.js → chunk-AQ5IYEZZ.js} +2 -2
  56. package/dist/cli-bundle/focused-chunks/{chunk-YO3ZF3FI.js → chunk-EKX37ZHA.js} +2 -2
  57. package/dist/cli-bundle/focused-chunks/{chunk-N7W67YIG.js → chunk-FC2AXLB5.js} +2 -2
  58. package/dist/cli-bundle/focused-chunks/{chunk-H5JZEIQV.js → chunk-HC7ODMH3.js} +2 -2
  59. package/dist/cli-bundle/focused-chunks/{chunk-NOOZGIXP.js → chunk-HVQ22RC4.js} +2 -2
  60. package/dist/cli-bundle/focused-chunks/{chunk-A644DUFQ.js → chunk-MEASX544.js} +2 -2
  61. package/dist/cli-bundle/focused-chunks/{chunk-RAFKLNZX.js → chunk-MXTYGECH.js} +2 -2
  62. package/dist/cli-bundle/focused-chunks/{chunk-2UIWOP3O.js → chunk-SUBSWYW3.js} +2 -2
  63. package/dist/cli-bundle/focused-chunks/{chunk-VXWATRFL.js → chunk-XDPYBQCF.js} +9 -9
  64. package/dist/cli-bundle/focused-chunks/{chunk-XUQPEKRN.js → chunk-Y3JJXRVK.js} +2 -2
  65. package/dist/cli-bundle/focused-chunks/{chunk-GQR3WH3F.js → chunk-Y5A7SJJ7.js} +2 -2
  66. package/dist/cli-bundle/focused-chunks/chunk-YHWHX6YY.js +2 -0
  67. package/dist/cli-bundle/focused-chunks/{chunk-ONYQCALA.js → chunk-YVVZ3LQ6.js} +6 -6
  68. package/dist/cli-bundle/focused-chunks/chunk-Z2USIBR2.js +5 -0
  69. package/dist/cli-bundle/main.js +15 -14
  70. package/dist/cli-bundle/sdk-authoring.js +1 -1
  71. package/dist/cli-bundle/sdk-contracts.js +2 -2
  72. package/dist/cli-bundle/sdk-core.js +31 -31
  73. package/dist/cli-bundle/sdk-governance.js +1 -1
  74. package/dist/cli-bundle/sdk-graph.js +1 -1
  75. package/dist/cli-bundle/sdk-merge.js +31 -31
  76. package/dist/cli-bundle/sdk-query.js +1 -1
  77. package/dist/cli-bundle/sdk-runtime.js +1 -1
  78. package/dist/cli-bundle/sdk-testing.js +1 -1
  79. package/dist/cli-bundle/sdk.js +32 -6
  80. package/dist/core/extensions/manifest-schema.d.ts +20 -0
  81. package/dist/core/extensions/manifest-schema.js +28 -10
  82. package/dist/core/governance/issue-codes.d.ts +11 -2
  83. package/dist/core/governance/issue-codes.js +29 -10
  84. package/dist/core/item/item-format.js +3 -3
  85. package/dist/core/store/item-store.js +12 -5
  86. package/dist/mcp/http-server.d.ts +60 -0
  87. package/dist/mcp/http-server.js +451 -0
  88. package/dist/mcp/legacy-adapter.d.ts +50 -0
  89. package/dist/mcp/legacy-adapter.js +64 -0
  90. package/dist/mcp/server.d.ts +42 -9
  91. package/dist/mcp/server.js +572 -59
  92. package/dist/mcp/tool-definitions.d.ts +2 -0
  93. package/dist/mcp/tool-definitions.js +2 -2
  94. package/dist/sdk/agent/closed-domain-contracts.d.ts +1 -1
  95. package/dist/sdk/agent/closed-domain-contracts.js +24 -2
  96. package/dist/sdk/agent/refusal-closure-census.d.ts +6 -2
  97. package/dist/sdk/agent/refusal-closure-census.js +16 -8
  98. package/dist/sdk/agent-capability-contracts.js +6 -2
  99. package/dist/sdk/cli-bootstrap.js +3 -2
  100. package/dist/sdk/cli-contracts/command-aliases.js +15 -2
  101. package/dist/sdk/cli-contracts/enum-contracts.d.ts +4 -1
  102. package/dist/sdk/cli-contracts/enum-contracts.js +7 -2
  103. package/dist/sdk/cli-contracts/flag-contracts.js +9 -5
  104. package/dist/sdk/cli-contracts/grammar-contracts.d.ts +3 -3
  105. package/dist/sdk/cli-contracts/grammar-contracts.js +24 -17
  106. package/dist/sdk/cli-contracts/runtime-contracts.js +13 -11
  107. package/dist/sdk/cli-contracts/tool-schema.js +18 -15
  108. package/dist/sdk/cli-contracts.d.ts +1 -1
  109. package/dist/sdk/cli-contracts.js +3 -3
  110. package/dist/sdk/cli-program.js +3 -2
  111. package/dist/sdk/completion.js +40 -13
  112. package/dist/sdk/compose.d.ts +4 -1
  113. package/dist/sdk/compose.js +23 -36
  114. package/dist/sdk/extension/author-manifest.d.ts +22 -0
  115. package/dist/sdk/extension/author-manifest.js +93 -0
  116. package/dist/sdk/extension.js +6 -3
  117. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +20 -5
  118. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +18 -3
  119. package/dist/sdk/governance/health.js +7 -2
  120. package/dist/sdk/governance/upgrade.d.ts +2 -0
  121. package/dist/sdk/governance/upgrade.js +30 -8
  122. package/dist/sdk/governance/validate.js +8 -6
  123. package/dist/sdk/guide-topics.js +6 -6
  124. package/dist/sdk/index.d.ts +10 -2
  125. package/dist/sdk/index.js +11 -3
  126. package/dist/sdk/mcp/apps.d.ts +70 -0
  127. package/dist/sdk/mcp/apps.js +154 -0
  128. package/dist/sdk/mcp/authorization.d.ts +134 -0
  129. package/dist/sdk/mcp/authorization.js +405 -0
  130. package/dist/sdk/mcp/interactions.d.ts +118 -0
  131. package/dist/sdk/mcp/interactions.js +337 -0
  132. package/dist/sdk/mcp/protocol.d.ts +142 -0
  133. package/dist/sdk/mcp/protocol.js +174 -0
  134. package/dist/sdk/mcp/skills.d.ts +127 -0
  135. package/dist/sdk/mcp/skills.js +390 -0
  136. package/dist/sdk/mcp/subscriptions.d.ts +65 -0
  137. package/dist/sdk/mcp/subscriptions.js +212 -0
  138. package/dist/sdk/mcp/tasks.d.ts +107 -0
  139. package/dist/sdk/mcp/tasks.js +431 -0
  140. package/dist/sdk/mcp/transport.d.ts +30 -0
  141. package/dist/sdk/mcp/transport.js +261 -0
  142. package/dist/sdk/merge/receipts.d.ts +16 -0
  143. package/dist/sdk/merge/receipts.js +9 -8
  144. package/dist/sdk/read-output-contracts.js +16 -3
  145. package/dist/sdk/runtime-action-aliases.js +7 -3
  146. package/dist/sdk/runtime-input.js +12 -4
  147. package/dist/sdk/runtime-primitives.d.ts +2 -2
  148. package/dist/sdk/runtime-primitives.js +4 -4
  149. package/dist/sdk/test/execution.d.ts +6 -0
  150. package/dist/sdk/test/execution.js +32 -3
  151. package/docs/AGENT_PROVENANCE_ADR.md +6 -4
  152. package/docs/AGENT_RUNTIME_PRIMITIVES.md +6 -5
  153. package/docs/CLAUDE_CODE_PLUGIN.md +12 -5
  154. package/docs/CLI_GRAMMAR.md +7 -1
  155. package/docs/COMMANDS.md +2 -2
  156. package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +8 -0
  157. package/docs/EXTENSIONS.md +36 -36
  158. package/docs/MCP_2026_07_28.md +160 -0
  159. package/docs/MCP_2026_07_28_CONFORMANCE.md +30 -0
  160. package/docs/MCP_REMOTE_TRANSPORT_SECURITY.md +180 -0
  161. package/docs/MCP_SKILLS_AND_APPS.md +107 -0
  162. package/docs/QUICKSTART.md +15 -15
  163. package/docs/README.md +5 -0
  164. package/docs/RELEASING.md +12 -3
  165. package/docs/SDK.md +22 -1
  166. package/docs/SDK_AGENT_SESSION_CONTEXT.md +18 -13
  167. package/docs/SDK_CONTEXT_INTEGRITY.md +6 -0
  168. package/docs/SDK_EVIDENCE_TRACEABILITY.md +9 -1
  169. package/docs/SDK_MCP_INTERACTIONS.md +227 -0
  170. package/docs/TESTING.md +4 -0
  171. package/docs/generated/AGENT_CAPABILITY_ROUTING.md +1 -1
  172. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +13 -11
  173. package/marketplace.json +2 -2
  174. package/package.json +15 -11
  175. package/packages/pm-beads/README.md +12 -6
  176. package/packages/pm-beads/docs/MIGRATION.md +53 -0
  177. package/packages/pm-beads/extensions/beads/index.ts +8 -0
  178. package/packages/pm-beads/extensions/beads/runtime.ts +671 -112
  179. package/packages/pm-beads/package.json +1 -1
  180. package/packages/pm-calendar/package.json +1 -1
  181. package/packages/pm-command-kit/package.json +1 -1
  182. package/packages/pm-digital-twin/package.json +1 -1
  183. package/packages/pm-governance-audit/package.json +1 -1
  184. package/packages/pm-guide-shell/package.json +1 -1
  185. package/packages/pm-kanban/package.json +1 -1
  186. package/packages/pm-lifecycle-hooks/package.json +1 -1
  187. package/packages/pm-linked-test-adapters/package.json +1 -1
  188. package/packages/pm-search-advanced/package.json +1 -1
  189. package/packages/pm-templates/package.json +1 -1
  190. package/packages/pm-todos/package.json +1 -1
  191. package/packages/pm-vcs/package.json +1 -1
  192. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  193. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  194. package/scripts/finalize-build.mjs +1 -0
  195. package/sdk/public-surface.json +902 -54
  196. package/dist/cli-bundle/chunks/chunk-2F3LUFMW.js +0 -8
  197. package/dist/cli-bundle/chunks/chunk-65MHLHAA.js +0 -2
  198. package/dist/cli-bundle/chunks/chunk-6C7GIMIL.js +0 -13
  199. package/dist/cli-bundle/chunks/chunk-QKGMHGEI.js +0 -202
  200. package/dist/cli-bundle/chunks/chunk-T2ENPRXF.js +0 -3
  201. package/dist/cli-bundle/chunks/chunk-TPQIBSL2.js +0 -3
  202. package/dist/cli-bundle/chunks/chunk-YQMYF3YD.js +0 -35
  203. package/dist/cli-bundle/chunks/register-setup-LXVBRCJ3.js +0 -2
  204. package/dist/cli-bundle/focused-chunks/chunk-42S3GGZ7.js +0 -50
  205. package/dist/cli-bundle/focused-chunks/chunk-7I23XGWO.js +0 -2
  206. package/dist/cli-bundle/focused-chunks/chunk-LMKG3DFE.js +0 -5
@@ -0,0 +1,227 @@
1
+ # MCP Interaction and Task SDK
2
+
3
+ Tracker references: [pm-rz9gep](../.agents/pm/features/pm-rz9gep.toon),
4
+ [pm-rzs24j](../.agents/pm/features/pm-rzs24j.toon), and
5
+ [pm-hv1x1x](../.agents/pm/features/pm-hv1x1x.toon). Transport and remote
6
+ trust primitives are tracked by
7
+ [pm-v7e337](../.agents/pm/features/pm-v7e337.toon) and
8
+ [pm-3zh9s4](../.agents/pm/features/pm-3zh9s4.toon).
9
+
10
+ The aggregate `@unbrained/pm-cli/sdk` entrypoint exposes transport-neutral
11
+ contracts for MCP 2026-07-28 multi round-trip requests (MRTR), explicit cache
12
+ policy, bounded JSON Schema 2020-12 validation, and the official durable tasks
13
+ extension. A custom stdio or HTTP host can reuse these primitives without
14
+ importing pm's executable server.
15
+
16
+ ## Request more host input
17
+
18
+ Throw `PmMcpInputRequiredError` from domain code. The host adapter converts the
19
+ signal into an `input_required` result after validating request method,
20
+ payload bounds, and the request-local client capability.
21
+
22
+ ```ts
23
+ import {
24
+ PmMcpInputRequiredError,
25
+ digestMcpRequestParameters,
26
+ sealMcpRequestState,
27
+ } from "@unbrained/pm-cli/sdk";
28
+
29
+ const requestState = sealMcpRequestState(
30
+ {
31
+ expiresAt: Date.now() + 5 * 60_000,
32
+ method: "tools/call",
33
+ parameterDigest: digestMcpRequestParameters({ name: "pm_mutate" }),
34
+ principal: "host-user-42",
35
+ state: { phase: "confirm" },
36
+ },
37
+ process.env.MCP_REQUEST_STATE_KEY!, // at least 32 bytes
38
+ );
39
+
40
+ throw new PmMcpInputRequiredError({
41
+ requestState,
42
+ inputRequests: {
43
+ confirmation: {
44
+ method: "elicitation/create",
45
+ params: {
46
+ mode: "form",
47
+ message: "Apply the proposed PM mutations?",
48
+ requestedSchema: {
49
+ type: "object",
50
+ properties: { approved: { type: "boolean" } },
51
+ required: ["approved"],
52
+ },
53
+ },
54
+ },
55
+ },
56
+ });
57
+ ```
58
+
59
+ Use `openMcpRequestState()` on retry to verify signature, expiry, original
60
+ method, parameter digest, and principal. Call
61
+ `PmMcpRequestStateReplayGuard.consume()` only after successful verification.
62
+ The bundled guard provides bounded single-process replay detection; a
63
+ multi-process host should persist the consumed state digest in its shared
64
+ store. `parseMcpInputResponses()` validates and clones retry responses.
65
+
66
+ The permitted input request methods are
67
+ `elicitation/create`, `roots/list`, and `sampling/createMessage`. The client
68
+ must advertise the corresponding capability on that same request.
69
+
70
+ ## Validate schemas and attach cache policy
71
+
72
+ `validateMcpJsonSchema()` accepts object and boolean JSON Schema 2020-12 roots,
73
+ resolves local JSON Pointer references, and applies byte, depth, and node work
74
+ bounds. It returns a clone so callers cannot mutate the validated input by
75
+ alias. External references remain identifiers; this validator does not perform
76
+ network retrieval.
77
+
78
+ ```ts
79
+ import {
80
+ validateMcpJsonSchema,
81
+ withMcpCachePolicy,
82
+ } from "@unbrained/pm-cli/sdk";
83
+
84
+ const inputSchema = validateMcpJsonSchema({
85
+ $schema: "https://json-schema.org/draft/2020-12/schema",
86
+ type: "object",
87
+ properties: { id: { type: "string" } },
88
+ required: ["id"],
89
+ additionalProperties: false,
90
+ });
91
+
92
+ const result = withMcpCachePolicy(
93
+ { tools: [{ name: "get_item", inputSchema }] },
94
+ { ttlMs: 30_000, cacheScope: "private" },
95
+ );
96
+ ```
97
+
98
+ Use `cacheScope: "private"` whenever a result depends on a workspace,
99
+ principal, authorization decision, or user data. A `public` result must be
100
+ safe for shared intermediaries and all principals for its full TTL.
101
+
102
+ ## Run durable extension tasks
103
+
104
+ `createMcpTaskStore()` persists task records below the supplied tracker root's
105
+ ignored `runtime/mcp-tasks` directory. It creates the durable record before
106
+ returning a handle and serializes mutations with pm's cross-process lock.
107
+
108
+ ```ts
109
+ import { createMcpTaskStore } from "@unbrained/pm-cli/sdk";
110
+
111
+ const tasks = createMcpTaskStore({
112
+ pmRoot: "/workspace/project/.agents/pm",
113
+ });
114
+
115
+ const handle = await tasks.create({
116
+ principal: "host-user-42",
117
+ ttlMs: 60 * 60_000,
118
+ statusMessage: "Validating the workspace.",
119
+ });
120
+
121
+ try {
122
+ const result = await validateWorkspace();
123
+ await tasks.complete(handle.taskId, "host-user-42", result);
124
+ } catch (error) {
125
+ await tasks.fail(handle.taskId, "host-user-42", {
126
+ code: -32603,
127
+ message: error instanceof Error ? error.message : "Validation failed",
128
+ });
129
+ }
130
+ ```
131
+
132
+ The lifecycle is `working` to `input_required`, `completed`, `failed`, or
133
+ `cancelled`. `get()` applies retention expiry and restart recovery;
134
+ `requireInput()` records MRTR requests; `update()` accepts matching responses;
135
+ `takeInputResponses()` transfers them to a resumed worker; and `cancel()` is a
136
+ cooperative state transition. Completed, failed, and cancelled records are
137
+ immutable. Task ids and principal mismatches intentionally return the same
138
+ not-found refusal to avoid disclosing another principal's work.
139
+
140
+ The bundled `pm-mcp` server negotiates the extension through
141
+ `io.modelcontextprotocol/tasks`. Eligible validation, health, graph, import,
142
+ reindex, and test operations may return a task handle when the client requests
143
+ asynchronous execution. Clients retrieve state with `tasks/get`, provide MRTR
144
+ answers with `tasks/update`, and request cancellation with `tasks/cancel`.
145
+
146
+ Task progress notifications and cross-transport request-scoped streams are a
147
+ separate concern from change subscriptions. A client polls at `pollIntervalMs`
148
+ for task state; `subscriptions/listen` carries only explicitly acknowledged
149
+ tool, prompt, and resource changes.
150
+
151
+ ## Open change subscriptions
152
+
153
+ `PmMcpSubscriptionRegistry` is transport-neutral. A stdio or HTTP adapter
154
+ opens a record with the `subscriptions/listen` JSON-RPC id, requested filter,
155
+ and an asynchronous sink. The registry sends the acknowledgment before any
156
+ other notification, intersects filters with advertised server capabilities,
157
+ tags every notification with the subscription id, and awaits each sink so
158
+ transport backpressure is visible.
159
+
160
+ ```ts
161
+ import { PmMcpSubscriptionRegistry } from "@unbrained/pm-cli/sdk";
162
+
163
+ const subscriptions = new PmMcpSubscriptionRegistry({
164
+ capabilities: { resources: { listChanged: true, subscribe: true } },
165
+ serverInfo: { name: "custom-pm-host", version: "1.0.0" },
166
+ });
167
+
168
+ await subscriptions.open({
169
+ id: "workspace-changes",
170
+ notifications: {
171
+ resourcesListChanged: true,
172
+ resourceSubscriptions: ["pm://workspace/context"],
173
+ },
174
+ sink: async (notification) => sendOnTransport(notification),
175
+ });
176
+
177
+ await subscriptions.emitResourceUpdated("pm://workspace/context");
178
+ ```
179
+
180
+ Closing returns the final modern result envelope. Abrupt disconnects should
181
+ delete the record without fabricating a replay cursor or redelivery promise.
182
+
183
+ ## Project and validate HTTP headers
184
+
185
+ `buildMcpHttpRequestHeaders()` constructs the required protocol, method, and
186
+ name headers from a request. `validateMcpHttpRequestHeaders()` checks the
187
+ received headers against both the JSON-RPC body and a tool's input schema.
188
+ `collectMcpHeaderAnnotations()` exposes the validated `x-mcp-header` mapping
189
+ when a custom adapter needs to inspect it.
190
+
191
+ Header values are strings, numbers, or booleans. The SDK Base64-encodes values
192
+ that cannot be represented unambiguously and rejects control bytes, reserved
193
+ MCP names, duplicate mappings, undeclared arguments, and body/header
194
+ mismatches. Never copy arbitrary client headers into tool arguments.
195
+
196
+ ## Compose remote authorization
197
+
198
+ Use `buildMcpProtectedResourceMetadata()` for RFC 9728 metadata,
199
+ `buildMcpAuthorizationDiscoveryUrls()` and
200
+ `validateMcpAuthorizationServerMetadata()` for exact issuer discovery, and
201
+ `selectMcpClientRegistrationMode()` to prefer Client ID Metadata Documents
202
+ over deprecated Dynamic Client Registration. Store credentials with
203
+ `PmMcpIssuerCredentialStore`; its exact issuer key prevents cross-issuer
204
+ reuse and its cloned values prevent alias mutation.
205
+
206
+ At the resource boundary, `authorizeMcpHttpRequest()` accepts bearer tokens
207
+ only in the Authorization header and verifies issuer, audience, and required
208
+ scopes through a host-provided verifier. `extractMcpTraceContext()` validates
209
+ W3C trace fields and retains only allowlisted baggage before
210
+ `runWithMcpTraceContext()` creates a concurrent-request-local scope.
211
+
212
+ See [MCP remote transport, authorization, and migration](MCP_REMOTE_TRANSPORT_SECURITY.md)
213
+ for executable configuration, lifecycle policy, and the threat model.
214
+
215
+ ## Failure and trust boundaries
216
+
217
+ - Keep signing keys outside request data and logs; rotate them using a bounded
218
+ overlap strategy owned by the host.
219
+ - Bind continuation state and tasks to an authenticated principal chosen by
220
+ the host, never to a caller-supplied display name.
221
+ - Treat `ttlMs` as retention/freshness policy, not proof that underlying data
222
+ is unchanged.
223
+ - A worker lost across process restart becomes a terminal, non-recoverable task
224
+ result. Create a new task instead of replaying side effects implicitly.
225
+ - The task store is durable local coordination, not a distributed queue. A
226
+ multi-host deployment should implement the same public lifecycle on a
227
+ shared transactional backend.
package/docs/TESTING.md CHANGED
@@ -443,6 +443,10 @@ context. This preserves source isolation without copying an unrelated tracker
443
443
  into constrained temporary storage.
444
444
  Capacity, permission, and resource failures while seeding a required tracker
445
445
  surface as typed, path-redacted host-environment refusals with recovery steps.
446
+ When a legacy source tracker has settings but no `_workspace` history, tracker
447
+ mode creates the sandbox's initial audited settings snapshot from the exact
448
+ source bytes. Existing source workspace history is copied unchanged, including
449
+ real drift, so linked validation never masks a source integrity failure.
446
450
 
447
451
  ## Source Workspace Modes
448
452
 
@@ -14,4 +14,4 @@ This file is generated from `PM_COMMAND_CAPABILITY_CONTRACTS`. Do not edit it ma
14
14
  | graph | `graph`, `deps`, `plan` |
15
15
  | quality | `test`, `test-all`, `validate`, `assurance`, `contracts` |
16
16
  | automation | `meet`, `event`, `remind` |
17
- | extensions | `extension`, `package`, `packages`, `install`, `upgrade` |
17
+ | extensions | `package` |
@@ -4,14 +4,14 @@ Tracker: `pm-f05lsg`.
4
4
 
5
5
  Every catalog code is listed. An `uncovered` row is an explicit closure obligation, never an omission or implied approval.
6
6
 
7
- - Catalog error codes: 342
8
- - Executable error codes: 16
9
- - Executable-code ratchet floor: 16
10
- - Required executable canonical codes: `bulk_ids_input_empty`, `bulk_ids_input_missing_path`, `bulk_ids_input_unreadable`, `invalid_argument_value`, `missing_lifecycle_target`, `missing_required_argument`, `projection_options_mutually_exclusive`, `tracker_not_initialized`, `tracker_root_missing`, `tracker_root_not_directory`, `tracker_root_unreadable`, `unknown_context_intent`, `unknown_field_projection`, `unknown_option`, `unknown_subcommand`
11
- - Uncovered error codes: 326
12
- - Coverage fraction: 0.046784
13
- - Closed-domain probes: 18
14
- - Grammar probes: 95
7
+ - Catalog error codes: 344
8
+ - Executable error codes: 19
9
+ - Executable-code ratchet floor: 18
10
+ - Required executable canonical codes: `bulk_ids_input_empty`, `bulk_ids_input_missing_path`, `bulk_ids_input_unreadable`, `invalid_argument_value`, `manifest_unknown_key`, `missing_lifecycle_target`, `missing_required_argument`, `no_version_bounds_declared`, `projection_options_mutually_exclusive`, `tracker_not_initialized`, `tracker_root_missing`, `tracker_root_not_directory`, `tracker_root_unreadable`, `unknown_context_intent`, `unknown_field_projection`, `unknown_option`, `unknown_subcommand`
11
+ - Uncovered error codes: 325
12
+ - Coverage fraction: 0.055233
13
+ - Closed-domain probes: 19
14
+ - Grammar probes: 94
15
15
 
16
16
  | Error code | Canonical code | Disposition | Evidence kinds | Probe count |
17
17
  | --- | --- | --- | --- | --- |
@@ -175,9 +175,10 @@ Every catalog code is listed. An `uncovered` row is an explicit closure obligati
175
175
  | `locks_unreadable` | `locks_unreadable` | uncovered | none | 0 |
176
176
  | `malformed_plan_step_evidence` | `malformed_plan_step_evidence` | uncovered | none | 0 |
177
177
  | `manifest_capabilities_absent` | `manifest_capabilities_absent` | uncovered | none | 0 |
178
- | `manifest_unknown_key` | `manifest_unknown_key` | uncovered | none | 0 |
178
+ | `manifest_unknown_key` | `manifest_unknown_key` | executable | owned_state | 1 |
179
179
  | `mcp_annotation_file_unavailable` | `mcp_annotation_file_unavailable` | uncovered | none | 0 |
180
180
  | `mcp_stdin_unavailable` | `mcp_stdin_unavailable` | uncovered | none | 0 |
181
+ | `mcp_task_not_found_or_not_authorized` | `mcp_task_not_found_or_not_authorized` | uncovered | none | 0 |
181
182
  | `merge_conflict_markers_detected` | `merge_conflict_markers_detected` | uncovered | none | 0 |
182
183
  | `merge_decisions_unreviewed` | `merge_decisions_unreviewed` | uncovered | none | 0 |
183
184
  | `merge_git_config_unwritable` | `merge_git_config_unwritable` | uncovered | none | 0 |
@@ -197,7 +198,7 @@ Every catalog code is listed. An `uncovered` row is an explicit closure obligati
197
198
  | `missing_observed_signature` | `missing_observed_signature` | uncovered | none | 0 |
198
199
  | `missing_parameter_alias` | `missing_parameter_alias` | uncovered | none | 0 |
199
200
  | `missing_probe` | `missing_probe` | uncovered | none | 0 |
200
- | `missing_required_argument` | `missing_required_argument` | executable | grammar | 58 |
201
+ | `missing_required_argument` | `missing_required_argument` | executable | grammar | 57 |
201
202
  | `missing_required_option` | `missing_required_option` | uncovered | none | 0 |
202
203
  | `missing_suggested_retry` | `missing_suggested_retry` | uncovered | none | 0 |
203
204
  | `missing_suggested_retry_args` | `missing_suggested_retry_args` | uncovered | none | 0 |
@@ -210,13 +211,14 @@ Every catalog code is listed. An `uncovered` row is an explicit closure obligati
210
211
  | `no_test_files_found` | `no_test_files_found` | uncovered | none | 0 |
211
212
  | `no_tests_found` | `no_tests_found` | uncovered | none | 0 |
212
213
  | `no_update_fields` | `no_update_fields` | uncovered | none | 0 |
213
- | `no_version_bounds_declared` | `no_version_bounds_declared` | uncovered | none | 0 |
214
+ | `no_version_bounds_declared` | `no_version_bounds_declared` | executable | owned_state | 1 |
214
215
  | `non_refusal_exit` | `non_refusal_exit` | uncovered | none | 0 |
215
216
  | `npm_package_not_found` | `npm_package_not_found` | uncovered | none | 0 |
216
217
  | `ownership_conflict` | `ownership_conflict` | uncovered | none | 0 |
217
218
  | `ownership_dependency_bypass_restricted_options` | `ownership_dependency_bypass_restricted_options` | uncovered | none | 0 |
218
219
  | `ownership_metadata_bypass_restricted_options` | `ownership_metadata_bypass_restricted_options` | uncovered | none | 0 |
219
220
  | `package_spec_empty` | `package_spec_empty` | uncovered | none | 0 |
221
+ | `package_upgrade_modes_mutually_exclusive` | `package_upgrade_modes_mutually_exclusive` | executable | closed_domain | 1 |
220
222
  | `positional_shape_budget_exceeded` | `positional_shape_budget_exceeded` | uncovered | none | 0 |
221
223
  | `positional_signature_mismatch` | `positional_signature_mismatch` | uncovered | none | 0 |
222
224
  | `profile_name_empty` | `profile_name_empty` | uncovered | none | 0 |
package/marketplace.json CHANGED
@@ -6,14 +6,14 @@
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": "2026.8.25"
9
+ "version": "2026.8.27"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "pm-claude",
14
14
  "source": "./plugins/pm-claude",
15
15
  "description": "Native pm CLI integration for Claude Code — 28 MCP tools, 5 workflow skills, 14 slash commands, 4 subagents, hybrid TUI task tracking, session context injection, and coordination subagents for git-based project management without leaving Claude Code.",
16
- "version": "2026.8.25",
16
+ "version": "2026.8.27",
17
17
  "author": {
18
18
  "name": "unbrained",
19
19
  "url": "https://github.com/unbraind/pm-cli"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbrained/pm-cli",
3
- "version": "2026.8.25",
3
+ "version": "2026.8.27",
4
4
  "description": "Git-native project management CLI for humans and agents.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.10.0",
@@ -16,7 +16,8 @@
16
16
  "bin": {
17
17
  "pm-cli": "dist/cli.js",
18
18
  "pm": "dist/cli.js",
19
- "pm-mcp": "dist/mcp/server.js"
19
+ "pm-mcp": "dist/mcp/server.js",
20
+ "pm-mcp-http": "dist/mcp/http-server.js"
20
21
  },
21
22
  "types": "dist/sdk/index.d.ts",
22
23
  "exports": {
@@ -103,6 +104,7 @@
103
104
  "scripts/finalize-build.mjs",
104
105
  "scripts/install.sh",
105
106
  "scripts/install.ps1",
107
+ ".agents/skills/**",
106
108
  "scripts/prepare-build-cache.mjs",
107
109
  "marketplace.json"
108
110
  ],
@@ -120,7 +122,7 @@
120
122
  "lint:complexity:baseline": "eslint . --suppress-rule complexity --suppress-rule sonarjs/cognitive-complexity",
121
123
  "lint:duplicates": "jscpd --config .jscpd.json",
122
124
  "lint:codefactor": "pnpm quality:static",
123
- "quality:static": "pnpm build && node scripts/contracts-snapshot.mjs --check && node scripts/generate-agent-capability-surfaces.mjs --check && node scripts/generate-error-code-catalog.mjs --check && node scripts/release/repository-assurance.mjs repository-static-quality --trigger ci --json && node scripts/release/audit-package-boundary.mjs && node scripts/release/package-sdk-contract-parity.mjs && node scripts/release/surface-replication-gate.mjs && node scripts/release/command-grammar-gate.mjs && node scripts/release/flag-invocation-parity.mjs && node scripts/release/flag-lexicon-gate.mjs && node scripts/release/refusal-closure-gate.mjs && node dist/cli.js assurance run tracker-context-quality --trigger ci --dry-run --json --output-budget unbounded && node scripts/release/gate-registry.mjs && node scripts/sdk-surface-snapshot.mjs --check && node scripts/bench/sdk-entrypoint-costs.mjs --check && node scripts/bench/cli-transport-floor.mjs --check && node dist/cli.js assurance run graph-composition --trigger ci --dry-run --json --output-budget unbounded && node dist/cli.js assurance run record-integrity --trigger ci --dry-run --json --output-budget unbounded",
125
+ "quality:static": "pnpm build && node scripts/contracts-snapshot.mjs --check && node scripts/generate-agent-capability-surfaces.mjs --check && node scripts/generate-error-code-catalog.mjs --check && node scripts/release/repository-assurance.mjs repository-static-quality --trigger ci --json && node scripts/release/audit-package-boundary.mjs && node scripts/release/package-sdk-contract-parity.mjs && node scripts/release/surface-replication-gate.mjs && node scripts/release/command-grammar-gate.mjs && node scripts/release/flag-invocation-parity.mjs && node scripts/release/flag-lexicon-gate.mjs && node scripts/release/refusal-closure-gate.mjs && pnpm quality:mcp-deprecations && node dist/cli.js assurance run tracker-context-quality --trigger ci --dry-run --json --output-budget unbounded && node scripts/release/gate-registry.mjs && node scripts/sdk-surface-snapshot.mjs --check && node scripts/bench/sdk-entrypoint-costs.mjs --check && node scripts/bench/cli-transport-floor.mjs --check && node dist/cli.js assurance run graph-composition --trigger ci --dry-run --json --output-budget unbounded && node dist/cli.js assurance run record-integrity --trigger ci --dry-run --json --output-budget unbounded",
124
126
  "quality:command-grammar": "pnpm build && node scripts/release/command-grammar-gate.mjs && node scripts/release/flag-invocation-parity.mjs && node scripts/release/flag-lexicon-gate.mjs",
125
127
  "quality:recovery-closure": "pnpm build && node scripts/release/refusal-closure-gate.mjs",
126
128
  "quality:token-budget": "node scripts/release/token-budget-gate.mjs",
@@ -139,6 +141,7 @@
139
141
  "quality:absence-tolerance": "node scripts/release/absence-tolerance-gate.mjs",
140
142
  "quality:docs-skills": "node scripts/release/docs-skills-gate.mjs",
141
143
  "quality:docs-links": "node scripts/release/docs-skills-gate.mjs --links-only",
144
+ "quality:mcp-deprecations": "node --input-type=module --eval 'import { main } from \"./scripts/release/mcp-deprecation-inventory.mjs\"; await main()'",
142
145
  "quality:defect-evidence": "pnpm build && node scripts/release/defect-evidence-gate.mjs",
143
146
  "quality:hosted-analysis": "node scripts/release/hosted-analysis-gate.mjs",
144
147
  "benchmark:scale:generate": "node scripts/bench/scale-workspace.mjs",
@@ -165,7 +168,7 @@
165
168
  "version:check": "node scripts/release-version.mjs check && node scripts/sync-versions.mjs check",
166
169
  "version:next": "node scripts/release-version.mjs next",
167
170
  "version:sync": "node scripts/sync-versions.mjs apply",
168
- "changelog:pm:install": "node dist/cli.js install npm:pm-changelog --project",
171
+ "changelog:pm:install": "node dist/cli.js package install npm:pm-changelog --project",
169
172
  "changelog:pm": "pnpm changelog:pm:install && node dist/cli.js changelog generate --output CHANGELOG.md --title \"Changelog\" --mode replace --all-release-tags --status closed --exclude-tag changelog-exclude --item-url-base https://github.com/unbraind/pm-cli/blob/main/.agents/pm",
170
173
  "changelog:pm:check": "pnpm changelog:pm:install && node dist/cli.js changelog generate --output CHANGELOG.md --title \"Changelog\" --mode replace --all-release-tags --status closed --exclude-tag changelog-exclude --item-url-base https://github.com/unbraind/pm-cli/blob/main/.agents/pm --check",
171
174
  "release:notes": "node scripts/generate-release-notes.mjs",
@@ -203,24 +206,26 @@
203
206
  "node": ">=22.18.0"
204
207
  },
205
208
  "dependencies": {
206
- "@sentry/node": "10.70.0",
209
+ "@sentry/node": "10.71.0",
207
210
  "@toon-format/toon": "^4.1.1",
208
211
  "@types/node": ">=22",
209
212
  "commander": "^15.0.0",
210
213
  "fast-glob": "^3.3.3",
211
214
  "fast-json-patch": "^3.1.1",
212
215
  "npm-package-arg": "^13.0.2",
213
- "tar": "7.5.22"
216
+ "tar": "7.5.22",
217
+ "yaml": "^2.9.0"
214
218
  },
215
219
  "devDependencies": {
220
+ "@modelcontextprotocol/ext-apps": "1.7.5",
216
221
  "@codspeed/vitest-plugin": "^5.7.1",
217
222
  "@eslint/js": "^10.0.1",
218
223
  "@sentry/cli": "^3.6.2",
219
- "@types/node": "^26.2.0",
224
+ "@types/node": "^26.3.0",
220
225
  "@types/npm-package-arg": "^6.1.4",
221
226
  "@vitest/coverage-v8": "^4.1.11",
222
227
  "esbuild": "0.28.2",
223
- "eslint": "^10.9.0",
228
+ "eslint": "^10.9.1",
224
229
  "eslint-plugin-sonarjs": "^4.2.0",
225
230
  "eslint-plugin-unicorn": "^73.0.0",
226
231
  "fast-check": "^4.9.0",
@@ -228,8 +233,7 @@
228
233
  "jscpd": "^5.0.16",
229
234
  "tsx": "^4.23.12",
230
235
  "typescript": "^6.0.3",
231
- "typescript-eslint": "^8.67.0",
232
- "vitest": "^4.1.11",
233
- "yaml": "^2.9.0"
236
+ "typescript-eslint": "^8.68.0",
237
+ "vitest": "^4.1.11"
234
238
  }
235
239
  }
@@ -1,10 +1,16 @@
1
1
  # pm Beads Package
2
2
 
3
- First-party pm package for importing Beads JSONL records.
3
+ First-party pm package for lossless Beads migration through public pm SDK
4
+ contracts. The importer preserves issue identity, comments, structured events,
5
+ relationships, labels, and terminal closure evidence before reporting a
6
+ complete count-parity receipt.
4
7
 
5
- ```bash
6
- pm install ./packages/pm-beads --project
7
- pm beads import --file .beads/issues.jsonl
8
- ```
8
+ ## Migration
9
9
 
10
- The package exposes the `beads import` extension command through the `pm.extensions` package manifest. Runtime sources are authored in TypeScript and shipped with JavaScript entry artifacts for Node extension loading.
10
+ Use a current portable backup for lossless relational migration. The focused
11
+ [migration guide](docs/MIGRATION.md) covers installation, source validation,
12
+ ID preservation, legacy exports, parity receipts, and post-import checks.
13
+
14
+ The package exposes the `beads import` extension command through the
15
+ `pm.extensions` package manifest. Runtime sources are TypeScript and use only
16
+ the published `@unbrained/pm-cli/sdk` surface.
@@ -0,0 +1,53 @@
1
+ # Beads Migration
2
+
3
+ Tracker: [pm-tpwde6](../../../.agents/pm/issues/pm-tpwde6.toon)
4
+
5
+ ## Lossless portable-backup migration
6
+
7
+ Install the package, create a current Beads portable backup, and import the
8
+ backup directory without modifying the source project:
9
+
10
+ ```bash
11
+ pm package install ./packages/pm-beads --project
12
+ bd backup --force
13
+ pm beads import --backup-dir .beads/backup --preserve-source-ids
14
+ ```
15
+
16
+ Current Beads backups contain relational `issues.jsonl`, `comments.jsonl`,
17
+ `events.jsonl`, `dependencies.jsonl`, and `labels.jsonl` files plus
18
+ `backup_state.json`. The importer validates those files, their foreign keys,
19
+ the backup counts, source-ID collisions, and every issue before the first pm
20
+ write. Structural source failures therefore cannot leave a partially imported
21
+ tracker; each later item commit also retains pm's normal lock and rollback
22
+ guarantees.
23
+
24
+ Successful output includes `complete: true`, source and imported counts for
25
+ each relation, and an exact `id_mapping`. Source IDs are preserved only when
26
+ they are safe path identifiers and do not collide case-insensitively with one
27
+ another or with the target tracker. Comments remain comments, Beads events are
28
+ stored as structured JSON notes, dependencies retain their source identity,
29
+ label text is normalized to canonical lowercase pm tags, and a
30
+ terminal Beads close reason becomes the pm resolution when no explicit source
31
+ resolution exists.
32
+
33
+ Verify representative records and the final tracker after import:
34
+
35
+ ```bash
36
+ pm get Tokenwerk-A1
37
+ pm comments Tokenwerk-A1
38
+ pm validate --check-resolution --check-history-drift
39
+ ```
40
+
41
+ ## Legacy single-file import
42
+
43
+ Older JSON/JSONL exports with embedded `comments`, `events`, `dependencies`,
44
+ and `labels` remain supported:
45
+
46
+ ```bash
47
+ pm beads import --file .beads/issues.jsonl
48
+ ```
49
+
50
+ A current plain `bd export` that advertises `comment_count` but omits comment
51
+ bodies is intentionally rejected before any write. Run `bd backup --force` and
52
+ use `--backup-dir` instead so the migration cannot silently lose discussion or
53
+ event history.
@@ -37,6 +37,7 @@ function toBeadsImportOptions(
37
37
  ): BeadsImportOptions {
38
38
  return {
39
39
  file: asOptionalString(options.file),
40
+ backupDir: asOptionalString(options.backupDir),
40
41
  author: global.author,
41
42
  message: asOptionalString(options.message),
42
43
  preserveSourceIds: asBoolean(options.preserveSourceIds),
@@ -69,6 +70,13 @@ export function activate(api: ExtensionApi): void {
69
70
  value_type: "string",
70
71
  description: "Path to the Beads JSONL source file.",
71
72
  },
73
+ {
74
+ long: "--backup-dir",
75
+ value_name: "path",
76
+ value_type: "string",
77
+ description:
78
+ "Path to a complete bd portable-backup directory with issue, event, comment, dependency, label, and count files.",
79
+ },
72
80
  {
73
81
  long: "--message",
74
82
  value_name: "text",