@unbrained/pm-cli 2026.9.3 → 2026.9.5

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 (228) 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 +52 -0
  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 +15 -6
  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 +6 -2
  21. package/dist/cli-bundle/bundle-manifest.json +154 -154
  22. package/dist/cli-bundle/chunks/{chunk-EDPIS7EB.js → chunk-3HBDTJRK.js} +2 -2
  23. package/dist/cli-bundle/chunks/chunk-66VPKFP2.js +5 -0
  24. package/dist/cli-bundle/chunks/{chunk-Y4PJ6HPK.js → chunk-HUAQITVW.js} +2 -2
  25. package/dist/cli-bundle/chunks/{chunk-DKGP3QLE.js → chunk-IBYREGSP.js} +2 -2
  26. package/dist/cli-bundle/chunks/chunk-LUI4E32I.js +231 -0
  27. package/dist/cli-bundle/chunks/{chunk-UPPM2FOZ.js → chunk-QPZHQY2O.js} +2 -2
  28. package/dist/cli-bundle/chunks/{chunk-34HASX3S.js → chunk-SF6SM6U5.js} +2 -2
  29. package/dist/cli-bundle/chunks/chunk-SVK5Y64D.js +40 -0
  30. package/dist/cli-bundle/chunks/chunk-V5GBD5KV.js +9 -0
  31. package/dist/cli-bundle/chunks/{chunk-LENC656S.js → chunk-WWAEGW4V.js} +67 -70
  32. package/dist/cli-bundle/chunks/chunk-ZRAQS3UA.js +8 -0
  33. package/dist/cli-bundle/chunks/{register-list-query-W2ZTOMKP.js → register-list-query-AYKGODWT.js} +3 -3
  34. package/dist/cli-bundle/chunks/{register-mutation-RVND5NCG.js → register-mutation-YZYG53SQ.js} +4 -4
  35. package/dist/cli-bundle/chunks/register-operations-KFSCC7QV.js +2 -0
  36. package/dist/cli-bundle/chunks/{register-setup-D3ZFHY3L.js → register-setup-UJCRVGBG.js} +2 -2
  37. package/dist/cli-bundle/focused-chunks/chunk-24IG6ONG.js +2 -0
  38. package/dist/cli-bundle/focused-chunks/{chunk-M5M6SVHS.js → chunk-3ASU6WGI.js} +2 -2
  39. package/dist/cli-bundle/focused-chunks/chunk-3ITLIBKS.js +56 -0
  40. package/dist/cli-bundle/focused-chunks/chunk-3NQD5YDG.js +2 -0
  41. package/dist/cli-bundle/focused-chunks/{chunk-S27XMBIN.js → chunk-4OSHLNUE.js} +2 -2
  42. package/dist/cli-bundle/focused-chunks/chunk-65N6JHAN.js +2 -0
  43. package/dist/cli-bundle/focused-chunks/{chunk-5RFXUPN5.js → chunk-B2TTQGFG.js} +2 -2
  44. package/dist/cli-bundle/focused-chunks/chunk-GUBM3RGY.js +20 -0
  45. package/dist/cli-bundle/focused-chunks/{chunk-Q45NHPF2.js → chunk-H5FOGAVD.js} +2 -2
  46. package/dist/cli-bundle/focused-chunks/chunk-JX3RCVCX.js +2 -0
  47. package/dist/cli-bundle/focused-chunks/{chunk-D7KXFBXV.js → chunk-KWWCBWFO.js} +2 -2
  48. package/dist/cli-bundle/focused-chunks/chunk-MV752SUC.js +12 -0
  49. package/dist/cli-bundle/focused-chunks/chunk-PKIPMCFS.js +6 -0
  50. package/dist/cli-bundle/focused-chunks/{chunk-4HJFY4MB.js → chunk-QL66QNWG.js} +2 -2
  51. package/dist/cli-bundle/focused-chunks/chunk-RJMR2JIF.js +9 -0
  52. package/dist/cli-bundle/focused-chunks/chunk-WIUPWIZR.js +177 -0
  53. package/dist/cli-bundle/focused-chunks/chunk-WOCIPMW7.js +2 -0
  54. package/dist/cli-bundle/focused-chunks/{chunk-GT7MXDLW.js → chunk-YEF5PQQ2.js} +2 -2
  55. package/dist/cli-bundle/main.js +22 -15
  56. package/dist/cli-bundle/sdk-authoring.js +1 -1
  57. package/dist/cli-bundle/sdk-contracts.js +1 -1
  58. package/dist/cli-bundle/sdk-core.js +29 -32
  59. package/dist/cli-bundle/sdk-governance.js +1 -1
  60. package/dist/cli-bundle/sdk-graph.js +1 -1
  61. package/dist/cli-bundle/sdk-merge.js +45 -37
  62. package/dist/cli-bundle/sdk-query.js +1 -1
  63. package/dist/cli-bundle/sdk-runtime.js +1 -1
  64. package/dist/cli-bundle/sdk-testing.js +1 -1
  65. package/dist/cli-bundle/sdk.js +10 -10
  66. package/dist/core/diagnostics/remediation.js +4 -4
  67. package/dist/core/extensions/extension-types.d.ts +2 -0
  68. package/dist/core/extensions/extension-types.js +2 -2
  69. package/dist/core/history/drift-scan.d.ts +5 -0
  70. package/dist/core/history/drift-scan.js +16 -6
  71. package/dist/core/history/event-classification.d.ts +1 -1
  72. package/dist/core/history/event-classification.js +3 -2
  73. package/dist/core/history/history.d.ts +37 -1
  74. package/dist/core/history/history.js +311 -59
  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 +70 -36
  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/lock/lock.d.ts +10 -0
  91. package/dist/core/lock/lock.js +42 -3
  92. package/dist/core/shared/author.d.ts +3 -1
  93. package/dist/core/shared/author.js +111 -23
  94. package/dist/core/shared/errors.d.ts +8 -0
  95. package/dist/core/shared/errors.js +2 -2
  96. package/dist/core/store/item-store.d.ts +14 -0
  97. package/dist/core/store/item-store.js +48 -10
  98. package/dist/core/store/settings-validator.js +3 -2
  99. package/dist/sdk/actionability.d.ts +1 -1
  100. package/dist/sdk/actionability.js +3 -3
  101. package/dist/sdk/cli-contracts/command-aliases.js +11 -2
  102. package/dist/sdk/cli-contracts/completeness.js +4 -3
  103. package/dist/sdk/cli-contracts/flag-contracts.js +29 -5
  104. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +19 -12
  105. package/dist/sdk/cli-contracts/tool-parameter-tables.js +14 -2
  106. package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
  107. package/dist/sdk/cli-contracts/tool-schema.js +19 -6
  108. package/dist/sdk/context-intent-contracts.js +3 -3
  109. package/dist/sdk/context-usage.js +9 -11
  110. package/dist/sdk/define.d.ts +1 -1
  111. package/dist/sdk/define.js +2 -2
  112. package/dist/sdk/environment/agent-environment.d.ts +296 -0
  113. package/dist/sdk/environment/agent-environment.js +467 -0
  114. package/dist/sdk/environment/project-runtime-compatibility.d.ts +19 -1
  115. package/dist/sdk/environment/project-runtime-compatibility.js +118 -21
  116. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +98 -38
  117. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -2
  118. package/dist/sdk/governance/health.js +13 -44
  119. package/dist/sdk/governance/merge-receipt-history.d.ts +62 -0
  120. package/dist/sdk/governance/merge-receipt-history.js +207 -0
  121. package/dist/sdk/governance/provenance-health.js +9 -3
  122. package/dist/sdk/governance/validate-history-drift.js +16 -5
  123. package/dist/sdk/guide-topics.js +116 -2
  124. package/dist/sdk/history/salvage.d.ts +35 -0
  125. package/dist/sdk/history/salvage.js +248 -0
  126. package/dist/sdk/history-compact.js +41 -37
  127. package/dist/sdk/history-read.d.ts +3 -2
  128. package/dist/sdk/history-read.js +6 -3
  129. package/dist/sdk/history-redact.js +58 -23
  130. package/dist/sdk/history-repair.d.ts +5 -0
  131. package/dist/sdk/history-repair.js +28 -6
  132. package/dist/sdk/index.d.ts +2 -0
  133. package/dist/sdk/index.js +4 -2
  134. package/dist/sdk/lifecycle/claim.d.ts +4 -0
  135. package/dist/sdk/lifecycle/claim.js +9 -3
  136. package/dist/sdk/lifecycle/restore.d.ts +1 -0
  137. package/dist/sdk/lifecycle/restore.js +19 -7
  138. package/dist/sdk/merge/driver.d.ts +3 -1
  139. package/dist/sdk/merge/driver.js +9 -9
  140. package/dist/sdk/merge/index.d.ts +1 -1
  141. package/dist/sdk/merge/index.js +3 -3
  142. package/dist/sdk/merge/receipts.d.ts +17 -6
  143. package/dist/sdk/merge/receipts.js +246 -75
  144. package/dist/sdk/merge/reconcile.d.ts +9 -7
  145. package/dist/sdk/merge/reconcile.js +175 -12
  146. package/dist/sdk/merge/three-way.d.ts +22 -2
  147. package/dist/sdk/merge/three-way.js +92 -25
  148. package/dist/sdk/output-projection.d.ts +3 -1
  149. package/dist/sdk/output-projection.js +11 -3
  150. package/dist/sdk/public-surface.json +1 -0
  151. package/dist/sdk/query/context.d.ts +9 -0
  152. package/dist/sdk/query/context.js +33 -21
  153. package/dist/sdk/query/get.d.ts +2 -2
  154. package/dist/sdk/query/get.js +4 -3
  155. package/dist/sdk/query/history.d.ts +11 -0
  156. package/dist/sdk/query/history.js +34 -10
  157. package/dist/sdk/query/next.d.ts +15 -1
  158. package/dist/sdk/query/next.js +43 -20
  159. package/dist/sdk/query.d.ts +1 -0
  160. package/dist/sdk/query.js +3 -2
  161. package/dist/sdk/runtime-primitives.d.ts +3 -3
  162. package/dist/sdk/runtime-primitives.js +5 -5
  163. package/dist/types.d.ts +27 -0
  164. package/dist/types.js +2 -2
  165. package/docs/AGENT_ENVIRONMENTS.md +47 -0
  166. package/docs/AGENT_GUIDE.md +36 -0
  167. package/docs/AGENT_PROVENANCE_ADR.md +17 -2
  168. package/docs/CONTEXT_INTEGRITY_CONTRACTS.md +38 -1
  169. package/docs/HISTORY_RECOVERY.md +146 -0
  170. package/docs/MERGE_SAFETY.md +119 -23
  171. package/docs/README.md +2 -0
  172. package/docs/RELEASING.md +25 -11
  173. package/docs/SDK_CONTEXT_EVIDENCE_CONTRACTS.md +24 -2
  174. package/docs/SDK_CONTEXT_TRUTH_CONTRACTS.md +24 -1
  175. package/docs/SDK_EXECUTION_CONTRACTS.md +105 -0
  176. package/docs/SDK_RUNTIME_BOUNDARIES.md +17 -1
  177. package/docs/TESTING.md +5 -0
  178. package/docs/agent-task-token-baseline.json +17 -17
  179. package/docs/agent-task-transcripts.json +2 -1
  180. package/docs/examples/sdk-agent-environment/README.md +14 -0
  181. package/docs/examples/sdk-agent-environment/package.json +8 -0
  182. package/docs/examples/sdk-agent-environment/run-agent-environment.mjs +154 -0
  183. package/docs/generated/FLAG_LEXICON_BUDGETS.md +10 -10
  184. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +12 -3
  185. package/marketplace.json +2 -2
  186. package/package.json +5 -6
  187. package/packages/pm-beads/package.json +1 -1
  188. package/packages/pm-calendar/package.json +1 -1
  189. package/packages/pm-command-kit/package.json +1 -1
  190. package/packages/pm-digital-twin/package.json +1 -1
  191. package/packages/pm-governance-audit/package.json +1 -1
  192. package/packages/pm-guide-shell/package.json +1 -1
  193. package/packages/pm-kanban/package.json +1 -1
  194. package/packages/pm-lifecycle-hooks/package.json +1 -1
  195. package/packages/pm-linked-test-adapters/package.json +1 -1
  196. package/packages/pm-search-advanced/package.json +1 -1
  197. package/packages/pm-templates/package.json +1 -1
  198. package/packages/pm-todos/package.json +1 -1
  199. package/packages/pm-vcs/package.json +1 -1
  200. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  201. package/plugins/pm-claude/skills/pm-audit/SKILL.md +2 -2
  202. package/plugins/pm-claude/skills/pm-developer/SKILL.md +2 -2
  203. package/plugins/pm-claude/skills/pm-planner/SKILL.md +2 -2
  204. package/plugins/pm-claude/skills/pm-release/SKILL.md +2 -2
  205. package/plugins/pm-claude/skills/pm-workflow/SKILL.md +3 -3
  206. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  207. package/plugins/pm-codex/skills/pm-auditor/SKILL.md +2 -2
  208. package/plugins/pm-codex/skills/pm-native/SKILL.md +3 -4
  209. package/plugins/pm-codex/skills/pm-release/SKILL.md +2 -2
  210. package/scripts/finalize-build.mjs +13 -1
  211. package/dist/cli-bundle/chunks/chunk-AY324UJ5.js +0 -9
  212. package/dist/cli-bundle/chunks/chunk-E5RBBCXO.js +0 -230
  213. package/dist/cli-bundle/chunks/chunk-IEHHE6GA.js +0 -5
  214. package/dist/cli-bundle/chunks/chunk-L7B7343B.js +0 -8
  215. package/dist/cli-bundle/chunks/chunk-LISESA7W.js +0 -35
  216. package/dist/cli-bundle/chunks/register-operations-TTROIVC4.js +0 -2
  217. package/dist/cli-bundle/focused-chunks/chunk-3ZBI35HU.js +0 -176
  218. package/dist/cli-bundle/focused-chunks/chunk-4RRHC3S4.js +0 -6
  219. package/dist/cli-bundle/focused-chunks/chunk-4WR46RMG.js +0 -9
  220. package/dist/cli-bundle/focused-chunks/chunk-BWKHEIVF.js +0 -2
  221. package/dist/cli-bundle/focused-chunks/chunk-GHCZ3YFR.js +0 -20
  222. package/dist/cli-bundle/focused-chunks/chunk-KBLZRU62.js +0 -2
  223. package/dist/cli-bundle/focused-chunks/chunk-KZ2NB3ET.js +0 -2
  224. package/dist/cli-bundle/focused-chunks/chunk-OL5EH6I3.js +0 -2
  225. package/dist/cli-bundle/focused-chunks/chunk-QKHCSUGJ.js +0 -51
  226. package/dist/cli-bundle/focused-chunks/chunk-TXE4TSHM.js +0 -12
  227. package/dist/cli-bundle/focused-chunks/chunk-UCLO3XDU.js +0 -2
  228. package/sdk/public-surface.json +0 -32524
