@unbrained/pm-cli 2026.9.10 → 2026.9.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +53 -11
  3. package/dist/cli/command-namespaces.d.ts +2 -2
  4. package/dist/cli/command-namespaces.js +1 -1
  5. package/dist/cli/error-guidance.d.ts +10 -0
  6. package/dist/cli/error-guidance.js +1 -1
  7. package/dist/cli/extension-command-help.js +3 -3
  8. package/dist/cli/main.d.ts +4 -0
  9. package/dist/cli/main.js +2 -2
  10. package/dist/cli/option-values.d.ts +3 -0
  11. package/dist/cli/option-values.js +2 -0
  12. package/dist/cli/register-history-maintenance.js +2 -1
  13. package/dist/cli/register-list-query.js +2 -2
  14. package/dist/cli/register-mutation.d.ts +5 -0
  15. package/dist/cli/register-mutation.js +2 -16
  16. package/dist/cli/schema/registration.d.ts +4 -0
  17. package/dist/cli/schema/registration.js +16 -0
  18. package/dist/cli-bundle/bundle-manifest.json +156 -156
  19. package/dist/cli-bundle/chunks/{chunk-NKOYVKFM.js → chunk-2JAY4LFI.js} +2 -2
  20. package/dist/cli-bundle/chunks/{chunk-I6XT3DLQ.js → chunk-3ZJDGTYC.js} +53 -53
  21. package/dist/cli-bundle/chunks/chunk-67H4PKQ5.js +3 -0
  22. package/dist/cli-bundle/chunks/{chunk-EOCKPCEY.js → chunk-7H33WPDF.js} +2 -2
  23. package/dist/cli-bundle/chunks/chunk-7KF6HCRC.js +20 -0
  24. package/dist/cli-bundle/chunks/chunk-DEGRLB6Y.js +235 -0
  25. package/dist/cli-bundle/chunks/chunk-GKY655T7.js +6 -0
  26. package/dist/cli-bundle/chunks/chunk-I6VQUHK6.js +8 -0
  27. package/dist/cli-bundle/chunks/chunk-PTX2JRFR.js +2 -0
  28. package/dist/cli-bundle/chunks/{chunk-PYUITRSV.js → chunk-TAGDYARO.js} +2 -2
  29. package/dist/cli-bundle/chunks/chunk-X6POOZKD.js +29 -0
  30. package/dist/cli-bundle/chunks/{chunk-4SFBH77G.js → chunk-YU75JRTW.js} +156 -142
  31. package/dist/cli-bundle/chunks/{register-list-query-CUIW7SSE.js → register-list-query-KEZPDR6X.js} +6 -6
  32. package/dist/cli-bundle/chunks/register-mutation-HEXA3ZDM.js +20 -0
  33. package/dist/cli-bundle/chunks/{register-operations-XIZPLPQY.js → register-operations-TEZT65JF.js} +2 -2
  34. package/dist/cli-bundle/chunks/{register-setup-JVGPCAIL.js → register-setup-IIL74WUG.js} +2 -2
  35. package/dist/cli-bundle/focused-chunks/{chunk-ZAWAL2CG.js → chunk-2BQ4JSJQ.js} +2 -2
  36. package/dist/cli-bundle/focused-chunks/chunk-5CRND7UA.js +12 -0
  37. package/dist/cli-bundle/focused-chunks/chunk-5PSYV3AT.js +164 -0
  38. package/dist/cli-bundle/focused-chunks/{chunk-SL5YVVPV.js → chunk-7EKXAUKF.js} +53 -52
  39. package/dist/cli-bundle/focused-chunks/chunk-BIOWOU6S.js +30 -0
  40. package/dist/cli-bundle/focused-chunks/chunk-EIXGDI77.js +2 -0
  41. package/dist/cli-bundle/focused-chunks/chunk-GAKFECOQ.js +2 -0
  42. package/dist/cli-bundle/focused-chunks/chunk-HFAW3FJQ.js +2 -0
  43. package/dist/cli-bundle/focused-chunks/{chunk-U5SHHU7E.js → chunk-IURELABV.js} +2 -2
  44. package/dist/cli-bundle/focused-chunks/chunk-KK7KSXUP.js +8 -0
  45. package/dist/cli-bundle/focused-chunks/{chunk-ZDNAWWQI.js → chunk-LWJBBM6X.js} +2 -2
  46. package/dist/cli-bundle/focused-chunks/chunk-MFVABYEU.js +2 -0
  47. package/dist/cli-bundle/focused-chunks/{chunk-7N5MRONP.js → chunk-PERRTPIY.js} +2 -2
  48. package/dist/cli-bundle/focused-chunks/{chunk-FHUARRMA.js → chunk-SDQOOL34.js} +2 -2
  49. package/dist/cli-bundle/focused-chunks/{chunk-M36SF4GE.js → chunk-TTRB47KM.js} +2 -2
  50. package/dist/cli-bundle/focused-chunks/chunk-VWMP6W7Y.js +20 -0
  51. package/dist/cli-bundle/focused-chunks/chunk-YNBACVQ2.js +2 -0
  52. package/dist/cli-bundle/main.js +21 -21
  53. package/dist/cli-bundle/sdk-authoring.js +1 -1
  54. package/dist/cli-bundle/sdk-contracts.js +2 -2
  55. package/dist/cli-bundle/sdk-core.js +29 -29
  56. package/dist/cli-bundle/sdk-governance.js +1 -1
  57. package/dist/cli-bundle/sdk-graph.js +1 -1
  58. package/dist/cli-bundle/sdk-merge.js +42 -42
  59. package/dist/cli-bundle/sdk-query.js +1 -1
  60. package/dist/cli-bundle/sdk-runtime.js +1 -1
  61. package/dist/cli-bundle/sdk-testing.js +1 -1
  62. package/dist/cli-bundle/sdk.js +10 -10
  63. package/dist/core/history/digest.d.ts +12 -0
  64. package/dist/core/history/digest.js +2 -0
  65. package/dist/core/history/drift-scan.js +1 -1
  66. package/dist/core/history/history.d.ts +5 -3
  67. package/dist/core/history/history.js +2 -2
  68. package/dist/core/history/operation-contract.d.ts +30 -0
  69. package/dist/core/history/operation-contract.js +2 -0
  70. package/dist/core/history/replay.d.ts +3 -2
  71. package/dist/core/history/replay.js +1 -1
  72. package/dist/core/history/tombstone.d.ts +3 -0
  73. package/dist/core/history/tombstone.js +2 -0
  74. package/dist/core/item/id.d.ts +8 -7
  75. package/dist/core/item/id.js +1 -1
  76. package/dist/core/output/mutation-projection.d.ts +1 -0
  77. package/dist/core/output/mutation-projection.js +1 -1
  78. package/dist/core/shared/command-line.d.ts +10 -0
  79. package/dist/core/shared/command-line.js +2 -0
  80. package/dist/core/shared/errors.d.ts +13 -0
  81. package/dist/core/shared/errors.js +1 -1
  82. package/dist/core/store/item-store.d.ts +5 -1
  83. package/dist/core/store/item-store.js +1 -1
  84. package/dist/core/telemetry/runtime.d.ts +1 -0
  85. package/dist/core/telemetry/runtime.js +2 -2
  86. package/dist/sdk/agent/command-recovery.js +1 -1
  87. package/dist/sdk/agent/item-addressing.js +1 -1
  88. package/dist/sdk/agent/refusal-corpus-contracts.js +1 -1
  89. package/dist/sdk/agent-capability-contracts.js +1 -1
  90. package/dist/sdk/cli-bootstrap.d.ts +2 -1
  91. package/dist/sdk/cli-bootstrap.js +1 -1
  92. package/dist/sdk/cli-contracts/command-aliases.d.ts +2 -0
  93. package/dist/sdk/cli-contracts/command-aliases.js +1 -1
  94. package/dist/sdk/cli-contracts/enum-contracts.d.ts +1 -1
  95. package/dist/sdk/cli-contracts/enum-contracts.js +1 -1
  96. package/dist/sdk/cli-contracts/flag-contracts.d.ts +2 -0
  97. package/dist/sdk/cli-contracts/flag-contracts.js +1 -1
  98. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -1
  99. package/dist/sdk/cli-contracts/grammar-contracts.js +1 -1
  100. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +3 -0
  101. package/dist/sdk/cli-contracts/runtime-contracts.js +1 -1
  102. package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
  103. package/dist/sdk/cli-contracts/tool-schema.js +1 -1
  104. package/dist/sdk/cli-contracts.d.ts +1 -1
  105. package/dist/sdk/cli-contracts.js +1 -1
  106. package/dist/sdk/command-line.d.ts +1 -6
  107. package/dist/sdk/command-line.js +1 -1
  108. package/dist/sdk/comments.js +1 -1
  109. package/dist/sdk/completion.d.ts +2 -0
  110. package/dist/sdk/completion.js +26 -14
  111. package/dist/sdk/contracts.d.ts +2 -0
  112. package/dist/sdk/contracts.js +1 -1
  113. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -1
  114. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
  115. package/dist/sdk/governance/storage-integrity.js +1 -1
  116. package/dist/sdk/governance/workflow-completeness.js +1 -1
  117. package/dist/sdk/governance/workflow-policy.js +2 -2
  118. package/dist/sdk/governance.d.ts +3 -0
  119. package/dist/sdk/governance.js +1 -1
  120. package/dist/sdk/history/attestation-command.d.ts +22 -0
  121. package/dist/sdk/history/attestation-command.js +3 -0
  122. package/dist/sdk/history/attestation-contract.d.ts +103 -0
  123. package/dist/sdk/history/attestation-contract.js +2 -0
  124. package/dist/sdk/history/attestation-scan.d.ts +16 -0
  125. package/dist/sdk/history/attestation-scan.js +2 -0
  126. package/dist/sdk/history/attestation.d.ts +8 -0
  127. package/dist/sdk/history/attestation.js +2 -0
  128. package/dist/sdk/history/salvage.js +1 -1
  129. package/dist/sdk/history-compact.js +1 -1
  130. package/dist/sdk/history-read.js +1 -1
  131. package/dist/sdk/history-redact.js +1 -1
  132. package/dist/sdk/history-repair.js +1 -1
  133. package/dist/sdk/index.d.ts +3 -1
  134. package/dist/sdk/index.js +1 -1
  135. package/dist/sdk/learnings.js +1 -1
  136. package/dist/sdk/lifecycle/claim.d.ts +2 -0
  137. package/dist/sdk/lifecycle/claim.js +1 -1
  138. package/dist/sdk/lifecycle/mcp-actions.d.ts +4 -0
  139. package/dist/sdk/lifecycle/mcp-actions.js +1 -1
  140. package/dist/sdk/lifecycle/task-composition.d.ts +2 -0
  141. package/dist/sdk/lifecycle/task-composition.js +1 -1
  142. package/dist/sdk/merge/reconcile.js +1 -1
  143. package/dist/sdk/merge/three-way.js +2 -2
  144. package/dist/sdk/notes.js +1 -1
  145. package/dist/sdk/public-surface.json +1 -1
  146. package/dist/sdk/query/projection-contracts.d.ts +1 -1
  147. package/dist/sdk/query/projection-contracts.js +1 -1
  148. package/dist/sdk/read-output-budget.d.ts +4 -10
  149. package/dist/sdk/read-output-budget.js +1 -1
  150. package/dist/sdk/read-output-contracts.d.ts +1 -1
  151. package/dist/sdk/read-output-contracts.js +1 -1
  152. package/dist/sdk/read-output-session.d.ts +1 -1
  153. package/dist/sdk/read-output-session.js +1 -1
  154. package/dist/sdk/runtime-input.js +1 -1
  155. package/dist/sdk/runtime.d.ts +3 -0
  156. package/dist/sdk/runtime.js +1 -1
  157. package/dist/types.d.ts +5 -1
  158. package/dist/types.js +1 -1
  159. package/docs/AGENT_UX_CONTRACTS.md +8 -0
  160. package/docs/ARCHITECTURE.md +7 -0
  161. package/docs/CLI_GRAMMAR.md +23 -0
  162. package/docs/HISTORY_ATTESTATION.md +164 -0
  163. package/docs/HISTORY_OPERATIONS.md +46 -0
  164. package/docs/HISTORY_RECOVERY.md +27 -2
  165. package/docs/LIFECYCLE_COMMANDS.md +19 -2
  166. package/docs/MERGE_SAFETY.md +64 -3
  167. package/docs/README.md +1 -0
  168. package/docs/READ_OUTPUT_CONTRACTS.md +13 -0
  169. package/docs/WORKFLOW_POLICIES.md +47 -3
  170. package/docs/generated/AGENT_CAPABILITY_ROUTING.md +4 -4
  171. package/docs/generated/AGENT_COMMAND_SURFACE.md +5 -0
  172. package/docs/generated/FLAG_LEXICON_BUDGETS.md +5 -0
  173. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +10 -7
  174. package/marketplace.json +2 -2
  175. package/package.json +4 -4
  176. package/packages/pm-beads/package.json +1 -1
  177. package/packages/pm-calendar/package.json +1 -1
  178. package/packages/pm-command-kit/package.json +1 -1
  179. package/packages/pm-digital-twin/package.json +1 -1
  180. package/packages/pm-governance-audit/README.md +31 -7
  181. package/packages/pm-governance-audit/extensions/governance-audit/index.ts +6 -3
  182. package/packages/pm-governance-audit/package.json +1 -1
  183. package/packages/pm-guide-shell/extensions/guide-shell/runtime.ts +7 -19
  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/README.md +9 -5
  189. package/packages/pm-search-advanced/extensions/search-advanced/index.ts +3 -2
  190. package/packages/pm-search-advanced/package.json +1 -1
  191. package/packages/pm-templates/package.json +1 -1
  192. package/packages/pm-todos/package.json +1 -1
  193. package/packages/pm-vcs/package.json +1 -1
  194. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  195. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  196. package/dist/cli-bundle/chunks/chunk-74RGSPLL.js +0 -2
  197. package/dist/cli-bundle/chunks/chunk-7WIHZI2M.js +0 -5
  198. package/dist/cli-bundle/chunks/chunk-GLQMKUGP.js +0 -2
  199. package/dist/cli-bundle/chunks/chunk-MACGGTLQ.js +0 -29
  200. package/dist/cli-bundle/chunks/chunk-P6BEYAON.js +0 -8
  201. package/dist/cli-bundle/chunks/chunk-TSWEX72T.js +0 -20
  202. package/dist/cli-bundle/chunks/chunk-YKQTETJI.js +0 -235
  203. package/dist/cli-bundle/chunks/register-mutation-5F5CYUWZ.js +0 -20
  204. package/dist/cli-bundle/focused-chunks/chunk-26O2WB73.js +0 -10
  205. package/dist/cli-bundle/focused-chunks/chunk-5YU75QLV.js +0 -2
  206. package/dist/cli-bundle/focused-chunks/chunk-B2CMFYRZ.js +0 -2
  207. package/dist/cli-bundle/focused-chunks/chunk-CRY5MHEI.js +0 -2
  208. package/dist/cli-bundle/focused-chunks/chunk-F6WKFXBT.js +0 -8
  209. package/dist/cli-bundle/focused-chunks/chunk-OROZM37I.js +0 -177
  210. package/dist/cli-bundle/focused-chunks/chunk-PNGYYQY7.js +0 -2
  211. package/dist/cli-bundle/focused-chunks/chunk-TPOL4TWE.js +0 -9
  212. package/dist/cli-bundle/focused-chunks/chunk-XSMA2W6Q.js +0 -12
  213. package/dist/cli-bundle/focused-chunks/chunk-ZJHYQOTM.js +0 -20
