@unbrained/pm-cli 2026.9.4 → 2026.9.6

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 (277) hide show
  1. package/.agents/skills/HARNESS_COMPATIBILITY.md +1 -1
  2. package/.agents/skills/README.md +2 -2
  3. package/.agents/skills/pm-developer/SKILL.md +4 -1
  4. package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +10 -0
  5. package/.agents/skills/pm-developer/references/GRAPH_AND_RELATIONSHIPS.md +3 -1
  6. package/.agents/skills/pm-extensions/SKILL.md +2 -2
  7. package/.agents/skills/pm-extensions/references/LIFECYCLE.md +3 -3
  8. package/.agents/skills/pm-extensions/references/TROUBLESHOOTING.md +3 -3
  9. package/.agents/skills/pm-user/SKILL.md +2 -0
  10. package/.agents/skills/pm-user/references/BACKLOG_SHAPING.md +5 -0
  11. package/.agents/skills/pm-user/references/WORKFLOWS.md +20 -5
  12. package/.claude-plugin/marketplace.json +2 -2
  13. package/CHANGELOG.md +58 -3
  14. package/dist/cli/commander-usage.d.ts +2 -0
  15. package/dist/cli/commander-usage.js +15 -12
  16. package/dist/cli/help-json-payload.js +12 -7
  17. package/dist/cli/main.js +22 -11
  18. package/dist/cli/register-list-query.js +4 -2
  19. package/dist/cli/register-mutation.js +4 -2
  20. package/dist/cli/register-operations.js +17 -8
  21. package/dist/cli-bundle/bundle-manifest.json +153 -161
  22. package/dist/cli-bundle/chunks/chunk-AZDFJGH6.js +9 -0
  23. package/dist/cli-bundle/chunks/{chunk-V72UV7QS.js → chunk-BAX2BYUW.js} +73 -73
  24. package/dist/cli-bundle/chunks/{chunk-HI6BHPCU.js → chunk-CKOL5U7J.js} +51 -51
  25. package/dist/cli-bundle/chunks/{chunk-A24WAVE6.js → chunk-JT6XF6GE.js} +2 -2
  26. package/dist/cli-bundle/chunks/{chunk-I2AS367G.js → chunk-JX4DH4WC.js} +2 -2
  27. package/dist/cli-bundle/chunks/{chunk-YW4QK2G7.js → chunk-NPN5I67J.js} +2 -2
  28. package/dist/cli-bundle/chunks/chunk-OF76PSDQ.js +5 -0
  29. package/dist/cli-bundle/chunks/chunk-QUWFABDM.js +232 -0
  30. package/dist/cli-bundle/chunks/{chunk-RI4XNOYS.js → chunk-RWWBOWJ5.js} +2 -2
  31. package/dist/cli-bundle/chunks/chunk-WGAOYSYH.js +40 -0
  32. package/dist/cli-bundle/chunks/{chunk-X6CMGV6L.js → chunk-WI2AYPA7.js} +2 -2
  33. package/dist/cli-bundle/chunks/{register-list-query-Z5YYSJJG.js → register-list-query-5JL52D33.js} +3 -3
  34. package/dist/cli-bundle/chunks/{register-mutation-ELSP6I4I.js → register-mutation-ZPG7KMVP.js} +4 -4
  35. package/dist/cli-bundle/chunks/register-operations-I5W3KMGB.js +2 -0
  36. package/dist/cli-bundle/chunks/{register-setup-E2AE72QG.js → register-setup-H4SVAVX7.js} +2 -2
  37. package/dist/cli-bundle/focused-chunks/{chunk-3646BZ4W.js → chunk-3BZEOXLT.js} +2 -2
  38. package/dist/cli-bundle/focused-chunks/chunk-AL5ON6K6.js +2 -0
  39. package/dist/cli-bundle/focused-chunks/chunk-CHC2IDXA.js +6 -0
  40. package/dist/cli-bundle/focused-chunks/chunk-CK6QFAPZ.js +20 -0
  41. package/dist/cli-bundle/focused-chunks/{chunk-NBMJD6MK.js → chunk-EZR3GHFE.js} +2 -2
  42. package/dist/cli-bundle/focused-chunks/chunk-H2WJWK7L.js +56 -0
  43. package/dist/cli-bundle/focused-chunks/{chunk-53IHPICX.js → chunk-LIJIA4TY.js} +2 -2
  44. package/dist/cli-bundle/focused-chunks/{chunk-25UJBH4M.js → chunk-M6PBRFSH.js} +2 -2
  45. package/dist/cli-bundle/focused-chunks/{chunk-AJR3OP2E.js → chunk-NTPY5GSO.js} +2 -2
  46. package/dist/cli-bundle/focused-chunks/chunk-P5O7MP5Y.js +2 -0
  47. package/dist/cli-bundle/focused-chunks/chunk-PDMW2E36.js +177 -0
  48. package/dist/cli-bundle/focused-chunks/{chunk-MHKUIPJW.js → chunk-PEFABF7E.js} +2 -2
  49. package/dist/cli-bundle/focused-chunks/{chunk-6PWPQKDN.js → chunk-QTVCLMSZ.js} +2 -2
  50. package/dist/cli-bundle/focused-chunks/{chunk-7N2TV7WZ.js → chunk-QTZRBUYA.js} +2 -2
  51. package/dist/cli-bundle/focused-chunks/chunk-SGQST3PQ.js +12 -0
  52. package/dist/cli-bundle/focused-chunks/chunk-UKHASMMP.js +10 -0
  53. package/dist/cli-bundle/focused-chunks/chunk-ZPEKQHOC.js +2 -0
  54. package/dist/cli-bundle/main.js +22 -15
  55. package/dist/cli-bundle/sdk-authoring.js +1 -1
  56. package/dist/cli-bundle/sdk-contracts.js +2 -2
  57. package/dist/cli-bundle/sdk-core.js +37 -37
  58. package/dist/cli-bundle/sdk-governance.js +1 -1
  59. package/dist/cli-bundle/sdk-graph.js +1 -1
  60. package/dist/cli-bundle/sdk-merge.js +42 -39
  61. package/dist/cli-bundle/sdk-query.js +1 -1
  62. package/dist/cli-bundle/sdk-runtime.js +1 -1
  63. package/dist/cli-bundle/sdk-testing.js +1 -1
  64. package/dist/cli-bundle/sdk.js +9 -9
  65. package/dist/core/extensions/extension-types.d.ts +2 -0
  66. package/dist/core/extensions/extension-types.js +2 -2
  67. package/dist/core/extensions/module-graph-snapshot.js +5 -4
  68. package/dist/core/fs/host-environment-errors.d.ts +27 -0
  69. package/dist/core/fs/host-environment-errors.js +142 -0
  70. package/dist/core/history/drift-scan.d.ts +5 -0
  71. package/dist/core/history/drift-scan.js +16 -6
  72. package/dist/core/history/event-classification.d.ts +1 -1
  73. package/dist/core/history/event-classification.js +3 -2
  74. package/dist/core/history/history.js +37 -5
  75. package/dist/core/history/identity.d.ts +15 -0
  76. package/dist/core/history/identity.js +31 -0
  77. package/dist/core/history/projection.js +50 -17
  78. package/dist/core/history/read.js +6 -3
  79. package/dist/core/history/replay.d.ts +1 -2
  80. package/dist/core/history/replay.js +4 -4
  81. package/dist/core/history/version-address.d.ts +13 -0
  82. package/dist/core/history/version-address.js +33 -0
  83. package/dist/core/item/actionability.d.ts +21 -1
  84. package/dist/core/item/actionability.js +45 -10
  85. package/dist/core/item/id.js +8 -4
  86. package/dist/core/item/item-type-definition.d.ts +2 -0
  87. package/dist/core/item/item-type-definition.js +9 -2
  88. package/dist/core/item/type-registry.d.ts +5 -1
  89. package/dist/core/item/type-registry.js +9 -4
  90. package/dist/core/output/mutation-projection.js +12 -5
  91. package/dist/core/shared/errors.d.ts +8 -0
  92. package/dist/core/shared/errors.js +2 -2
  93. package/dist/core/store/item-metadata-query-index.js +13 -10
  94. package/dist/core/store/item-metadata-read-work.d.ts +19 -0
  95. package/dist/core/store/item-metadata-read-work.js +44 -0
  96. package/dist/core/store/item-store.d.ts +14 -0
  97. package/dist/core/store/item-store.js +52 -10
  98. package/dist/core/store/settings-validator.js +3 -2
  99. package/dist/core/validate/fix-planning.d.ts +1 -1
  100. package/dist/core/validate/fix-planning.js +2 -2
  101. package/dist/core/validate/missing-link-owners.d.ts +1 -1
  102. package/dist/core/validate/missing-link-owners.js +5 -3
  103. package/dist/core/validate/stale-file-classification.d.ts +6 -4
  104. package/dist/core/validate/stale-file-classification.js +20 -5
  105. package/dist/mcp/server.js +12 -5
  106. package/dist/sdk/actionability.d.ts +1 -1
  107. package/dist/sdk/actionability.js +3 -3
  108. package/dist/sdk/cli-contracts/command-aliases.js +11 -2
  109. package/dist/sdk/cli-contracts/completeness.js +4 -3
  110. package/dist/sdk/cli-contracts/flag-contracts.d.ts +2 -0
  111. package/dist/sdk/cli-contracts/flag-contracts.js +31 -5
  112. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +21 -13
  113. package/dist/sdk/cli-contracts/grammar-contracts.js +11 -2
  114. package/dist/sdk/cli-contracts/runtime-contracts.js +5 -2
  115. package/dist/sdk/cli-contracts/schemas/assurance-definition.d.ts +254 -5
  116. package/dist/sdk/cli-contracts/schemas/assurance-definition.js +52 -2
  117. package/dist/sdk/cli-contracts/tool-parameter-tables.js +30 -6
  118. package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
  119. package/dist/sdk/cli-contracts/tool-schema.js +32 -7
  120. package/dist/sdk/context/usage-ledger.d.ts +41 -0
  121. package/dist/sdk/context/usage-ledger.js +186 -0
  122. package/dist/sdk/context-intent-contracts.js +3 -3
  123. package/dist/sdk/context-usage.d.ts +18 -9
  124. package/dist/sdk/context-usage.js +44 -121
  125. package/dist/sdk/define.d.ts +1 -1
  126. package/dist/sdk/define.js +2 -2
  127. package/dist/sdk/dependency-provenance.d.ts +7 -0
  128. package/dist/sdk/dependency-provenance.js +14 -4
  129. package/dist/sdk/duplicates.d.ts +2 -0
  130. package/dist/sdk/duplicates.js +3 -2
  131. package/dist/sdk/environment/host-environment-errors.d.ts +5 -27
  132. package/dist/sdk/environment/host-environment-errors.js +4 -137
  133. package/dist/sdk/extension/install-runtime.js +9 -6
  134. package/dist/sdk/extension/install-snapshot.js +7 -6
  135. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +104 -56
  136. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -2
  137. package/dist/sdk/governance/assurance-action.d.ts +3 -2
  138. package/dist/sdk/governance/assurance-action.js +23 -11
  139. package/dist/sdk/governance/assurance-runtime.d.ts +2 -0
  140. package/dist/sdk/governance/assurance-runtime.js +6 -3
  141. package/dist/sdk/governance/defect-recurrence-coverage.d.ts +93 -0
  142. package/dist/sdk/governance/defect-recurrence-coverage.js +189 -0
  143. package/dist/sdk/governance/defect-recurrence-graph.d.ts +33 -0
  144. package/dist/sdk/governance/defect-recurrence-graph.js +121 -0
  145. package/dist/sdk/governance/defect-recurrence.d.ts +8 -0
  146. package/dist/sdk/governance/defect-recurrence.js +118 -17
  147. package/dist/sdk/governance/health.d.ts +17 -2
  148. package/dist/sdk/governance/health.js +31 -10
  149. package/dist/sdk/governance/linked-file-report.d.ts +41 -0
  150. package/dist/sdk/governance/linked-file-report.js +72 -0
  151. package/dist/sdk/governance/validate-history-drift.js +16 -5
  152. package/dist/sdk/governance/validate.d.ts +5 -2
  153. package/dist/sdk/governance/validate.js +21 -37
  154. package/dist/sdk/governance.d.ts +2 -0
  155. package/dist/sdk/governance.js +4 -2
  156. package/dist/sdk/guide-topics.js +116 -2
  157. package/dist/sdk/history/salvage.d.ts +35 -0
  158. package/dist/sdk/history/salvage.js +248 -0
  159. package/dist/sdk/history-compact.js +32 -37
  160. package/dist/sdk/history-read.d.ts +3 -2
  161. package/dist/sdk/history-read.js +6 -3
  162. package/dist/sdk/history-repair.d.ts +12 -0
  163. package/dist/sdk/history-repair.js +60 -13
  164. package/dist/sdk/lifecycle/claim.d.ts +4 -0
  165. package/dist/sdk/lifecycle/claim.js +9 -3
  166. package/dist/sdk/lifecycle/close.d.ts +8 -0
  167. package/dist/sdk/lifecycle/close.js +16 -8
  168. package/dist/sdk/lifecycle/create.js +9 -12
  169. package/dist/sdk/lifecycle/restore.d.ts +1 -0
  170. package/dist/sdk/lifecycle/restore.js +19 -7
  171. package/dist/sdk/lifecycle/update.js +12 -12
  172. package/dist/sdk/lifecycle-policy.d.ts +3 -0
  173. package/dist/sdk/lifecycle-policy.js +2 -2
  174. package/dist/sdk/merge/abandoned-receipts.d.ts +15 -0
  175. package/dist/sdk/merge/abandoned-receipts.js +47 -0
  176. package/dist/sdk/merge/driver.js +4 -2
  177. package/dist/sdk/merge/index.d.ts +1 -0
  178. package/dist/sdk/merge/index.js +2 -2
  179. package/dist/sdk/merge/receipt-operation.d.ts +15 -0
  180. package/dist/sdk/merge/receipt-operation.js +97 -0
  181. package/dist/sdk/merge/receipt-schema.d.ts +20 -0
  182. package/dist/sdk/merge/receipt-schema.js +398 -0
  183. package/dist/sdk/merge/receipts.d.ts +16 -7
  184. package/dist/sdk/merge/receipts.js +54 -340
  185. package/dist/sdk/merge/reconcile.d.ts +2 -0
  186. package/dist/sdk/merge/reconcile.js +11 -4
  187. package/dist/sdk/output-projection.d.ts +3 -1
  188. package/dist/sdk/output-projection.js +11 -3
  189. package/dist/sdk/public-surface.json +1 -0
  190. package/dist/sdk/query/context.d.ts +9 -0
  191. package/dist/sdk/query/context.js +33 -21
  192. package/dist/sdk/query/duplicate-candidates.d.ts +7 -0
  193. package/dist/sdk/query/duplicate-candidates.js +71 -0
  194. package/dist/sdk/query/get.d.ts +2 -2
  195. package/dist/sdk/query/get.js +9 -8
  196. package/dist/sdk/query/history.d.ts +11 -0
  197. package/dist/sdk/query/history.js +34 -10
  198. package/dist/sdk/query/next.d.ts +15 -1
  199. package/dist/sdk/query/next.js +43 -20
  200. package/dist/sdk/query.d.ts +3 -0
  201. package/dist/sdk/query.js +5 -2
  202. package/dist/sdk/read-output-session.js +5 -3
  203. package/dist/sdk/runtime-primitives.d.ts +1 -1
  204. package/dist/sdk/runtime-primitives.js +3 -3
  205. package/dist/sdk/runtime.js +4 -2
  206. package/dist/sdk/similarity.d.ts +24 -3
  207. package/dist/sdk/similarity.js +50 -55
  208. package/dist/types.d.ts +2 -0
  209. package/dist/types.js +2 -2
  210. package/docs/AGENT_GUIDE.md +58 -1
  211. package/docs/BOUNDED_CONTEXT_READS.md +185 -0
  212. package/docs/CLOSE_EVIDENCE_RECOVERY.md +35 -0
  213. package/docs/COMMANDS.md +30 -8
  214. package/docs/CONTEXT_RELEVANCE.md +16 -4
  215. package/docs/DEFECT_RECURRENCE.md +80 -6
  216. package/docs/EXTENSIONS.md +18 -19
  217. package/docs/HISTORY_RECOVERY.md +146 -0
  218. package/docs/MERGE_SAFETY.md +50 -0
  219. package/docs/OUTPUT_PROJECTION_CONTRACTS.md +66 -0
  220. package/docs/PR_REVIEW_LOOP.md +18 -3
  221. package/docs/README.md +19 -1
  222. package/docs/RELEASING.md +31 -13
  223. package/docs/SDK_CONTEXT_TRUTH_CONTRACTS.md +24 -1
  224. package/docs/SDK_EXECUTION_CONTRACTS.md +105 -0
  225. package/docs/SDK_LIFECYCLE.md +27 -0
  226. package/docs/SDK_RUNTIME_BOUNDARIES.md +11 -0
  227. package/docs/TESTING.md +5 -0
  228. package/docs/agent-task-token-baseline.json +17 -17
  229. package/docs/agent-task-transcripts.json +2 -1
  230. package/docs/generated/FLAG_LEXICON_BUDGETS.md +11 -11
  231. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +11 -3
  232. package/marketplace.json +2 -2
  233. package/package.json +8 -6
  234. package/packages/pm-beads/package.json +1 -1
  235. package/packages/pm-calendar/package.json +1 -1
  236. package/packages/pm-command-kit/package.json +1 -1
  237. package/packages/pm-digital-twin/package.json +1 -1
  238. package/packages/pm-governance-audit/README.md +10 -1
  239. package/packages/pm-governance-audit/extensions/governance-audit/dedupe-audit.ts +50 -65
  240. package/packages/pm-governance-audit/extensions/governance-audit/index.ts +2 -2
  241. package/packages/pm-governance-audit/extensions/governance-audit/sdk.ts +1 -0
  242. package/packages/pm-governance-audit/package.json +1 -1
  243. package/packages/pm-guide-shell/package.json +1 -1
  244. package/packages/pm-kanban/package.json +1 -1
  245. package/packages/pm-lifecycle-hooks/package.json +1 -1
  246. package/packages/pm-linked-test-adapters/package.json +1 -1
  247. package/packages/pm-search-advanced/package.json +1 -1
  248. package/packages/pm-templates/package.json +1 -1
  249. package/packages/pm-todos/package.json +1 -1
  250. package/packages/pm-vcs/package.json +1 -1
  251. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  252. package/plugins/pm-claude/skills/pm-audit/SKILL.md +2 -2
  253. package/plugins/pm-claude/skills/pm-developer/SKILL.md +2 -2
  254. package/plugins/pm-claude/skills/pm-planner/SKILL.md +2 -2
  255. package/plugins/pm-claude/skills/pm-release/SKILL.md +2 -2
  256. package/plugins/pm-claude/skills/pm-workflow/SKILL.md +3 -3
  257. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  258. package/plugins/pm-codex/skills/pm-auditor/SKILL.md +2 -2
  259. package/plugins/pm-codex/skills/pm-native/SKILL.md +3 -4
  260. package/plugins/pm-codex/skills/pm-release/SKILL.md +2 -2
  261. package/scripts/finalize-build.mjs +13 -1
  262. package/dist/cli-bundle/chunks/chunk-6XSKPNCF.js +0 -230
  263. package/dist/cli-bundle/chunks/chunk-OGBVU67G.js +0 -5
  264. package/dist/cli-bundle/chunks/chunk-TXW6VL33.js +0 -38
  265. package/dist/cli-bundle/chunks/chunk-VGLHECAP.js +0 -9
  266. package/dist/cli-bundle/chunks/register-operations-OH7R3ZT4.js +0 -2
  267. package/dist/cli-bundle/focused-chunks/chunk-4YRAVI43.js +0 -12
  268. package/dist/cli-bundle/focused-chunks/chunk-5P4HVOWG.js +0 -176
  269. package/dist/cli-bundle/focused-chunks/chunk-636VVQ7F.js +0 -54
  270. package/dist/cli-bundle/focused-chunks/chunk-B3A6MJYE.js +0 -2
  271. package/dist/cli-bundle/focused-chunks/chunk-BFDDJ2T2.js +0 -2
  272. package/dist/cli-bundle/focused-chunks/chunk-BHUIRZWQ.js +0 -9
  273. package/dist/cli-bundle/focused-chunks/chunk-JADHHPY6.js +0 -6
  274. package/dist/cli-bundle/focused-chunks/chunk-NSKBLHVI.js +0 -20
  275. package/dist/cli-bundle/focused-chunks/chunk-P2GOAOQN.js +0 -2
  276. package/dist/cli-bundle/focused-chunks/chunk-YARWJM2B.js +0 -2
  277. package/sdk/public-surface.json +0 -33034