@@ -0,0 +1,62 @@
1
+ /** First commit timestamp at which merge receipts gained a tracked durable copy. */
2
+ export declare const DURABLE_MERGE_RECEIPT_INTRODUCED_AT = "2026-08-09T16:15:18.000Z";
3
+ /** One receipt reference discovered at an immutable history coordinate. */
4
+ export interface HistoryMergeReceiptReference {
5
+ /** Item whose history contains the summary. */
6
+ itemId: string;
7
+ /** One-based history line containing the summary. */
8
+ line: number;
9
+ /** Privacy-safe receipt identifier. */
10
+ receiptId: string;
11
+ /** Whether the summary is a complete supported preferred-era record. */
12
+ legacySummaryAccepted: boolean;
13
+ /** Timestamp of the history event that introduced the reference, when valid. */
14
+ eventTimestamp?: string;
15
+ }
16
+ /** Audited disposition for one receipt that a pre-durable writer could never publish. */
17
+ export interface HistoryMergeReceiptDisposition {
18
+ /** Item whose history contains both the original reference and disposition. */
19
+ itemId: string;
20
+ /** Receipt identity explicitly accepted as unrecoverable. */
21
+ receiptId: string;
22
+ /** One-based coordinate of the original merge event. */
23
+ originalHistoryLine: number;
24
+ /** Timestamp copied from the original merge event for exact matching. */
25
+ originalEventTimestamp: string;
26
+ /** One-based coordinate of the later audit event that records this disposition. */
27
+ auditHistoryLine: number;
28
+ /** Closed reason vocabulary for this exceptional compatibility path. */
29
+ reason: "legacy_clone_local_only";
30
+ }
31
+ /** Missing-reference coordinate returned to bounded integrity diagnostics. */
32
+ export interface MissingHistoryMergeReceiptReference {
33
+ /** Item whose history contains the unresolved reference. */
34
+ item_id: string;
35
+ /** One-based history line containing the unresolved reference. */
36
+ history_line: number;
37
+ /** Safe identifier when the source value is suitable for diagnostics. */
38
+ receipt_id?: string;
39
+ /** Digest used instead of an unsafe identifier. */
40
+ receipt_reference_hash?: string;
41
+ }
42
+ /** Partitioned compatibility outcome for all scanned history references. */
43
+ export interface HistoryMergeReceiptReferenceClassification {
44
+ /** References requiring authoritative external evidence. */
45
+ missing: MissingHistoryMergeReceiptReference[];
46
+ /** Complete preferred-era summaries accepted without impossible migration. */
47
+ acceptedLegacyCount: number;
48
+ /** Pre-durable references accepted by a later explicit audited disposition. */
49
+ acceptedDispositionCount: number;
50
+ }
51
+ /** Return whether one summary is a complete, self-contained preferred-era receipt. */
52
+ export declare function isLegacyMergeReceiptSummary(value: Record<string, unknown>, historyItemId: string): boolean;
53
+ /** Return whether a summary matches the final clone-local-only schema before durable receipts. */
54
+ export declare function isPreDurableCloneLocalReceiptSummary(value: Record<string, unknown>, historyItemId: string): boolean;
55
+ /** Return whether an extracted reference carried a validated pre-durable summary. */
56
+ export declare function isPreDurableDispositionEligibleReference(reference: Omit<HistoryMergeReceiptReference, "itemId" | "line">): boolean;
57
+ /** Extract receipt ids and legacy compatibility disposition from one history entry. */
58
+ export declare function extractHistoryMergeReceiptReferences(value: unknown, historyItemId: string): Array<Omit<HistoryMergeReceiptReference, "itemId" | "line">>;
59
+ /** Extract validated explicit missing-receipt dispositions from one merge audit event. */
60
+ export declare function extractHistoryMergeReceiptDispositions(value: unknown, historyItemId: string, historyLine: number): HistoryMergeReceiptDisposition[];
61
+ /** Classify scanned references without treating complete legacy summaries as absent. */
62
+ export declare function classifyHistoryMergeReceiptReferences(references: readonly HistoryMergeReceiptReference[], availableReceiptIds: ReadonlySet<string>, dispositions?: readonly HistoryMergeReceiptDisposition[]): HistoryMergeReceiptReferenceClassification;
@@ -0,0 +1,207 @@
1
+ /**
2
+ * @module sdk/governance/merge-receipt-history
3
+ *
4
+ * Classifies privacy-safe merge receipt references embedded in history.
5
+ */
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]="1e73338f-221a-580f-85a8-6f2a488fb89d")}catch(e){}}();
8
+ import { createHash } from "node:crypto";
9
+ import path from "node:path";
10
+ import { compareTimestampStrings, isRfc3339DateTime, } from "../../core/shared/time.js";
11
+ import { isSafeReceiptId } from "../merge/receipts.js";
12
+ /** First commit timestamp at which merge receipts gained a tracked durable copy. */
13
+ export const DURABLE_MERGE_RECEIPT_INTRODUCED_AT = "2026-08-09T16:15:18.000Z";
14
+ const PRE_DURABLE_DISPOSITION_ELIGIBLE = Symbol("pre-durable-disposition-eligible");
15
+ /** Return whether an unknown value is a non-array record. */
16
+ function isRecord(value) {
17
+ return typeof value === "object" && value !== null && !Array.isArray(value);
18
+ }
19
+ /** Return a bounded dense list of unique, non-empty field names. */
20
+ function isFieldArray(value) {
21
+ if (!Array.isArray(value) || value.length > 256)
22
+ return false;
23
+ const fields = new Set();
24
+ for (let index = 0; index < value.length; index += 1) {
25
+ const field = value[index];
26
+ if (!(index in value) ||
27
+ typeof field !== "string" ||
28
+ field.length === 0 ||
29
+ field.length > 256 ||
30
+ field.includes("\0") ||
31
+ fields.has(field)) {
32
+ return false;
33
+ }
34
+ fields.add(field);
35
+ }
36
+ return true;
37
+ }
38
+ /** Return whether an unknown value is one complete legacy field decision. */
39
+ function isLegacyDecision(value) {
40
+ if (!isRecord(value))
41
+ return false;
42
+ return (typeof value.field === "string" &&
43
+ value.field.length > 0 &&
44
+ value.field.length <= 256 &&
45
+ !value.field.includes("\0") &&
46
+ typeof value.retained_hash === "string" &&
47
+ /^[a-f0-9]{64}$/u.test(value.retained_hash) &&
48
+ typeof value.discarded_hash === "string" &&
49
+ /^[a-f0-9]{64}$/u.test(value.discarded_hash));
50
+ }
51
+ /** Return whether a legacy item path is normalized, bounded, and item-scoped. */
52
+ function isLegacyItemPath(value, historyItemId) {
53
+ if (typeof value !== "string")
54
+ return false;
55
+ const normalized = path.posix.normalize(value);
56
+ return (value.length <= 4_096 &&
57
+ !value.includes("\\") &&
58
+ !value.includes("\0") &&
59
+ !path.posix.isAbsolute(value) &&
60
+ normalized === value &&
61
+ !normalized.startsWith("../") &&
62
+ (path.posix.basename(normalized) === `${historyItemId}.toon` ||
63
+ path.posix.basename(normalized) === `${historyItemId}.md`));
64
+ }
65
+ /** Return whether a preferred-era summary has one safe canonical identity. */
66
+ function hasLegacyReceiptIdentity(value, historyItemId) {
67
+ return (typeof value.receipt_id === "string" &&
68
+ isSafeReceiptId(value.receipt_id) &&
69
+ (value.preferred === "ours" || value.preferred === "theirs") &&
70
+ value.requested_preference === undefined &&
71
+ value.conflict_resolution === undefined &&
72
+ value.item_id === historyItemId &&
73
+ isLegacyItemPath(value.item_path, historyItemId));
74
+ }
75
+ /** Return whether preferred-era summary collections are dense and self-consistent. */
76
+ function hasLegacyReceiptCollections(value) {
77
+ const conflictFields = value.conflict_fields;
78
+ const fieldsFromTheirs = value.fields_from_theirs;
79
+ const unionFields = value.union_fields;
80
+ const decisions = value.decisions;
81
+ const decisionFields = Array.isArray(decisions)
82
+ ? new Set(decisions.flatMap((decision) => isLegacyDecision(decision) ? [decision.field] : []))
83
+ : new Set();
84
+ return (isFieldArray(conflictFields) &&
85
+ isFieldArray(fieldsFromTheirs) &&
86
+ isFieldArray(unionFields) &&
87
+ Array.isArray(decisions) &&
88
+ decisions.length > 0 &&
89
+ decisions.length <= 256 &&
90
+ Object.keys(decisions).length === decisions.length &&
91
+ decisions.every(isLegacyDecision) &&
92
+ decisionFields.size === decisions.length &&
93
+ conflictFields.length === decisionFields.size &&
94
+ conflictFields.every((field) => decisionFields.has(field)));
95
+ }
96
+ /** Return whether one summary is a complete, self-contained preferred-era receipt. */
97
+ export function isLegacyMergeReceiptSummary(value, historyItemId) {
98
+ return (hasLegacyReceiptIdentity(value, historyItemId) &&
99
+ hasLegacyReceiptCollections(value));
100
+ }
101
+ /** Return whether a summary matches the final clone-local-only schema before durable receipts. */
102
+ export function isPreDurableCloneLocalReceiptSummary(value, historyItemId) {
103
+ return (typeof value.receipt_id === "string" &&
104
+ isSafeReceiptId(value.receipt_id) &&
105
+ (value.preferred === "ours" || value.preferred === "theirs") &&
106
+ value.requested_preference === undefined &&
107
+ (value.conflict_resolution === "preferred_side" ||
108
+ value.conflict_resolution === "stable_value_order") &&
109
+ value.item_id === historyItemId &&
110
+ isLegacyItemPath(value.item_path, historyItemId) &&
111
+ hasLegacyReceiptCollections(value));
112
+ }
113
+ /** Return whether an extracted reference carried a validated pre-durable summary. */
114
+ export function isPreDurableDispositionEligibleReference(reference) {
115
+ return (reference[PRE_DURABLE_DISPOSITION_ELIGIBLE] === true);
116
+ }
117
+ /** Extract receipt ids and legacy compatibility disposition from one history entry. */
118
+ export function extractHistoryMergeReceiptReferences(value, historyItemId) {
119
+ if (!isRecord(value) || !isRecord(value.context))
120
+ return [];
121
+ const merge = value.context.merge;
122
+ if (!isRecord(merge) || !Array.isArray(merge.receipts))
123
+ return [];
124
+ return merge.receipts.flatMap((receipt) => {
125
+ if (!isRecord(receipt) ||
126
+ typeof receipt.receipt_id !== "string" ||
127
+ receipt.receipt_id.trim().length === 0) {
128
+ return [];
129
+ }
130
+ const reference = {
131
+ receiptId: receipt.receipt_id,
132
+ legacySummaryAccepted: isLegacyMergeReceiptSummary(receipt, historyItemId),
133
+ [PRE_DURABLE_DISPOSITION_ELIGIBLE]: isPreDurableCloneLocalReceiptSummary(receipt, historyItemId),
134
+ ...(typeof value.ts === "string" && isRfc3339DateTime(value.ts)
135
+ ? { eventTimestamp: value.ts }
136
+ : {}),
137
+ };
138
+ return [reference];
139
+ });
140
+ }
141
+ /** Extract validated explicit missing-receipt dispositions from one merge audit event. */
142
+ export function extractHistoryMergeReceiptDispositions(value, historyItemId, historyLine) {
143
+ if (!isRecord(value) || value.op !== "merge_reconcile")
144
+ return [];
145
+ if (!isRecord(value.context) || !isRecord(value.context.merge))
146
+ return [];
147
+ const dispositions = value.context.merge.missing_receipt_dispositions;
148
+ if (!Array.isArray(dispositions) || dispositions.length > 256)
149
+ return [];
150
+ return dispositions.flatMap((disposition) => {
151
+ if (!isRecord(disposition) ||
152
+ typeof disposition.receipt_id !== "string" ||
153
+ !isSafeReceiptId(disposition.receipt_id) ||
154
+ typeof disposition.original_history_line !== "number" ||
155
+ !Number.isSafeInteger(disposition.original_history_line) ||
156
+ disposition.original_history_line < 1 ||
157
+ typeof disposition.original_event_ts !== "string" ||
158
+ !isRfc3339DateTime(disposition.original_event_ts) ||
159
+ disposition.reason !== "legacy_clone_local_only") {
160
+ return [];
161
+ }
162
+ return [
163
+ {
164
+ itemId: historyItemId,
165
+ receiptId: disposition.receipt_id,
166
+ originalHistoryLine: disposition.original_history_line,
167
+ originalEventTimestamp: disposition.original_event_ts,
168
+ auditHistoryLine: historyLine,
169
+ reason: disposition.reason,
170
+ },
171
+ ];
172
+ });
173
+ }
174
+ /** Classify scanned references without treating complete legacy summaries as absent. */
175
+ export function classifyHistoryMergeReceiptReferences(references, availableReceiptIds, dispositions = []) {
176
+ const dispositionAuditLineByCoordinate = new Map();
177
+ for (const disposition of dispositions) {
178
+ const coordinate = `${disposition.itemId}\0${disposition.originalHistoryLine}\0${disposition.receiptId}\0${disposition.originalEventTimestamp}`;
179
+ dispositionAuditLineByCoordinate.set(coordinate, Math.max(dispositionAuditLineByCoordinate.get(coordinate) ?? 0, disposition.auditHistoryLine));
180
+ }
181
+ const dispositionAccepts = (reference) => isPreDurableDispositionEligibleReference(reference) &&
182
+ reference.eventTimestamp !== undefined &&
183
+ compareTimestampStrings(reference.eventTimestamp, DURABLE_MERGE_RECEIPT_INTRODUCED_AT) < 0 &&
184
+ (dispositionAuditLineByCoordinate.get(`${reference.itemId}\0${reference.line}\0${reference.receiptId}\0${reference.eventTimestamp}`) ?? 0) > reference.line;
185
+ const missing = references
186
+ .filter((reference) => !reference.legacySummaryAccepted &&
187
+ !availableReceiptIds.has(reference.receiptId) &&
188
+ !dispositionAccepts(reference))
189
+ .map((reference) => ({
190
+ item_id: reference.itemId,
191
+ history_line: reference.line,
192
+ ...(isSafeReceiptId(reference.receiptId)
193
+ ? { receipt_id: reference.receiptId }
194
+ : {
195
+ receipt_reference_hash: createHash("sha256")
196
+ .update(reference.receiptId)
197
+ .digest("hex"),
198
+ }),
199
+ }));
200
+ return {
201
+ missing,
202
+ acceptedLegacyCount: references.filter((reference) => reference.legacySummaryAccepted).length,
203
+ acceptedDispositionCount: references.filter(dispositionAccepts).length,
204
+ };
205
+ }
206
+ //# sourceMappingURL=merge-receipt-history.js.map
207
+ //# debugId=1e73338f-221a-580f-85a8-6f2a488fb89d
@@ -4,9 +4,10 @@
4
4
  * Reads bounded, privacy-safe provenance resolver outcomes for health checks.
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]="6efed404-acd2-5c3a-a008-856df67c8b77")}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]="cb3bf7ee-808f-5ff6-af84-edb034760c54")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
+ import { resealHistoryRewrite, verifyHistoryRecordHash, } from "../../core/history/history.js";
10
11
  const DEFAULT_PROVENANCE_HISTORY_BYTE_LIMIT = 8_388_608;
