@unbrained/pm-cli 2026.8.30 → 2026.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/.agents/skills/HARNESS_COMPATIBILITY.md +1 -1
  2. package/.agents/skills/README.md +1 -1
  3. package/.agents/skills/pm-developer/SKILL.md +1 -1
  4. package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +2 -2
  5. package/.agents/skills/pm-developer/references/MULTI_AGENT_MERGE.md +1 -1
  6. package/.agents/skills/pm-developer/references/TOKEN_BUDGETS.md +1 -1
  7. package/.agents/skills/pm-extensions/SKILL.md +2 -2
  8. package/.agents/skills/pm-extensions/references/AUTHORING.md +1 -1
  9. package/.agents/skills/pm-extensions/references/LIFECYCLE.md +1 -1
  10. package/.agents/skills/pm-sdk/SKILL.md +1 -1
  11. package/.agents/skills/pm-user/SKILL.md +2 -2
  12. package/.agents/skills/pm-user/references/WORKFLOWS.md +2 -2
  13. package/.claude-plugin/marketplace.json +2 -2
  14. package/AGENTS.md +16 -14
  15. package/CHANGELOG.md +41 -6
  16. package/README.md +3 -3
  17. package/dist/cli/commands/merge.d.ts +1 -1
  18. package/dist/cli/commands/merge.js +3 -3
  19. package/dist/cli/register-list-query.js +32 -17
  20. package/dist/cli/register-mutation.js +8 -5
  21. package/dist/cli/register-operations.d.ts +2 -0
  22. package/dist/cli/register-operations.js +20 -9
  23. package/dist/cli-bundle/bundle-manifest.json +144 -144
  24. package/dist/cli-bundle/chunks/{chunk-CMIEDWAY.js → chunk-2MC2LCXZ.js} +41 -41
  25. package/dist/cli-bundle/chunks/{chunk-WS2GJQVG.js → chunk-3WICXLVT.js} +2 -2
  26. package/dist/cli-bundle/chunks/{chunk-7SKMLSMX.js → chunk-6XIIGE7U.js} +2 -2
  27. package/dist/cli-bundle/chunks/chunk-ALKKAUFN.js +35 -0
  28. package/dist/cli-bundle/chunks/{chunk-MTTKAUBX.js → chunk-DTGWEL23.js} +2 -2
  29. package/dist/cli-bundle/chunks/chunk-GOACULJW.js +13 -0
  30. package/dist/cli-bundle/chunks/chunk-NOPL37X4.js +205 -0
  31. package/dist/cli-bundle/chunks/{chunk-2UETTHY6.js → chunk-TAG4VC22.js} +30 -30
  32. package/dist/cli-bundle/chunks/{chunk-3TEF3HM5.js → chunk-U45JXJCC.js} +2 -2
  33. package/dist/cli-bundle/chunks/{chunk-TGNAA66W.js → chunk-X4RCGLTX.js} +2 -2
  34. package/dist/cli-bundle/chunks/{chunk-2MKLQL2E.js → chunk-Y7VOMSZT.js} +2 -2
  35. package/dist/cli-bundle/chunks/{register-list-query-OMKJ5ONN.js → register-list-query-XYNX4ASQ.js} +11 -11
  36. package/dist/cli-bundle/chunks/register-mutation-2MVLRS3J.js +20 -0
  37. package/dist/cli-bundle/chunks/register-operations-WCIDXBU3.js +2 -0
  38. package/dist/cli-bundle/chunks/{register-setup-GLQ5SYV3.js → register-setup-KVNC5KPL.js} +2 -2
  39. package/dist/cli-bundle/focused-chunks/{chunk-HVQ22RC4.js → chunk-2FEZ5SKM.js} +2 -2
  40. package/dist/cli-bundle/focused-chunks/{chunk-Y3JJXRVK.js → chunk-4O4CJAR6.js} +5 -5
  41. package/dist/cli-bundle/focused-chunks/chunk-7VATS5QY.js +16 -0
  42. package/dist/cli-bundle/focused-chunks/{chunk-LYFWQMVC.js → chunk-BEVHCEWG.js} +2 -2
  43. package/dist/cli-bundle/focused-chunks/{chunk-TDK3OCX3.js → chunk-FWPLDEXF.js} +2 -2
  44. package/dist/cli-bundle/focused-chunks/chunk-JEFKLWMM.js +2 -0
  45. package/dist/cli-bundle/focused-chunks/{chunk-JZYPPMXF.js → chunk-KB5OFSFD.js} +2 -2
  46. package/dist/cli-bundle/focused-chunks/{chunk-73EDXGYE.js → chunk-MKHG3T76.js} +2 -2
  47. package/dist/cli-bundle/focused-chunks/{chunk-3AVAWVZA.js → chunk-PF3E6Q36.js} +2 -2
  48. package/dist/cli-bundle/focused-chunks/{chunk-AD6ULRAF.js → chunk-QDFJIRKN.js} +4 -4
  49. package/dist/cli-bundle/focused-chunks/{chunk-RKOKG43G.js → chunk-RMRCQPWU.js} +2 -2
  50. package/dist/cli-bundle/focused-chunks/{chunk-XXOWRJZ5.js → chunk-S4U5CN5Q.js} +2 -2
  51. package/dist/cli-bundle/focused-chunks/{chunk-THEPQMLX.js → chunk-SVXJYD6G.js} +2 -2
  52. package/dist/cli-bundle/focused-chunks/chunk-T2LXXSOD.js +158 -0
  53. package/dist/cli-bundle/focused-chunks/chunk-Y6JJIX6I.js +51 -0
  54. package/dist/cli-bundle/main.js +2 -2
  55. package/dist/cli-bundle/sdk-authoring.js +1 -1
  56. package/dist/cli-bundle/sdk-contracts.js +1 -1
  57. package/dist/cli-bundle/sdk-core.js +27 -27
  58. package/dist/cli-bundle/sdk-governance.js +1 -1
  59. package/dist/cli-bundle/sdk-graph.js +1 -1
  60. package/dist/cli-bundle/sdk-merge.js +33 -33
  61. package/dist/cli-bundle/sdk-query.js +1 -1
  62. package/dist/cli-bundle/sdk-runtime.js +1 -1
  63. package/dist/cli-bundle/sdk-testing.js +1 -1
  64. package/dist/cli-bundle/sdk.js +10 -10
  65. package/dist/core/history/drift-scan.js +6 -6
  66. package/dist/core/history/history.d.ts +6 -0
  67. package/dist/core/history/history.js +47 -5
  68. package/dist/core/history/replay.d.ts +12 -1
  69. package/dist/core/history/replay.js +60 -39
  70. package/dist/core/schema/runtime-schema.d.ts +4 -0
  71. package/dist/core/schema/runtime-schema.js +60 -48
  72. package/dist/core/schema/status-defs-file.js +5 -2
  73. package/dist/mcp/legacy-adapter.d.ts +11 -2
  74. package/dist/mcp/legacy-adapter.js +26 -12
  75. package/dist/mcp/server.d.ts +2 -2
  76. package/dist/mcp/server.js +78 -15
  77. package/dist/mcp/tool-definitions.js +56 -2
  78. package/dist/sdk/agent-capability-contracts.js +4 -2
  79. package/dist/sdk/cli-contracts/flag-contracts.d.ts +2 -0
  80. package/dist/sdk/cli-contracts/flag-contracts.js +6 -2
  81. package/dist/sdk/cli-contracts/grammar-contracts.d.ts +1 -1
  82. package/dist/sdk/cli-contracts/grammar-contracts.js +12 -2
  83. package/dist/sdk/cli-contracts/runtime-contracts.js +3 -2
  84. package/dist/sdk/cli-contracts/tool-schema.js +11 -3
  85. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +14 -2
  86. package/dist/sdk/governance/health.js +17 -6
  87. package/dist/sdk/governance/status-role-diagnostics.d.ts +27 -0
  88. package/dist/sdk/governance/status-role-diagnostics.js +36 -0
  89. package/dist/sdk/governance/validate-normalization.d.ts +6 -0
  90. package/dist/sdk/governance/validate-normalization.js +37 -0
  91. package/dist/sdk/governance/validate.d.ts +1 -1
  92. package/dist/sdk/governance/validate.js +20 -35
  93. package/dist/sdk/governance/workspace-position.d.ts +69 -0
  94. package/dist/sdk/governance/workspace-position.js +164 -0
  95. package/dist/sdk/governance.d.ts +2 -0
  96. package/dist/sdk/governance.js +4 -2
  97. package/dist/sdk/history-read.js +14 -6
  98. package/dist/sdk/history-repair.js +17 -10
  99. package/dist/sdk/index.d.ts +2 -1
  100. package/dist/sdk/index.js +4 -3
  101. package/dist/sdk/init-agent-guidance.js +4 -4
  102. package/dist/sdk/lifecycle/update.js +23 -10
  103. package/dist/sdk/mcp/discovery.d.ts +152 -0
  104. package/dist/sdk/mcp/discovery.js +495 -0
  105. package/dist/sdk/mcp/protocol.d.ts +10 -2
  106. package/dist/sdk/mcp/protocol.js +15 -4
  107. package/dist/sdk/merge/index.d.ts +1 -1
  108. package/dist/sdk/merge/index.js +3 -3
  109. package/dist/sdk/merge/receipts.d.ts +27 -1
  110. package/dist/sdk/merge/receipts.js +27 -8
  111. package/dist/sdk/merge/three-way.d.ts +3 -1
  112. package/dist/sdk/merge/three-way.js +9 -7
  113. package/dist/sdk/query/context.js +11 -14
  114. package/dist/sdk/query/list.d.ts +2 -0
  115. package/dist/sdk/query/list.js +33 -12
  116. package/dist/sdk/runtime-extended-actions.js +10 -6
  117. package/dist/sdk/schema.js +12 -2
  118. package/dist/sdk/test/execution.d.ts +15 -0
  119. package/dist/sdk/test/execution.js +35 -27
  120. package/docs/AGENT_GUIDE.md +12 -4
  121. package/docs/AGENT_PROVENANCE_ADR.md +1 -1
  122. package/docs/AGENT_RUNTIME_PRIMITIVES.md +2 -2
  123. package/docs/ARCHITECTURE.md +5 -0
  124. package/docs/CLAUDE_CODE_PLUGIN.md +5 -5
  125. package/docs/COMMANDS.md +12 -12
  126. package/docs/CONFIGURATION.md +1 -1
  127. package/docs/CONTEXT_RECOVERY_PRIMITIVES.md +14 -5
  128. package/docs/DEFECT_RECURRENCE.md +2 -0
  129. package/docs/MCP_2026_07_28.md +33 -9
  130. package/docs/MCP_2026_07_28_CONFORMANCE.md +1 -0
  131. package/docs/MCP_CAPABILITY_SURFACES.md +7 -1
  132. package/docs/MCP_REMOTE_TRANSPORT_SECURITY.md +15 -3
  133. package/docs/MERGE_SAFETY.md +30 -2
  134. package/docs/ONBOARDING.md +1 -1
  135. package/docs/OUTPUT_TOKEN_ACCOUNTING.md +5 -3
  136. package/docs/PROGRESSIVE_TOOL_DISCOVERY.md +42 -0
  137. package/docs/README.md +3 -1
  138. package/docs/READ_OUTPUT_CONTRACTS.md +1 -1
  139. package/docs/RECURRENCE_RECOVERY_CONTRACTS.md +1 -1
  140. package/docs/SDK.md +3 -3
  141. package/docs/TESTING.md +23 -14
  142. package/docs/WORKSPACE_POSITION_AND_LIFECYCLE.md +113 -0
  143. package/docs/agent-task-token-baseline.json +157 -3
  144. package/docs/agent-task-transcripts.json +143 -0
  145. package/docs/examples/policy-restricted-extension/README.md +2 -2
  146. package/docs/examples/starter-extension/README.md +1 -1
  147. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +4 -3
  148. package/docs/performance/cli-transport-overhead.md +8 -6
  149. package/marketplace.json +2 -2
  150. package/package.json +4 -4
  151. package/packages/pm-beads/package.json +1 -1
  152. package/packages/pm-calendar/package.json +1 -1
  153. package/packages/pm-command-kit/package.json +1 -1
  154. package/packages/pm-digital-twin/package.json +1 -1
  155. package/packages/pm-governance-audit/package.json +1 -1
  156. package/packages/pm-guide-shell/package.json +1 -1
  157. package/packages/pm-kanban/package.json +1 -1
  158. package/packages/pm-lifecycle-hooks/package.json +1 -1
  159. package/packages/pm-linked-test-adapters/package.json +1 -1
  160. package/packages/pm-search-advanced/package.json +1 -1
  161. package/packages/pm-templates/package.json +1 -1
  162. package/packages/pm-todos/package.json +1 -1
  163. package/packages/pm-vcs/package.json +1 -1
  164. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  165. package/plugins/pm-claude/README.md +4 -3
  166. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  167. package/sdk/public-surface.json +314 -10
  168. package/dist/cli-bundle/chunks/chunk-7X6OZEIV.js +0 -34
  169. package/dist/cli-bundle/chunks/chunk-GNWPTEBW.js +0 -205
  170. package/dist/cli-bundle/chunks/chunk-N6OR6FAR.js +0 -13
  171. package/dist/cli-bundle/chunks/register-mutation-QBSNCOY3.js +0 -20
  172. package/dist/cli-bundle/chunks/register-operations-UC77FQZC.js +0 -2
  173. package/dist/cli-bundle/focused-chunks/chunk-3UMBF26I.js +0 -158
  174. package/dist/cli-bundle/focused-chunks/chunk-AXZ5AJAF.js +0 -50
  175. package/dist/cli-bundle/focused-chunks/chunk-G6PATS5E.js +0 -16
  176. package/dist/cli-bundle/focused-chunks/chunk-LLNTHF5X.js +0 -2