@@ -4,7 +4,7 @@
4
4
  * Provides CLI runtime support for Guide Topics.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7c57f381-8318-5235-aa92-c96c6cedb021")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="feba1227-c2a2-5ca3-83e6-3fd2780e6cbb")}catch(e){}}();
8
8
  import { listPmCommandCapabilityGroups } from "./agent-capability-contracts.js";
9
9
  function normalizeTopicToken(value) {
10
10
  return value.trim().toLowerCase().replaceAll("_", "-");
@@ -518,6 +518,8 @@ const GUIDE_TOPICS = [
518
518
  intent: "Use this when more than one agent or worktree mutates the same tracker and the results must merge without hand resolution.",
519
519
  commands: [
520
520
  "pm merge install",
521
+ "pm merge report",
522
+ "pm merge reconcile --dry-run",
521
523
  "pm claim <ID>",
522
524
  "pm release <ID>",
523
525
  "pm validate --check-history-drift",
@@ -530,6 +532,17 @@ const GUIDE_TOPICS = [
530
532
  prompt: "Run the merge installer in every fresh clone or worktree before the first branch merge of tracker data.",
531
533
  commands: ["pm merge install", "pm health --check-only"],
532
534
  },
535
+ {
536
+ name: "Settle A Merge Before Trusting Health",
537
+ goal: "A lossless merge still leaves pending receipts that strict health reports until they are reconciled.",
538
+ prompt: "After any branch merge that touched tracker data, read the merge report, preview the reconciliation, then apply it; only then treat a health verdict as a statement about the data.",
539
+ commands: [
540
+ "pm merge report",
541
+ "pm merge reconcile --dry-run",
542
+ 'pm merge reconcile --message "Post-merge history reconciliation"',
543
+ "pm health --check-only",
544
+ ],
545
+ },
533
546
  {
534
547
  name: "Hand Work Between Agents Safely",
535
548
  goal: "Ownership and evidence survive the handoff.",
@@ -553,6 +566,107 @@ const GUIDE_TOPICS = [
553
566
  ],
554
567
  related: ["workflows", "assurance", "commands"],
555
568
  },
569
+ {
570
+ id: "evidence",
571
+ aliases: ["record", "annotations", "learnings", "history-maintenance"],
572
+ title: "Evidence, Durable Knowledge, and Record Maintenance",
573
+ summary: "Append comments, notes, learnings, files, docs, and tests to items, and maintain the immutable history those records live in.",
574
+ intent: "Use this when work must be explained to the next agent, when a durable lesson should outlive the item, or when a history stream needs verification, repair, redaction, compaction, or author attribution.",
575
+ commands: [
576
+ 'pm comments <ID> "<progress or verification evidence>"',
577
+ 'pm notes <ID> --add "<rationale that belongs on the item>"',
578
+ 'pm learnings <ID> --add "<lesson that should outlive the item>"',
579
+ "pm append <ID> --body -",
580
+ "pm files <ID> --add path=<path>,scope=project,note=<why>",
581
+ "pm history <ID> --verify --strict-exit",
582
+ "pm history-repair --all --dry-run",
583
+ "pm history-redact <ID> --literal <secret> --dry-run",
584
+ "pm history-compact <ID> --dry-run",
585
+ "pm history-author-acknowledge --all-actionable --dry-run",
586
+ "pm close-many --ids <ID>,<ID> --reason <text> --dry-run",
587
+ "pm test-all --status open --limit 10 --progress",
588
+ ],
589
+ workflows: [
590
+ {
591
+ name: "Record While Working, Not After",
592
+ goal: "Another agent can rebuild the full situation from the item alone.",
593
+ prompt: "Add a comment for each verified step, a note for each rationale the item body does not carry, and a learning for each lesson that applies beyond this item. Prefer appending over rewriting.",
594
+ commands: [
595
+ 'pm comments <ID> "Evidence: <what changed and what passed>"',
596
+ 'pm notes <ID> --add "Decision log: <why this shape>"',
597
+ 'pm learnings <ID> --add "<durable lesson>"',
598
+ "pm learnings <ID> --limit 5",
599
+ ],
600
+ },
601
+ {
602
+ name: "Verify And Repair A History Stream",
603
+ goal: "Every mutation stays provable and the chain re-anchors after drift.",
604
+ prompt: "Verify the chain with a strict exit before trusting a stream, preview any repair, and record why the repair was needed in the audit message.",
605
+ commands: [
606
+ "pm history <ID> --verify --strict-exit",
607
+ "pm history-repair --all --dry-run",
608
+ 'pm history-repair --all --message "<why the chain drifted>"',
609
+ "pm validate --check-history-drift",
610
+ ],
611
+ },
612
+ {
613
+ name: "Redact, Compact, Or Attribute Without Losing Proof",
614
+ goal: "Sensitive text, stream length, and unknown authors are handled through audited rewrites.",
615
+ prompt: "Preview every history rewrite with --dry-run, read the receipt, then apply. Compaction renumbers ordinal versions, so record the checkpoint it created.",
616
+ commands: [
617
+ "pm history-redact <ID> --literal <secret> --dry-run",
618
+ "pm history-compact <ID> --dry-run",
619
+ "pm history-author-acknowledge --all-actionable --dry-run",
620
+ ],
621
+ },
622
+ ],
623
+ docs: [
624
+ {
625
+ path: "docs/COMMANDS.md",
626
+ purpose: "Annotation, bulk, and history-and-recovery command families.",
627
+ },
628
+ {
629
+ path: "docs/MUTATION_INTEGRITY.md",
630
+ purpose: "Provenance and content-safety policy every mutation shares.",
631
+ },
632
+ {
633
+ path: "docs/AGENT_GUIDE.md",
634
+ purpose: "Evidence expectations in the agent loop and self-repair remediation.",
635
+ },
636
+ ],
637
+ related: ["workflows", "assurance", "merge", "graph"],
638
+ },
639
+ {
640
+ id: "automation",
641
+ aliases: ["calendar", "reminders", "meetings", "events"],
642
+ title: "Reminders, Events, and Meetings",
643
+ summary: "Attach time to items so context and agenda views can surface deadlines, meetings, and reminders when they matter.",
644
+ intent: "Use this when an item needs a due signal, a scheduled event, or a meeting record that later context reads should surface.",
645
+ commands: [
646
+ "pm remind <title> --at <when> --parent <ID>",
647
+ "pm event <title> --start <when> --parent <ID>",
648
+ "pm meet <title> --start <when> --duration <span> --parent <ID>",
649
+ "pm context --limit 10",
650
+ ],
651
+ workflows: [
652
+ {
653
+ name: "Put A Deadline Where Context Will Find It",
654
+ goal: "Time-bound work surfaces in the agenda section of context reads.",
655
+ prompt: "Record the reminder or event under the item that owns the work, then confirm it appears in the agenda summary of a context read.",
656
+ commands: [
657
+ "pm remind <title> --at <when> --parent <ID>",
658
+ "pm context --limit 10",
659
+ ],
660
+ },
661
+ ],
662
+ docs: [
663
+ {
664
+ path: "docs/COMMANDS.md",
665
+ purpose: "Calendar and context command family.",
666
+ },
667
+ ],
668
+ related: ["workflows", "quickstart", "extensions"],
669
+ },
556
670
  ];
557
671
  const TOPIC_BY_TOKEN = new Map();
558
672
  for (const topic of GUIDE_TOPICS) {
@@ -591,4 +705,4 @@ export function resolveGuideTopic(rawTopic) {
591
705
  return TOPIC_BY_TOKEN.get(normalized) ?? null;
592
706
  }
593
707
  //# sourceMappingURL=guide-topics.js.map
594
- //# debugId=7c57f381-8318-5235-aa92-c96c6cedb021
708
+ //# debugId=feba1227-c2a2-5ca3-83e6-3fd2780e6cbb
@@ -0,0 +1,35 @@
1
+ import { type HistoryItemHashVersion } from "../../core/history/history.js";
2
+ import type { ItemTypeRegistry } from "../../core/item/type-registry.js";
3
+ import type { HistoryEntry, PmSettings } from "../../types/index.js";
4
+ import type { HistorySubject } from "../history-redact.js";
5
+ import type { HistoryRepairCommandOptions, HistoryRepairResult } from "../history-repair.js";
6
+ /** Evidence describing only the discarded suffix, without retaining its contents. */
7
+ export interface HistorySalvageReceipt {
8
+ /** One-based physical line where invalid trailing bytes begin. */
9
+ first_invalid_line: number;
10
+ /** UTF-8 bytes removed from the suffix. */
11
+ discarded_bytes: number;
12
+ /** SHA-256 of the removed bytes for local backup comparison. */
13
+ discarded_sha256: string;
14
+ /** Number of complete verified records retained. */
15
+ retained_entries: number;
16
+ }
17
+ /**
18
+ * Select a hash-verified prefix. Any parseable JSON after the first invalid
19
+ * line makes the corruption interior and therefore unsalvageable by truncation.
20
+ */
21
+ export declare function inspectHistoryTail(raw: string): {
22
+ entries: HistoryEntry[];
23
+ prefix: string;
24
+ receipt: HistorySalvageReceipt | null;
25
+ itemHashVersion: HistoryItemHashVersion;
26
+ };
27
+ /** Salvage one explicitly selected stream under its normal ownership and lock policy. */
28
+ export declare function salvageHistoryTail(params: {
29
+ pmRoot: string;
30
+ subject: HistorySubject;
31
+ settings: PmSettings;
32
+ typeRegistry: ItemTypeRegistry;
33
+ options: HistoryRepairCommandOptions;
34
+ author: string;
35
+ }): Promise<HistoryRepairResult>;
@@ -0,0 +1,248 @@
1
+ /**
2
+ * @module sdk/history/salvage
3
+ * Recover an invalid JSONL suffix while preserving every verified prefix byte.
4
+ */
5
+
6
+ !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]="49af8ec4-dd6b-56ef-8833-9c776fa35c85")}catch(e){}}();
7
+ import { isUtf8 } from "node:buffer";
8
+ import { readFile } from "node:fs/promises";
9
+ import { isFileMissingError, readFileIfExists, } from "../../core/fs/fs-utils.js";
10
+ import { acquireLock } from "../../core/lock/lock.js";
11
+ import { createHistoryEntry, sealHistoryRecord, } from "../../core/history/history.js";
12
+ import { checkHistoryRewriteOwnership, writeHistoryRawWithRollback, } from "../../core/history/history-rewrite.js";
13
+ import { replayHistoryToTarget } from "../../core/history/projection.js";
14
+ import { replayToItemDocument, verifyHistoryChainWithVersion, } from "../../core/history/replay.js";
15
+ import { findFirstMergeConflictMarker } from "../../core/shared/conflict-markers.js";
16
+ import { EXIT_CODE } from "../../core/shared/constants.js";
17
+ import { PmCliError } from "../../core/shared/errors.js";
18
+ import { sha256Hex } from "../../core/shared/serialization.js";
19
+ import { nowIso } from "../../core/shared/time.js";
20
+ import { runActiveOnReadHooks, runActiveOnWriteHooks, } from "../../core/extensions/index.js";
21
+ import { locateItem, readLocatedItemSnapshot, } from "../../core/store/item-store.js";
22
+ /** Decode a whole record or identify an invalid suffix without hiding a valid record. */
23
+ function decodeSalvageLine(line) {
24
+ let parsed;
25
+ try {
26
+ parsed = JSON.parse(line);
27
+ }
28
+ catch {
29
+ // A complete record followed by crash padding is not a disposable line.
30
+ // Refuse instead of silently dropping that record along with the padding.
31
+ if (line.trimStart().startsWith("{") && line.includes("}")) {
32
+ throw new PmCliError("History salvage cannot discard a potentially complete record with trailing corruption.", EXIT_CODE.CONFLICT, { code: "history_salvage_refused" });
33
+ }
34
+ return null;
35
+ }
36
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
37
+ throw new PmCliError("History salvage would conceal interior corruption or a malformed record.", EXIT_CODE.CONFLICT, { code: "history_salvage_refused" });
38
+ }
39
+ const entry = parsed;
40
+ if (!Array.isArray(entry.patch) ||
41
+ ![
42
+ entry.ts,
43
+ entry.author,
44
+ entry.op,
45
+ entry.before_hash,
46
+ entry.after_hash,
47
+ ].every((field) => typeof field === "string")) {
48
+ throw new PmCliError("History salvage requires complete history records before the invalid tail.", EXIT_CODE.CONFLICT, { code: "history_salvage_refused" });
49
+ }
50
+ return entry;
51
+ }
52
+ /**
53
+ * Select a hash-verified prefix. Any parseable JSON after the first invalid
54
+ * line makes the corruption interior and therefore unsalvageable by truncation.
55
+ */
56
+ export function inspectHistoryTail(raw) {
57
+ if (findFirstMergeConflictMarker(raw)) {
58
+ throw new PmCliError("Resolve history merge conflicts before salvage.", EXIT_CODE.CONFLICT, { code: "history_salvage_refused" });
59
+ }
60
+ const entries = [];
61
+ let offset = 0;
62
+ let invalidOffset;
63
+ let invalidLine = 0;
64
+ for (const [index, line] of raw.split("\n").entries()) {
65
+ if (!line.trim()) {
66
+ offset += line.length + 1;
67
+ continue;
68
+ }
69
+ const parsed = decodeSalvageLine(line);
70
+ if (parsed === null) {
71
+ if (invalidOffset === undefined) {
72
+ invalidOffset = offset;
73
+ invalidLine = index + 1;
74
+ }
75
+ offset += line.length + 1;
76
+ continue;
77
+ }
78
+ if (invalidOffset !== undefined) {
79
+ throw new PmCliError("History salvage would discard a record or conceal interior corruption.", EXIT_CODE.CONFLICT, {
80
+ code: "history_salvage_refused",
81
+ required: "Recover the damaged record from version control or a backup; no bytes were changed.",
82
+ });
83
+ }
84
+ entries.push(parsed);
85
+ offset += line.length + 1;
86
+ }
87
+ const verification = verifyHistoryChainWithVersion(entries);
88
+ if (!verification.ok || verification.item_hash_version === undefined) {
89
+ throw new PmCliError("History salvage requires a nonempty verified prefix.", EXIT_CODE.CONFLICT, {
90
+ code: "history_salvage_refused",
91
+ verification_errors: verification.errors,
92
+ required: "Recover an intact history prefix from version control or a backup.",
93
+ });
94
+ }
95
+ return {
96
+ entries,
97
+ itemHashVersion: verification.item_hash_version,
98
+ prefix: invalidOffset === undefined ? raw : raw.slice(0, invalidOffset),
99
+ receipt: invalidOffset === undefined
100
+ ? null
101
+ : {
102
+ first_invalid_line: invalidLine,
103
+ discarded_bytes: Buffer.byteLength(raw.slice(invalidOffset)),
104
+ discarded_sha256: sha256Hex(raw.slice(invalidOffset)),
105
+ retained_entries: entries.length,
106
+ },
107
+ };
108
+ }
109
+ /** Prefer the live item's owner; history supplies ownership only when its file is unreadable. */
110
+ async function readSalvageOwnership(subject, settings, fallback) {
111
+ if (!subject.located)
112
+ return { itemRaw: null, document: fallback };
113
+ const snapshot = await readLocatedItemSnapshot(subject.located, {
114
+ schema: settings.schema,
115
+ });
116
+ return { itemRaw: snapshot.raw, document: snapshot.document ?? fallback };
117
+ }
118
+ /** Refuse lossy decoding so suffix receipts and rollback always describe original bytes. */
119
+ async function readSalvageStream(historyPath) {
120
+ let bytes;
121
+ try {
122
+ bytes = await readFile(historyPath);
123
+ }
124
+ catch (error) {
125
+ if (isFileMissingError(error))
126
+ return null;
127
+ throw error;
128
+ }
129
+ if (!isUtf8(bytes)) {
130
+ throw new PmCliError("History salvage requires UTF-8 input; recover binary corruption from a byte-preserving backup.", EXIT_CODE.CONFLICT, { code: "history_salvage_refused" });
131
+ }
132
+ return bytes.toString("utf8");
133
+ }
134
+ /** Salvage one explicitly selected stream under its normal ownership and lock policy. */
135
+ export async function salvageHistoryTail(params) {
136
+ const { subject, settings, options, author } = params;
137
+ if ([
138
+ options.normalizeProvenance,
139
+ options.auditOperation,
140
+ options.auditContext,
141
+ options.auditContextById,
142
+ options.forceAuditEntry,
143
+ options.mergeReceiptProof,
144
+ options.mergeReceiptProofById,
145
+ ].some(Boolean)) {
146
+ throw new PmCliError("Tail salvage cannot be combined with other repair modes.", EXIT_CODE.USAGE);
147
+ }
148
+ const raw = await readSalvageStream(subject.historyPath);
149
+ if (raw === null)
150
+ throw new PmCliError(`No history stream exists for ${subject.id}.`, EXIT_CODE.NOT_FOUND);
151
+ await runActiveOnReadHooks({ path: subject.historyPath, scope: "project" });
152
+ const selected = inspectHistoryTail(raw);
153
+ const replay = replayHistoryToTarget(selected.entries, selected.entries.length - 1);
154
+ const document = replayToItemDocument(replay);
155
+ if (typeof replay.metadata.id === "string" &&
156
+ replay.metadata.id !== subject.id) {
157
+ throw new PmCliError("History belongs to another item; salvage refused.", EXIT_CODE.CONFLICT, { code: "history_salvage_refused" });
158
+ }
159
+ const ownership = await readSalvageOwnership(subject, settings, document);
160
+ const warnings = checkHistoryRewriteOwnership({
161
+ itemDocument: ownership.document,
162
+ subjectId: subject.id,
163
+ author,
164
+ force: options.force,
165
+ settings,
166
+ });
167
+ const version = selected.itemHashVersion;
168
+ const dryRun = options.dryRun === true;
169
+ const changed = selected.receipt !== null;
170
+ if (changed && !dryRun) {
171
+ const release = await acquireLock(params.pmRoot, subject.id, settings.locks.ttl_seconds, author, Boolean(options.force), settings.governance.force_required_for_stale_lock, settings.locks.wait_ms);
172
+ try {
173
+ const currentRaw = await readSalvageStream(subject.historyPath);
174
+ const located = await locateItem(params.pmRoot, subject.id, settings.id_prefix, settings.item_format, params.typeRegistry.type_to_folder);
175
+ const currentItem = located
176
+ ? await readFileIfExists(located.itemPath)
177
+ : null;
178
+ if (currentRaw !== raw || currentItem !== ownership.itemRaw) {
179
+ throw new PmCliError("History or item changed while waiting for salvage lock; retry.", EXIT_CODE.CONFLICT);
180
+ }
181
+ const audit = sealHistoryRecord({
182
+ ...createHistoryEntry({
183
+ nowIso: nowIso(),
184
+ author,
185
+ op: "history_salvage",
186
+ before: document,
187
+ after: document,
188
+ message: options.message,
189
+ context: { history_salvage: selected.receipt },
190
+ }),
191
+ before_hash: selected.entries.at(-1).after_hash,
192
+ after_hash: selected.entries.at(-1).after_hash,
193
+ item_hash_version: version,
194
+ });
195
+ await writeHistoryRawWithRollback({
196
+ historyPath: subject.historyPath,
197
+ historyRawUnderLock: raw,
198
+ nextHistoryRaw: `${selected.prefix}${JSON.stringify(audit)}\n`,
199
+ });
200
+ warnings.push(...(await runActiveOnWriteHooks({
201
+ path: subject.historyPath,
202
+ scope: "project",
203
+ op: "history_salvage:history",
204
+ })));
205
+ }
206
+ finally {
207
+ await release();
208
+ }
209
+ }
210
+ return {
211
+ id: subject.id,
212
+ dry_run: dryRun,
213
+ changed,
214
+ history: {
215
+ path: subject.historyPath,
216
+ entries_scanned: selected.entries.length,
217
+ chain_drift_before: false,
218
+ entries_rehashed: 0,
219
+ entries_patch_repaired: 0,
220
+ converted_replace_to_add: 0,
221
+ skipped_ops: 0,
222
+ reconciled_with_item: false,
223
+ audit_entry_added: changed && !dryRun,
224
+ verify_ok: true,
225
+ verify_errors: [],
226
+ item_hash_version_before: version,
227
+ item_hash_version_after: version,
228
+ version_disposition: "preserved",
229
+ },
230
+ item: {
231
+ exists: subject.located !== null,
232
+ path: subject.located?.itemPath ?? null,
233
+ matched_chain_before: null,
234
+ },
235
+ provenance_normalization: {
236
+ requested: false,
237
+ changed: false,
238
+ events_changed: 0,
239
+ observations_removed: 0,
240
+ invalid_values: [],
241
+ },
242
+ ...(selected.receipt ? { salvage: selected.receipt } : {}),
243
+ warnings,
244
+ generated_at: nowIso(),
245
+ };
246
+ }
247
+ //# sourceMappingURL=salvage.js.map
248
+ //# debugId=49af8ec4-dd6b-56ef-8833-9c776fa35c85
@@ -4,16 +4,17 @@
4
4
  * Implements the pm history compact command surface and its agent-facing runtime behavior.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7570ecac-7f15-5a1b-9b2d-2f1744a00720")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="26c39ecd-5d72-5cc9-b22b-6abc33fbf4ac")}catch(e){}}();