11
12
  const ATTEMPTED_PROVENANCE_OUTCOME_STATUSES = new Set(["resolved", "failed"]);
12
13
  const INVALID_PROVENANCE_VALUE_CLASSIFIERS = [
@@ -45,6 +46,8 @@ export function normalizeInvalidHistoryProvenance(entries) {
45
46
  : undefined;
46
47
  if (provenance === undefined)
47
48
  return entry;
49
+ if (!verifyHistoryRecordHash(entry).ok)
50
+ return entry;
48
51
  const retained = {};
49
52
  let eventChanged = false;
50
53
  for (const [dimension, observation] of Object.entries(provenance)) {
@@ -78,7 +81,10 @@ export function normalizeInvalidHistoryProvenance(entries) {
78
81
  else {
79
82
  next.agent_provenance = retained;
80
83
  }
81
- return next;
84
+ return resealHistoryRewrite(entry, next, {
85
+ retainPriorRecord: true,
86
+ retainPriorRecordHash: false,
87
+ });
82
88
  });
83
89
  return {
84
90
  entries: normalized,
@@ -274,4 +280,4 @@ export async function scanProvenanceResolverHealth(pmRoot, eventLimit = 10_000)
274
280
  };
275
281
  }
276
282
  //# sourceMappingURL=provenance-health.js.map
277
- //# debugId=6efed404-acd2-5c3a-a008-856df67c8b77
283
+ //# debugId=cb3bf7ee-808f-5ff6-af84-edb034760c54
@@ -6,7 +6,7 @@
6
6
  * orchestration module.
7
7
  */
8
8
 
9
- !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]="8bec3c39-b871-5c7c-907c-6da66274d9be")}catch(e){}}();
9
+ !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]="a2c96f3a-fa7a-538f-ae11-7b821e5b7ab2")}catch(e){}}();
10
10
  import { scanHistoryDrift } from "../../core/history/drift-scan.js";