@@ -1,14 +1,14 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="65c0fed6-315a-5930-a23f-83996d3f5081")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1c6c65ef-115b-50e2-815e-84f6e91158cd")}catch(e){}}();
3
3
  import fs from "node:fs/promises";
4
4
  import { createHash } from "node:crypto";
5
5
  import path from "node:path";
6
6
  import { getHistoryPath } from "../store/paths.js";
7
7
  import { isFileMissingError, writeFileAtomic } from "../fs/fs-utils.js";
8
- import { CURRENT_HISTORY_ITEM_HASH_VERSION, SUPPORTED_HISTORY_ITEM_HASH_VERSIONS, hashDocumentForVersion, } from "./history.js";
8
+ import { CURRENT_HISTORY_ITEM_HASH_VERSION, SUPPORTED_HISTORY_ITEM_HASH_VERSIONS, hashDocumentVerificationCandidates, } from "./history.js";
9
9
  import { verifyHistoryChainWithVersion } from "./replay.js";
10
10
  import { getWorkspaceHistoryPath, inspectWorkspaceHistoryState, WORKSPACE_HISTORY_ID, } from "./workspace-history.js";
11
- const DRIFT_CACHE_VERSION = 7;
11
+ const DRIFT_CACHE_VERSION = 9;
12
12
  const DRIFT_CACHE_FILENAME = "history-drift-cache.json";