8
8
  import { assertInitializedTracker } from "./environment/tracker-preflight.js";
9
9
  import fs from "node:fs/promises";
10
10
  import path from "node:path";
11
- import { createHistoryEntry, hashHistoryStream, resealHistoryRewrite, } from "../core/history/history.js";
11
+ import { createHistoryEntry, hashHistoryStream, sealHistoryRecord, SUPPORTED_HISTORY_ITEM_HASH_VERSIONS, } from "../core/history/history.js";
12
12
  import { selectHistoryCompactBulkTargets, } from "../core/history/history-compact-bulk.js";
13
13
  import { executeHistoryRewrite, writeHistoryRawWithRollback, } from "../core/history/history-rewrite.js";
14
- import { cloneEmptyReplayDocument, historyEntriesToRaw, replayHash, replayToItemDocument, toReplayDocument, verifyHistoryChain, } from "../core/history/replay.js";
14
+ import { cloneEmptyReplayDocument, historyEntriesToRaw, replayHashVerificationCandidates, replayToItemDocument, toReplayDocument, verifyHistoryChain, } from "../core/history/replay.js";
15
15
  import { applyHistoryPatch } from "../core/history/projection.js";
16
16
  import { readHistoryEntries } from "../core/history/read.js";
17
+ import { historyVersionOffset } from "../core/history/version-address.js";
17
18
  import { resolveItemTypeRegistry } from "../core/item/type-registry.js";