@@ -0,0 +1,12 @@
1
+ /** Digest algorithms supported for item anchors and immutable record envelopes. */
2
+ export declare const HISTORY_HASH_ALGORITHMS: readonly ["sha256", "sha512"];
3
+ /** Explicit algorithm accepted by history writers. */
4
+ export type HistoryHashAlgorithm = (typeof HISTORY_HASH_ALGORITHMS)[number];
5
+ /** Historical default, fixed permanently so unlabeled records remain readable. */
6
+ export declare const LEGACY_HISTORY_HASH_ALGORITHM: "sha256";
7
+ /** Algorithm written on new records unless a caller explicitly selects another. */
8
+ export declare const CURRENT_HISTORY_HASH_ALGORITHM: "sha256";
9
+ /** Validate a persisted algorithm before passing it to the crypto provider. */
10
+ export declare function resolveHistoryHashAlgorithm(value?: string): HistoryHashAlgorithm;
11
+ /** Hash canonical UTF-8 bytes using the declared algorithm, rejecting unknown labels. */
12
+ export declare function historyDigest(value: string, algorithm?: string): string;
@@ -0,0 +1,2 @@
1
+ !(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]="1e3cba21-c5a4-541a-9841-484cfbb70f4e")}catch(e2){}})();import{createHash}from"node:crypto";const HISTORY_HASH_ALGORITHMS=["sha256","sha512"];const LEGACY_HISTORY_HASH_ALGORITHM="sha256";const CURRENT_HISTORY_HASH_ALGORITHM="sha256";function resolveHistoryHashAlgorithm(value){if(value===void 0)return LEGACY_HISTORY_HASH_ALGORITHM;if(value==="sha256"||value==="sha512")return value;throw new TypeError(`unsupported_history_hash_algorithm:${String(value)}`)}function historyDigest(value,algorithm){return createHash(resolveHistoryHashAlgorithm(algorithm)).update(value,"utf8").digest("hex")}export{CURRENT_HISTORY_HASH_ALGORITHM,HISTORY_HASH_ALGORITHMS,LEGACY_HISTORY_HASH_ALGORITHM,historyDigest,resolveHistoryHashAlgorithm};
2
+ //# sourceMappingURL=digest.js.map
@@ -1,2 +1,2 @@
1
- !(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]="613616a9-118d-5fe7-8871-5406cc2b43a2")}catch(e2){}})();import fs from"node:fs/promises";import{createHash}from"node:crypto";import path from"node:path";import{getHistoryPath}from"../store/paths.js";import{isFileMissingError,writeFileAtomic}from"../fs/fs-utils.js";import{CURRENT_HISTORY_ITEM_HASH_VERSION,SUPPORTED_HISTORY_ITEM_HASH_VERSIONS,hashDocumentVerificationCandidates}from"./history.js";import{verifyHistoryChainWithVersion}from"./replay.js";import{findHistoryIdentityDiscontinuities}from"./identity.js";import{getWorkspaceHistoryPath,inspectWorkspaceHistoryState,WORKSPACE_HISTORY_ID}from"./workspace-history.js";const DRIFT_CACHE_VERSION=10;const DRIFT_CACHE_FILENAME="history-drift-cache.json";function getDriftCachePath(pmRoot){return path.join(pmRoot,"runtime",DRIFT_CACHE_FILENAME)}async function loadDriftCache(pmRoot){try{const raw=await fs.readFile(getDriftCachePath(pmRoot),"utf8");const parsed=JSON.parse(raw);if(parsed.version!==DRIFT_CACHE_VERSION||parsed.history_item_hash_version!==CURRENT_HISTORY_ITEM_HASH_VERSION||typeof parsed.entries!=="object"||parsed.entries===null||Object.values(parsed.entries).some(entry=>typeof entry.chain_ok!=="boolean"||typeof entry.latest_hash_comparable!=="boolean"||!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(entry.item_hash_version)&&entry.version_skew!==true||entry.chain_ok&&entry.version_skew!==true&&SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(entry.item_hash_version)&&!entry.latest_hash_comparable)){return null}return parsed}catch{return null}}async function scanWorkspaceHistory(pmRoot,previousEntries,nextEntries,verifyCacheHitByContent,accumulator){const historyPath=getWorkspaceHistoryPath(pmRoot);let stat;try{stat=await fs.stat(historyPath)}catch(error){if(isFileMissingError(error))return false;accumulator.unreadableStreams.push(WORKSPACE_HISTORY_ID);return false}const missingCount=accumulator.missingStreams.length;const resolved=await resolveStreamVerification({itemId:WORKSPACE_HISTORY_ID,historyPath,stat,cached:previousEntries[WORKSPACE_HISTORY_ID],verifyCacheHitByContent,accumulator});if(!resolved.verification){accumulator.missingStreams.splice(missingCount);return resolved.cacheDirty}if(resolved.verification.versionSkew){accumulator.versionSkews.push(WORKSPACE_HISTORY_ID)}if(!resolved.verification.chainOk){accumulator.chainMismatches.push(WORKSPACE_HISTORY_ID)}nextEntries[WORKSPACE_HISTORY_ID]={mtime_ms:stat.mtimeMs,ctime_ms:stat.ctimeMs,size:stat.size,content_hash:resolved.verification.contentHash,latest_after_hash:resolved.verification.latestAfterHash,chain_ok:resolved.verification.chainOk,version_skew:resolved.verification.versionSkew,latest_hash_comparable:resolved.verification.latestHashComparable,item_hash_version:resolved.verification.itemHashVersion};return resolved.cacheDirty}function hashContent(raw){return createHash("sha256").update(raw).digest("hex")}async function verifyHistoryStream(historyPath){const raw=await fs.readFile(historyPath,"utf8");const contentHash=hashContent(raw);if(raw.trim().length===0){return null}const entries=[];let latestAfterHash=null;for(const line of raw.split(/\r?\n/)){const trimmed=line.trim();if(trimmed.length===0){continue}const parsed=JSON.parse(trimmed);if(typeof parsed.after_hash!=="string"||parsed.after_hash.trim().length===0){throw new Error("missing after_hash")}entries.push(parsed);latestAfterHash=parsed.after_hash}if(!latestAfterHash){return null}const verification=verifyHistoryChainWithVersion(entries);const versionSkew=entries.some(entry=>entry.item_hash_version!==void 0&&!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(entry.item_hash_version));const latestEntry=entries[entries.length-1];const latestExplicitVersion=latestEntry.item_hash_version;const latestExplicitVersionSupported=latestExplicitVersion!==void 0&&SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(latestExplicitVersion);const latestHashVersion=latestExplicitVersionSupported?latestExplicitVersion:verification.item_hash_version;return{latestAfterHash,identityDiscontinuities:findHistoryIdentityDiscontinuities(entries),chainOk:verification.ok,versionSkew,latestHashComparable:latestHashVersion!==void 0&&(!versionSkew||latestExplicitVersionSupported||latestExplicitVersion===void 0),contentHash,itemHashVersion:latestHashVersion??CURRENT_HISTORY_ITEM_HASH_VERSION}}function cacheMetadataMatches(cached,stat){return cached!==void 0&&cached.mtime_ms===stat.mtimeMs&&cached.ctime_ms===stat.ctimeMs&&cached.size===stat.size}async function loadFreshStreamVerification(itemId,historyPath,accumulator){try{const loaded=await verifyHistoryStream(historyPath);if(!loaded){accumulator.missingStreams.push(itemId);return null}return loaded}catch{accumulator.unreadableStreams.push(itemId);return null}}async function resolveStreamVerification(params){const cachedContentHash=typeof params.cached?.content_hash==="string"&&params.cached.content_hash.length>0?params.cached.content_hash:void 0;const canUseCache=cacheMetadataMatches(params.cached,params.stat)&&cachedContentHash!==void 0;if(!canUseCache||!params.cached||!params.cached.chain_ok){return{verification:await loadFreshStreamVerification(params.itemId,params.historyPath,params.accumulator),cacheDirty:true}}if(params.verifyCacheHitByContent){const verification=await loadFreshStreamVerification(params.itemId,params.historyPath,params.accumulator);return{verification,cacheDirty:verification===null||verification.contentHash!==cachedContentHash||verification.latestAfterHash!==params.cached.latest_after_hash||verification.chainOk!==params.cached.chain_ok||verification.versionSkew!==(params.cached.version_skew===true)||verification.latestHashComparable!==params.cached.latest_hash_comparable||verification.itemHashVersion!==params.cached.item_hash_version}}return{verification:{identityDiscontinuities:[],latestAfterHash:params.cached.latest_after_hash,chainOk:params.cached.chain_ok,versionSkew:params.cached.version_skew===true,latestHashComparable:params.cached.latest_hash_comparable&&SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(params.cached.item_hash_version),contentHash:cachedContentHash,itemHashVersion:params.cached.item_hash_version},cacheDirty:false}}async function scanItemHistory(pmRoot,item,cache,accumulator){let historyPath;let stat;try{historyPath=getHistoryPath(pmRoot,item.id);stat=await fs.stat(historyPath)}catch(error){(isFileMissingError(error)?accumulator.missingStreams:accumulator.unreadableStreams).push(item.id);return false}const resolved=await resolveStreamVerification({itemId:item.id,historyPath,stat,cached:cache.previousEntries[item.id],verifyCacheHitByContent:cache.verifyCacheHitByContent,accumulator});if(!resolved.verification)return resolved.cacheDirty;if(resolved.verification.identityDiscontinuities.length>0){(accumulator.identityDiscontinuities??=[]).push(...resolved.verification.identityDiscontinuities.map(finding=>({...finding,item_id:item.id})))}if(resolved.verification.versionSkew){accumulator.versionSkews.push(item.id)}if(!resolved.verification.chainOk){accumulator.chainMismatches.push(item.id)}cache.nextEntries[item.id]={mtime_ms:stat.mtimeMs,ctime_ms:stat.ctimeMs,size:stat.size,content_hash:resolved.verification.contentHash,latest_after_hash:resolved.verification.latestAfterHash,chain_ok:resolved.verification.chainOk,version_skew:resolved.verification.versionSkew,latest_hash_comparable:resolved.verification.latestHashComparable,item_hash_version:resolved.verification.itemHashVersion};const{body,...itemMetadata}=item;if(!resolved.verification.latestHashComparable)return resolved.cacheDirty;const currentHashes=hashDocumentVerificationCandidates({metadata:itemMetadata,body},resolved.verification.itemHashVersion);if(!currentHashes.includes(resolved.verification.latestAfterHash))accumulator.hashMismatches.push(item.id);return resolved.cacheDirty}async function scanWorkspaceStateAgreement(pmRoot,accumulator){if(accumulator.unreadableStreams.includes(WORKSPACE_HISTORY_ID)||accumulator.chainMismatches.includes(WORKSPACE_HISTORY_ID)||accumulator.versionSkews.includes(WORKSPACE_HISTORY_ID))return;try{const agreement=await inspectWorkspaceHistoryState(pmRoot);accumulator.workspaceStateMismatches.push(...agreement.mismatched_documents);accumulator.workspaceStateMissing.push(...agreement.missing_documents);accumulator.workspaceStateUnreadable.push(...agreement.unreadable_documents)}catch{accumulator.unreadableStreams.push(WORKSPACE_HISTORY_ID)}}async function scanHistoryDrift(pmRoot,items,options={}){const accumulator={missingStreams:[],unreadableStreams:[],hashMismatches:[],chainMismatches:[],versionSkews:[],workspaceStateMismatches:[],workspaceStateMissing:[],workspaceStateUnreadable:[]};const cache=await loadDriftCache(pmRoot);const previousEntries=cache?.entries??{};const nextEntries={};let cacheDirty=false;const verifyCacheHitByContent=options.cacheHitVerification!=="metadata";const cacheState={previousEntries,nextEntries,verifyCacheHitByContent};for(const item of items){if(await scanItemHistory(pmRoot,item,cacheState,accumulator))cacheDirty=true}const workspaceCacheDirty=await scanWorkspaceHistory(pmRoot,previousEntries,nextEntries,verifyCacheHitByContent,accumulator);cacheDirty||=workspaceCacheDirty;await scanWorkspaceStateAgreement(pmRoot,accumulator);if(cacheDirty||Object.keys(previousEntries).length!==Object.keys(nextEntries).length){const cachePath=getDriftCachePath(pmRoot);try{await fs.mkdir(path.dirname(cachePath),{recursive:true});await writeFileAtomic(cachePath,JSON.stringify({version:DRIFT_CACHE_VERSION,history_item_hash_version:CURRENT_HISTORY_ITEM_HASH_VERSION,entries:nextEntries}))}catch{}}const driftedItems=[...new Set([...accumulator.missingStreams,...accumulator.unreadableStreams,...accumulator.hashMismatches,...accumulator.chainMismatches,...accumulator.versionSkews,...accumulator.workspaceStateMismatches.length>0||accumulator.workspaceStateMissing.length>0||accumulator.workspaceStateUnreadable.length>0?[WORKSPACE_HISTORY_ID]:[]])].sort((a,b)=>a.localeCompare(b));return{...accumulator,driftedItems}}export{scanHistoryDrift};
1
+ !(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]="d876d1ab-2de0-5c32-b999-721038adafcd")}catch(e2){}})();import{HISTORY_HASH_ALGORITHMS,resolveHistoryHashAlgorithm}from"./digest.js";import fs from"node:fs/promises";import{createHash}from"node:crypto";import path from"node:path";import{getHistoryPath}from"../store/paths.js";import{isFileMissingError,writeFileAtomic}from"../fs/fs-utils.js";import{CURRENT_HISTORY_ITEM_HASH_VERSION,SUPPORTED_HISTORY_ITEM_HASH_VERSIONS,hashDocumentVerificationCandidates}from"./history.js";import{verifyHistoryChainWithVersion}from"./replay.js";import{findHistoryIdentityDiscontinuities}from"./identity.js";import{getWorkspaceHistoryPath,inspectWorkspaceHistoryState,WORKSPACE_HISTORY_ID}from"./workspace-history.js";const READABLE_HISTORY_HASH_ALGORITHMS=new Set([void 0,...HISTORY_HASH_ALGORITHMS]);const DRIFT_CACHE_VERSION=11;const DRIFT_CACHE_FILENAME="history-drift-cache.json";function getDriftCachePath(pmRoot){return path.join(pmRoot,"runtime",DRIFT_CACHE_FILENAME)}async function loadDriftCache(pmRoot){try{const raw=await fs.readFile(getDriftCachePath(pmRoot),"utf8");const parsed=JSON.parse(raw);if(parsed.version!==DRIFT_CACHE_VERSION||parsed.history_item_hash_version!==CURRENT_HISTORY_ITEM_HASH_VERSION||typeof parsed.entries!=="object"||parsed.entries===null||Object.values(parsed.entries).some(entry=>typeof entry.chain_ok!=="boolean"||typeof entry.latest_hash_comparable!=="boolean"||!READABLE_HISTORY_HASH_ALGORITHMS.has(entry.hash_algorithm)||!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(entry.item_hash_version)&&entry.version_skew!==true||entry.chain_ok&&entry.version_skew!==true&&SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(entry.item_hash_version)&&!entry.latest_hash_comparable)){return null}return parsed}catch{return null}}async function scanWorkspaceHistory(pmRoot,previousEntries,nextEntries,verifyCacheHitByContent,accumulator){const historyPath=getWorkspaceHistoryPath(pmRoot);let stat;try{stat=await fs.stat(historyPath)}catch(error){if(isFileMissingError(error))return false;accumulator.unreadableStreams.push(WORKSPACE_HISTORY_ID);return false}const missingCount=accumulator.missingStreams.length;const resolved=await resolveStreamVerification({itemId:WORKSPACE_HISTORY_ID,historyPath,stat,cached:previousEntries[WORKSPACE_HISTORY_ID],verifyCacheHitByContent,accumulator});if(!resolved.verification){accumulator.missingStreams.splice(missingCount);return resolved.cacheDirty}if(resolved.verification.versionSkew){accumulator.versionSkews.push(WORKSPACE_HISTORY_ID)}if(!resolved.verification.chainOk){accumulator.chainMismatches.push(WORKSPACE_HISTORY_ID)}nextEntries[WORKSPACE_HISTORY_ID]={mtime_ms:stat.mtimeMs,ctime_ms:stat.ctimeMs,size:stat.size,content_hash:resolved.verification.contentHash,latest_after_hash:resolved.verification.latestAfterHash,chain_ok:resolved.verification.chainOk,version_skew:resolved.verification.versionSkew,latest_hash_comparable:resolved.verification.latestHashComparable,item_hash_version:resolved.verification.itemHashVersion,hash_algorithm:resolved.verification.hashAlgorithm};return resolved.cacheDirty}function hashContent(raw){return createHash("sha256").update(raw).digest("hex")}function hasUnsupportedHistoryCapability(entry){return!READABLE_HISTORY_HASH_ALGORITHMS.has(entry.hash_algorithm)||entry.item_hash_version!==void 0&&!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(entry.item_hash_version)}async function verifyHistoryStream(historyPath){const raw=await fs.readFile(historyPath,"utf8");const contentHash=hashContent(raw);if(raw.trim().length===0){return null}const entries=[];let latestAfterHash=null;for(const line of raw.split(/\r?\n/)){const trimmed=line.trim();if(trimmed.length===0){continue}const parsed=JSON.parse(trimmed);if(typeof parsed.after_hash!=="string"||parsed.after_hash.trim().length===0){throw new Error("missing after_hash")}entries.push(parsed);latestAfterHash=parsed.after_hash}if(!latestAfterHash){return null}const verification=verifyHistoryChainWithVersion(entries);const versionSkew=entries.some(hasUnsupportedHistoryCapability);const latestEntry=entries[entries.length-1];const algorithmSupported=READABLE_HISTORY_HASH_ALGORITHMS.has(latestEntry.hash_algorithm);const latestExplicitVersion=latestEntry.item_hash_version;const latestExplicitVersionSupported=latestExplicitVersion!==void 0&&SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(latestExplicitVersion);const latestHashVersion=latestExplicitVersionSupported?latestExplicitVersion:verification.item_hash_version;return{latestAfterHash,hashAlgorithm:algorithmSupported?resolveHistoryHashAlgorithm(latestEntry.hash_algorithm):void 0,identityDiscontinuities:findHistoryIdentityDiscontinuities(entries),chainOk:verification.ok,versionSkew,latestHashComparable:algorithmSupported&&latestHashVersion!==void 0&&(!versionSkew||latestExplicitVersionSupported||latestExplicitVersion===void 0),contentHash,itemHashVersion:latestHashVersion??CURRENT_HISTORY_ITEM_HASH_VERSION}}function cacheMetadataMatches(cached,stat){return cached!==void 0&&cached.mtime_ms===stat.mtimeMs&&cached.ctime_ms===stat.ctimeMs&&cached.size===stat.size}async function loadFreshStreamVerification(itemId,historyPath,accumulator){try{const loaded=await verifyHistoryStream(historyPath);if(!loaded){accumulator.missingStreams.push(itemId);return null}return loaded}catch{accumulator.unreadableStreams.push(itemId);return null}}function matchesCachedVerification(verification,cached){return verification!==null&&verification.contentHash===cached.content_hash&&verification.latestAfterHash===cached.latest_after_hash&&verification.chainOk===cached.chain_ok&&verification.versionSkew===(cached.version_skew===true)&&verification.latestHashComparable===cached.latest_hash_comparable&&verification.itemHashVersion===cached.item_hash_version&&verification.hashAlgorithm===cached.hash_algorithm}async function resolveStreamVerification(params){const cachedContentHash=typeof params.cached?.content_hash==="string"&&params.cached.content_hash.length>0?params.cached.content_hash:void 0;const canUseCache=cacheMetadataMatches(params.cached,params.stat)&&cachedContentHash!==void 0;if(!canUseCache||!params.cached||!params.cached.chain_ok){return{verification:await loadFreshStreamVerification(params.itemId,params.historyPath,params.accumulator),cacheDirty:true}}if(params.verifyCacheHitByContent){const verification=await loadFreshStreamVerification(params.itemId,params.historyPath,params.accumulator);return{verification,cacheDirty:!matchesCachedVerification(verification,params.cached)}}return{verification:{identityDiscontinuities:[],latestAfterHash:params.cached.latest_after_hash,chainOk:params.cached.chain_ok,versionSkew:params.cached.version_skew===true,latestHashComparable:params.cached.latest_hash_comparable&&SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(params.cached.item_hash_version),contentHash:cachedContentHash,itemHashVersion:params.cached.item_hash_version,hashAlgorithm:params.cached.hash_algorithm},cacheDirty:false}}async function scanItemHistory(pmRoot,item,cache,accumulator){let historyPath;let stat;try{historyPath=getHistoryPath(pmRoot,item.id);stat=await fs.stat(historyPath)}catch(error){(isFileMissingError(error)?accumulator.missingStreams:accumulator.unreadableStreams).push(item.id);return false}const resolved=await resolveStreamVerification({itemId:item.id,historyPath,stat,cached:cache.previousEntries[item.id],verifyCacheHitByContent:cache.verifyCacheHitByContent,accumulator});if(!resolved.verification)return resolved.cacheDirty;if(resolved.verification.identityDiscontinuities.length>0){(accumulator.identityDiscontinuities??=[]).push(...resolved.verification.identityDiscontinuities.map(finding=>({...finding,item_id:item.id})))}if(resolved.verification.versionSkew){accumulator.versionSkews.push(item.id)}if(!resolved.verification.chainOk){accumulator.chainMismatches.push(item.id)}cache.nextEntries[item.id]={mtime_ms:stat.mtimeMs,ctime_ms:stat.ctimeMs,size:stat.size,content_hash:resolved.verification.contentHash,latest_after_hash:resolved.verification.latestAfterHash,chain_ok:resolved.verification.chainOk,version_skew:resolved.verification.versionSkew,latest_hash_comparable:resolved.verification.latestHashComparable,item_hash_version:resolved.verification.itemHashVersion,hash_algorithm:resolved.verification.hashAlgorithm};const{body,...itemMetadata}=item;if(!resolved.verification.latestHashComparable)return resolved.cacheDirty;const currentHashes=hashDocumentVerificationCandidates({metadata:itemMetadata,body},resolved.verification.itemHashVersion,resolved.verification.hashAlgorithm);if(!currentHashes.includes(resolved.verification.latestAfterHash))accumulator.hashMismatches.push(item.id);return resolved.cacheDirty}async function scanWorkspaceStateAgreement(pmRoot,accumulator){if(accumulator.unreadableStreams.includes(WORKSPACE_HISTORY_ID)||accumulator.chainMismatches.includes(WORKSPACE_HISTORY_ID)||accumulator.versionSkews.includes(WORKSPACE_HISTORY_ID))return;try{const agreement=await inspectWorkspaceHistoryState(pmRoot);accumulator.workspaceStateMismatches.push(...agreement.mismatched_documents);accumulator.workspaceStateMissing.push(...agreement.missing_documents);accumulator.workspaceStateUnreadable.push(...agreement.unreadable_documents)}catch{accumulator.unreadableStreams.push(WORKSPACE_HISTORY_ID)}}async function scanHistoryDrift(pmRoot,items,options={}){const accumulator={missingStreams:[],unreadableStreams:[],hashMismatches:[],chainMismatches:[],versionSkews:[],workspaceStateMismatches:[],workspaceStateMissing:[],workspaceStateUnreadable:[]};const cache=await loadDriftCache(pmRoot);const previousEntries=cache?.entries??{};const nextEntries={};let cacheDirty=false;const verifyCacheHitByContent=options.cacheHitVerification!=="metadata";const cacheState={previousEntries,nextEntries,verifyCacheHitByContent};for(const item of items){if(await scanItemHistory(pmRoot,item,cacheState,accumulator))cacheDirty=true}const workspaceCacheDirty=await scanWorkspaceHistory(pmRoot,previousEntries,nextEntries,verifyCacheHitByContent,accumulator);cacheDirty||=workspaceCacheDirty;await scanWorkspaceStateAgreement(pmRoot,accumulator);if(cacheDirty||Object.keys(previousEntries).length!==Object.keys(nextEntries).length){const cachePath=getDriftCachePath(pmRoot);try{await fs.mkdir(path.dirname(cachePath),{recursive:true});await writeFileAtomic(cachePath,JSON.stringify({version:DRIFT_CACHE_VERSION,history_item_hash_version:CURRENT_HISTORY_ITEM_HASH_VERSION,entries:nextEntries}))}catch{}}const driftedItems=[...new Set([...accumulator.missingStreams,...accumulator.unreadableStreams,...accumulator.hashMismatches,...accumulator.chainMismatches,...accumulator.versionSkews,...accumulator.workspaceStateMismatches.length>0||accumulator.workspaceStateMissing.length>0||accumulator.workspaceStateUnreadable.length>0?[WORKSPACE_HISTORY_ID]:[]])].sort((a,b)=>a.localeCompare(b));return{...accumulator,driftedItems}}export{scanHistoryDrift};
2
2
  //# sourceMappingURL=drift-scan.js.map