13
13
  function getDriftCachePath(pmRoot) {
14
14
  return path.join(pmRoot, "runtime", DRIFT_CACHE_FILENAME);
@@ -237,8 +237,8 @@ async function scanItemHistory(pmRoot, item, cache, accumulator) {
237
237
  const { body, ...itemMetadata } = item;
238
238
  if (!resolved.verification.latestHashComparable)
239
239
  return resolved.cacheDirty;
240
- const currentHash = hashDocumentForVersion({ metadata: itemMetadata, body }, resolved.verification.itemHashVersion);
241
- if (currentHash !== resolved.verification.latestAfterHash)
240
+ const currentHashes = hashDocumentVerificationCandidates({ metadata: itemMetadata, body }, resolved.verification.itemHashVersion);
241
+ if (!currentHashes.includes(resolved.verification.latestAfterHash))
242
242
  accumulator.hashMismatches.push(item.id);
243
243
  return resolved.cacheDirty;
244
244
  }
@@ -330,4 +330,4 @@ export async function scanHistoryDrift(pmRoot, items, options = {}) {
330
330
  return { ...accumulator, driftedItems };
331
331
  }
332
332
  //# sourceMappingURL=drift-scan.js.map
333
- //# debugId=65c0fed6-315a-5930-a23f-83996d3f5081
333
+ //# debugId=1c6c65ef-115b-50e2-815e-84f6e91158cd
@@ -12,6 +12,12 @@ declare function isDefinedPointerPath(document: unknown, path: string): boolean;
12
12
  export declare function hashDocument(document: ItemDocument): string;
13
13
  /** Hash an item with an explicit canonicalization epoch for replay compatibility. */
14
14
  export declare function hashDocumentForVersion(document: ItemDocument, version: HistoryItemHashVersion): string;
15
+ /**
16
+ * Return the ordered hash candidates accepted when verifying one immutable
17
+ * history epoch. Epoch 2 has both its established expanded hash first and the
18
+ * earlier field-frozen writer hash second; the other epochs have one form.
19
+ */
20
+ export declare function hashDocumentVerificationCandidates(document: ItemDocument, version: HistoryItemHashVersion): [string, ...string[]];
15
21
  /** Implements hash empty document for the public runtime surface of this module. */
16
22
  export declare function hashEmptyDocument(): string;
17
23
  /** Implements create history entry for the public runtime surface of this module. */
@@ -4,7 +4,7 @@
4
4
  * Implements append-only history and replay behavior for History.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8581413f-e74e-5db3-86bf-5e39290de741")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="60d6ec0e-a8ed-5a5d-b5bd-d29da8532a79")}catch(e){}}();
8
8
  import jsonPatch from "fast-json-patch";
9
9
  import { ITEM_METADATA_KEY_ORDER } from "../shared/constants.js";
10
10
  import { runActiveServiceOverride } from "../extensions/index.js";
@@ -117,7 +117,7 @@ function normalizeHistoryPatchOps(beforeDocument, patch) {
117
117
  }
118
118
  return normalized;
119
119
  }