11
11
  const DEFAULT_DIAGNOSTIC_LIMIT = 5;
12
12
  /** Build the validation warning and bounded evidence projection for history drift. */
@@ -14,7 +14,10 @@ export async function buildValidateHistoryDriftCheck(pmRoot, items, verboseDiagn
14
14
  const drift = await scanHistoryDrift(pmRoot, items);
15
15
  const warningCounts = [
16
16
  ["validate_history_drift_missing_streams", drift.missingStreams.length],
17
- ["validate_history_drift_unreadable_streams", drift.unreadableStreams.length],
17
+ [
18
+ "validate_history_drift_unreadable_streams",
19
+ drift.unreadableStreams.length,
20
+ ],
18
21
  ["validate_history_drift_hash_mismatches", drift.hashMismatches.length],
19
22
  ["validate_history_drift_chain_mismatches", drift.chainMismatches.length],
20
23
  ["validate_history_drift_version_skews", drift.versionSkews.length],
@@ -38,12 +41,20 @@ export async function buildValidateHistoryDriftCheck(pmRoot, items, verboseDiagn
38
41
  ? Number.POSITIVE_INFINITY
39
42
  : DEFAULT_DIAGNOSTIC_LIMIT;
40
43
  const driftedItems = drift.driftedItems.slice(0, diagnosticLimit);
44
+ const identityDiscontinuities = drift.identityDiscontinuities ?? [];
41
45
  return {
42
46
  check: {
43
47
  name: "history_drift",
44
- status: warnings.length === 0 ? "ok" : "warn",
45
- ok: warnings.length === 0,
48
+ status: identityDiscontinuities.length > 0
49
+ ? "error"
50
+ : warnings.length === 0
51
+ ? "ok"
52
+ : "warn",
53
+ ok: identityDiscontinuities.length === 0 && warnings.length === 0,
46
54
  details: {
55
+ identity_discontinuities: identityDiscontinuities.slice(0, diagnosticLimit),
56
+ identity_discontinuities_count: identityDiscontinuities.length,
57
+ identity_discontinuities_truncated: identityDiscontinuities.length > diagnosticLimit,
47
58
  checked_items: items.length,
48
59
  drifted_items_count: drift.driftedItems.length,
49
60
  drifted_items: driftedItems,
@@ -68,4 +79,4 @@ export async function buildValidateHistoryDriftCheck(pmRoot, items, verboseDiagn
68
79
  };
69
80
  }
70
81
  //# sourceMappingURL=validate-history-drift.js.map
71
- //# debugId=8bec3c39-b871-5c7c-907c-6da66274d9be
82
+ //# debugId=a2c96f3a-fa7a-538f-ae11-7b821e5b7ab2
@@ -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>;