@@ -1,3 +1,4 @@
1
+ import { type HistoryHashAlgorithm } from "./digest.js";
1
2
  import { type AuthorSource } from "../shared/author.js";
2
3
  import type { HistoryEntry, HistoryPatchOp, ItemDocument } from "../../types/index.js";
3
4
  /** Hash epoch for the current canonical item surface written into immutable history. */
@@ -26,7 +27,7 @@ export declare function verifyHistoryRecordHash(entry: HistoryEntry): {
26
27
  coverage: "record_and_item_state" | "item_state_only";
27
28
  } | {
28
29
  ok: false;
29
- error: "incomplete_record_hash_envelope" | "record_hash_mismatch" | "unsupported_record_hash_version";
30
+ error: "incomplete_record_hash_envelope" | "record_hash_mismatch" | "unsupported_record_hash_version" | "unsupported_history_hash_algorithm";
30
31
  };
31
32
  /** Reseal a maintenance rewrite and retain the anchors and patch digest it replaced. */
32
33
  export declare function resealHistoryRewrite(original: HistoryEntry, rewritten: HistoryEntry, options?: Readonly<{
@@ -47,13 +48,13 @@ declare function isDefinedPointerPath(document: unknown, path: string): boolean;
47
48
  /** Implements hash document for the public runtime surface of this module. */
48
49
  export declare function hashDocument(document: ItemDocument): string;
49
50
  /** Hash an item with an explicit canonicalization epoch for replay compatibility. */
50
- export declare function hashDocumentForVersion(document: ItemDocument, version: HistoryItemHashVersion): string;
51
+ export declare function hashDocumentForVersion(document: ItemDocument, version: HistoryItemHashVersion, algorithm?: HistoryHashAlgorithm): string;
51
52
  /**
52
53
  * Return the ordered hash candidates accepted when verifying one immutable
53
54
  * history epoch. Epoch 2 has both its established expanded hash first and the
54
55
  * earlier field-frozen writer hash second; the other epochs have one form.
55
56
  */
56
- export declare function hashDocumentVerificationCandidates(document: ItemDocument, version: HistoryItemHashVersion): [string, ...string[]];
57
+ export declare function hashDocumentVerificationCandidates(document: ItemDocument, version: HistoryItemHashVersion, algorithm?: HistoryHashAlgorithm): [string, ...string[]];
57
58
  /** Implements hash empty document for the public runtime surface of this module. */
58
59
  export declare function hashEmptyDocument(): string;
59
60
  /** Implements create history entry for the public runtime surface of this module. */
@@ -66,6 +67,7 @@ export declare function createHistoryEntry(params: {
66
67
  after: ItemDocument;
67
68
  message?: string;
68
69
  context?: Record<string, unknown>;
70
+ hashAlgorithm?: HistoryHashAlgorithm;
69
71
  }): HistoryEntry;
70
72
  /** Implements append history entry for the public runtime surface of this module. */
71
73
  export declare function appendHistoryEntry(historyPath: string, entry: HistoryEntry): Promise<void>;
@@ -1,3 +1,3 @@
1
- !(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]="70eda133-68fd-5dd6-afe9-c892f23e50a5")}catch(e2){}})();import jsonPatch from"fast-json-patch";import fs from"node:fs/promises";import path from"node:path";import{EXIT_CODE,ITEM_METADATA_KEY_ORDER}from"../shared/constants.js";import{runActiveServiceOverride}from"../extensions/index.js";import{appendLineAtomic}from"../fs/fs-utils.js";import{canonicalDocument}from"../item/item-format.js";import{toItemRecord}from"../item/item-record.js";import{orderObject,sha256Hex,stableStringify}from"../shared/serialization.js";import{isMillisecondPrecisionRfc3339DateTime,nowIso}from"../shared/time.js";import{diagnoseAgentIdentity,resolveHistoryAgentIdentity,resolveHistoryAuthorSource}from"../shared/author.js";import{appendHistoryEntryWithEventIndex,removeHistoryEventIndexForHistoryPath}from"./event-index.js";import{classifyHistoryEvent}from"./event-classification.js";import{invalidateHistoryDriftCacheForPath}from"./drift-cache.js";import{PmCliError}from"../shared/errors.js";const EMPTY_LEGACY_HASH_DOCUMENT={front_matter:{},body:""};const CURRENT_HISTORY_ITEM_HASH_VERSION=3;const SUPPORTED_HISTORY_ITEM_HASH_VERSIONS=[1,2,3];const CURRENT_HISTORY_RECORD_HASH_VERSION=1;const SUPPORTED_HISTORY_RECORD_HASH_VERSIONS=[1];function hashHistoryRecord(entry){return sha256Hex(stableStringify(entry))}function hashHistoryPatch(patch){return sha256Hex(stableStringify(patch))}function hashHistoryStream(entries){return sha256Hex(stableStringify(entries))}function sealHistoryRecord(entry){const sealed={...entry,record_hash_version:CURRENT_HISTORY_RECORD_HASH_VERSION};const{record_hash:_recordHash,...canonical}=sealed;return{...sealed,record_hash:hashHistoryRecord(canonical)}}function verifyHistoryRecordHash(entry){if(entry.record_hash_version===void 0&&entry.record_hash===void 0){return{ok:true,coverage:"item_state_only"}}if(entry.record_hash_version===void 0||entry.record_hash===void 0){return{ok:false,error:"incomplete_record_hash_envelope"}}if(!SUPPORTED_HISTORY_RECORD_HASH_VERSIONS.includes(entry.record_hash_version)){return{ok:false,error:"unsupported_record_hash_version"}}const{record_hash:_recordHash,...canonical}=entry;return hashHistoryRecord(canonical)===entry.record_hash?{ok:true,coverage:"record_and_item_state"}:{ok:false,error:"record_hash_mismatch"}}function createHistoryRewriteEvidence(original,options){const evidence={before_hash:original.before_hash,after_hash:original.after_hash,patch_hash:hashHistoryPatch(original.patch)};if(original.item_hash_version!==void 0){evidence.item_hash_version=original.item_hash_version}if(options.retainOriginalPatch){evidence.patch=structuredClone(original.patch)}if(options.retainPriorRecordHash!==false&&original.record_hash_version!==void 0&&original.record_hash!==void 0){evidence.record_hash_version=original.record_hash_version;evidence.record_hash=original.record_hash;evidence.record=structuredClone(original)}return evidence}function resealHistoryRewrite(original,rewritten,options={}){const originalRecordVerification=verifyHistoryRecordHash(original);if(!originalRecordVerification.ok){throw new TypeError(originalRecordVerification.error)}const originalPatchHash=hashHistoryPatch(original.patch);const retainsRewriteEvidence=options.retainPriorRecord===true||original.before_hash!==rewritten.before_hash||original.after_hash!==rewritten.after_hash||original.item_hash_version!==rewritten.item_hash_version||originalPatchHash!==hashHistoryPatch(rewritten.patch);const sealed=sealHistoryRecord({...rewritten,...retainsRewriteEvidence?{reanchor_evidence:[...rewritten.reanchor_evidence??[],createHistoryRewriteEvidence(original,options)]}:{}});const evidenceVerification=verifyHistoryRewriteEvidence(sealed);if(!evidenceVerification.ok){throw new TypeError(evidenceVerification.error)}return sealed}function isHistoryPatch(value){if(!Array.isArray(value)||Object.keys(value).length!==value.length){return false}return value.every(operation=>{if(!isRecord(operation)||typeof operation.path!=="string"){return false}if(operation.op==="move"||operation.op==="copy"){return typeof operation.from==="string"}if(["add","replace","test"].includes(operation.op)){return Object.hasOwn(operation,"value")}return operation.op==="remove"})}function isRetainedHistoryRecordShape(value){return isRecord(value)&&typeof value.ts==="string"&&typeof value.author==="string"&&typeof value.op==="string"&&typeof value.before_hash==="string"&&typeof value.after_hash==="string"&&isHistoryPatch(value.patch)}function hasCompleteRetainedRecordHashEnvelope(evidence){const hasVersion=evidence.record_hash_version!==void 0;const hasHash=evidence.record_hash!==void 0;return hasVersion===hasHash}function isHistoryReanchorEvidence(evidence){if(!isRecord(evidence)||!hasCompleteRetainedRecordHashEnvelope(evidence)||typeof evidence.before_hash!=="string"||typeof evidence.after_hash!=="string"||typeof evidence.patch_hash!=="string"||!/^[a-f0-9]{64}$/u.test(evidence.patch_hash)||evidence.patch!==void 0&&!isHistoryPatch(evidence.patch)||evidence.record_hash_version!==void 0&&typeof evidence.record_hash_version!=="number"||evidence.record_hash!==void 0&&(typeof evidence.record_hash!=="string"||!/^[a-f0-9]{64}$/u.test(evidence.record_hash))){return false}return evidence.record===void 0||isRetainedHistoryRecordShape(evidence.record)}function matchesRetainedHistoryRecord(evidence){const record=evidence.record;return record!==void 0&&record.before_hash===evidence.before_hash&&record.after_hash===evidence.after_hash&&record.item_hash_version===evidence.item_hash_version&&record.record_hash_version===evidence.record_hash_version&&record.record_hash===evidence.record_hash&&hashHistoryPatch(record.patch)===evidence.patch_hash}function reconstructPriorHistoryRecord(current,evidence,priorEvidence){if(evidence.patch&&hashHistoryPatch(evidence.patch)!==evidence.patch_hash){return{kind:"patch_hash_mismatch"}}if(evidence.record){if(!matchesRetainedHistoryRecord(evidence)){return{kind:"record_hash_mismatch"}}return{kind:"record",entry:evidence.record}}const priorPatch=evidence.patch??current.patch;if(hashHistoryPatch(priorPatch)!==evidence.patch_hash){return{kind:"digest_only"}}const priorRecord={...current,before_hash:evidence.before_hash,after_hash:evidence.after_hash,patch:priorPatch,...evidence.item_hash_version===void 0?{}:{item_hash_version:evidence.item_hash_version},...evidence.record_hash_version===void 0?{}:{record_hash_version:evidence.record_hash_version},...evidence.record_hash===void 0?{}:{record_hash:evidence.record_hash},...priorEvidence.length===0?{}:{reanchor_evidence:priorEvidence}};if(priorEvidence.length===0)delete priorRecord.reanchor_evidence;if(evidence.item_hash_version===void 0){delete priorRecord.item_hash_version}return evidence.record_hash_version===void 0||evidence.record_hash===void 0?{kind:"legacy",entry:priorRecord}:{kind:"record",entry:priorRecord}}function verifyHistoryRewriteEvidence(entry){const evidenceEntries=entry.reanchor_evidence;if(evidenceEntries===void 0)return{ok:true,coverage:"none"};if(!Array.isArray(evidenceEntries)){return{ok:false,error:"rewrite_evidence_invalid"}}if(evidenceEntries.length===0)return{ok:true,coverage:"none"};let reconstructed=entry;for(let index=evidenceEntries.length-1;index>=0;index-=1){const evidence=evidenceEntries[index];if(!(index in evidenceEntries)||!isHistoryReanchorEvidence(evidence)){return{ok:false,error:"rewrite_evidence_invalid"}}const prior=reconstructPriorHistoryRecord(reconstructed,evidence,evidenceEntries.slice(0,index));if(prior.kind==="patch_hash_mismatch"){return{ok:false,error:"rewrite_evidence_patch_hash_mismatch"}}if(prior.kind==="record_hash_mismatch"){return{ok:false,error:"rewrite_evidence_record_hash_mismatch"}}if(prior.kind==="digest_only"){return{ok:true,coverage:"digest_only"}}if(prior.kind==="legacy"){return{ok:true,coverage:"legacy_anchor_only"}}if(!verifyHistoryRecordHash(prior.entry).ok){return{ok:false,error:"rewrite_evidence_record_hash_mismatch"}}reconstructed=prior.entry}return{ok:true,coverage:"complete"}}function compareOptionalStrings(left,right){return(left??"").localeCompare(right??"")}function compareOptionalNumbers(left,right){return(left??0)-(right??0)}function compareJsonValues(left,right,fallback){return JSON.stringify(left??fallback).localeCompare(JSON.stringify(right??fallback))}function compareLegacyLinkedTests(left,right){const comparisons=[left.scope.localeCompare(right.scope),compareOptionalStrings(left.path,right.path),compareOptionalStrings(left.command,right.command),compareOptionalNumbers(left.timeout_seconds,right.timeout_seconds),compareOptionalStrings(left.pm_context_mode,right.pm_context_mode),Number(Boolean(left.shared_host_safe))-Number(Boolean(right.shared_host_safe)),compareJsonValues(left.env_clear,right.env_clear,[]),compareJsonValues(left.env_set,right.env_set,{}),compareJsonValues(left.assert_stdout_contains,right.assert_stdout_contains,[]),compareJsonValues(left.assert_stdout_regex,right.assert_stdout_regex,[]),compareJsonValues(left.assert_stderr_contains,right.assert_stderr_contains,[]),compareJsonValues(left.assert_stderr_regex,right.assert_stderr_regex,[]),compareOptionalNumbers(left.assert_stdout_min_lines,right.assert_stdout_min_lines),compareJsonValues(left.assert_json_field_equals,right.assert_json_field_equals,{}),compareJsonValues(left.assert_json_field_gte,right.assert_json_field_gte,{}),compareOptionalStrings(left.note,right.note)];return comparisons.find(comparison=>comparison!==0)??0}function decodeJsonPointer(path2){if(!path2||path2==="/"){return[]}if(!path2.startsWith("/")){return[]}return path2.slice(1).split("/").map(segment=>segment.replaceAll("~1","/").replaceAll("~0","~"))}function isDefinedPointerPath(document,path2){const segments=decodeJsonPointer(path2);if(segments.length===0){return true}let cursor=document;for(const segment of segments){const arrayIndex=/^(0|[1-9]\d*)$/.test(segment)?Number(segment):-1;const next=Array.isArray(cursor)?arrayIndex>=0&&arrayIndex<cursor.length?cursor[arrayIndex]:void 0:isRecord(cursor)&&Object.prototype.hasOwnProperty.call(cursor,segment)?cursor[segment]:void 0;if(next===void 0)return false;cursor=next}return true}function normalizeHistoryPatchOps(beforeDocument,patch){const normalized=[];let replayCursor=structuredClone(beforeDocument);for(const operation of patch){const normalizedOperation=operation.op==="replace"&&!isDefinedPointerPath(replayCursor,operation.path)?{...operation,op:"add"}:operation;normalized.push(normalizedOperation);replayCursor=jsonPatch.applyPatch(replayCursor,[normalizedOperation],true,true).newDocument}return normalized}function canonicalHashDocument(document,version,legacyV2Fields=false){const hasMetadata=document.metadata&&Object.keys(document.metadata).length>0;if(!hasMetadata){return{front_matter:{},body:document.body??""}}const canonical=canonicalDocument(document);const usesLegacyFields=version===1||version===2&&legacyV2Fields;const epochMetadata=usesLegacyFields?{...canonical.metadata,...canonical.metadata.dependencies===void 0?{}:{dependencies:canonical.metadata.dependencies.map(dependency=>({...dependency,id:dependency.id.toLowerCase()}))},...canonical.metadata.tests===void 0?{}:{tests:canonical.metadata.tests.map(({workspace_context_mode:_workspaceContextMode,provenance:_provenance,provenance_invalid:_provenanceInvalid,...test})=>test)},...canonical.metadata.test_runs===void 0?{}:{test_runs:canonical.metadata.test_runs.map(({executions:_executions,...testRun})=>testRun)}}:canonical.metadata;const metadata=version===1&&epochMetadata.tests?{...epochMetadata,tests:[...epochMetadata.tests].sort(compareLegacyLinkedTests)}:epochMetadata;const orderedMetadata=orderObject(toItemRecord(metadata),ITEM_METADATA_KEY_ORDER);return{front_matter:orderedMetadata,body:canonical.body}}function canonicalPatchDocument(document){const hasMetadata=document.metadata&&Object.keys(document.metadata).length>0;if(!hasMetadata){return{metadata:{},body:document.body??""}}const canonical=canonicalDocument(document);const orderedMetadata=orderObject(toItemRecord(canonical.metadata),ITEM_METADATA_KEY_ORDER);return{metadata:orderedMetadata,body:canonical.body}}function hashDocument(document){return hashDocumentForVersion(document,CURRENT_HISTORY_ITEM_HASH_VERSION)}function hashDocumentForVersion(document,version){if(!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.some(supportedVersion=>supportedVersion===version)){throw new TypeError(`unsupported_item_hash_version:${String(version)}`)}return sha256Hex(stableStringify(canonicalHashDocument(document,version)))}function hashDocumentVerificationCandidates(document,version){const canonicalHash=hashDocumentForVersion(document,version);return version===2?[canonicalHash,sha256Hex(stableStringify(canonicalHashDocument(document,version,true)))]:[canonicalHash]}function hashEmptyDocument(){return sha256Hex(stableStringify(EMPTY_LEGACY_HASH_DOCUMENT))}function createHistoryEntry(params){const beforeHashCanonical=canonicalHashDocument(params.before,CURRENT_HISTORY_ITEM_HASH_VERSION);const afterHashCanonical=canonicalHashDocument(params.after,CURRENT_HISTORY_ITEM_HASH_VERSION);const beforePatchCanonical=canonicalPatchDocument(params.before);const afterPatchCanonical=canonicalPatchDocument(params.after);const rawPatch=jsonPatch.compare(beforePatchCanonical,afterPatchCanonical);const patch=normalizeHistoryPatchOps(beforePatchCanonical,rawPatch);const agentIdentity=resolveHistoryAgentIdentity(params.author);const provenanceOutcomes=agentIdentity.harness?Object.fromEntries(Object.entries(diagnoseAgentIdentity().provenance_outcomes).filter(([,outcome])=>outcome.resolver!==void 0&&outcome.status!=="resolved")):void 0;const context=provenanceOutcomes===void 0||Object.keys(provenanceOutcomes).length===0?params.context:{...params.context,agent_provenance_outcomes:provenanceOutcomes};const entry={ts:params.nowIso,author:params.author,author_source:params.authorSource??resolveHistoryAuthorSource(params.author),...agentIdentity.harness?{agent_harness:agentIdentity.harness}:{},...agentIdentity.model?{agent_model:agentIdentity.model}:{},...agentIdentity.model_source?{agent_model_source:agentIdentity.model_source}:{},...agentIdentity.instance?{agent_instance:agentIdentity.instance}:{},...agentIdentity.provenance?{agent_provenance:agentIdentity.provenance}:{},...agentIdentity.episode?{agent_episode:agentIdentity.episode}:{},op:params.op,patch,before_hash:sha256Hex(stableStringify(beforeHashCanonical)),after_hash:sha256Hex(stableStringify(afterHashCanonical)),item_hash_version:CURRENT_HISTORY_ITEM_HASH_VERSION,message:params.message===void 0?void 0:params.message,...context===void 0?{}:{context}};return sealHistoryRecord({...entry,event_class:classifyHistoryEvent(entry)})}function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function invalidHistoryTimestamp(message){return new PmCliError(message,EXIT_CODE.GENERIC_FAILURE,{code:"history_timestamp_invalid"})}function fallbackHistoryTimestamp(entry){const ts=entry.ts.trim();if(ts.length===0)return nowIso();if(!isMillisecondPrecisionRfc3339DateTime(ts)){throw invalidHistoryTimestamp("History timestamp must be a valid RFC 3339 date-time with millisecond precision")}if(ts!==entry.ts){throw invalidHistoryTimestamp("History timestamp must not contain surrounding whitespace")}return entry.ts}function withHistoryTimestamp(value,fallbackTs){const ts=value.ts;if(typeof ts==="string"&&ts.trim().length>0){if(!isMillisecondPrecisionRfc3339DateTime(ts)){throw invalidHistoryTimestamp("History timestamp must be a valid RFC 3339 date-time with millisecond precision")}return value}return{...value,ts:fallbackTs}}function serializeHistoryLine(value,fallbackEntry){const fallbackTs=fallbackHistoryTimestamp(fallbackEntry);if(typeof value==="string"){let parsed;try{parsed=JSON.parse(value)}catch{return value}if(isRecord(parsed)){return JSON.stringify(withHistoryTimestamp(parsed,fallbackTs))}return value}if(isRecord(value)){return JSON.stringify(withHistoryTimestamp(value,fallbackTs))}return JSON.stringify(value)}async function applyHistoryAppendOverride(historyPath,entry,result){if(result===false)return true;if(typeof result==="string"){const line2=serializeHistoryLine(result,entry);await appendHistoryLineWithIdentityReservation(historyPath,line2);await invalidateHistoryDriftCacheForPath(historyPath);await removeHistoryEventIndexForHistoryPath(historyPath);return true}if(typeof result!=="object"||result===null)return false;const record=result;if(record.skip===true)return true;const nextHistoryPath=typeof record.history_path==="string"?record.history_path:historyPath;const line=serializeHistoryLine(typeof record.line==="string"?record.line:record.entry??entry,entry);await appendHistoryLineWithIdentityReservation(nextHistoryPath,line);await invalidateHistoryDriftCacheForPath(nextHistoryPath);await removeHistoryEventIndexForHistoryPath(nextHistoryPath);return true}async function appendHistoryLineWithIdentityReservation(historyPath,line){let record;try{record=JSON.parse(line)}catch{record=null}if(!isRecord(record)||record.op!=="create"){await appendLineAtomic(historyPath,line);return}await fs.mkdir(path.dirname(historyPath),{recursive:true});try{await fs.writeFile(historyPath,`${line}
2
- `,{encoding:"utf8",flag:"wx"})}catch(error){if(error.code!=="EEXIST")throw error;throw new PmCliError("This item identity is reserved by an existing history stream.",EXIT_CODE.CONFLICT,{code:"item_identity_reserved",required:"Choose a new item ID or restore the original item from its history.",nextSteps:["Run pm history <id> --full, then pm restore <id> <version> to recover the original item."]})}}async function appendHistoryEntry(historyPath,entry){const override=await runActiveServiceOverride("history_append",{history_path:historyPath,entry});if(override.handled&&await applyHistoryAppendOverride(historyPath,entry,override.result)){return}const timestampedEntry=entry.ts.trim().length>0?entry:{...entry,ts:fallbackHistoryTimestamp(entry)};const normalizedEntry=sealHistoryRecord({...timestampedEntry,event_class:classifyHistoryEvent(timestampedEntry)});await appendHistoryEntryWithEventIndex(historyPath,normalizedEntry,async()=>{await appendHistoryLineWithIdentityReservation(historyPath,serializeHistoryLine(normalizedEntry,normalizedEntry))});await invalidateHistoryDriftCacheForPath(historyPath)}const _testOnly={decodeJsonPointer,isDefinedPointerPath};export{CURRENT_HISTORY_ITEM_HASH_VERSION,CURRENT_HISTORY_RECORD_HASH_VERSION,SUPPORTED_HISTORY_ITEM_HASH_VERSIONS,SUPPORTED_HISTORY_RECORD_HASH_VERSIONS,_testOnly,appendHistoryEntry,createHistoryEntry,hashDocument,hashDocumentForVersion,hashDocumentVerificationCandidates,hashEmptyDocument,hashHistoryPatch,hashHistoryRecord,hashHistoryStream,resealHistoryRewrite,sealHistoryRecord,verifyHistoryRecordHash,verifyHistoryRewriteEvidence};
1
+ !(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]="6583b1e2-5eae-5e97-af83-a78adac1d571")}catch(e2){}})();import jsonPatch from"fast-json-patch";import{normalizeHistoryOperationForWrite}from"./operation-contract.js";import{CURRENT_HISTORY_HASH_ALGORITHM,historyDigest,resolveHistoryHashAlgorithm}from"./digest.js";import fs from"node:fs/promises";import path from"node:path";import{EXIT_CODE,ITEM_METADATA_KEY_ORDER}from"../shared/constants.js";import{runActiveServiceOverride}from"../extensions/index.js";import{appendLineAtomic}from"../fs/fs-utils.js";import{canonicalDocument}from"../item/item-format.js";import{toItemRecord}from"../item/item-record.js";import{orderObject,sha256Hex,stableStringify}from"../shared/serialization.js";import{isMillisecondPrecisionRfc3339DateTime,nowIso}from"../shared/time.js";import{diagnoseAgentIdentity,resolveHistoryAgentIdentity,resolveHistoryAuthorSource}from"../shared/author.js";import{appendHistoryEntryWithEventIndex,removeHistoryEventIndexForHistoryPath}from"./event-index.js";import{classifyHistoryEvent}from"./event-classification.js";import{invalidateHistoryDriftCacheForPath}from"./drift-cache.js";import{PmCliError}from"../shared/errors.js";const EMPTY_LEGACY_HASH_DOCUMENT={front_matter:{},body:""};const CURRENT_HISTORY_ITEM_HASH_VERSION=3;const SUPPORTED_HISTORY_ITEM_HASH_VERSIONS=[1,2,3];const CURRENT_HISTORY_RECORD_HASH_VERSION=1;const SUPPORTED_HISTORY_RECORD_HASH_VERSIONS=[1];function hashHistoryRecord(entry){return historyDigest(stableStringify(entry),entry.hash_algorithm)}function hashHistoryPatch(patch){return sha256Hex(stableStringify(patch))}function hashHistoryStream(entries){return sha256Hex(stableStringify(entries))}function sealHistoryRecord(entry){const sealed={...entry,record_hash_version:CURRENT_HISTORY_RECORD_HASH_VERSION};const{record_hash:_recordHash,...canonical}=sealed;return{...sealed,record_hash:hashHistoryRecord(canonical)}}function verifyHistoryRecordHash(entry){try{resolveHistoryHashAlgorithm(entry.hash_algorithm)}catch{return{ok:false,error:"unsupported_history_hash_algorithm"}}if(entry.record_hash_version===void 0&&entry.record_hash===void 0){return{ok:true,coverage:"item_state_only"}}if(entry.record_hash_version===void 0||entry.record_hash===void 0){return{ok:false,error:"incomplete_record_hash_envelope"}}if(!SUPPORTED_HISTORY_RECORD_HASH_VERSIONS.includes(entry.record_hash_version)){return{ok:false,error:"unsupported_record_hash_version"}}const{record_hash:_recordHash,...canonical}=entry;return hashHistoryRecord(canonical)===entry.record_hash?{ok:true,coverage:"record_and_item_state"}:{ok:false,error:"record_hash_mismatch"}}function createHistoryRewriteEvidence(original,options){const evidence={before_hash:original.before_hash,after_hash:original.after_hash,patch_hash:hashHistoryPatch(original.patch)};if(original.hash_algorithm!==void 0)evidence.hash_algorithm=original.hash_algorithm;if(original.item_hash_version!==void 0){evidence.item_hash_version=original.item_hash_version}if(options.retainOriginalPatch){evidence.patch=structuredClone(original.patch)}if(options.retainPriorRecordHash!==false&&original.record_hash_version!==void 0&&original.record_hash!==void 0){evidence.record_hash_version=original.record_hash_version;evidence.record_hash=original.record_hash;evidence.record=structuredClone(original)}return evidence}function resealHistoryRewrite(original,rewritten,options={}){const originalRecordVerification=verifyHistoryRecordHash(original);if(!originalRecordVerification.ok){throw new TypeError(originalRecordVerification.error)}const originalPatchHash=hashHistoryPatch(original.patch);const retainsRewriteEvidence=options.retainPriorRecord===true||original.before_hash!==rewritten.before_hash||original.after_hash!==rewritten.after_hash||original.item_hash_version!==rewritten.item_hash_version||original.hash_algorithm!==rewritten.hash_algorithm||originalPatchHash!==hashHistoryPatch(rewritten.patch);const sealed=sealHistoryRecord({...rewritten,...retainsRewriteEvidence?{reanchor_evidence:[...rewritten.reanchor_evidence??[],createHistoryRewriteEvidence(original,options)]}:{}});const evidenceVerification=verifyHistoryRewriteEvidence(sealed);if(!evidenceVerification.ok){throw new TypeError(evidenceVerification.error)}return sealed}function isHistoryPatch(value){if(!Array.isArray(value)||Object.keys(value).length!==value.length){return false}return value.every(operation=>{if(!isRecord(operation)||typeof operation.path!=="string"){return false}if(operation.op==="move"||operation.op==="copy"){return typeof operation.from==="string"}if(["add","replace","test"].includes(operation.op)){return Object.hasOwn(operation,"value")}return operation.op==="remove"})}function isRetainedHistoryRecordShape(value){return isRecord(value)&&typeof value.ts==="string"&&typeof value.author==="string"&&typeof value.op==="string"&&typeof value.before_hash==="string"&&typeof value.after_hash==="string"&&isHistoryPatch(value.patch)}function hasCompleteRetainedRecordHashEnvelope(evidence){const hasVersion=evidence.record_hash_version!==void 0;const hasHash=evidence.record_hash!==void 0;return hasVersion===hasHash}function isHistoryReanchorEvidence(evidence){if(!isRecord(evidence)||!hasCompleteRetainedRecordHashEnvelope(evidence)||typeof evidence.before_hash!=="string"||typeof evidence.after_hash!=="string"||typeof evidence.patch_hash!=="string"||!/^[a-f0-9]{64}$/u.test(evidence.patch_hash)||evidence.patch!==void 0&&!isHistoryPatch(evidence.patch)||evidence.record_hash_version!==void 0&&typeof evidence.record_hash_version!=="number"||evidence.record_hash!==void 0&&(typeof evidence.record_hash!=="string"||!/^(?:[a-f0-9]{64}|[a-f0-9]{128})$/u.test(evidence.record_hash))){return false}return evidence.record===void 0||isRetainedHistoryRecordShape(evidence.record)}function isHistoryRewriteEvidenceList(evidenceEntries){try{for(const evidence of evidenceEntries){if(!isHistoryReanchorEvidence(evidence))return false;resolveHistoryHashAlgorithm(evidence.hash_algorithm)}return true}catch{return false}}function matchesRetainedHistoryRecord(evidence){const record=evidence.record;return record!==void 0&&record.before_hash===evidence.before_hash&&record.after_hash===evidence.after_hash&&record.item_hash_version===evidence.item_hash_version&&record.hash_algorithm===evidence.hash_algorithm&&record.record_hash_version===evidence.record_hash_version&&record.record_hash===evidence.record_hash&&hashHistoryPatch(record.patch)===evidence.patch_hash}function reconstructPriorHistoryRecord(current,evidence,priorEvidence){if(evidence.patch&&hashHistoryPatch(evidence.patch)!==evidence.patch_hash){return{kind:"patch_hash_mismatch"}}if(evidence.record){if(!matchesRetainedHistoryRecord(evidence)){return{kind:"record_hash_mismatch"}}return{kind:"record",entry:evidence.record}}const priorPatch=evidence.patch??current.patch;if(hashHistoryPatch(priorPatch)!==evidence.patch_hash){return{kind:"digest_only"}}const priorRecord={...current,before_hash:evidence.before_hash,after_hash:evidence.after_hash,patch:priorPatch,hash_algorithm:evidence.hash_algorithm,...evidence.item_hash_version===void 0?{}:{item_hash_version:evidence.item_hash_version},...evidence.record_hash_version===void 0?{}:{record_hash_version:evidence.record_hash_version},...evidence.record_hash===void 0?{}:{record_hash:evidence.record_hash},...priorEvidence.length===0?{}:{reanchor_evidence:priorEvidence}};if(evidence.hash_algorithm===void 0)delete priorRecord.hash_algorithm;if(priorEvidence.length===0)delete priorRecord.reanchor_evidence;if(evidence.item_hash_version===void 0){delete priorRecord.item_hash_version}return evidence.record_hash_version===void 0||evidence.record_hash===void 0?{kind:"legacy",entry:priorRecord}:{kind:"record",entry:priorRecord}}function verifyHistoryRewriteEvidence(entry){const evidenceEntries=entry.reanchor_evidence;if(evidenceEntries===void 0)return{ok:true,coverage:"none"};if(!Array.isArray(evidenceEntries)||!isHistoryRewriteEvidenceList(evidenceEntries)){return{ok:false,error:"rewrite_evidence_invalid"}}if(evidenceEntries.length===0)return{ok:true,coverage:"none"};let reconstructed=entry;for(let index=evidenceEntries.length-1;index>=0;index-=1){const evidence=evidenceEntries[index];const prior=reconstructPriorHistoryRecord(reconstructed,evidence,evidenceEntries.slice(0,index));if(prior.kind==="patch_hash_mismatch"){return{ok:false,error:"rewrite_evidence_patch_hash_mismatch"}}if(prior.kind==="record_hash_mismatch"){return{ok:false,error:"rewrite_evidence_record_hash_mismatch"}}if(prior.kind==="digest_only"){return{ok:true,coverage:"digest_only"}}if(prior.kind==="legacy"){return{ok:true,coverage:"legacy_anchor_only"}}if(!verifyHistoryRecordHash(prior.entry).ok){return{ok:false,error:"rewrite_evidence_record_hash_mismatch"}}reconstructed=prior.entry}return{ok:true,coverage:"complete"}}function compareOptionalStrings(left,right){return(left??"").localeCompare(right??"")}function compareOptionalNumbers(left,right){return(left??0)-(right??0)}function compareJsonValues(left,right,fallback){return JSON.stringify(left??fallback).localeCompare(JSON.stringify(right??fallback))}function compareLegacyLinkedTests(left,right){const comparisons=[left.scope.localeCompare(right.scope),compareOptionalStrings(left.path,right.path),compareOptionalStrings(left.command,right.command),compareOptionalNumbers(left.timeout_seconds,right.timeout_seconds),compareOptionalStrings(left.pm_context_mode,right.pm_context_mode),Number(Boolean(left.shared_host_safe))-Number(Boolean(right.shared_host_safe)),compareJsonValues(left.env_clear,right.env_clear,[]),compareJsonValues(left.env_set,right.env_set,{}),compareJsonValues(left.assert_stdout_contains,right.assert_stdout_contains,[]),compareJsonValues(left.assert_stdout_regex,right.assert_stdout_regex,[]),compareJsonValues(left.assert_stderr_contains,right.assert_stderr_contains,[]),compareJsonValues(left.assert_stderr_regex,right.assert_stderr_regex,[]),compareOptionalNumbers(left.assert_stdout_min_lines,right.assert_stdout_min_lines),compareJsonValues(left.assert_json_field_equals,right.assert_json_field_equals,{}),compareJsonValues(left.assert_json_field_gte,right.assert_json_field_gte,{}),compareOptionalStrings(left.note,right.note)];return comparisons.find(comparison=>comparison!==0)??0}function decodeJsonPointer(path2){if(!path2||path2==="/"){return[]}if(!path2.startsWith("/")){return[]}return path2.slice(1).split("/").map(segment=>segment.replaceAll("~1","/").replaceAll("~0","~"))}function isDefinedPointerPath(document,path2){const segments=decodeJsonPointer(path2);if(segments.length===0){return true}let cursor=document;for(const segment of segments){const arrayIndex=/^(0|[1-9]\d*)$/.test(segment)?Number(segment):-1;const next=Array.isArray(cursor)?arrayIndex>=0&&arrayIndex<cursor.length?cursor[arrayIndex]:void 0:isRecord(cursor)&&Object.prototype.hasOwnProperty.call(cursor,segment)?cursor[segment]:void 0;if(next===void 0)return false;cursor=next}return true}function normalizeHistoryPatchOps(beforeDocument,patch){const normalized=[];let replayCursor=structuredClone(beforeDocument);for(const operation of patch){const normalizedOperation=operation.op==="replace"&&!isDefinedPointerPath(replayCursor,operation.path)?{...operation,op:"add"}:operation;normalized.push(normalizedOperation);replayCursor=jsonPatch.applyPatch(replayCursor,[normalizedOperation],true,true).newDocument}return normalized}function canonicalHashDocument(document,version,legacyV2Fields=false){const hasMetadata=document.metadata&&Object.keys(document.metadata).length>0;if(!hasMetadata){return{front_matter:{},body:document.body??""}}const canonical=canonicalDocument(document);const usesLegacyFields=version===1||version===2&&legacyV2Fields;const epochMetadata=usesLegacyFields?{...canonical.metadata,...canonical.metadata.dependencies===void 0?{}:{dependencies:canonical.metadata.dependencies.map(dependency=>({...dependency,id:dependency.id.toLowerCase()}))},...canonical.metadata.tests===void 0?{}:{tests:canonical.metadata.tests.map(({workspace_context_mode:_workspaceContextMode,provenance:_provenance,provenance_invalid:_provenanceInvalid,...test})=>test)},...canonical.metadata.test_runs===void 0?{}:{test_runs:canonical.metadata.test_runs.map(({executions:_executions,...testRun})=>testRun)}}:canonical.metadata;const metadata=version===1&&epochMetadata.tests?{...epochMetadata,tests:[...epochMetadata.tests].sort(compareLegacyLinkedTests)}:epochMetadata;const orderedMetadata=orderObject(toItemRecord(metadata),ITEM_METADATA_KEY_ORDER);return{front_matter:orderedMetadata,body:canonical.body}}function canonicalPatchDocument(document){const hasMetadata=document.metadata&&Object.keys(document.metadata).length>0;if(!hasMetadata){return{metadata:{},body:document.body??""}}const canonical=canonicalDocument(document);const orderedMetadata=orderObject(toItemRecord(canonical.metadata),ITEM_METADATA_KEY_ORDER);return{metadata:orderedMetadata,body:canonical.body}}function hashDocument(document){return hashDocumentForVersion(document,CURRENT_HISTORY_ITEM_HASH_VERSION)}function hashDocumentForVersion(document,version,algorithm){if(!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.some(supportedVersion=>supportedVersion===version)){throw new TypeError(`unsupported_item_hash_version:${String(version)}`)}return historyDigest(stableStringify(canonicalHashDocument(document,version)),algorithm)}function hashDocumentVerificationCandidates(document,version,algorithm){const canonicalHash=hashDocumentForVersion(document,version,algorithm);return version===2?[canonicalHash,historyDigest(stableStringify(canonicalHashDocument(document,version,true)),algorithm)]:[canonicalHash]}function hashEmptyDocument(){return sha256Hex(stableStringify(EMPTY_LEGACY_HASH_DOCUMENT))}function createHistoryEntry(params){const operation=normalizeHistoryOperationForWrite(params.op);const beforeHashCanonical=canonicalHashDocument(params.before,CURRENT_HISTORY_ITEM_HASH_VERSION);const afterHashCanonical=canonicalHashDocument(params.after,CURRENT_HISTORY_ITEM_HASH_VERSION);const beforePatchCanonical=canonicalPatchDocument(params.before);const afterPatchCanonical=canonicalPatchDocument(params.after);const rawPatch=jsonPatch.compare(beforePatchCanonical,afterPatchCanonical);const patch=normalizeHistoryPatchOps(beforePatchCanonical,rawPatch);const agentIdentity=resolveHistoryAgentIdentity(params.author);const provenanceOutcomes=agentIdentity.harness?Object.fromEntries(Object.entries(diagnoseAgentIdentity().provenance_outcomes).filter(([,outcome])=>outcome.resolver!==void 0&&outcome.status!=="resolved")):void 0;const context=provenanceOutcomes===void 0||Object.keys(provenanceOutcomes).length===0?params.context:{...params.context,agent_provenance_outcomes:provenanceOutcomes};const algorithm=params.hashAlgorithm??CURRENT_HISTORY_HASH_ALGORITHM;const entry={hash_algorithm:algorithm,ts:params.nowIso,author:params.author,author_source:params.authorSource??resolveHistoryAuthorSource(params.author),...agentIdentity.harness?{agent_harness:agentIdentity.harness}:{},...agentIdentity.model?{agent_model:agentIdentity.model}:{},...agentIdentity.model_source?{agent_model_source:agentIdentity.model_source}:{},...agentIdentity.instance?{agent_instance:agentIdentity.instance}:{},...agentIdentity.provenance?{agent_provenance:agentIdentity.provenance}:{},...agentIdentity.episode?{agent_episode:agentIdentity.episode}:{},op:operation,patch,before_hash:historyDigest(stableStringify(beforeHashCanonical),algorithm),after_hash:historyDigest(stableStringify(afterHashCanonical),algorithm),item_hash_version:CURRENT_HISTORY_ITEM_HASH_VERSION,message:params.message===void 0?void 0:params.message,...context===void 0?{}:{context}};return sealHistoryRecord({...entry,event_class:classifyHistoryEvent(entry)})}function isRecord(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function invalidHistoryTimestamp(message){return new PmCliError(message,EXIT_CODE.GENERIC_FAILURE,{code:"history_timestamp_invalid"})}function fallbackHistoryTimestamp(entry){const ts=entry.ts.trim();if(ts.length===0)return nowIso();if(!isMillisecondPrecisionRfc3339DateTime(ts)){throw invalidHistoryTimestamp("History timestamp must be a valid RFC 3339 date-time with millisecond precision")}if(ts!==entry.ts){throw invalidHistoryTimestamp("History timestamp must not contain surrounding whitespace")}return entry.ts}function withHistoryTimestamp(value,fallbackTs){const ts=value.ts;if(typeof ts==="string"&&ts.trim().length>0){if(!isMillisecondPrecisionRfc3339DateTime(ts)){throw invalidHistoryTimestamp("History timestamp must be a valid RFC 3339 date-time with millisecond precision")}return value}return{...value,ts:fallbackTs}}function serializeHistoryLine(value,fallbackEntry){const fallbackTs=fallbackHistoryTimestamp(fallbackEntry);if(typeof value==="string"){let parsed;try{parsed=JSON.parse(value)}catch{return value}if(isRecord(parsed)){return JSON.stringify(withHistoryTimestamp(parsed,fallbackTs))}return value}if(isRecord(value)){return JSON.stringify(withHistoryTimestamp(value,fallbackTs))}return JSON.stringify(value)}async function applyHistoryAppendOverride(historyPath,entry,result){if(result===false)return true;if(typeof result==="string"){const line2=serializeHistoryLine(result,entry);await appendHistoryLineWithIdentityReservation(historyPath,line2);await invalidateHistoryDriftCacheForPath(historyPath);await removeHistoryEventIndexForHistoryPath(historyPath);return true}if(typeof result!=="object"||result===null)return false;const record=result;if(record.skip===true)return true;const nextHistoryPath=typeof record.history_path==="string"?record.history_path:historyPath;const line=serializeHistoryLine(typeof record.line==="string"?record.line:record.entry??entry,entry);await appendHistoryLineWithIdentityReservation(nextHistoryPath,line);await invalidateHistoryDriftCacheForPath(nextHistoryPath);await removeHistoryEventIndexForHistoryPath(nextHistoryPath);return true}async function appendHistoryLineWithIdentityReservation(historyPath,line){let record;try{record=JSON.parse(line)}catch{record=null}if(!isRecord(record)||record.op!=="create"){await appendLineAtomic(historyPath,line);return}await fs.mkdir(path.dirname(historyPath),{recursive:true});try{await fs.writeFile(historyPath,`${line}
2
+ `,{encoding:"utf8",flag:"wx"})}catch(error){if(error.code!=="EEXIST")throw error;throw new PmCliError("This item identity is reserved by an existing history stream.",EXIT_CODE.CONFLICT,{code:"item_identity_reserved",required:"Choose a new item ID or restore the original item from its history.",nextSteps:["Run pm history <id> --full, then pm restore <id> <version> to recover the original item."]})}}async function appendHistoryEntry(historyPath,entry){const override=await runActiveServiceOverride("history_append",{history_path:historyPath,entry});if(override.handled&&await applyHistoryAppendOverride(historyPath,entry,override.result)){return}const timestampedEntry=entry.ts.trim().length>0?entry:{...entry,ts:fallbackHistoryTimestamp(entry)};const normalizedEntry=sealHistoryRecord({...timestampedEntry,hash_algorithm:resolveHistoryHashAlgorithm(timestampedEntry.hash_algorithm),event_class:classifyHistoryEvent(timestampedEntry)});await appendHistoryEntryWithEventIndex(historyPath,normalizedEntry,async()=>{await appendHistoryLineWithIdentityReservation(historyPath,serializeHistoryLine(normalizedEntry,normalizedEntry))});await invalidateHistoryDriftCacheForPath(historyPath)}const _testOnly={decodeJsonPointer,isDefinedPointerPath};export{CURRENT_HISTORY_ITEM_HASH_VERSION,CURRENT_HISTORY_RECORD_HASH_VERSION,SUPPORTED_HISTORY_ITEM_HASH_VERSIONS,SUPPORTED_HISTORY_RECORD_HASH_VERSIONS,_testOnly,appendHistoryEntry,createHistoryEntry,hashDocument,hashDocumentForVersion,hashDocumentVerificationCandidates,hashEmptyDocument,hashHistoryPatch,hashHistoryRecord,hashHistoryStream,resealHistoryRewrite,sealHistoryRecord,verifyHistoryRecordHash,verifyHistoryRewriteEvidence};
3
3
  //# sourceMappingURL=history.js.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @module core/history/operation-contract
3
+ * Declares immutable operation identities separately from hooks and JSON Patch verbs.
4
+ */
5
+ /** Native item-event vocabulary. New names require an explicit contract change. */
6
+ export declare const PM_ITEM_HISTORY_OPERATIONS: readonly ["append", "cancel", "claim", "close", "comment_add", "comment_edit", "comment_delete", "create", "delete", "docs_add", "docs_remove", "files_add", "files_remove", "files_discover", "history_author_acknowledge", "history_compact", "history_compact_baseline", "history_redact", "history_repair", "history_salvage", "import", "improvement_observe", "learning_add", "learning_edit", "learning_delete", "normalize", "note_add", "note_edit", "note_delete", "plan_create_metadata", "plan_create_initial_step", "plan_add_step", "plan_reorder_step", "plan_remove_step", "plan_link_step", "plan_unlink_step", "plan_append_decision", "plan_append_discovery", "plan_append_validation", "plan_resume", "plan_approve", "plan_materialize", "plan_update_step", "plan_complete_step", "plan_block_step", "policy_approve", "policy_refused", "release", "reopen", "restore", "schema_migration", "schema_migration_reference", "test_run_track", "tests_add", "tests_remove", "tests_update", "update", "update_audit", "update_ownership_bypass", "workspace_snapshot_restore", "extension_migrations_apply", "merge_reconcile"];
7
+ /** Exact singleton identities retained for compatibility with existing workspace streams. */
8
+ export declare const PM_WORKSPACE_HISTORY_OPERATIONS: readonly ["history:author-acknowledge", "settings:write", "init:type_preset", "templates:save", "profile:apply-types", "profile:apply-statuses", "profile:apply-fields", "profile:apply-config", "schema:add-type", "schema:remove-type", "schema:add-status", "schema:remove-status", "schema:add-field", "schema:remove-field", "schema:apply-preset", "schema:infer-types", "schema:policy-put", "schema:policy-remove", "schema:policy-mode", "assurance:bundle:apply", "assurance:gate:verdict", "telemetry:install_id", "telemetry:first_run_prompt", "telemetry:clear", "item_format:auto_select_default"];
9
+ /** Retired writer spellings; readers preserve original bytes and may resolve aliases explicitly. */
10
+ export declare const PM_HISTORY_OPERATION_ALIASES: Readonly<Record<string, string>>;
11
+ /** Parameterized operation families whose operands are governed by their owning SDK contracts. */
12
+ export declare const PM_HISTORY_OPERATION_PATTERNS: readonly ["^config:(?:set|unset):[a-z][a-z0-9_.:-]*$", "^assurance:(?:measurement|invariant|gate):(?:put|remove)$", "^schema_(?:rename_type|rename_status|remap_status|rename_field|remove_type|remove_status|remove_field)(?:_compensate)?$", "^extension:[a-z][a-z0-9_-]*:[a-z][a-z0-9_]*$"];
13
+ /** Public immutable-event naming and compatibility contract. */
14
+ export declare const PM_HISTORY_OPERATION_CONTRACT: {
15
+ readonly version: 1;
16
+ readonly item: readonly ["append", "cancel", "claim", "close", "comment_add", "comment_edit", "comment_delete", "create", "delete", "docs_add", "docs_remove", "files_add", "files_remove", "files_discover", "history_author_acknowledge", "history_compact", "history_compact_baseline", "history_redact", "history_repair", "history_salvage", "import", "improvement_observe", "learning_add", "learning_edit", "learning_delete", "normalize", "note_add", "note_edit", "note_delete", "plan_create_metadata", "plan_create_initial_step", "plan_add_step", "plan_reorder_step", "plan_remove_step", "plan_link_step", "plan_unlink_step", "plan_append_decision", "plan_append_discovery", "plan_append_validation", "plan_resume", "plan_approve", "plan_materialize", "plan_update_step", "plan_complete_step", "plan_block_step", "policy_approve", "policy_refused", "release", "reopen", "restore", "schema_migration", "schema_migration_reference", "test_run_track", "tests_add", "tests_remove", "tests_update", "update", "update_audit", "update_ownership_bypass", "workspace_snapshot_restore", "extension_migrations_apply", "merge_reconcile"];
17
+ readonly workspace: readonly ["history:author-acknowledge", "settings:write", "init:type_preset", "templates:save", "profile:apply-types", "profile:apply-statuses", "profile:apply-fields", "profile:apply-config", "schema:add-type", "schema:remove-type", "schema:add-status", "schema:remove-status", "schema:add-field", "schema:remove-field", "schema:apply-preset", "schema:infer-types", "schema:policy-put", "schema:policy-remove", "schema:policy-mode", "assurance:bundle:apply", "assurance:gate:verdict", "telemetry:install_id", "telemetry:first_run_prompt", "telemetry:clear", "item_format:auto_select_default"];
18
+ readonly aliases: Readonly<Record<string, string>>;
19
+ readonly patterns: readonly ["^config:(?:set|unset):[a-z][a-z0-9_.:-]*$", "^assurance:(?:measurement|invariant|gate):(?:put|remove)$", "^schema_(?:rename_type|rename_status|remap_status|rename_field|remove_type|remove_status|remove_field)(?:_compensate)?$", "^extension:[a-z][a-z0-9_-]*:[a-z][a-z0-9_]*$"];
20
+ readonly read_policy: "preserve_original_operation";
21
+ readonly custom_operation_grammar: "extension:<package_name>:<snake_case_operation>";
22
+ readonly legacy_custom_operation_grammar: "lowercase segments separated by underscore, hyphen, colon, or dot; optional opaque colon-suffixed retry key";
23
+ readonly excluded_surfaces: readonly ["json_patch", "on_write_hook", "telemetry_span"];
24
+ };
25
+ /** Resolve known historical aliases without changing or rejecting an immutable record. */
26
+ export declare function resolveHistoryOperation(operation: string): string;
27
+ /** Validate a new operation and return its declared canonical writer spelling. */
28
+ export declare function requireHistoryOperation(operation: string): string;
29
+ /** Canonicalize native aliases while retaining well-formed custom SDK operation identities. */
30
+ export declare function normalizeHistoryOperationForWrite(operation: string): string;
@@ -0,0 +1,2 @@
1
+ !(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]="da97ee67-b4ef-5eed-94d4-03c9b3b494be")}catch(e2){}})();const PM_ITEM_HISTORY_OPERATIONS=["append","cancel","claim","close","comment_add","comment_edit","comment_delete","create","delete","docs_add","docs_remove","files_add","files_remove","files_discover","history_author_acknowledge","history_compact","history_compact_baseline","history_redact","history_repair","history_salvage","import","improvement_observe","learning_add","learning_edit","learning_delete","normalize","note_add","note_edit","note_delete","plan_create_metadata","plan_create_initial_step","plan_add_step","plan_reorder_step","plan_remove_step","plan_link_step","plan_unlink_step","plan_append_decision","plan_append_discovery","plan_append_validation","plan_resume","plan_approve","plan_materialize","plan_update_step","plan_complete_step","plan_block_step","policy_approve","policy_refused","release","reopen","restore","schema_migration","schema_migration_reference","test_run_track","tests_add","tests_remove","tests_update","update","update_audit","update_ownership_bypass","workspace_snapshot_restore","extension_migrations_apply","merge_reconcile"];const PM_WORKSPACE_HISTORY_OPERATIONS=["history:author-acknowledge","settings:write","init:type_preset","templates:save","profile:apply-types","profile:apply-statuses","profile:apply-fields","profile:apply-config","schema:add-type","schema:remove-type","schema:add-status","schema:remove-status","schema:add-field","schema:remove-field","schema:apply-preset","schema:infer-types","schema:policy-put","schema:policy-remove","schema:policy-mode","assurance:bundle:apply","assurance:gate:verdict","telemetry:install_id","telemetry:first_run_prompt","telemetry:clear","item_format:auto_select_default"];const PM_HISTORY_OPERATION_ALIASES={"init:type-preset":"init:type_preset"};const PM_HISTORY_OPERATION_PATTERNS=["^config:(?:set|unset):[a-z][a-z0-9_.:-]*$","^assurance:(?:measurement|invariant|gate):(?:put|remove)$","^schema_(?:rename_type|rename_status|remap_status|rename_field|remove_type|remove_status|remove_field)(?:_compensate)?$","^extension:[a-z][a-z0-9_-]*:[a-z][a-z0-9_]*$"];const PM_HISTORY_OPERATION_CONTRACT={version:1,item:PM_ITEM_HISTORY_OPERATIONS,workspace:PM_WORKSPACE_HISTORY_OPERATIONS,aliases:PM_HISTORY_OPERATION_ALIASES,patterns:PM_HISTORY_OPERATION_PATTERNS,read_policy:"preserve_original_operation",custom_operation_grammar:"extension:<package_name>:<snake_case_operation>",legacy_custom_operation_grammar:"lowercase segments separated by underscore, hyphen, colon, or dot; optional opaque colon-suffixed retry key",excluded_surfaces:["json_patch","on_write_hook","telemetry_span"]};const declared=new Set([...PM_ITEM_HISTORY_OPERATIONS,...PM_WORKSPACE_HISTORY_OPERATIONS]);const patterns=PM_HISTORY_OPERATION_PATTERNS.map(pattern=>new RegExp(pattern,"u"));function resolveHistoryOperation(operation){return Object.hasOwn(PM_HISTORY_OPERATION_ALIASES,operation)?PM_HISTORY_OPERATION_ALIASES[operation]:operation}function requireHistoryOperation(operation){const canonical=resolveHistoryOperation(operation);if(declared.has(canonical)||patterns.some(pattern=>pattern.test(canonical)))return canonical;throw new TypeError("Undeclared history operation; use a native contract identity or extension:<package_name>:<snake_case_operation>.")}function normalizeHistoryOperationForWrite(operation){const canonical=resolveHistoryOperation(operation);const colon=canonical.indexOf(":");const prefix=colon<0?canonical:canonical.slice(0,colon);const validSuffix=colon<0||colon<canonical.length-1&&!/[\s\p{C}]/u.test(canonical.slice(colon+1));if(/^[a-z][a-z0-9]*(?:[_.-][a-z0-9]+)*$/u.test(prefix)&&validSuffix)return canonical;throw new TypeError("History operation must use lowercase alphanumeric segments with an optional non-whitespace colon-suffixed retry key.")}export{PM_HISTORY_OPERATION_ALIASES,PM_HISTORY_OPERATION_CONTRACT,PM_HISTORY_OPERATION_PATTERNS,PM_ITEM_HISTORY_OPERATIONS,PM_WORKSPACE_HISTORY_OPERATIONS,normalizeHistoryOperationForWrite,requireHistoryOperation,resolveHistoryOperation};
2
+ //# sourceMappingURL=operation-contract.js.map
@@ -1,3 +1,4 @@
1
+ import { type HistoryHashAlgorithm } from "./digest.js";
1
2
  import { canonicalDocument } from "../item/item-format.js";