120
- function canonicalHashDocument(document, version) {
120
+ function canonicalHashDocument(document, version, legacyV2Fields = false) {
121
121
  const hasMetadata = document.metadata && Object.keys(document.metadata).length > 0;
122
122
  if (!hasMetadata) {
123
123
  return {
@@ -126,12 +126,40 @@ function canonicalHashDocument(document, version) {
126
126
  };
127
127
  }
128
128
  const canonical = canonicalDocument(document);
129
- const metadata = version === 1 && canonical.metadata.tests
129
+ // Epoch 1 and the earliest epoch-2 writer predate linked-test provenance,
130
+ // workspace isolation, per-execution receipts, and case-preserving
131
+ // dependency ids. Later epoch-2 writers included those fields without
132
+ // advancing the marker, so verification must retain both immutable forms.
133
+ const usesLegacyFields = version === 1 || (version === 2 && legacyV2Fields);
134
+ const epochMetadata = usesLegacyFields
130
135
  ? {
131
136
  ...canonical.metadata,
132
- tests: [...canonical.metadata.tests].sort(compareLegacyLinkedTests),
137
+ ...(canonical.metadata.dependencies === undefined
138
+ ? {}
139
+ : {
140
+ dependencies: canonical.metadata.dependencies.map((dependency) => ({
141
+ ...dependency,
142
+ id: dependency.id.toLowerCase(),
143
+ })),
144
+ }),
145
+ ...(canonical.metadata.tests === undefined
146
+ ? {}
147
+ : {
148
+ tests: canonical.metadata.tests.map(({ workspace_context_mode: _workspaceContextMode, provenance: _provenance, provenance_invalid: _provenanceInvalid, ...test }) => test),
149
+ }),
150
+ ...(canonical.metadata.test_runs === undefined
151
+ ? {}
152
+ : {
153
+ test_runs: canonical.metadata.test_runs.map(({ executions: _executions, ...testRun }) => testRun),
154
+ }),
133
155
  }
134
156
  : canonical.metadata;
157
+ const metadata = version === 1 && epochMetadata.tests
158
+ ? {
159
+ ...epochMetadata,
160
+ tests: [...epochMetadata.tests].sort(compareLegacyLinkedTests),
161
+ }
162
+ : epochMetadata;
135
163
  const orderedMetadata = orderObject(toItemRecord(metadata), ITEM_METADATA_KEY_ORDER);
136
164
  return {
137
165
  front_matter: orderedMetadata,
@@ -164,6 +192,20 @@ export function hashDocumentForVersion(document, version) {
164
192
  }
165
193
  return sha256Hex(stableStringify(canonicalHashDocument(document, version)));
166
194
  }
195
+ /**
196
+ * Return the ordered hash candidates accepted when verifying one immutable
197
+ * history epoch. Epoch 2 has both its established expanded hash first and the
198
+ * earlier field-frozen writer hash second; the other epochs have one form.
199
+ */
200
+ export function hashDocumentVerificationCandidates(document, version) {
201
+ const canonicalHash = hashDocumentForVersion(document, version);
202
+ return version === 2
203
+ ? [
204
+ canonicalHash,
205
+ sha256Hex(stableStringify(canonicalHashDocument(document, version, true))),
206
+ ]
207
+ : [canonicalHash];
208
+ }
167
209
  /** Implements hash empty document for the public runtime surface of this module. */
168
210
  export function hashEmptyDocument() {
169
211
  return sha256Hex(stableStringify(EMPTY_LEGACY_HASH_DOCUMENT));
@@ -292,4 +334,4 @@ export const _testOnly = {
292
334
  isDefinedPointerPath,
293
335
  };
294
336
  //# sourceMappingURL=history.js.map
295
- //# debugId=8581413f-e74e-5db3-86bf-5e39290de741
337
+ //# debugId=60d6ec0e-a8ed-5a5d-b5bd-d29da8532a79
@@ -21,6 +21,12 @@ export declare const EMPTY_REPLAY_DOCUMENT: ReplayDocument;
21
21
  export declare function cloneEmptyReplayDocument(): ReplayDocument;
22
22
  /** Implements replay hash for the public runtime surface of this module. */
23
23
  export declare function replayHash(document: ReplayDocument, version?: HistoryItemHashVersion): string;
24
+ /**
25
+ * Return hash candidates that preserve the semantic variant within an epoch.
26
+ * Duplicate values are intentional: before and after candidates use the same
27
+ * index when a patch introduces a field that distinguishes legacy epoch 2.
28
+ */
29
+ export declare function replayHashVerificationCandidates(document: ReplayDocument, version: HistoryItemHashVersion): [string, ...string[]];
24
30
  /** Implements replay to item document for the public runtime surface of this module. */
25
31
  export declare function replayToItemDocument(document: ReplayDocument): ItemDocument;
26
32
  /** Converts a materialized replay document into a canonical item document. Use this when callers have already rejected the empty/deleted replay state and need restored metadata validated through the normal item-metadata rules. */
@@ -98,6 +104,11 @@ export interface ReanchorResult {
98
104
  /** Whether rewritten entries explicitly carry the hash epoch field. */
99
105
  explicitItemHashVersion: boolean;
100
106
  }
107
+ /** Controls whether re-anchoring preserves historical writer transitions or emits one exact hash surface. */
108
+ export interface ReanchorHistoryOptions {
109
+ /** Keep one semantic hash candidate for the complete rewritten stream so adjacent stored endpoints are identical. */
110
+ continuousHashSurface?: boolean;
111
+ }
101
112
  /**
102
113
  * Resolve the hash epoch a repair must retain.
103
114
  *
@@ -108,6 +119,6 @@ export interface ReanchorResult {
108
119
  */
109
120
  export declare function resolveHistoryRepairItemHashVersion(entries: HistoryEntry[]): HistoryItemHashVersion;
110
121
  /** Re-anchor a drifted history chain: replay every entry from empty, recompute the before/after hashes, and only rewrite a patch when the original op set no longer strictly applies (legacy drift). Clean entries keep their patch verbatim so the on-disk diff stays minimal. The returned chain verifies via verifyHistoryChain. */
111
- export declare function reanchorHistoryEntries(entries: HistoryEntry[], itemHashVersion?: 1 | 2 | 3): ReanchorResult;
122
+ export declare function reanchorHistoryEntries(entries: HistoryEntry[], itemHashVersion?: 1 | 2 | 3, options?: ReanchorHistoryOptions): ReanchorResult;
112
123
  /** Implements history entries to raw for the public runtime surface of this module. */
113
124
  export declare function historyEntriesToRaw(entries: HistoryEntry[]): string;
@@ -4,13 +4,13 @@
4
4
  * Implements append-only history and replay behavior for Replay.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c823af51-0cfd-536b-8f85-1f3e72db1c86")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c9488ed4-8228-5e7c-9717-69dd7a3275c4")}catch(e){}}();
8
8
  import jsonPatch from "fast-json-patch";
9
9
  import { ITEM_METADATA_KEY_ORDER } from "../shared/constants.js";
10
10
  import { canonicalDocument } from "../item/item-format.js";
11
11
  import { toItemRecord } from "../item/item-record.js";
12
12
  import { orderObject, sha256Hex, stableStringify, } from "../shared/serialization.js";
13
- import { CURRENT_HISTORY_ITEM_HASH_VERSION, SUPPORTED_HISTORY_ITEM_HASH_VERSIONS, hashDocumentForVersion, } from "./history.js";
13
+ import { CURRENT_HISTORY_ITEM_HASH_VERSION, SUPPORTED_HISTORY_ITEM_HASH_VERSIONS, hashDocumentVerificationCandidates, } from "./history.js";
14
14
  /** Public contract for empty replay document, shared by SDK and presentation-layer consumers. */
15
15
  export const EMPTY_REPLAY_DOCUMENT = {
16
16
  metadata: {},
@@ -22,23 +22,42 @@ export function cloneEmptyReplayDocument() {
22
22
  }
23
23
  /** Implements replay hash for the public runtime surface of this module. */
24
24
  export function replayHash(document, version = CURRENT_HISTORY_ITEM_HASH_VERSION) {
25
+ return replayHashVerificationCandidates(document, version)[0];
26
+ }
27
+ /**
28
+ * Return hash candidates that preserve the semantic variant within an epoch.
29
+ * Duplicate values are intentional: before and after candidates use the same
30
+ * index when a patch introduces a field that distinguishes legacy epoch 2.
31
+ */
32
+ export function replayHashVerificationCandidates(document, version) {
25
33
  if (Object.keys(document.metadata).length === 0 ||
26
34
  Array.isArray(document.metadata.tags)) {
27
35
  try {
28
- return hashDocumentForVersion(replayToItemDocument(document), version);
36
+ return hashDocumentVerificationCandidates(replayToItemDocument(document), version);
29
37
  }
30
38
  catch {
31
39
  // Fall through when another malformed legacy field cannot be canonicalized.
32
40
  }
33
41
  }
34
- // Preserve the structural hashes recorded before missing tags became safe to
35
- // normalize. Pre-create/legacy replay states and other malformed metadata cannot
36
- // switch hash algorithms without invalidating immutable history chains.
37
- return sha256Hex(stableStringify({
42
+ const fallback = sha256Hex(stableStringify({
38
43
  replay_fallback: true,
39
44
  metadata: document.metadata,
40
45
  body: document.body,
41
46
  }));
47
+ return version === 2 ? [fallback, fallback] : [fallback];
48
+ }
49
+ /** Match one recorded entry against corresponding before/after hash variants. */
50
+ function matchReplayHashCandidates(before, after, version, entry) {
51
+ const beforeHashes = replayHashVerificationCandidates(before, version);
52
+ const afterHashes = replayHashVerificationCandidates(after, version);
53
+ return {
54
+ beforeHashes,
55
+ afterHashes,
56
+ pairIndex: beforeHashes.findIndex((beforeHash, hashIndex) => beforeHash === entry.before_hash &&
57
+ afterHashes[hashIndex] === entry.after_hash),
58
+ beforeIndex: beforeHashes.indexOf(entry.before_hash),
59
+ afterIndex: afterHashes.indexOf(entry.after_hash),
60
+ };
42
61
  }
43
62
  /** Implements replay to item document for the public runtime surface of this module. */
44
63
  export function replayToItemDocument(document) {
@@ -156,22 +175,9 @@ export function verifyHistoryChainWithVersion(entries) {
156
175
  for (let index = 0; index < entries.length; index += 1) {
157
176
  const entry = entries[index];
158
177
  const explicitVersion = entry.item_hash_version;
159
- if (isUnsupportedExplicitHistoryItemHashVersion(explicitVersion)) {
178
+ const unsupportedVersion = isUnsupportedExplicitHistoryItemHashVersion(explicitVersion);
179
+ if (unsupportedVersion) {
160
180
  errors.push(`verify_failed:unsupported_item_hash_version:${String(explicitVersion)}:entry_${index + 1}`);
161
- const applied = tryApplyReplayPatch(replay, entry.patch);
162
- if (!applied.ok) {
163
- return {
164
- ok: false,
165
- errors: [
166
- ...errors,
167
- `verify_failed:patch_apply_failed:entry_${index + 1}`,
168
- ],
169
- };
170
- }
171
- replay = applied.document;
172
- detectedVersion = undefined;
173
- authoritativeExplicitVersion = undefined;
174
- continue;
175
181
  }
176
182
  const applied = tryApplyReplayPatch(replay, entry.patch);
177
183
  if (!applied.ok) {
@@ -183,30 +189,32 @@ export function verifyHistoryChainWithVersion(entries) {
183
189
  ],
184
190
  };
185
191
  }
192
+ if (unsupportedVersion) {
193
+ replay = applied.document;
194
+ detectedVersion = undefined;
195
+ authoritativeExplicitVersion = undefined;
196
+ continue;
197
+ }
186
198
  // Prefer legacy epoch 1 when an unversioned entry is valid under both
187
199
  // algorithms, but retain compatibility with transitional epoch-2 writers
188
200
  // that shipped before item_hash_version became explicit.
189
201
  const candidates = historyEntryHashCandidates(explicitVersion, authoritativeExplicitVersion);
190
- const beforeMatches = candidates.filter((version) => replayHash(replay, version) === entry.before_hash);
191
- if (beforeMatches.length === 0) {
202
+ const candidateMatches = candidates.map((version) => ({
203
+ version,
204
+ match: matchReplayHashCandidates(replay, applied.document, version, entry),
205
+ }));
206
+ const matchingVersion = candidateMatches.find(({ match }) => match.pairIndex >= 0);
207
+ if (matchingVersion === undefined) {
208
+ const beforeMatches = candidateMatches.some(({ match }) => match.beforeIndex >= 0);
192
209
  return {
193
210
  ok: false,
194
211
  errors: [
195
212
  ...errors,
196
- `verify_failed:before_hash_mismatch:entry_${index + 1}`,
197
- ],
198
- };
199
- }
200
- const version = beforeMatches.find((candidate) => replayHash(applied.document, candidate) === entry.after_hash);
201
- if (version === undefined) {
202
- return {
203
- ok: false,
204
- errors: [
205
- ...errors,
206
- `verify_failed:after_hash_mismatch:entry_${index + 1}`,
213
+ `verify_failed:${beforeMatches ? "after" : "before"}_hash_mismatch:entry_${index + 1}`,
207
214
  ],
208
215
  };
209
216
  }
217
+ const version = matchingVersion.version;
210
218
  replay = applied.document;
211
219
  detectedVersion = version;
212
220
  authoritativeExplicitVersion =
@@ -297,7 +305,7 @@ export function resolveHistoryRepairItemHashVersion(entries) {
297
305
  return CURRENT_HISTORY_ITEM_HASH_VERSION;
298
306
  }
299
307
  /** Re-anchor a drifted history chain: replay every entry from empty, recompute the before/after hashes, and only rewrite a patch when the original op set no longer strictly applies (legacy drift). Clean entries keep their patch verbatim so the on-disk diff stays minimal. The returned chain verifies via verifyHistoryChain. */
300
- export function reanchorHistoryEntries(entries, itemHashVersion = resolveHistoryRepairItemHashVersion(entries)) {
308
+ export function reanchorHistoryEntries(entries, itemHashVersion = resolveHistoryRepairItemHashVersion(entries), options = {}) {
301
309
  const unsupportedIndex = entries.findIndex((entry) => isUnsupportedExplicitHistoryItemHashVersion(entry.item_hash_version));
302
310
  if (unsupportedIndex >= 0) {
303
311
  throw new TypeError(`unsupported_item_hash_version:${String(entries[unsupportedIndex]?.item_hash_version)}:entry_${unsupportedIndex + 1}`);
@@ -309,11 +317,11 @@ export function reanchorHistoryEntries(entries, itemHashVersion = resolveHistory
309
317
  let entriesPatchRepaired = 0;
310
318
  let convertedReplaceToAdd = 0;
311
319
  let skippedOps = 0;
320
+ let semanticIndex;
312
321
  const explicitItemHashVersion = itemHashVersion !== 1 ||
313
322
  entries.some((entry) => entry.item_hash_version !== undefined);
314
323
  for (let index = 0; index < entries.length; index += 1) {
315
324
  const entry = entries[index];
316
- const beforeHash = replayHash(replay, itemHashVersion);
317
325
  const strict = tryApplyReplayPatch(replay, entry.patch);
318
326
  let next;
319
327
  let outPatch;
@@ -335,7 +343,20 @@ export function reanchorHistoryEntries(entries, itemHashVersion = resolveHistory
335
343
  skippedOps += entrySkipped;
336
344
  entriesPatchRepaired += 1;
337
345
  }
338
- const afterHash = replayHash(next, itemHashVersion);
346
+ const hashMatch = matchReplayHashCandidates(replay, next, itemHashVersion, entry);
347
+ if (semanticIndex === undefined || options.continuousHashSurface !== true) {
348
+ semanticIndex = [
349
+ hashMatch.pairIndex,
350
+ hashMatch.beforeIndex,
351
+ hashMatch.afterIndex,
352
+ Math.min(semanticIndex ?? 0, hashMatch.beforeHashes.length - 1),
353
+ ].find((candidate) => candidate >= 0);
354
+ }
355
+ else {
356
+ semanticIndex = Math.min(semanticIndex, hashMatch.beforeHashes.length - 1);
357
+ }
358
+ const beforeHash = hashMatch.beforeHashes[semanticIndex];
359
+ const afterHash = hashMatch.afterHashes[semanticIndex];
339
360
  const rehashed = beforeHash !== entry.before_hash || afterHash !== entry.after_hash;
340
361
  if (rehashed) {
341
362
  entriesRehashed += 1;
@@ -382,4 +403,4 @@ export function historyEntriesToRaw(entries) {
382
403
  return `${entries.map((entry) => JSON.stringify(entry)).join("\n")}\n`;
383
404
  }
384
405
  //# sourceMappingURL=replay.js.map
385
- //# debugId=c823af51-0cfd-536b-8f85-1f3e72db1c86
406
+ //# debugId=c9488ed4-8228-5e7c-9717-69dd7a3275c4
@@ -75,6 +75,10 @@ export interface RuntimeStatusRegistry {
75
75
  draft_statuses: Set<string>;
76
76
  /** Configured status id representing the open lifecycle state. */
77
77
  open_status: string;
78
+ /** Configured status id representing the in-progress lifecycle state. */
79
+ in_progress_status: string;
80
+ /** Configured status id representing the blocked lifecycle state. */
81
+ blocked_status: string;
78
82
  /** Configured status id representing the closed lifecycle state. */
79
83
  close_status: string;
80
84
  /** Configured status id representing the canceled lifecycle state. */
@@ -4,7 +4,7 @@
4
4
  * Resolves configurable schema, fields, statuses, and workflows for Runtime Schema.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="88b9179f-569e-5cd6-b67c-c27431961554")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="633ef301-42a3-5b73-a4ed-7af0e0e40371")}catch(e){}}();
8
8
  import path from "node:path";
9
9
  import { pathExists, readFileIfExists, writeFileAtomic, } from "../fs/fs-utils.js";
10
10
  import { DEFAULT_STATUS_DEFINITIONS, DEFAULT_WORKFLOW_DEFINITION, } from "../shared/constants.js";
@@ -52,8 +52,7 @@ const RUNTIME_FIELD_VALUE_SCHEMA_SHAPE_VALIDATORS = [
52
52
  (Array.isArray(schema.enum) &&
53
53
  schema.enum.every((entry) => isStructuredJsonValue(entry))),
54
54
  (schema) => schema.min_length === undefined ||
55
- (Number.isInteger(schema.min_length) &&
56
- schema.min_length >= 0),
55
+ (Number.isInteger(schema.min_length) && schema.min_length >= 0),
57
56
  (schema) => schema.min_items === undefined ||
58
57
  (Number.isInteger(schema.min_items) && schema.min_items >= 0),
59
58
  (schema) => schema.format === undefined || schema.format === "date-time",
@@ -62,8 +61,7 @@ const RUNTIME_FIELD_VALUE_SCHEMA_SHAPE_VALIDATORS = [
62
61
  schema.required.every((entry) => typeof entry === "string" && entry.length > 0)),
63
62
  (schema) => schema.additional_properties === undefined ||
64
63
  typeof schema.additional_properties === "boolean",
65
- (schema) => schema.properties === undefined ||
66
- isPlainObject(schema.properties),
64
+ (schema) => schema.properties === undefined || isPlainObject(schema.properties),
67
65
  (schema) => schema.one_of === undefined ||
68
66
  (Array.isArray(schema.one_of) && schema.one_of.length > 0),
69
67
  ];
@@ -137,9 +135,7 @@ function normalizeRuntimeFieldValueSchema(value, depth = 0, ancestors = new Set(
137
135
  min_items: minItems,
138
136
  format: format,
139
137
  properties: normalizedProperties,
140
- required: required === undefined
141
- ? undefined
142
- : [...new Set(required)],
138
+ required: required === undefined ? undefined : [...new Set(required)],
143
139
  additional_properties: additionalProperties,
144
140
  items: normalizedItems,
145
141
  one_of: normalizedOneOf,
@@ -329,7 +325,10 @@ function normalizeRuntimeFieldDefinition(definition) {
329
325
  description: description && description.length > 0 ? description : undefined,
330
326
  type,
331
327
  commands,
332
- repeatable: [definition.repeatable === true, type === "string_array"].includes(true),
328
+ repeatable: [
329
+ definition.repeatable === true,
330
+ type === "string_array",
331
+ ].includes(true),
333
332
  required: definition.required === true,
334
333
  required_on_create: definition.required_on_create === true,
335
334
  required_types: requiredTypes,
@@ -658,27 +657,22 @@ export async function loadRuntimeSchemaFromOptionalFiles(pmRoot, schema) {
658
657
  created_paths: [],
659
658
  };
660
659
  }
661
- function preferredStatusForRole(definitions, role, fallbackValues) {
662
- const withRole = definitions.filter((definition) => definition.roles.includes(role));
663
- if (withRole.length > 0) {
664
- return withRole[0].id;
665
- }
660
+ function preferredStatusForRole(definitions, role, fallbackValues, fallbackFirst = false) {
666
661
  const normalizedFallbacks = fallbackValues
667
662
  .map((value) => normalizeStatusId(value))
668
663
  .filter((value) => typeof value === "string");
669
- for (const normalized of normalizedFallbacks) {
670
- if (definitions.some((definition) => definition.id === normalized)) {
671
- return normalized;
672
- }
664
+ const fallbackMatch = normalizedFallbacks.find((normalized) => definitions.some((definition) => definition.id === normalized));
665
+ if (fallbackFirst && fallbackMatch !== undefined) {
666
+ return fallbackMatch;
673
667
  }
674
- return definitions[0]?.id;
668
+ const withRole = definitions.find((definition) => definition.roles.includes(role));
669
+ if (withRole !== undefined) {
670
+ return withRole.id;
671
+ }
672
+ return fallbackMatch ?? definitions[0]?.id;
675
673
  }
676
- /** Implements resolve runtime status registry for the public runtime surface of this module. */
677
- export function resolveRuntimeStatusRegistry(schema) {
678
- const normalizedSchema = normalizeRuntimeSchemaSettings(schema);
679
- const definitions = normalizedSchema.statuses
680
- .map((definition, index) => normalizeRuntimeStatusDefinition(definition, index))
681
- .filter((definition) => definition !== null);
674
+ /** Build normalized identifier and alias indexes for runtime status lookup. */
675
+ function buildRuntimeStatusIndexes(definitions) {
682
676
  const aliasToId = new Map();
683
677
  const byId = new Map();
684
678
  for (const definition of definitions) {
@@ -692,42 +686,58 @@ export function resolveRuntimeStatusRegistry(schema) {
692
686
  aliasToId.set(alias.replaceAll("_", " "), definition.id);
693
687
  }
694
688
  }
695
- const terminalStatuses = new Set();
696
- const terminalDoneStatuses = new Set();
697
- const terminalCanceledStatuses = new Set();
698
- const activeStatuses = new Set();
699
- const blockedStatuses = new Set();
700
- const draftStatuses = new Set();
689
+ return { aliasToId, byId };
690
+ }
691
+ /** Classify runtime statuses into lifecycle role sets used by all consumers. */
692
+ function buildRuntimeStatusRoleSets(definitions) {
693
+ const result = {
694
+ activeStatuses: new Set(),
695
+ blockedStatuses: new Set(),
696
+ draftStatuses: new Set(),
697
+ terminalCanceledStatuses: new Set(),
698
+ terminalDoneStatuses: new Set(),
699
+ terminalStatuses: new Set(),
700
+ };
701
701
  for (const definition of definitions) {
702
702
  const roles = new Set(definition.roles);
703
703
  if (roles.has("terminal") ||
704
704
  roles.has("terminal_done") ||
705
705
  roles.has("terminal_canceled")) {
706
- terminalStatuses.add(definition.id);
707
- }
708
- if (roles.has("terminal_done")) {
709
- terminalDoneStatuses.add(definition.id);
706
+ result.terminalStatuses.add(definition.id);
710
707
  }
708
+ if (roles.has("terminal_done"))
709
+ result.terminalDoneStatuses.add(definition.id);
711
710
  if (roles.has("terminal_canceled")) {
712
- terminalCanceledStatuses.add(definition.id);
713
- }
714
- if (roles.has("active")) {
715
- activeStatuses.add(definition.id);
716
- }
717
- if (roles.has("blocked")) {
718
- blockedStatuses.add(definition.id);
719
- }
720
- if (roles.has("draft")) {
721
- draftStatuses.add(definition.id);
711
+ result.terminalCanceledStatuses.add(definition.id);
722
712
  }
713
+ if (roles.has("active"))
714
+ result.activeStatuses.add(definition.id);
715
+ if (roles.has("blocked"))
716
+ result.blockedStatuses.add(definition.id);
717
+ if (roles.has("draft"))
718
+ result.draftStatuses.add(definition.id);
723
719
  }
720
+ return result;
721
+ }
722
+ /** Implements resolve runtime status registry for the public runtime surface of this module. */
723
+ export function resolveRuntimeStatusRegistry(schema) {
724
+ const normalizedSchema = normalizeRuntimeSchemaSettings(schema);
725
+ const definitions = normalizedSchema.statuses
726
+ .map((definition, index) => normalizeRuntimeStatusDefinition(definition, index))
727
+ .filter((definition) => definition !== null);
728
+ const { aliasToId, byId } = buildRuntimeStatusIndexes(definitions);
729
+ const { activeStatuses, blockedStatuses, draftStatuses, terminalCanceledStatuses, terminalDoneStatuses, terminalStatuses, } = buildRuntimeStatusRoleSets(definitions);
724
730
  const workflow = normalizedSchema.workflow;
725
- const openStatus = normalizeStatusId(workflow.open_status) ??
731
+ const openStatus = (normalizeStatusId(workflow.open_status) ??
726
732
  preferredStatusForRole(definitions, "default_open", [
727
733
  "open",
728
734
  "in_progress",
729
735
  STATUS_VALUES[0],
730
- ]);
736
+ ]));
737
+ const inProgressStatus = normalizeStatusId(workflow.in_progress_status) ??
738
+ preferredStatusForRole(definitions, "active", ["in_progress", "in-progress", openStatus], true);
739
+ const blockedStatus = normalizeStatusId(workflow.blocked_status) ??
740
+ preferredStatusForRole(definitions, "blocked", ["blocked"]);
731
741
  const closeStatus = normalizeStatusId(workflow.close_status) ??
732
742
  preferredStatusForRole(definitions, "default_close", [
733
743
  "closed",
@@ -750,6 +760,8 @@ export function resolveRuntimeStatusRegistry(schema) {
750
760
  blocked_statuses: blockedStatuses,
751
761
  draft_statuses: draftStatuses,
752
762
  open_status: openStatus,
763
+ in_progress_status: inProgressStatus,
764
+ blocked_status: blockedStatus,
753
765
  close_status: closeStatus,
754
766
  canceled_status: canceledStatus,
755
767
  };
@@ -812,4 +824,4 @@ export function statusIsTerminal(status, registry) {
812
824
  return registry.terminal_statuses.has(normalized);
813
825
  }
814
826
  //# sourceMappingURL=runtime-schema.js.map
815
- //# debugId=88b9179f-569e-5cd6-b67c-c27431961554
827
+ //# debugId=633ef301-42a3-5b73-a4ed-7af0e0e40371
@@ -4,7 +4,7 @@
4
4
  * Resolves configurable schema, fields, statuses, and workflows for Status Defs File.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3eac0218-43c9-5bd2-8eaf-589d02d2c8ad")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ec456832-5120-5171-93fd-861ea4125acb")}catch(e){}}();
8
8
  import { RUNTIME_STATUS_ROLE_VALUES } from "../../types/index.js";
9
9
  import { DEFAULT_RUNTIME_STATUS_DEFINITIONS } from "./runtime-schema.js";
10
10
  import { normalizeStatusToken } from "./status-token.js";
@@ -72,6 +72,9 @@ export function normalizeAddStatusInput(raw) {
72
72
  roles.push(role);
73
73
  }
74
74
  }
75
+ if (roles.length === 0) {
76
+ throw new Error(`Status role must include at least one lifecycle role. Allowed roles: ${RUNTIME_STATUS_ROLE_VALUES.join(", ")}.`);
77
+ }
75
78
  }
76
79
  const aliases = raw.aliases === undefined
77
80
  ? undefined
@@ -222,4 +225,4 @@ export function assertStatusTokensAvailable(input, resolvedAliasToId) {
222
225
  }
223
226
  }
224
227
  //# sourceMappingURL=status-defs-file.js.map
225
- //# debugId=3eac0218-43c9-5bd2-8eaf-589d02d2c8ad
228
+ //# debugId=ec456832-5120-5171-93fd-861ea4125acb
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * @module mcp/legacy-adapter
3
3
  *
4
- * Isolates the bounded MCP 2025-06-18 stdio compatibility surface from the
4
+ * Isolates the bounded initialize-era stdio compatibility surface from the
5
5
  * canonical stateless dispatcher. No modern transport imports policy from it.
6
6
  */
7
7
  import { type AgentClientInfo } from "../sdk/runtime-primitives.js";
8
- import { type PmMcpImplementation, type PmMcpServerCapabilities } from "../sdk/mcp/protocol.js";
8
+ import { PM_MCP_LEGACY_PROTOCOL_VERSIONS, type PmMcpImplementation, type PmMcpServerCapabilities } from "../sdk/mcp/protocol.js";
9
9
  /** Minimal request shape consumed by the compatibility adapter. */
10
10
  export interface LegacyMcpRequest {
11
11
  /** Legacy method name. */
@@ -36,6 +36,15 @@ export interface LegacyMcpAdapterOptions {
36
36
  /** Render one legacy prompt. */
37
37
  getPrompt: (params: Record<string, unknown> | undefined) => Record<string, unknown>;
38
38
  }
39
+ /**
40
+ * Resolve the legacy revision a handshake negotiates, or refuse with the full
41
+ * supported set.
42
+ *
43
+ * A legacy client has no fall-forward mechanism, so the refusal names every
44
+ * accepted legacy revision alongside the canonical modern one: the error text
45
+ * is the only diagnostic such a client can surface.
46
+ */
47
+ export declare function resolveLegacyProtocolVersion(requestedVersion: unknown): (typeof PM_MCP_LEGACY_PROTOCOL_VERSIONS)[number];
39
48
  /** Explicit compatibility adapter with no cross-process or modern-session role. */
40
49
  export declare class LegacyMcpAdapter {
41
50
  #private;