18
19
  import { lifecycleClassifierFromStatusRegistry } from "../core/governance/metadata-coverage.js";
19
20
  import { resolveRuntimeStatusRegistry } from "../core/schema/runtime-schema.js";
@@ -29,6 +30,7 @@ import { resolvePmRoot } from "../core/store/paths.js";
29
30
  import { readSettings } from "../core/store/settings.js";
30
31
  import { resolveAuthor } from "../core/shared/author.js";
31
32
  import { resolveHistorySubject } from "./history-redact.js";
33
+ /** Translate a durable version or timestamp boundary into physical compacted and retained counts. */
32
34
  function parseBeforeBoundary(before, entries) {
33
35
  if (before === undefined) {
34
36
  return {
@@ -44,12 +46,13 @@ function parseBeforeBoundary(before, entries) {
44
46
  }
45
47
  if (/^\d+$/.test(raw)) {
46
48
  const version = Number.parseInt(raw, 10);
49
+ const offset = historyVersionOffset(entries);
47
50
  if (!Number.isSafeInteger(version) ||
48
- version < 1 ||
49
- version > entries.length + 1) {
50
- throw new PmCliError(`history-compact --before version must be between 1 and ${entries.length + 1}.`, EXIT_CODE.USAGE);
51
+ version < offset + 1 ||
52
+ version > offset + entries.length + 1) {
53
+ throw new PmCliError(`history-compact --before version must be between ${offset + 1} and ${offset + entries.length + 1}.`, EXIT_CODE.USAGE);
51
54
  }
52
- const compactCount = Math.max(0, Math.min(entries.length, version - 1));
55
+ const compactCount = version - offset - 1;
53
56
  return {
54
57
  kind: "version",
55
58
  raw,
@@ -79,18 +82,13 @@ function parseBeforeBoundary(before, entries) {
79
82
  retainedCount: entries.length - compactCount,
80
83
  };
81
84
  }
85
+ /** Fold the already verified stream once, capturing its compaction checkpoint. */
82
86
  function replayHistoryAndResolveCheckpoint(entries, compactCount) {
83
87
  let replay = cloneEmptyReplayDocument();
84
88
  let checkpoint = cloneEmptyReplayDocument();
85
89
  for (let index = 0; index < entries.length; index += 1) {
86
90
  const entry = entries[index];
87
- if (replayHash(replay) !== entry.before_hash) {
88
- throw new PmCliError(`history-compact detected before-hash drift at entry ${index + 1}; run pm history-repair first.`, EXIT_CODE.CONFLICT);
89
- }
90
91
  replay = applyHistoryPatch(replay, entry.patch, index + 1, entry.op);
91
- if (replayHash(replay) !== entry.after_hash) {
92
- throw new PmCliError(`history-compact detected after-hash drift at entry ${index + 1}; run pm history-repair first.`, EXIT_CODE.CONFLICT);
93
- }
94
92
  if (index + 1 === compactCount) {
95
93
  checkpoint = structuredClone(replay);
96
94
  }
@@ -100,23 +98,7 @@ function replayHistoryAndResolveCheckpoint(entries, compactCount) {
100
98
  finalReplay: replay,
101
99
  };
102
100
  }
103
- function reanchorRetainedEntries(retainedEntries, seed, retainedEntryOffset) {
104
- let replay = structuredClone(seed);
105
- const rewritten = [];
106
- for (const [index, entry] of retainedEntries.entries()) {
107
- const beforeHash = replayHash(replay);
108
- replay = applyHistoryPatch(replay, entry.patch, retainedEntryOffset + index + 1, entry.op);
109
- rewritten.push(resealHistoryRewrite(entry, {
110
- ...entry,
111
- before_hash: beforeHash,
112
- after_hash: replayHash(replay),
113
- }));
114
- }
115
- return {
116
- entries: rewritten,
117
- finalReplay: replay,
118
- };
119
- }
101
+ /** Snapshot the live item and compare it with the stream's supported historical hash surfaces. */
120
102
  async function loadHistoryCompactCurrentItem(subject, settings, historyEntries) {
121
103
  const loadedItem = subject.located
122
104
  ? await readLocatedItem(subject.located, { schema: settings.schema })
@@ -128,11 +110,12 @@ async function loadHistoryCompactCurrentItem(subject, settings, historyEntries)
128
110
  matchedChainBefore: null,
129
111
  };
130
112
  }
113
+ const lastEntry = historyEntries[historyEntries.length - 1];
131
114
  return {
132
115
  loadedItem,
133
116
  currentItemRawBeforeLock: loadedItem.raw,
134
- matchedChainBefore: replayHash(toReplayDocument(loadedItem.document)) ===
135
- historyEntries[historyEntries.length - 1]?.after_hash,
117
+ matchedChainBefore: SUPPORTED_HISTORY_ITEM_HASH_VERSIONS.some((version) => (lastEntry.item_hash_version === undefined || lastEntry.item_hash_version === version) &&
118
+ replayHashVerificationCandidates(toReplayDocument(loadedItem.document), version).includes(lastEntry.after_hash)),
136
119
  };
137
120
  }
138
121
  function buildHistoryCompactMessage(options, boundary) {
@@ -151,6 +134,7 @@ function buildHistoryCompactBaselineMessage(boundary) {
151
134
  }
152
135
  return `history-compact baseline snapshot before ${boundary.raw}.`;
153
136
  }
137
+ /** Replace the pruned prefix with a durable-addressed checkpoint while retaining original records and hash semantics. */
154
138
  function buildHistoryCompactEntries(params) {
155
139
  if (!params.changed) {
156
140
  return {
@@ -161,9 +145,9 @@ function buildHistoryCompactEntries(params) {
161
145
  }
162
146
  const { checkpoint, finalReplay } = replayHistoryAndResolveCheckpoint(params.historyEntries, params.boundary.compactCount);
163
147
  const retained = params.historyEntries.slice(params.boundary.compactCount);
164
- const reanchored = reanchorRetainedEntries(retained, checkpoint, params.boundary.compactCount);
148
+ const offset = historyVersionOffset(params.historyEntries, true);
165
149
  const baselineEntry = createHistoryEntry({
166
- nowIso: nowIso(),
150
+ nowIso: params.historyEntries[params.boundary.compactCount - 1].ts,
167
151
  author: params.author,
168
152
  op: "history_compact_baseline",
169
153
  before: replayToItemDocument(cloneEmptyReplayDocument()),
@@ -172,6 +156,8 @@ function buildHistoryCompactEntries(params) {
172
156
  context: {
173
157
  history_compaction: {
174
158
  contract_version: 1,
159
+ version_offset: offset === null ? null : offset + params.boundary.compactCount - 1,
160
+ checkpoint_timestamp_semantics: "last_compacted_entry",
175
161
  pruned_entry_count: params.boundary.compactCount,
176
162
  pruned_stream_digest: hashHistoryStream(params.historyEntries.slice(0, params.boundary.compactCount)),
177
163
  retained_proof: "stream_digest_and_checkpoint",
@@ -179,7 +165,15 @@ function buildHistoryCompactEntries(params) {
179
165
  },
180
166
  },
181
167
  });
182
- const rewrittenEntries = [baselineEntry, ...reanchored.entries];
168
+ const checkpointEntry = params.historyEntries[params.boundary.compactCount - 1];
169
+ // Preserve the checkpoint's epoch and semantic hash variant. Do not introduce
170
+ // an explicit epoch into an unversioned stream: it would pin later legacy reads.
171
+ const rewrittenEntries = [sealHistoryRecord({
172
+ ...baselineEntry,
173
+ before_hash: params.historyEntries[0].before_hash,
174
+ after_hash: checkpointEntry.after_hash,
175
+ item_hash_version: checkpointEntry.item_hash_version,
176
+ }), ...retained];
183
177
  if (!params.dryRun) {
184
178
  rewrittenEntries.push(createHistoryEntry({
185
179
  nowIso: nowIso(),
@@ -279,7 +273,8 @@ export async function runHistoryCompact(id, options, global) {
279
273
  rewrittenEntries,
280
274
  })));
281
275
  }
282
- const firstRetainedEntry = boundary.retainedCount > 0 ? boundary.compactCount + 1 : null;
276
+ const offset = historyVersionOffset(historyEntries, true);
277
+ const firstRetainedEntry = boundary.retainedCount > 0 && offset !== null ? offset + boundary.compactCount + 1 : null;
283
278
  return {
284
279
  id: subject.id,
285
280
  dry_run: dryRun,
@@ -530,4 +525,4 @@ export async function runHistoryCompactBulk(options, global) {
530
525
  };
531
526
  }
532
527
  //# sourceMappingURL=history-compact.js.map
533
- //# debugId=7570ecac-7f15-5a1b-9b2d-2f1744a00720
528
+ //# debugId=26c39ecd-5d72-5cc9-b22b-6abc33fbf4ac
@@ -1,6 +1,7 @@
1
1
  import { applyHistoryPatch, ensureMaterializedHistoryTarget, extractPatchFailureContext, replayHistoryToTarget, resolveHistoryTarget, type ResolvedHistoryTarget } from "../core/history/projection.js";
2
2
  import { readHistoryEntries } from "../core/history/read.js";
3
3
  import type { HistoryEntry, ItemDocument } from "../types/index.js";
4
+ export { findHistoryIdentityDiscontinuities, type HistoryIdentityDiscontinuity, } from "../core/history/identity.js";
4
5
  /** Workspace resolution controls accepted by {@link getItemAt}. */
5
6
  export interface GetItemAtOptions {
6
7
  /** Explicit tracker root, equivalent to the CLI global `--pm-path`. */
@@ -14,8 +15,8 @@ export interface GetItemAtResult {
14
15
  document: ItemDocument;
15
16
  /** Always true, preventing consumers from confusing this with current state. */
16
17
  reconstructed: true;
17
- /** One-based version included in the projection. */
18
- as_of_version: number;
18
+ /** Durable one-based version; null when a legacy checkpoint lost its mapping. */
19
+ as_of_version: number | null;
19
20
  /** Timestamp of the final included history entry. */
20
21
  as_of_timestamp: string;
21
22
  /** Normalized target resolution metadata shared with restore. */
@@ -7,11 +7,12 @@
7
7
  * systems without acquiring locks or appending history.
8
8
  */
9
9
 
10
- !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]="f1ea4209-59d4-53f0-a8ea-2e060e385d14")}catch(e){}}();
10
+ !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]="6fe766e2-93e8-5653-beb5-16bd92efae51")}catch(e){}}();
11
11
  import { assertInitializedTracker } from "./environment/tracker-preflight.js";
12
12
  import { getActiveExtensionRegistrations } from "../core/extensions/index.js";
13
13
  import { applyHistoryPatch, ensureMaterializedHistoryTarget, extractPatchFailureContext, replayHistoryToTarget, resolveHistoryTarget, } from "../core/history/projection.js";
14
14
  import { readHistoryEntries } from "../core/history/read.js";
15
+ import { historyVersionOffset } from "../core/history/version-address.js";
15
16
  import { hashDocument, hashDocumentVerificationCandidates, hashEmptyDocument, } from "../core/history/history.js";
16
17
  import { replayToCanonicalItemDocument, verifyHistoryChainWithVersion, } from "../core/history/replay.js";
17
18
  import { resolveItemTypeRegistry } from "../core/item/type-registry.js";
@@ -20,6 +21,7 @@ import { PmCliError } from "../core/shared/errors.js";
20
21
  import { resolvePmRoot } from "../core/store/paths.js";
21
22
  import { readSettings } from "../core/store/settings.js";
22
23
  import { resolveHistorySubject } from "./history-redact.js";
24
+ export { findHistoryIdentityDiscontinuities, } from "../core/history/identity.js";
23
25
  /**
24
26
  * Verify a history chain and optionally compare it with a current document.
25
27
  *
@@ -80,10 +82,11 @@ export async function getItemAt(id, target, options = {}) {
80
82
  throw new PmCliError(`History target resolved to item ${document.metadata.id}, expected ${subject.id}.`, EXIT_CODE.GENERIC_FAILURE);
81
83
  }
82
84
  const targetEntry = history[resolvedTarget.historyIndex];
85
+ const offset = historyVersionOffset(history, true);
83
86
  return {
84
87
  document,
85
88
  reconstructed: true,
86
- as_of_version: resolvedTarget.historyIndex + 1,
89
+ as_of_version: offset === null ? null : offset + resolvedTarget.historyIndex + 1,
87
90
  as_of_timestamp: targetEntry.ts,
88
91
  target: resolvedTarget,
89
92
  history_length: history.length,
@@ -91,4 +94,4 @@ export async function getItemAt(id, target, options = {}) {
91
94
  }
92
95
  export { applyHistoryPatch, ensureMaterializedHistoryTarget, extractPatchFailureContext, readHistoryEntries, replayHistoryToTarget, resolveHistoryTarget, };
93
96
  //# sourceMappingURL=history-read.js.map
94
- //# debugId=f1ea4209-59d4-53f0-a8ea-2e060e385d14
97
+ //# debugId=6fe766e2-93e8-5653-beb5-16bd92efae51