2
3
  import { type HistoryItemHashVersion } from "./history.js";
3
4
  import type { HistoryEntry, HistoryPatchOp, ItemDocument } from "../../types/index.js";
@@ -20,13 +21,13 @@ export declare const EMPTY_REPLAY_DOCUMENT: ReplayDocument;
20
21
  /** Implements clone empty replay document for the public runtime surface of this module. */
21
22
  export declare function cloneEmptyReplayDocument(): ReplayDocument;
22
23
  /** Implements replay hash for the public runtime surface of this module. */
23
- export declare function replayHash(document: ReplayDocument, version?: HistoryItemHashVersion): string;
24
+ export declare function replayHash(document: ReplayDocument, version?: HistoryItemHashVersion, algorithm?: HistoryHashAlgorithm): string;
24
25
  /**
25
26
  * Return hash candidates that preserve the semantic variant within an epoch.
26
27
  * Duplicate values are intentional: before and after candidates use the same
27
28
  * index when a patch introduces a field that distinguishes legacy epoch 2.
28
29
  */
29
- export declare function replayHashVerificationCandidates(document: ReplayDocument, version: HistoryItemHashVersion): [string, ...string[]];
30
+ export declare function replayHashVerificationCandidates(document: ReplayDocument, version: HistoryItemHashVersion, algorithm?: HistoryHashAlgorithm): [string, ...string[]];
30
31
  /** Implements replay to item document for the public runtime surface of this module. */
31
32
  export declare function replayToItemDocument(document: ReplayDocument): ItemDocument;
32
33
  /** 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. */
@@ -1,3 +1,3 @@
1
- !(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]="19838bc7-d35d-5fae-a023-2e39697ffec9")}catch(e2){}})();import jsonPatch from"fast-json-patch";import{findHistoryIdentityDiscontinuities}from"./identity.js";import{ITEM_METADATA_KEY_ORDER}from"../shared/constants.js";import{canonicalDocument}from"../item/item-format.js";import{toItemRecord}from"../item/item-record.js";import{orderObject,sha256Hex,stableStringify}from"../shared/serialization.js";import{CURRENT_HISTORY_ITEM_HASH_VERSION,SUPPORTED_HISTORY_ITEM_HASH_VERSIONS,hashDocumentVerificationCandidates,resealHistoryRewrite,verifyHistoryRecordHash,verifyHistoryRewriteEvidence}from"./history.js";const EMPTY_REPLAY_DOCUMENT={metadata:{},body:""};function cloneEmptyReplayDocument(){return structuredClone(EMPTY_REPLAY_DOCUMENT)}function replayHash(document,version=CURRENT_HISTORY_ITEM_HASH_VERSION){return replayHashVerificationCandidates(document,version)[0]}function replayHashVerificationCandidates(document,version){if(Object.keys(document.metadata).length===0||Array.isArray(document.metadata.tags)){try{return hashDocumentVerificationCandidates(replayToItemDocument(document),version)}catch{}}const fallback=sha256Hex(stableStringify({replay_fallback:true,metadata:document.metadata,body:document.body}));return version===2?[fallback,fallback]:[fallback]}function matchReplayHashCandidates(before,after,version,entry){const beforeHashes=replayHashVerificationCandidates(before,version);const afterHashes=replayHashVerificationCandidates(after,version);return{beforeHashes,afterHashes,pairIndex:beforeHashes.findIndex((beforeHash,hashIndex)=>beforeHash===entry.before_hash&&afterHashes[hashIndex]===entry.after_hash),beforeIndex:beforeHashes.indexOf(entry.before_hash),afterIndex:afterHashes.indexOf(entry.after_hash)}}function replayToItemDocument(document){return{metadata:document.metadata,body:document.body}}function replayToCanonicalItemDocument(document,options={}){return canonicalDocument(replayToItemDocument(document),options)}function toReplayDocument(document){if(!document.metadata||Object.keys(document.metadata).length===0){return{metadata:{},body:document.body??""}}const canonical=canonicalDocument(document);return{metadata:orderObject(toItemRecord(canonical.metadata),ITEM_METADATA_KEY_ORDER),body:canonical.body}}function normalizeReplayPatchPath(path){if(path==="/front_matter"){return"/metadata"}if(path.startsWith("/front_matter/")){return`/metadata/${path.slice("/front_matter/".length)}`}return path}function isHistoryPatchOp(value){return typeof value==="object"&&value!==null&&typeof value.op==="string"&&typeof value.path==="string"}function normalizeReplayPatchOps(patch){if(!Array.isArray(patch)){return[]}return patch.filter(isHistoryPatchOp).map(operation=>({...operation,path:normalizeReplayPatchPath(operation.path),from:typeof operation.from==="string"?normalizeReplayPatchPath(operation.from):void 0}))}function isReplayDocumentShape(value){return typeof value==="object"&&value!==null&&"metadata"in value&&"body"in value&&typeof value.body==="string"&&typeof value.metadata==="object"&&value.metadata!==null}function tryApplyReplayPatch(current,patch){try{const normalizedPatch=normalizeReplayPatchOps(patch);const applied=jsonPatch.applyPatch(structuredClone(current),normalizedPatch,true,false).newDocument;if(!isReplayDocumentShape(applied)){return{ok:false,error:new Error("history_replay_invalid_document_shape")}}return{ok:true,document:{metadata:applied.metadata,body:applied.body}}}catch(error){return{ok:false,error}}}function supportedExplicitHistoryItemHashVersions(entries){return[...new Set(entries.map(entry=>entry.item_hash_version).filter(version=>version!==void 0&&SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(version)))]}function isUnsupportedExplicitHistoryItemHashVersion(version){return version!==void 0&&!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(version)}function historyEntryHashCandidates(explicitVersion,authoritativeVersion){if(explicitVersion!==void 0){return[explicitVersion]}return authoritativeVersion===void 0?[...SUPPORTED_HISTORY_ITEM_HASH_VERSIONS]:[authoritativeVersion]}function historyEntryIntegrityError(entry){const recordVerification=verifyHistoryRecordHash(entry);if(!recordVerification.ok)return recordVerification.error;const rewriteVerification=verifyHistoryRewriteEvidence(entry);return rewriteVerification.ok?void 0:rewriteVerification.error}function verifyHistoryEntryInput(entry,replay){const integrityError=historyEntryIntegrityError(entry);if(integrityError)return{ok:false,error:integrityError};const applied=tryApplyReplayPatch(replay,entry.patch);return applied.ok?{ok:true,document:applied.document}:{ok:false,error:"patch_apply_failed"}}function assertHistoryEntryIntegrity(entry,index){const integrityError=historyEntryIntegrityError(entry);if(integrityError){throw new TypeError(`${integrityError}:entry_${index+1}`)}}function verifyHistoryChainWithVersion(entries){let replay=cloneEmptyReplayDocument();let detectedVersion;let authoritativeExplicitVersion;const errors=findHistoryIdentityDiscontinuities(entries).map(finding=>`verify_failed:duplicate_create:entry_${finding.repeated_create_index}:prior_${finding.prior_genesis_index}`);for(let index=0;index<entries.length;index+=1){const entry=entries[index];const explicitVersion=entry.item_hash_version;const unsupportedVersion=isUnsupportedExplicitHistoryItemHashVersion(explicitVersion);if(unsupportedVersion){errors.push(`verify_failed:unsupported_item_hash_version:${String(explicitVersion)}:entry_${index+1}`)}const input=verifyHistoryEntryInput(entry,replay);if(!input.ok){return{ok:false,errors:[...errors,`verify_failed:${input.error}:entry_${index+1}`]}}if(unsupportedVersion){replay=input.document;detectedVersion=void 0;authoritativeExplicitVersion=void 0;continue}const candidates=historyEntryHashCandidates(explicitVersion,authoritativeExplicitVersion);const candidateMatches=candidates.map(version2=>({version:version2,match:matchReplayHashCandidates(replay,input.document,version2,entry)}));const matchingVersion=candidateMatches.find(({match})=>match.pairIndex>=0);if(matchingVersion===void 0){const beforeMatches=candidateMatches.some(({match})=>match.beforeIndex>=0);return{ok:false,errors:[...errors,`verify_failed:${beforeMatches?"after":"before"}_hash_mismatch:entry_${index+1}`]}}const version=matchingVersion.version;replay=input.document;detectedVersion=version;authoritativeExplicitVersion=explicitVersion??authoritativeExplicitVersion}if(errors.length>0){return{ok:false,errors,...detectedVersion===void 0?{}:{item_hash_version:detectedVersion}}}return{ok:true,errors:[],...detectedVersion===void 0?{}:{item_hash_version:detectedVersion}}}function verifyHistoryChain(entries){const result=verifyHistoryChainWithVersion(entries);return{ok:result.ok,errors:result.errors}}function tryApplySingleOp(document,op){try{const applied=jsonPatch.applyPatch(structuredClone(document),[op],true,false).newDocument;return{ok:true,document:applied}}catch{return{ok:false}}}function lenientApplyReplayPatch(current,patch){let working=structuredClone(current);let convertedReplaceToAdd=0;let skippedOps=0;for(const op of normalizeReplayPatchOps(patch)){const direct=tryApplySingleOp(working,op);if(direct.ok){working=direct.document;continue}if(op.op==="replace"){const asAdd=tryApplySingleOp(working,{...op,op:"add"});if(asAdd.ok){working=asAdd.document;convertedReplaceToAdd+=1;continue}}skippedOps+=1}const candidate=working;const document={metadata:typeof candidate.metadata==="object"&&candidate.metadata!==null?candidate.metadata:{},body:typeof candidate.body==="string"?candidate.body:current.body};return{document,convertedReplaceToAdd,skippedOps}}function resolveHistoryRepairItemHashVersion(entries){const explicitVersions=supportedExplicitHistoryItemHashVersions(entries);if(explicitVersions.length===1){return explicitVersions[0]}const verified=verifyHistoryChainWithVersion(entries);if(verified.ok&&verified.item_hash_version!==void 0){return verified.item_hash_version}if(explicitVersions.length===0){return 1}return CURRENT_HISTORY_ITEM_HASH_VERSION}function applyReanchorPatch(replay,entry){const strict=tryApplyReplayPatch(replay,entry.patch);if(strict.ok){return{next:strict.document,patch:entry.patch,repaired:false,converted:0,skipped:0}}const lenient=lenientApplyReplayPatch(replay,entry.patch);return{next:lenient.document,patch:jsonPatch.compare(replay,lenient.document),repaired:true,converted:lenient.convertedReplaceToAdd,skipped:lenient.skippedOps}}function reanchorHistoryEntries(entries,itemHashVersion=resolveHistoryRepairItemHashVersion(entries),options={}){const unsupportedIndex=entries.findIndex(entry=>isUnsupportedExplicitHistoryItemHashVersion(entry.item_hash_version));if(unsupportedIndex>=0){throw new TypeError(`unsupported_item_hash_version:${String(entries[unsupportedIndex]?.item_hash_version)}:entry_${unsupportedIndex+1}`)}let replay=cloneEmptyReplayDocument();const rewritten=[];const details=[];let entriesRehashed=0;let entriesPatchRepaired=0;let convertedReplaceToAdd=0;let skippedOps=0;let semanticIndex;const explicitItemHashVersion=itemHashVersion!==1||entries.some(entry=>entry.item_hash_version!==void 0);for(let index=0;index<entries.length;index+=1){const entry=entries[index];assertHistoryEntryIntegrity(entry,index);const patchApplication=applyReanchorPatch(replay,entry);const{next,patch:outPatch,repaired:patchRepaired,converted:entryConverted,skipped:entrySkipped}=patchApplication;convertedReplaceToAdd+=entryConverted;skippedOps+=entrySkipped;entriesPatchRepaired+=Number(patchRepaired);const hashMatch=matchReplayHashCandidates(replay,next,itemHashVersion,entry);if(semanticIndex===void 0||options.continuousHashSurface!==true){semanticIndex=[hashMatch.pairIndex,hashMatch.beforeIndex,hashMatch.afterIndex,Math.min(semanticIndex??0,hashMatch.beforeHashes.length-1)].find(candidate=>candidate>=0)}else{semanticIndex=Math.min(semanticIndex,hashMatch.beforeHashes.length-1)}const beforeHash=hashMatch.beforeHashes[semanticIndex];const afterHash=hashMatch.afterHashes[semanticIndex];const rehashed=beforeHash!==entry.before_hash||afterHash!==entry.after_hash;if(rehashed){entriesRehashed+=1}let rewrittenEntry={...entry,patch:outPatch,before_hash:beforeHash,after_hash:afterHash};if(explicitItemHashVersion){rewrittenEntry.item_hash_version=itemHashVersion}else{delete rewrittenEntry.item_hash_version}const versionChanged=rewrittenEntry.item_hash_version!==entry.item_hash_version;if(rehashed||patchRepaired||versionChanged){rewrittenEntry=resealHistoryRewrite(entry,rewrittenEntry,{retainOriginalPatch:patchRepaired})}rewritten.push(rewrittenEntry);details.push({index:index+1,rehashed,patch_repaired:patchRepaired,converted_replace_to_add:entryConverted,skipped_ops:entrySkipped});replay=next}return{entries:rewritten,finalDocument:replay,entriesRehashed,entriesPatchRepaired,convertedReplaceToAdd,skippedOps,details,itemHashVersion,explicitItemHashVersion}}function historyEntriesToRaw(entries){if(entries.length===0){return""}return`${entries.map(entry=>JSON.stringify(entry)).join("\n")}
1
+ !(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]="7a0fa585-7e3c-57fd-b29c-c26e9c522cb1")}catch(e2){}})();import jsonPatch from"fast-json-patch";import{historyDigest,resolveHistoryHashAlgorithm}from"./digest.js";import{findHistoryIdentityDiscontinuities}from"./identity.js";import{ITEM_METADATA_KEY_ORDER}from"../shared/constants.js";import{canonicalDocument}from"../item/item-format.js";import{toItemRecord}from"../item/item-record.js";import{orderObject,stableStringify}from"../shared/serialization.js";import{CURRENT_HISTORY_ITEM_HASH_VERSION,SUPPORTED_HISTORY_ITEM_HASH_VERSIONS,hashDocumentVerificationCandidates,resealHistoryRewrite,verifyHistoryRecordHash,verifyHistoryRewriteEvidence}from"./history.js";const EMPTY_REPLAY_DOCUMENT={metadata:{},body:""};function cloneEmptyReplayDocument(){return structuredClone(EMPTY_REPLAY_DOCUMENT)}function replayHash(document,version=CURRENT_HISTORY_ITEM_HASH_VERSION,algorithm){return replayHashVerificationCandidates(document,version,algorithm)[0]}function replayHashVerificationCandidates(document,version,algorithm){if(Object.keys(document.metadata).length===0||Array.isArray(document.metadata.tags)){try{return hashDocumentVerificationCandidates(replayToItemDocument(document),version,algorithm)}catch{}}const fallback=historyDigest(stableStringify({replay_fallback:true,metadata:document.metadata,body:document.body}),algorithm);return version===2?[fallback,fallback]:[fallback]}function matchReplayHashCandidates(before,after,version,entry){const algorithm=resolveHistoryHashAlgorithm(entry.hash_algorithm);const beforeHashes=replayHashVerificationCandidates(before,version,algorithm);const afterHashes=replayHashVerificationCandidates(after,version,algorithm);return{beforeHashes,afterHashes,pairIndex:beforeHashes.findIndex((beforeHash,hashIndex)=>beforeHash===entry.before_hash&&afterHashes[hashIndex]===entry.after_hash),beforeIndex:beforeHashes.indexOf(entry.before_hash),afterIndex:afterHashes.indexOf(entry.after_hash)}}function replayToItemDocument(document){return{metadata:document.metadata,body:document.body}}function replayToCanonicalItemDocument(document,options={}){return canonicalDocument(replayToItemDocument(document),options)}function toReplayDocument(document){if(!document.metadata||Object.keys(document.metadata).length===0){return{metadata:{},body:document.body??""}}const canonical=canonicalDocument(document);return{metadata:orderObject(toItemRecord(canonical.metadata),ITEM_METADATA_KEY_ORDER),body:canonical.body}}function normalizeReplayPatchPath(path){if(path==="/front_matter"){return"/metadata"}if(path.startsWith("/front_matter/")){return`/metadata/${path.slice("/front_matter/".length)}`}return path}function isHistoryPatchOp(value){return typeof value==="object"&&value!==null&&typeof value.op==="string"&&typeof value.path==="string"}function normalizeReplayPatchOps(patch){if(!Array.isArray(patch)){return[]}return patch.filter(isHistoryPatchOp).map(operation=>({...operation,path:normalizeReplayPatchPath(operation.path),from:typeof operation.from==="string"?normalizeReplayPatchPath(operation.from):void 0}))}function isReplayDocumentShape(value){return typeof value==="object"&&value!==null&&"metadata"in value&&"body"in value&&typeof value.body==="string"&&typeof value.metadata==="object"&&value.metadata!==null}function tryApplyReplayPatch(current,patch){try{const normalizedPatch=normalizeReplayPatchOps(patch);const applied=jsonPatch.applyPatch(structuredClone(current),normalizedPatch,true,false).newDocument;if(!isReplayDocumentShape(applied)){return{ok:false,error:new Error("history_replay_invalid_document_shape")}}return{ok:true,document:{metadata:applied.metadata,body:applied.body}}}catch(error){return{ok:false,error}}}function supportedExplicitHistoryItemHashVersions(entries){return[...new Set(entries.map(entry=>entry.item_hash_version).filter(version=>version!==void 0&&SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(version)))]}function isUnsupportedExplicitHistoryItemHashVersion(version){return version!==void 0&&!SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.includes(version)}function historyEntryHashCandidates(explicitVersion,authoritativeVersion){if(explicitVersion!==void 0){return[explicitVersion]}return authoritativeVersion===void 0?[...SUPPORTED_HISTORY_ITEM_HASH_VERSIONS]:[authoritativeVersion]}function historyEntryIntegrityError(entry){const recordVerification=verifyHistoryRecordHash(entry);if(!recordVerification.ok)return recordVerification.error;const rewriteVerification=verifyHistoryRewriteEvidence(entry);return rewriteVerification.ok?void 0:rewriteVerification.error}function verifyHistoryEntryInput(entry,replay){const integrityError=historyEntryIntegrityError(entry);if(integrityError)return{ok:false,error:integrityError};const applied=tryApplyReplayPatch(replay,entry.patch);return applied.ok?{ok:true,document:applied.document}:{ok:false,error:"patch_apply_failed"}}function assertHistoryEntryIntegrity(entry,index){const integrityError=historyEntryIntegrityError(entry);if(integrityError){throw new TypeError(`${integrityError}:entry_${index+1}`)}}function verifyHistoryChainWithVersion(entries){let replay=cloneEmptyReplayDocument();let detectedVersion;let authoritativeExplicitVersion;const errors=findHistoryIdentityDiscontinuities(entries).map(finding=>`verify_failed:duplicate_create:entry_${finding.repeated_create_index}:prior_${finding.prior_genesis_index}`);for(let index=0;index<entries.length;index+=1){const entry=entries[index];const explicitVersion=entry.item_hash_version;const unsupportedVersion=isUnsupportedExplicitHistoryItemHashVersion(explicitVersion);if(unsupportedVersion){errors.push(`verify_failed:unsupported_item_hash_version:${String(explicitVersion)}:entry_${index+1}`)}const input=verifyHistoryEntryInput(entry,replay);if(!input.ok){return{ok:false,errors:[...errors,`verify_failed:${input.error}:entry_${index+1}`]}}if(unsupportedVersion){replay=input.document;detectedVersion=void 0;authoritativeExplicitVersion=void 0;continue}const candidates=historyEntryHashCandidates(explicitVersion,authoritativeExplicitVersion);const candidateMatches=candidates.map(version2=>({version:version2,match:matchReplayHashCandidates(replay,input.document,version2,entry)}));const matchingVersion=candidateMatches.find(({match})=>match.pairIndex>=0);if(matchingVersion===void 0){const beforeMatches=candidateMatches.some(({match})=>match.beforeIndex>=0);return{ok:false,errors:[...errors,`verify_failed:${beforeMatches?"after":"before"}_hash_mismatch:entry_${index+1}`]}}const version=matchingVersion.version;replay=input.document;detectedVersion=version;authoritativeExplicitVersion=explicitVersion??authoritativeExplicitVersion}if(errors.length>0){return{ok:false,errors,...detectedVersion===void 0?{}:{item_hash_version:detectedVersion}}}return{ok:true,errors:[],...detectedVersion===void 0?{}:{item_hash_version:detectedVersion}}}function verifyHistoryChain(entries){const result=verifyHistoryChainWithVersion(entries);return{ok:result.ok,errors:result.errors}}function tryApplySingleOp(document,op){try{const applied=jsonPatch.applyPatch(structuredClone(document),[op],true,false).newDocument;return{ok:true,document:applied}}catch{return{ok:false}}}function lenientApplyReplayPatch(current,patch){let working=structuredClone(current);let convertedReplaceToAdd=0;let skippedOps=0;for(const op of normalizeReplayPatchOps(patch)){const direct=tryApplySingleOp(working,op);if(direct.ok){working=direct.document;continue}if(op.op==="replace"){const asAdd=tryApplySingleOp(working,{...op,op:"add"});if(asAdd.ok){working=asAdd.document;convertedReplaceToAdd+=1;continue}}skippedOps+=1}const candidate=working;const document={metadata:typeof candidate.metadata==="object"&&candidate.metadata!==null?candidate.metadata:{},body:typeof candidate.body==="string"?candidate.body:current.body};return{document,convertedReplaceToAdd,skippedOps}}function resolveHistoryRepairItemHashVersion(entries){const explicitVersions=supportedExplicitHistoryItemHashVersions(entries);if(explicitVersions.length===1){return explicitVersions[0]}const verified=verifyHistoryChainWithVersion(entries);if(verified.ok&&verified.item_hash_version!==void 0){return verified.item_hash_version}if(explicitVersions.length===0){return 1}return CURRENT_HISTORY_ITEM_HASH_VERSION}function applyReanchorPatch(replay,entry){const strict=tryApplyReplayPatch(replay,entry.patch);if(strict.ok){return{next:strict.document,patch:entry.patch,repaired:false,converted:0,skipped:0}}const lenient=lenientApplyReplayPatch(replay,entry.patch);return{next:lenient.document,patch:jsonPatch.compare(replay,lenient.document),repaired:true,converted:lenient.convertedReplaceToAdd,skipped:lenient.skippedOps}}function reanchorHistoryEntries(entries,itemHashVersion=resolveHistoryRepairItemHashVersion(entries),options={}){const unsupportedIndex=entries.findIndex(entry=>isUnsupportedExplicitHistoryItemHashVersion(entry.item_hash_version));if(unsupportedIndex>=0){throw new TypeError(`unsupported_item_hash_version:${String(entries[unsupportedIndex]?.item_hash_version)}:entry_${unsupportedIndex+1}`)}let replay=cloneEmptyReplayDocument();const rewritten=[];const details=[];let entriesRehashed=0;let entriesPatchRepaired=0;let convertedReplaceToAdd=0;let skippedOps=0;let semanticIndex;const explicitItemHashVersion=itemHashVersion!==1||entries.some(entry=>entry.item_hash_version!==void 0);for(let index=0;index<entries.length;index+=1){const entry=entries[index];assertHistoryEntryIntegrity(entry,index);const patchApplication=applyReanchorPatch(replay,entry);const{next,patch:outPatch,repaired:patchRepaired,converted:entryConverted,skipped:entrySkipped}=patchApplication;convertedReplaceToAdd+=entryConverted;skippedOps+=entrySkipped;entriesPatchRepaired+=Number(patchRepaired);const hashMatch=matchReplayHashCandidates(replay,next,itemHashVersion,entry);if(semanticIndex===void 0||options.continuousHashSurface!==true){semanticIndex=[hashMatch.pairIndex,hashMatch.beforeIndex,hashMatch.afterIndex,Math.min(semanticIndex??0,hashMatch.beforeHashes.length-1)].find(candidate=>candidate>=0)}else{semanticIndex=Math.min(semanticIndex,hashMatch.beforeHashes.length-1)}const beforeHash=hashMatch.beforeHashes[semanticIndex];const afterHash=hashMatch.afterHashes[semanticIndex];const rehashed=beforeHash!==entry.before_hash||afterHash!==entry.after_hash;if(rehashed){entriesRehashed+=1}let rewrittenEntry={...entry,patch:outPatch,before_hash:beforeHash,after_hash:afterHash};if(explicitItemHashVersion){rewrittenEntry.item_hash_version=itemHashVersion}else{delete rewrittenEntry.item_hash_version}const versionChanged=rewrittenEntry.item_hash_version!==entry.item_hash_version;if(rehashed||patchRepaired||versionChanged){rewrittenEntry=resealHistoryRewrite(entry,rewrittenEntry,{retainOriginalPatch:patchRepaired})}rewritten.push(rewrittenEntry);details.push({index:index+1,rehashed,patch_repaired:patchRepaired,converted_replace_to_add:entryConverted,skipped_ops:entrySkipped});replay=next}return{entries:rewritten,finalDocument:replay,entriesRehashed,entriesPatchRepaired,convertedReplaceToAdd,skippedOps,details,itemHashVersion,explicitItemHashVersion}}function historyEntriesToRaw(entries){if(entries.length===0){return""}return`${entries.map(entry=>JSON.stringify(entry)).join("\n")}
2
2
  `}export{EMPTY_REPLAY_DOCUMENT,cloneEmptyReplayDocument,historyEntriesToRaw,lenientApplyReplayPatch,normalizeReplayPatchOps,normalizeReplayPatchPath,reanchorHistoryEntries,replayHash,replayHashVerificationCandidates,replayToCanonicalItemDocument,replayToItemDocument,resolveHistoryRepairItemHashVersion,toReplayDocument,tryApplyReplayPatch,verifyHistoryChain,verifyHistoryChainWithVersion};
3
3
  //# sourceMappingURL=replay.js.map
@@ -0,0 +1,3 @@
1
+ import { PmCliError } from "../shared/errors.js";
2
+ /** Return a bounded recovery error only when verified history proves deletion. */
3
+ export declare function buildDeletedItemError(pmRoot: string, rawId: string, idPrefix: string): Promise<PmCliError | undefined>;
@@ -0,0 +1,2 @@
1
+ !(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]="401ead12-fb72-586b-8625-33ae44ed2eb9")}catch(e2){}})();import{statSync}from"node:fs";import{normalizeItemId,normalizeRawItemId}from"../item/id.js";import{getHistoryPath}from"../store/paths.js";import{EXIT_CODE}from"../shared/constants.js";import{renderPmCommand}from"../shared/command-line.js";import{PmCliError}from"../shared/errors.js";import{readHistoryEntries}from"./read.js";import{applyHistoryPatch,replayHistoryToTarget,resolveHistoryTarget}from"./projection.js";import{EMPTY_REPLAY_DOCUMENT}from"./replay.js";import{historyVersionOffset}from"./version-address.js";function resolveDeletedRecoveryTarget(entries,id){let materializedIndex=-1;let document=structuredClone(EMPTY_REPLAY_DOCUMENT);for(const[index,entry]of entries.entries()){document=applyHistoryPatch(document,entry.patch,index+1,entry.op);if(document.metadata.id!==void 0&&document.metadata.id!==id){throw new PmCliError(`History belongs to item ${String(document.metadata.id)}, expected ${id}.`,EXIT_CODE.GENERIC_FAILURE,{code:"history_replay_invalid",required:"Recover the correct history stream for this item before attempting restoration."})}if(document.metadata.id===id&&Array.isArray(document.metadata.tags))materializedIndex=index}const offset=historyVersionOffset(entries,true);const version=materializedIndex<0||offset===null?null:offset+materializedIndex+1;let target=version===null?void 0:String(version);if(materializedIndex>=0&&target===void 0){const timestamp=entries[materializedIndex].ts;if(resolveHistoryTarget(timestamp,entries).historyIndex===materializedIndex)target=timestamp}return{version,target}}async function buildDeletedItemError(pmRoot,rawId,idPrefix){const candidates=new Set([normalizeItemId(rawId,idPrefix),normalizeRawItemId(rawId)]);for(const id of candidates){const historyPath=getHistoryPath(pmRoot,id);if(!statSync(historyPath,{throwIfNoEntry:false})?.isFile())continue;const entries=await readHistoryEntries(historyPath,id);let deletionIndex=-1;entries.forEach((entry,index)=>{if(entry.op==="delete")deletionIndex=index});if(deletionIndex<0)continue;const final=replayHistoryToTarget(entries,entries.length-1);if(Object.keys(final.metadata).length!==0)continue;const{version,target}=resolveDeletedRecoveryTarget(entries,id);const readArgs=target===void 0?["history",id,"--verify"]:["get",id,"--at",target];const readCommand=renderPmCommand(readArgs);return new PmCliError(`Item ${id} was deleted at ${entries[deletionIndex].ts}; its history is retained.`,EXIT_CODE.NOT_FOUND,{code:"item_deleted",required:"Read a retained materialized version, then restore it if the item should exist again.",item_id:id,tombstone:{deleted:true,deleted_at:entries[deletionIndex].ts,recoverable:target!==void 0,last_materialized_version:version},nextSteps:[readCommand,...target===void 0?["Recover the pre-compaction history from version control."]:[renderPmCommand(["restore",id,target])]],recovery:{suggested_retry:readCommand,suggested_retry_args:readArgs}})}return void 0}export{buildDeletedItemError};
2
+ //# sourceMappingURL=tombstone.js.map
@@ -1,8 +1,8 @@
1
- /** Implements normalize prefix for the public runtime surface of this module. */
1
+ /** Normalize a prefix to lowercase ASCII segments followed by one hyphen. */
2
2
  export declare function normalizePrefix(input: string | undefined): string;
3
- /** Implements normalize raw item id for the public runtime surface of this module. */
3
+ /** Remove surrounding whitespace and optional hash shorthand, then lowercase an id. */
4
4
  export declare function normalizeRawItemId(input: string): string;
5
- /** Implements normalize item id for the public runtime surface of this module. */
5
+ /** Apply the normalized workspace prefix unless the supplied id already carries it. */
6
6
  export declare function normalizeItemId(input: string, prefix: string): string;
7
7
  /** Bounds accepted for the configurable random id token length (`ids.token_length`). */
8
8
  export declare const ID_TOKEN_LENGTH_MIN = 4;
@@ -12,13 +12,14 @@ export declare const ID_TOKEN_LENGTH_MAX = 12;
12
12
  export declare function clampIdTokenLength(value: number | undefined): number;
13
13
  /**
14
14
  * Mint a new item id as `<prefix><random base36 token>`. The starting token
15
- * length comes from the workspace `ids.token_length` setting (default 4) and
16
- * escalates automatically when the local uniqueness probe keeps colliding.
15
+ * length comes from the workspace `ids.token_length` setting (default 4 for
16
+ * small synchronized workspaces) and increases after 32 local collisions.
17
17
  * Uniqueness is only verifiable against the local working tree: concurrent
18
18
  * branches can still mint the same id independently, which is why longer
19
19
  * configured tokens matter for multi-agent workflows and why
20
- * `pm validate --check-storage-integrity` detects post-merge duplicate-id
21
- * collisions (GH-600).
20
+ * the identity-refusing merge and storage-integrity boundaries remain necessary.
21
+ * For n reserved ids and m unsynchronized creations, choose width L with
22
+ * m*(m-1)/(2*(36^L-n)) below the tolerated per-sync collision probability.
22
23
  */
23
24
  export declare function generateItemId(pmRoot: string, prefix: string, options?: {
24
25
  tokenLength?: number;
@@ -1,2 +1,2 @@
1
- !(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]="72c5a2e2-4e90-587d-a461-946b4836e447")}catch(e2){}})();import crypto from"node:crypto";import path from"node:path";import{TYPE_TO_FOLDER}from"../shared/constants.js";import{pathExists}from"../fs/fs-utils.js";import{nextReproducibleToken}from"../reproducibility/context.js";function normalizePrefix(input){const normalized=[];let separatorPending=false;for(const character of(input??"").toLowerCase()){const codePoint=character.charCodeAt(0);const isAsciiDigit=codePoint>=48&&codePoint<=57;const isAsciiLetter=codePoint>=97&&codePoint<=122;if(!isAsciiDigit&&!isAsciiLetter){separatorPending=normalized.length>0;continue}if(separatorPending){normalized.push("-");separatorPending=false}normalized.push(character)}if(normalized.length===0)return"pm-";return`${normalized.join("")}-`}function normalizeRawItemId(input){let normalized=input.trim().toLowerCase();if(normalized.startsWith("#")){normalized=normalized.slice(1)}return normalized}function normalizeItemId(input,prefix){const canonicalPrefix=normalizePrefix(prefix);const normalized=normalizeRawItemId(input);if(normalized.startsWith(canonicalPrefix)){return normalized}return`${canonicalPrefix}${normalized}`}function randomToken(length){const reproducibleToken=nextReproducibleToken(length);if(reproducibleToken!==void 0){return reproducibleToken}let token="";for(let index=0;index<length;index+=1){token+=crypto.randomInt(0,36).toString(36)}return token}async function idExists(pmRoot,id,typeToFolder){const checks=[...new Set(Object.values(typeToFolder))].flatMap(folder=>[path.join(pmRoot,folder,`${id}.md`),path.join(pmRoot,folder,`${id}.toon`)]);checks.push(path.join(pmRoot,"history",`${id}.jsonl`));return(await Promise.all(checks.map(target=>pathExists(target)))).some(Boolean)}const ID_TOKEN_LENGTH_MIN=4;const ID_TOKEN_LENGTH_MAX=12;function clampIdTokenLength(value){if(typeof value!=="number"||!Number.isFinite(value)){return ID_TOKEN_LENGTH_MIN}return Math.min(ID_TOKEN_LENGTH_MAX,Math.max(ID_TOKEN_LENGTH_MIN,Math.trunc(value)))}async function generateItemId(pmRoot,prefix,options={}){let tokenLength=clampIdTokenLength(options.tokenLength);const maxTokenLength=Math.min(tokenLength+6,ID_TOKEN_LENGTH_MAX);let attempts=0;while(tokenLength<=maxTokenLength){for(let i=0;i<32;i+=1){const id=`${normalizePrefix(prefix)}${randomToken(tokenLength)}`;const occupied=await(options.probeExisting===false?pathExists(path.join(pmRoot,"history",`${id}.jsonl`)):idExists(pmRoot,id,options.typeToFolder??TYPE_TO_FOLDER));if(!occupied){return id}attempts+=1}tokenLength+=1}throw new Error(`Unable to generate unique id after ${attempts} attempts`)}export{ID_TOKEN_LENGTH_MAX,ID_TOKEN_LENGTH_MIN,clampIdTokenLength,generateItemId,normalizeItemId,normalizePrefix,normalizeRawItemId};
1
+ !(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]="1a689c0c-972a-5aff-a15e-ea48fcdf478b")}catch(e2){}})();import crypto from"node:crypto";import path from"node:path";import{TYPE_TO_FOLDER}from"../shared/constants.js";import{pathExists}from"../fs/fs-utils.js";import{nextReproducibleToken}from"../reproducibility/context.js";function normalizePrefix(input){const normalized=[];let separatorPending=false;for(const character of(input??"").toLowerCase()){const codePoint=character.charCodeAt(0);const isAsciiDigit=codePoint>=48&&codePoint<=57;const isAsciiLetter=codePoint>=97&&codePoint<=122;if(!isAsciiDigit&&!isAsciiLetter){separatorPending=normalized.length>0;continue}if(separatorPending){normalized.push("-");separatorPending=false}normalized.push(character)}if(normalized.length===0)return"pm-";return`${normalized.join("")}-`}function normalizeRawItemId(input){let normalized=input.trim().toLowerCase();if(normalized.startsWith("#")){normalized=normalized.slice(1)}return normalized}function normalizeItemId(input,prefix){const canonicalPrefix=normalizePrefix(prefix);const normalized=normalizeRawItemId(input);if(normalized.startsWith(canonicalPrefix)){return normalized}return`${canonicalPrefix}${normalized}`}function randomToken(length){const reproducibleToken=nextReproducibleToken(length);if(reproducibleToken!==void 0){return reproducibleToken}let token="";for(let index=0;index<length;index+=1){token+=crypto.randomInt(0,36).toString(36)}return token}async function idExists(pmRoot,id,typeToFolder){const checks=[...new Set(Object.values(typeToFolder))].flatMap(folder=>[path.join(pmRoot,folder,`${id}.md`),path.join(pmRoot,folder,`${id}.toon`)]);checks.push(path.join(pmRoot,"history",`${id}.jsonl`));return(await Promise.all(checks.map(target=>pathExists(target)))).some(Boolean)}const ID_TOKEN_LENGTH_MIN=4;const ID_TOKEN_LENGTH_MAX=12;function clampIdTokenLength(value){if(typeof value!=="number"||!Number.isFinite(value)){return ID_TOKEN_LENGTH_MIN}return Math.min(ID_TOKEN_LENGTH_MAX,Math.max(ID_TOKEN_LENGTH_MIN,Math.trunc(value)))}async function generateItemId(pmRoot,prefix,options={}){let tokenLength=clampIdTokenLength(options.tokenLength);const maxTokenLength=Math.min(tokenLength+6,ID_TOKEN_LENGTH_MAX);let attempts=0;while(tokenLength<=maxTokenLength){for(let i=0;i<32;i+=1){const id=`${normalizePrefix(prefix)}${randomToken(tokenLength)}`;const occupied=await(options.probeExisting===false?pathExists(path.join(pmRoot,"history",`${id}.jsonl`)):idExists(pmRoot,id,options.typeToFolder??TYPE_TO_FOLDER));if(!occupied){return id}attempts+=1}tokenLength+=1}throw new Error(`Unable to generate unique id after ${attempts} attempts`)}export{ID_TOKEN_LENGTH_MAX,ID_TOKEN_LENGTH_MIN,clampIdTokenLength,generateItemId,normalizeItemId,normalizePrefix,normalizeRawItemId};
2
2
  //# sourceMappingURL=id.js.map
@@ -11,6 +11,7 @@
11
11
  * Compaction is deliberately scoped to the mutation envelope only:
12
12
  * - the envelope's own top-level `changed_fields` (create/update/close/append), and
13
13
  * - `rows[*].changed_fields` (update-many reports its delta per row).
14
+ * - recognized start/pause/close composition steps sharing the root item id.
14
15
  * It does NOT recurse into arbitrary nested objects, so unrelated payloads that
15
16
  * legitimately carry `changed_fields` (for example `pm history --diff` entries, or a
16
17
  * custom runtime metadata field) are left untouched.
@@ -1,2 +1,2 @@
1
- !(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]="3d2360c6-41c1-5527-a53c-38d0590e3f04")}catch(e2){}})();const CHANGED_FIELDS_KEY="changed_fields";const CHANGED_FIELD_COUNT_KEY="changed_field_count";const ROWS_KEY="rows";const UPDATE_MANY_MUTATION_MODES=new Set(["apply","rollback"]);const DELETE_OUTCOMES=new Set(["deleted","would_delete"]);const COMPACT_RECURRENCE_TEXT_LIMIT=256;function truncateCompactRecurrenceText(value){if(typeof value!=="string"||value.length<=COMPACT_RECURRENCE_TEXT_LIMIT){return value}return`${value.slice(0,COMPACT_RECURRENCE_TEXT_LIMIT-1)}\u2026`}function projectCompactRecurrence(value){if(!isPlainObject(value))return null;const recurrence={...value};recurrence.reason=truncateCompactRecurrenceText(recurrence.reason);if(isPlainObject(recurrence.previous_terminal)){recurrence.previous_terminal=Object.fromEntries(Object.entries(recurrence.previous_terminal).map(([key,entry])=>[key,truncateCompactRecurrenceText(entry)]))}return recurrence}function isPlainObject(value){if(typeof value!=="object"||value===null||Array.isArray(value)){return false}const proto=Object.getPrototypeOf(value);return proto===null||proto===Object.prototype}function compactOwnChangedFields(envelope){const changedFields=envelope[CHANGED_FIELDS_KEY];if(!Array.isArray(changedFields)){return null}const projected=Object.getPrototypeOf(envelope)===null?Object.create(null):{};for(const[key,value]of Object.entries(envelope)){if(key!==CHANGED_FIELDS_KEY){projected[key]=value}}projected[CHANGED_FIELD_COUNT_KEY]=changedFields.length;return projected}function isMutationEnvelope(value){return"item"in value&&Array.isArray(value[CHANGED_FIELDS_KEY])}function isUpdateManyMutationEnvelope(value){return typeof value.mode==="string"&&UPDATE_MANY_MUTATION_MODES.has(value.mode)&&Array.isArray(value[ROWS_KEY])}function replaceRows(envelope,rows){const projected=Object.getPrototypeOf(envelope)===null?Object.create(null):{};Object.assign(projected,envelope);projected[ROWS_KEY]=rows;return projected}function projectIdOnlyResult(result){if(!isPlainObject(result)){return null}const subject=isPlainObject(result.item)?result.item:isPlainObject(result.plan)?result.plan:null;if(subject===null){return null}const id=typeof subject.id==="string"?subject.id:void 0;const status=typeof result.outcome==="string"&&DELETE_OUTCOMES.has(result.outcome)?result.outcome:typeof subject.status==="string"?subject.status:void 0;if(!id){return null}return status?{id,status,...typeof result.deleted==="boolean"?{deleted:result.deleted}:{}}:{id}}function projectCompactMutationEnvelope(result){if(!isPlainObject(result)||!isPlainObject(result.item))return null;if(typeof result.item.id!=="string")return null;const changedFields=result[CHANGED_FIELDS_KEY];if(!Array.isArray(changedFields))return null;const compact={id:result.item.id,...typeof result.outcome==="string"&&DELETE_OUTCOMES.has(result.outcome)?{status:result.outcome}:typeof result.item.status==="string"?{status:result.item.status}:{},...typeof result.deleted==="boolean"?{deleted:result.deleted}:{},...typeof result.previous_status==="string"?{previous_status:result.previous_status}:{},changed_field_count:changedFields.length};appendCompactMutationEvidence(result,result.item,compact);return compact}function appendCompactMutationEvidence(result,item,compact){const closeReason=typeof result.close_reason==="string"?result.close_reason:typeof item.close_reason==="string"?item.close_reason:void 0;if(closeReason!==void 0)compact.close_reason=closeReason;const recurrence=projectCompactRecurrence(result.recurrence);if(recurrence!==null)compact.recurrence=recurrence;if(Array.isArray(result.warnings)&&result.warnings.length>0)compact.warnings=result.warnings;if(isPlainObject(result.recovery))compact.recovery=result.recovery;if(typeof result.claimed_by==="string"){for(const key of["claimed_by","previous_assignee","forced","skipped","available","attempts"]){if(Object.hasOwn(result,key))compact[key]=result[key]}}}function compactUpdateManyRows(envelope){const rows=isUpdateManyMutationEnvelope(envelope)?envelope[ROWS_KEY]:void 0;if(!Array.isArray(rows)){return{projected:envelope,changed:false}}let rowsChanged=false;const nextRows=rows.map(row=>{if(!isPlainObject(row)){return row}const compactedRow=compactOwnChangedFields(row);if(compactedRow){rowsChanged=true;return compactedRow}return row});return rowsChanged?{projected:replaceRows(envelope,nextRows),changed:true}:{projected:envelope,changed:false}}function projectMutationResult(result,options={}){if(options.idOnly===true){const idOnly=projectIdOnlyResult(result);if(idOnly!==null){return idOnly}}if(options.compactEnvelope===true){const compact=projectCompactMutationEnvelope(result);if(compact!==null)return compact}const mode=options.changedFields??"full";if(mode==="full"||!isPlainObject(result)){return result}let changed=false;let projected=result;const compactedTop=isMutationEnvelope(result)?compactOwnChangedFields(result):null;if(compactedTop!==null){projected=compactedTop;changed=true}const rowProjection=compactUpdateManyRows(projected);if(rowProjection.changed){projected=rowProjection.projected;changed=true}return changed?projected:result}export{projectMutationResult};
1
+ !(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]="6e88d6b7-aa5f-5515-8ea4-481916b12ef1")}catch(e2){}})();const CHANGED_FIELDS_KEY="changed_fields";const CHANGED_FIELD_COUNT_KEY="changed_field_count";const ROWS_KEY="rows";const UPDATE_MANY_MUTATION_MODES=new Set(["apply","rollback"]);const DELETE_OUTCOMES=new Set(["deleted","would_delete"]);const COMPACT_RECURRENCE_TEXT_LIMIT=256;const COMPOUND_MUTATION_STEPS={start_task:["claim","update"],pause_task:["update","release"],close_task:["close","release"]};function projectCompoundMutation(result,options){if(!isPlainObject(result)||typeof result.action!=="string"||typeof result.id!=="string"||result.id.length===0)return null;const steps=Object.hasOwn(COMPOUND_MUTATION_STEPS,result.action)?COMPOUND_MUTATION_STEPS[result.action]:void 0;if(!steps||!steps.every(step=>{const value=result[step];return isPlainObject(value)&&isPlainObject(value.item)&&value.item.id===result.id&&Array.isArray(value.changed_fields)&&value.changed_fields.every(field=>typeof field==="string")}))return null;const final=result[steps.at(-1)];const identity=projectIdOnlyResult(final);if(options.idOnly)return identity;if(!options.compactEnvelope&&options.changedFields!=="compact")return null;return{...result,...options.compactEnvelope?{...identity,changed_field_count:new Set(steps.flatMap(step=>result[step].changed_fields)).size}:{},...Object.fromEntries(steps.map(step=>[step,projectMutationResult(result[step],options)]))}}function truncateCompactRecurrenceText(value){if(typeof value!=="string"||value.length<=COMPACT_RECURRENCE_TEXT_LIMIT){return value}return`${value.slice(0,COMPACT_RECURRENCE_TEXT_LIMIT-1)}\u2026`}function projectCompactRecurrence(value){if(!isPlainObject(value))return null;const recurrence={...value};recurrence.reason=truncateCompactRecurrenceText(recurrence.reason);if(isPlainObject(recurrence.previous_terminal)){recurrence.previous_terminal=Object.fromEntries(Object.entries(recurrence.previous_terminal).map(([key,entry])=>[key,truncateCompactRecurrenceText(entry)]))}return recurrence}function isPlainObject(value){if(typeof value!=="object"||value===null||Array.isArray(value)){return false}const proto=Object.getPrototypeOf(value);return proto===null||proto===Object.prototype}function compactOwnChangedFields(envelope){const changedFields=envelope[CHANGED_FIELDS_KEY];if(!Array.isArray(changedFields)){return null}const projected=Object.getPrototypeOf(envelope)===null?Object.create(null):{};for(const[key,value]of Object.entries(envelope)){if(key!==CHANGED_FIELDS_KEY){projected[key]=value}}projected[CHANGED_FIELD_COUNT_KEY]=changedFields.length;return projected}function isMutationEnvelope(value){return"item"in value&&Array.isArray(value[CHANGED_FIELDS_KEY])}function isUpdateManyMutationEnvelope(value){return typeof value.mode==="string"&&UPDATE_MANY_MUTATION_MODES.has(value.mode)&&Array.isArray(value[ROWS_KEY])}function replaceRows(envelope,rows){const projected=Object.getPrototypeOf(envelope)===null?Object.create(null):{};Object.assign(projected,envelope);projected[ROWS_KEY]=rows;return projected}function projectIdOnlyResult(result){if(!isPlainObject(result)){return null}const subject=isPlainObject(result.item)?result.item:isPlainObject(result.plan)?result.plan:null;if(subject===null){return null}const id=typeof subject.id==="string"?subject.id:void 0;const status=typeof result.outcome==="string"&&DELETE_OUTCOMES.has(result.outcome)?result.outcome:typeof subject.status==="string"?subject.status:void 0;if(!id){return null}return status?{id,status,...typeof result.deleted==="boolean"?{deleted:result.deleted}:{}}:{id}}function projectCompactMutationEnvelope(result){if(!isPlainObject(result)||!isPlainObject(result.item))return null;if(typeof result.item.id!=="string")return null;const changedFields=result[CHANGED_FIELDS_KEY];if(!Array.isArray(changedFields))return null;const compact={id:result.item.id,...typeof result.outcome==="string"&&DELETE_OUTCOMES.has(result.outcome)?{status:result.outcome}:typeof result.item.status==="string"?{status:result.item.status}:{},...typeof result.deleted==="boolean"?{deleted:result.deleted}:{},...typeof result.previous_status==="string"?{previous_status:result.previous_status}:{},changed_field_count:changedFields.length};appendCompactMutationEvidence(result,result.item,compact);return compact}function appendCompactMutationEvidence(result,item,compact){const closeReason=typeof result.close_reason==="string"?result.close_reason:typeof item.close_reason==="string"?item.close_reason:void 0;if(closeReason!==void 0)compact.close_reason=closeReason;const recurrence=projectCompactRecurrence(result.recurrence);if(recurrence!==null)compact.recurrence=recurrence;if(Array.isArray(result.warnings)&&result.warnings.length>0)compact.warnings=result.warnings;if(isPlainObject(result.recovery))compact.recovery=result.recovery;if(typeof result.claimed_by==="string"||typeof result.released_by==="string"){for(const key of["claimed_by","released_by","previous_assignee","forced","skipped","available","attempts","suggestions"]){if(Object.hasOwn(result,key))compact[key]=result[key]}}}function compactUpdateManyRows(envelope){const rows=isUpdateManyMutationEnvelope(envelope)?envelope[ROWS_KEY]:void 0;if(!Array.isArray(rows)){return{projected:envelope,changed:false}}let rowsChanged=false;const nextRows=rows.map(row=>{if(!isPlainObject(row)){return row}const compactedRow=compactOwnChangedFields(row);if(compactedRow){rowsChanged=true;return compactedRow}return row});return rowsChanged?{projected:replaceRows(envelope,nextRows),changed:true}:{projected:envelope,changed:false}}function projectMutationResult(result,options={}){const compound=projectCompoundMutation(result,options);if(compound!==null)return compound;if(options.idOnly===true){const idOnly=projectIdOnlyResult(result);if(idOnly!==null){return idOnly}}if(options.compactEnvelope===true){const compact=projectCompactMutationEnvelope(result);if(compact!==null)return compact}const mode=options.changedFields??"full";if(mode==="full"||!isPlainObject(result)){return result}let changed=false;let projected=result;const compactedTop=isMutationEnvelope(result)?compactOwnChangedFields(result):null;if(compactedTop!==null){projected=compactedTop;changed=true}const rowProjection=compactUpdateManyRows(projected);if(rowProjection.changed){projected=rowProjection.projected;changed=true}return changed?projected:result}export{projectMutationResult};
2
2
  //# sourceMappingURL=mutation-projection.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @module core/shared/command-line
3
+ * Quotes tokenized recovery commands for the current platform shell.
4
+ */
5
+ /** Quote one Windows argument with the linear CommandLineToArgvW escaping algorithm. */
6
+ export declare const quoteWindowsCommandArg: (arg: string) => string;
7
+ /** Quote one command argument only when platform shell-significant characters require it. */
8
+ export declare const quoteCommandArg: (arg: string, platform?: NodeJS.Platform) => string;
9
+ /** Render a complete pm command from already-tokenized arguments. */
10
+ export declare const renderPmCommand: (argv: string[], platform?: NodeJS.Platform) => string;
@@ -0,0 +1,2 @@
1
+ !(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]="4f014bd9-39b6-5017-93ed-f0e7fba8497a")}catch(e2){}})();const quoteWindowsCommandArg=arg=>{let escaped='"';let pendingBackslashes=0;for(const character of arg){if(character==="\\"){pendingBackslashes+=1;continue}escaped+="\\".repeat(character==='"'?pendingBackslashes*2+1:pendingBackslashes);escaped+=character;pendingBackslashes=0}return`${escaped}${"\\".repeat(pendingBackslashes*2)}"`};const quoteCommandArg=(arg,platform=process.platform)=>{const safePattern=platform==="win32"?/^[A-Za-z0-9._:/\\@=-]+$/:/^[A-Za-z0-9._:/@=-]+$/;if(safePattern.test(arg)){return arg}if(platform==="win32"){return quoteWindowsCommandArg(arg)}return`"${arg.replace(/(["\\$`])/g,"\\$1")}"`};const renderPmCommand=(argv,platform=process.platform)=>{const args=argv.map(token=>quoteCommandArg(token,platform)).join(" ");return args.length>0?`pm ${args}`:"pm"};export{quoteCommandArg,quoteWindowsCommandArg,renderPmCommand};
2
+ //# sourceMappingURL=command-line.js.map
@@ -55,8 +55,21 @@ export interface PmCliErrorContext {
55
55
  code?: string;
56
56
  /** Item whose document could not be decoded or parsed. */
57
57
  item_id?: string;
58
+ /** Verified retained deletion and the latest recoverable durable address. */
59
+ tombstone?: {
60
+ /** The retained stream proves the item is currently deleted. */
61
+ deleted: true;
62
+ /** Timestamp of the most recent recorded deletion. */
63
+ deleted_at: string;
64
+ /** Whether a retained materialized state has an unambiguous recovery address. */
65
+ recoverable: boolean;
66
+ /** Durable version before deletion, or null when compaction lost the mapping. */
67
+ last_materialized_version: number | null;
68
+ };
58
69
  /** Exact filesystem path of the unreadable item document. */
59
70
  item_path?: string;
71
+ /** Tracker-relative documents claiming the same item identity. */
72
+ paths?: string[];
60
73
  /** Original document size before decoding or parsing. */
61
74
  byte_length?: number;
62
75
  /** Whether the original item document contained no bytes. */
@@ -1,2 +1,2 @@
1
- !(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]="20b70512-0d72-5ed0-a27c-df849db200a4")}catch(e2){}})();class PmCliError extends Error{exitCode;code;context;constructor(message,exitCode,context={}){super(message);this.name="PmCliError";this.exitCode=exitCode;this.context=context;this.code=context.code}}export{PmCliError};
1
+ !(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]="0f7e5fb3-86d2-5af5-a189-a40dd223ef26")}catch(e2){}})();class PmCliError extends Error{exitCode;code;context;constructor(message,exitCode,context={}){super(message);this.name="PmCliError";this.exitCode=exitCode;this.context=context;this.code=context.code}}export{PmCliError};
2
2
  //# sourceMappingURL=errors.js.map
@@ -14,7 +14,11 @@ export interface LocatedItem {
14
14
  }
15
15
  declare function isErrno(error: unknown, code: string): boolean;
16
16
  declare function appendWarning(warnings: string[] | undefined, warning: string): void;
17
- /** Implements locate item for the public runtime surface of this module. */
17
+ /**
18
+ * Resolve exact then normalized identifiers across registered type folders.
19
+ * Refuse multiple physical documents for the selected identifier; format
20
+ * preference orders probes but cannot choose between conflicting identities.
21
+ */
18
22
  export declare function locateItem(pmRoot: string, rawId: string, idPrefix?: string, preferredFormat?: ItemFormat, typeToFolder?: Record<string, string>): Promise<LocatedItem | null>;
19
23
  /** Implements read located item for the public runtime surface of this module. */
20
24
  export declare function readLocatedItem(item: LocatedItem, options?: {