@unbrained/pm-cli 2026.9.2 → 2026.9.4

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 (165) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +44 -0
  3. package/dist/cli/after-command-context-usage.js +16 -3
  4. package/dist/cli-bundle/bundle-manifest.json +151 -151
  5. package/dist/cli-bundle/chunks/chunk-6XSKPNCF.js +230 -0
  6. package/dist/cli-bundle/chunks/chunk-A24WAVE6.js +8 -0
  7. package/dist/cli-bundle/chunks/{chunk-TAG4VC22.js → chunk-HI6BHPCU.js} +27 -27
  8. package/dist/cli-bundle/chunks/{chunk-Y7VOMSZT.js → chunk-I2AS367G.js} +2 -2
  9. package/dist/cli-bundle/chunks/{chunk-X4RCGLTX.js → chunk-OGBVU67G.js} +5 -5
  10. package/dist/cli-bundle/chunks/{chunk-DTGWEL23.js → chunk-RI4XNOYS.js} +2 -2
  11. package/dist/cli-bundle/chunks/chunk-TXW6VL33.js +38 -0
  12. package/dist/cli-bundle/chunks/{chunk-FZ4Z2J4F.js → chunk-V72UV7QS.js} +76 -79
  13. package/dist/cli-bundle/chunks/chunk-VGLHECAP.js +9 -0
  14. package/dist/cli-bundle/chunks/{chunk-T6H5BZCP.js → chunk-X6CMGV6L.js} +2 -2
  15. package/dist/cli-bundle/chunks/{chunk-3WICXLVT.js → chunk-YW4QK2G7.js} +2 -2
  16. package/dist/cli-bundle/chunks/{register-list-query-XYNX4ASQ.js → register-list-query-Z5YYSJJG.js} +2 -2
  17. package/dist/cli-bundle/chunks/{register-mutation-WFQ7MJTX.js → register-mutation-ELSP6I4I.js} +2 -2
  18. package/dist/cli-bundle/chunks/{register-operations-JVTI7JPP.js → register-operations-OH7R3ZT4.js} +2 -2
  19. package/dist/cli-bundle/chunks/{register-setup-KVNC5KPL.js → register-setup-E2AE72QG.js} +2 -2
  20. package/dist/cli-bundle/focused-chunks/{chunk-MEASX544.js → chunk-25UJBH4M.js} +2 -2
  21. package/dist/cli-bundle/focused-chunks/{chunk-SVXJYD6G.js → chunk-3646BZ4W.js} +2 -2
  22. package/dist/cli-bundle/focused-chunks/chunk-4YRAVI43.js +12 -0
  23. package/dist/cli-bundle/focused-chunks/chunk-53IHPICX.js +3 -0
  24. package/dist/cli-bundle/focused-chunks/chunk-5P4HVOWG.js +176 -0
  25. package/dist/cli-bundle/focused-chunks/chunk-636VVQ7F.js +54 -0
  26. package/dist/cli-bundle/focused-chunks/{chunk-4O4CJAR6.js → chunk-6PWPQKDN.js} +2 -2
  27. package/dist/cli-bundle/focused-chunks/chunk-7N2TV7WZ.js +8 -0
  28. package/dist/cli-bundle/focused-chunks/chunk-AJR3OP2E.js +3 -0
  29. package/dist/cli-bundle/focused-chunks/chunk-B3A6MJYE.js +2 -0
  30. package/dist/cli-bundle/focused-chunks/chunk-BFDDJ2T2.js +2 -0
  31. package/dist/cli-bundle/focused-chunks/chunk-BHUIRZWQ.js +9 -0
  32. package/dist/cli-bundle/focused-chunks/chunk-JADHHPY6.js +6 -0
  33. package/dist/cli-bundle/focused-chunks/{chunk-KB5OFSFD.js → chunk-MHKUIPJW.js} +2 -2
  34. package/dist/cli-bundle/focused-chunks/chunk-NBMJD6MK.js +2 -0
  35. package/dist/cli-bundle/focused-chunks/chunk-NSKBLHVI.js +20 -0
  36. package/dist/cli-bundle/focused-chunks/{chunk-BEVHCEWG.js → chunk-P2GOAOQN.js} +2 -2
  37. package/dist/cli-bundle/focused-chunks/chunk-YARWJM2B.js +2 -0
  38. package/dist/cli-bundle/main.js +15 -15
  39. package/dist/cli-bundle/sdk-authoring.js +1 -1
  40. package/dist/cli-bundle/sdk-contracts.js +1 -1
  41. package/dist/cli-bundle/sdk-core.js +28 -31
  42. package/dist/cli-bundle/sdk-governance.js +1 -1
  43. package/dist/cli-bundle/sdk-graph.js +1 -1
  44. package/dist/cli-bundle/sdk-merge.js +43 -36
  45. package/dist/cli-bundle/sdk-query.js +1 -1
  46. package/dist/cli-bundle/sdk-runtime.js +1 -1
  47. package/dist/cli-bundle/sdk-testing.js +1 -1
  48. package/dist/cli-bundle/sdk.js +10 -10
  49. package/dist/core/diagnostics/remediation.js +4 -4
  50. package/dist/core/history/event-classification.d.ts +21 -0
  51. package/dist/core/history/event-classification.js +109 -0
  52. package/dist/core/history/event-index.d.ts +14 -3
  53. package/dist/core/history/event-index.js +543 -88
  54. package/dist/core/history/history.d.ts +37 -1
  55. package/dist/core/history/history.js +320 -71
  56. package/dist/core/history/replay.js +68 -34
  57. package/dist/core/history/workspace-history.js +7 -6
  58. package/dist/core/lock/lock.d.ts +32 -2
  59. package/dist/core/lock/lock.js +161 -20
  60. package/dist/core/output/output.js +31 -7
  61. package/dist/core/shared/author.d.ts +3 -1
  62. package/dist/core/shared/author.js +111 -23
  63. package/dist/core/shared/time.d.ts +2 -0
  64. package/dist/core/shared/time.js +8 -2
  65. package/dist/core/store/item-metadata-query-index.js +5 -5
  66. package/dist/sdk/context/recency.d.ts +9 -0
  67. package/dist/sdk/context/recency.js +34 -0
  68. package/dist/sdk/context/usage-egress.d.ts +9 -0
  69. package/dist/sdk/context/usage-egress.js +30 -0
  70. package/dist/sdk/context-intent-contracts.js +7 -3
  71. package/dist/sdk/context-relevance.d.ts +23 -0
  72. package/dist/sdk/context-relevance.js +94 -23
  73. package/dist/sdk/context-signal-store.d.ts +7 -3
  74. package/dist/sdk/context-signal-store.js +155 -42
  75. package/dist/sdk/context-usage.d.ts +54 -0
  76. package/dist/sdk/context-usage.js +245 -16
  77. package/dist/sdk/environment/agent-environment.d.ts +296 -0
  78. package/dist/sdk/environment/agent-environment.js +467 -0
  79. package/dist/sdk/environment/project-runtime-compatibility.d.ts +19 -1
  80. package/dist/sdk/environment/project-runtime-compatibility.js +118 -21
  81. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +14 -2
  82. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +14 -2
  83. package/dist/sdk/governance/health.js +13 -44
  84. package/dist/sdk/governance/merge-receipt-history.d.ts +62 -0
  85. package/dist/sdk/governance/merge-receipt-history.js +207 -0
  86. package/dist/sdk/governance/provenance-health.js +9 -3
  87. package/dist/sdk/history-compact.js +14 -5
  88. package/dist/sdk/history-redact.js +58 -23
  89. package/dist/sdk/history-repair.js +16 -6
  90. package/dist/sdk/index.d.ts +4 -0
  91. package/dist/sdk/index.js +6 -2
  92. package/dist/sdk/init.d.ts +2 -0
  93. package/dist/sdk/init.js +18 -9
  94. package/dist/sdk/merge/driver.d.ts +3 -1
  95. package/dist/sdk/merge/driver.js +9 -9
  96. package/dist/sdk/merge/index.d.ts +1 -1
  97. package/dist/sdk/merge/index.js +3 -3
  98. package/dist/sdk/merge/receipts.d.ts +17 -6
  99. package/dist/sdk/merge/receipts.js +246 -75
  100. package/dist/sdk/merge/reconcile.d.ts +9 -7
  101. package/dist/sdk/merge/reconcile.js +175 -12
  102. package/dist/sdk/merge/three-way.d.ts +22 -2
  103. package/dist/sdk/merge/three-way.js +92 -25
  104. package/dist/sdk/query/context.d.ts +3 -1
  105. package/dist/sdk/query/context.js +21 -9
  106. package/dist/sdk/query/next.js +18 -9
  107. package/dist/sdk/runtime-input.d.ts +2 -0
  108. package/dist/sdk/runtime-input.js +25 -2
  109. package/dist/sdk/runtime-primitives.d.ts +2 -2
  110. package/dist/sdk/runtime-primitives.js +4 -4
  111. package/dist/sdk/runtime.d.ts +1 -0
  112. package/dist/sdk/runtime.js +17 -26
  113. package/dist/types.d.ts +27 -0
  114. package/dist/types.js +2 -2
  115. package/docs/AGENT_ENVIRONMENTS.md +47 -0
  116. package/docs/AGENT_PROVENANCE_ADR.md +17 -2
  117. package/docs/CONTEXT_INTEGRITY_CONTRACTS.md +38 -1
  118. package/docs/CONTEXT_RELEVANCE.md +44 -1
  119. package/docs/MERGE_SAFETY.md +119 -23
  120. package/docs/PERFORMANCE.md +6 -3
  121. package/docs/README.md +1 -0
  122. package/docs/READ_OUTPUT_CONTRACTS.md +9 -1
  123. package/docs/SDK.md +11 -8
  124. package/docs/SDK_CONTEXT.md +7 -0
  125. package/docs/SDK_CONTEXT_EVIDENCE_CONTRACTS.md +24 -2
  126. package/docs/SDK_RUNTIME_BOUNDARIES.md +17 -1
  127. package/docs/examples/sdk-agent-environment/README.md +14 -0
  128. package/docs/examples/sdk-agent-environment/package.json +8 -0
  129. package/docs/examples/sdk-agent-environment/run-agent-environment.mjs +154 -0
  130. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +5 -3
  131. package/marketplace.json +2 -2
  132. package/package.json +5 -5
  133. package/packages/pm-beads/package.json +1 -1
  134. package/packages/pm-calendar/package.json +1 -1
  135. package/packages/pm-command-kit/package.json +1 -1
  136. package/packages/pm-digital-twin/package.json +1 -1
  137. package/packages/pm-governance-audit/package.json +1 -1
  138. package/packages/pm-guide-shell/package.json +1 -1
  139. package/packages/pm-kanban/package.json +1 -1
  140. package/packages/pm-lifecycle-hooks/package.json +1 -1
  141. package/packages/pm-linked-test-adapters/package.json +1 -1
  142. package/packages/pm-search-advanced/package.json +1 -1
  143. package/packages/pm-templates/package.json +1 -1
  144. package/packages/pm-todos/package.json +1 -1
  145. package/packages/pm-vcs/package.json +1 -1
  146. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  147. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  148. package/sdk/public-surface.json +773 -46
  149. package/dist/cli-bundle/chunks/chunk-GOACULJW.js +0 -13
  150. package/dist/cli-bundle/chunks/chunk-NOPL37X4.js +0 -205
  151. package/dist/cli-bundle/chunks/chunk-UDW64J2W.js +0 -8
  152. package/dist/cli-bundle/chunks/chunk-ZLJIFSOE.js +0 -35
  153. package/dist/cli-bundle/focused-chunks/chunk-242AXYB2.js +0 -2
  154. package/dist/cli-bundle/focused-chunks/chunk-2FEZ5SKM.js +0 -3
  155. package/dist/cli-bundle/focused-chunks/chunk-6GCRSLPG.js +0 -2
  156. package/dist/cli-bundle/focused-chunks/chunk-7VATS5QY.js +0 -16
  157. package/dist/cli-bundle/focused-chunks/chunk-JEFKLWMM.js +0 -2
  158. package/dist/cli-bundle/focused-chunks/chunk-MKHG3T76.js +0 -20
  159. package/dist/cli-bundle/focused-chunks/chunk-O67VDLOT.js +0 -51
  160. package/dist/cli-bundle/focused-chunks/chunk-PF3E6Q36.js +0 -8
  161. package/dist/cli-bundle/focused-chunks/chunk-QDFJIRKN.js +0 -4
  162. package/dist/cli-bundle/focused-chunks/chunk-RMRCQPWU.js +0 -2
  163. package/dist/cli-bundle/focused-chunks/chunk-S4U5CN5Q.js +0 -2
  164. package/dist/cli-bundle/focused-chunks/chunk-T2LXXSOD.js +0 -158
  165. package/dist/cli-bundle/focused-chunks/chunk-Z2USIBR2.js +0 -5
@@ -5,7 +5,7 @@
5
5
  * leaving diagnosis reads available.
6
6
  */
7
7
 
8
- !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]="962636b0-ed3b-5ad0-ae0c-904435025986")}catch(e){}}();
8
+ !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]="f9737b75-b285-5fe9-a9ce-63e7c07626cb")}catch(e){}}();
9
9
  import fs from "node:fs";
10
10
  import path from "node:path";
11
11
  import { EXIT_CODE } from "../../core/shared/constants.js";
@@ -80,6 +80,8 @@ const GLOBAL_VALUE_FLAGS = new Set([
80
80
  "--pm-path",
81
81
  ]);
82
82
  const VERSION_PATTERN = /\b(\d{4})\.(\d{1,2})\.(\d{1,2})(?:-(\d+))?\b/u;
83
+ /** First pm release whose history writer and reader support item-hash epoch 3. */
84
+ export const HISTORY_ITEM_HASH_VERSION_3_INTRODUCED_IN = "2026.8.31";
83
85
  /** Return whether an invocation includes one of the exact mutation switches. */
84
86
  function hasAnyToken(argv, tokens) {
85
87
  return argv.some((token) => tokens.includes(token.split("=", 1)[0]));
@@ -194,6 +196,21 @@ export function comparePmDateVersions(left, right) {
194
196
  }
195
197
  return 0;
196
198
  }
199
+ /** Resolve the item-hash epoch written by a known pm runtime release. */
200
+ export function historyItemHashVersionForRuntime(version) {
201
+ return comparePmDateVersions(version, HISTORY_ITEM_HASH_VERSION_3_INTRODUCED_IN) !== -1
202
+ ? 3
203
+ : 2;
204
+ }
205
+ /** Find the oldest declaration that cannot select a reader for the executing writer epoch. */
206
+ function findIncompatibleHistoryEpochPin(pins, writerItemHashVersion) {
207
+ if (writerItemHashVersion !== 3)
208
+ return undefined;
209
+ return pins
210
+ .filter((pin) => pin.history_epoch_compatible === false)
211
+ .map((pin) => ({ ...pin, declaration: pin.declaration ?? pin.version }))
212
+ .sort((left, right) => comparePmDateVersions(left.version, right.version))[0];
213
+ }
197
214
  /** Read one optional JSON object without turning absence or corruption into startup failure. */
198
215
  function readJsonRecord(filePath) {
199
216
  try {
@@ -208,27 +225,61 @@ function readJsonRecord(filePath) {
208
225
  return null;
209
226
  }
210
227
  }
211
- /** Extract the highest explicit lower-bound pm date version from dependency declarations. */
212
- function dependencyPin(packageJson) {
213
- const versions = [];
214
- for (const field of [
228
+ /** Extract explicit comparator and hyphen upper bounds from one range branch. */
229
+ function rangeUpperBounds(alternative) {
230
+ const comparators = [
231
+ ...alternative.matchAll(/(<=|<)\s*v?(\d{4}\.\d{1,2}\.\d{1,2}(?:-\d+)?)/gu),
232
+ ].map((match) => ({ inclusive: match[1] === "<=", version: match[2] }));
233
+ const hyphen = alternative.match(/\b\d{4}\.\d{1,2}\.\d{1,2}(?:-\d+)?\s+-\s+v?(\d{4}\.\d{1,2}\.\d{1,2}(?:-\d+)?)/u);
234
+ return hyphen
235
+ ? [...comparators, { inclusive: true, version: hyphen[1] }]
236
+ : comparators;
237
+ }
238
+ /** Classify whether a range is bounded and can select an epoch-3 reader. */
239
+ function analyzeHistoryEpochRange(specification) {
240
+ const alternativeBounds = specification
241
+ .split("||")
242
+ .map((alternative) => rangeUpperBounds(alternative));
243
+ return {
244
+ bounded: alternativeBounds.some((bounds) => bounds.length > 0),
245
+ compatible: alternativeBounds.some((bounds) => bounds.every((bound) => {
246
+ const comparison = comparePmDateVersions(HISTORY_ITEM_HASH_VERSION_3_INTRODUCED_IN, bound.version);
247
+ return (comparison !== null &&
248
+ (bound.inclusive ? comparison !== 1 : comparison === -1));
249
+ })),
250
+ };
251
+ }
252
+ /** Extract every supported pm declaration without letting one section hide another. */
253
+ function dependencyPins(packageJson) {
254
+ return [
215
255
  "dependencies",
216
256
  "devDependencies",
217
257
  "optionalDependencies",
218
258
  "peerDependencies",
219
- ]) {
259
+ ].flatMap((field) => {
220
260
  const dependencies = packageJson[field];
221
261
  if (typeof dependencies !== "object" || dependencies === null)
222
- continue;
262
+ return [];
223
263
  const value = dependencies[PACKAGE_NAME];
224
264
  const specification = typeof value === "string" ? value.trim() : "";
225
265
  const version = /^[<!]/u.test(specification)
226
266
  ? undefined
227
267
  : specification.match(VERSION_PATTERN)?.[0];
228
- if (version)
229
- versions.push(version);
230
- }
231
- return versions.sort((left, right) => comparePmDateVersions(right, left))[0];
268
+ if (!version)
269
+ return [];
270
+ const exact = /^(?:=|v)?\d{4}\.\d{1,2}\.\d{1,2}(?:-\d+)?$/u.test(specification);
271
+ const range = analyzeHistoryEpochRange(specification);
272
+ return [
273
+ {
274
+ version,
275
+ constraint: exact ? "exact" : range.bounded ? "range" : "minimum",
276
+ ...(exact ? {} : { declaration: specification }),
277
+ history_epoch_compatible: exact
278
+ ? comparePmDateVersions(version, HISTORY_ITEM_HASH_VERSION_3_INTRODUCED_IN) !== -1
279
+ : range.compatible,
280
+ },
281
+ ];
282
+ });
232
283
  }
233
284
  /** Read npm's exact installed package coordinate from package-lock.json. */
234
285
  function packageLockPin(projectRoot) {
@@ -273,23 +324,42 @@ function textLockPin(projectRoot, file) {
273
324
  export function discoverProjectRuntimeVersionPins(projectRoot) {
274
325
  const pins = [];
275
326
  const projectPackage = readJsonRecord(path.join(projectRoot, "package.json"));
276
- const declared = projectPackage ? dependencyPin(projectPackage) : undefined;
277
- if (declared)
278
- pins.push({ version: declared, source: "package.json" });
327
+ if (projectPackage) {
328
+ pins.push(...dependencyPins(projectPackage).map((pin) => ({
329
+ ...pin,
330
+ source: "package.json",
331
+ })));
332
+ }
279
333
  const installedPackage = readJsonRecord(path.join(projectRoot, "node_modules", "@unbrained", "pm-cli", "package.json"));
280
334
  const installedVersion = installedPackage?.version;
281
335
  if (typeof installedVersion === "string" &&
282
336
  parseDateVersion(installedVersion)) {
283
- pins.push({ version: installedVersion, source: "installed-package" });
337
+ pins.push({
338
+ version: installedVersion,
339
+ source: "installed-package",
340
+ constraint: "exact",
341
+ history_epoch_compatible: historyItemHashVersionForRuntime(installedVersion) === 3,
342
+ });
284
343
  }
285
344
  const packageLockVersion = packageLockPin(projectRoot);
286
345
  if (packageLockVersion && parseDateVersion(packageLockVersion)) {
287
- pins.push({ version: packageLockVersion, source: "package-lock.json" });
346
+ pins.push({
347
+ version: packageLockVersion,
348
+ source: "package-lock.json",
349
+ constraint: "exact",
350
+ history_epoch_compatible: historyItemHashVersionForRuntime(packageLockVersion) === 3,
351
+ });
288
352
  }
289
353
  for (const file of ["pnpm-lock.yaml", "yarn.lock"]) {
290
354
  const version = textLockPin(projectRoot, file);
291
- if (version)
292
- pins.push({ version, source: file });
355
+ if (version) {
356
+ pins.push({
357
+ version,
358
+ source: file,
359
+ constraint: "exact",
360
+ history_epoch_compatible: historyItemHashVersionForRuntime(version) === 3,
361
+ });
362
+ }
293
363
  }
294
364
  return pins;
295
365
  }
@@ -339,6 +409,9 @@ export function inspectProjectRuntimeCompatibility(options) {
339
409
  const newest = pins[0];
340
410
  const stale = newest !== undefined &&
341
411
  comparePmDateVersions(options.executingVersion, newest.version) === -1;
412
+ const writerItemHashVersion = historyItemHashVersionForRuntime(options.executingVersion);
413
+ const incompatibleEpochPin = findIncompatibleHistoryEpochPin(pins, writerItemHashVersion);
414
+ const historyEpochIncompatible = mutating && incompatibleEpochPin !== undefined;
342
415
  const warning = stale && !mutating
343
416
  ? {
344
417
  code: "project_runtime_stale_read",
@@ -353,7 +426,9 @@ export function inspectProjectRuntimeCompatibility(options) {
353
426
  }
354
427
  : undefined;
355
428
  return {
356
- compatible: !mutating || !stale || options.allowStale === true,
429
+ compatible: !mutating ||
430
+ (!stale && !historyEpochIncompatible) ||
431
+ options.allowStale === true,
357
432
  executing_version: options.executingVersion,
358
433
  ...(newest
359
434
  ? { project_version: newest.version, source: newest.source }
@@ -361,8 +436,18 @@ export function inspectProjectRuntimeCompatibility(options) {
361
436
  ...(command ? { command } : {}),
362
437
  mutating,
363
438
  stale,
439
+ history_epoch_incompatible: historyEpochIncompatible,
440
+ writer_item_hash_version: writerItemHashVersion,
441
+ ...(incompatibleEpochPin
442
+ ? {
443
+ incompatible_project_version: incompatibleEpochPin.declaration,
444
+ incompatible_source: incompatibleEpochPin.source,
445
+ }
446
+ : {}),
364
447
  ...(warning ? { warning } : {}),
365
- override_applied: stale && mutating && options.allowStale === true,
448
+ override_applied: mutating &&
449
+ (stale || historyEpochIncompatible) &&
450
+ options.allowStale === true,
366
451
  };
367
452
  }
368
453
  /** Refuse stale mutations with a stable SDK error and package-neutral recovery. */
@@ -370,6 +455,18 @@ export function assertProjectRuntimeCompatibility(options) {
370
455
  const result = inspectProjectRuntimeCompatibility(options);
371
456
  if (result.compatible)
372
457
  return result;
458
+ if (result.history_epoch_incompatible) {
459
+ throw new PmCliError(`pm ${result.executing_version} cannot write item-hash epoch ${result.writer_item_hash_version} into a project pinned to pm ${result.incompatible_project_version}.`, EXIT_CODE.CONFLICT, {
460
+ code: "project_runtime_history_epoch_incompatible",
461
+ reason: result.incompatible_source,
462
+ why: `The pinned runtime cannot read item_hash_version ${result.writer_item_hash_version}; allowing the write would break its health and validation gates.`,
463
+ nextSteps: [
464
+ `Upgrade the project's ${PACKAGE_NAME} pin to ${HISTORY_ITEM_HASH_VERSION_3_INTRODUCED_IN} or newer before mutating tracker history.`,
465
+ "For an intentional coordinated migration only, set PM_ALLOW_STALE_CLI=1 for this invocation and record why.",
466
+ "Read-only commands remain available without an override.",
467
+ ],
468
+ });
469
+ }
373
470
  throw new PmCliError(`pm ${result.executing_version} cannot mutate a project pinned to newer pm ${result.project_version}.`, EXIT_CODE.CONFLICT, {
374
471
  code: "project_runtime_stale_mutation",
375
472
  reason: result.source,
@@ -382,4 +479,4 @@ export function assertProjectRuntimeCompatibility(options) {
382
479
  });
383
480
  }
384
481
  //# sourceMappingURL=project-runtime-compatibility.js.map
385
- //# debugId=962636b0-ed3b-5ad0-ae0c-904435025986
482
+ //# debugId=f9737b75-b285-5fe9-a9ce-63e7c07626cb
@@ -1,6 +1,6 @@
1
1
  /** Generated partition 1 of the exhaustive error-code catalog. */
2
2
 
3
- !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]="4734edf6-c174-50d0-b4e9-1003bc8a20bf")}catch(e){}}();
3
+ !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]="f9059953-1d3c-5c1c-b739-4ad6cc8815a3")}catch(e){}}();
4
4
  export const PM_ERROR_CODE_CATALOG_PART_1 = [
5
5
  {
6
6
  code: "acceptance_criteria_mutation_conflict",
@@ -1271,6 +1271,18 @@ export const PM_ERROR_CODE_CATALOG_PART_1 = [
1271
1271
  canonical_code: "history_target_out_of_range",
1272
1272
  aliases: [],
1273
1273
  },
1274
+ {
1275
+ code: "history_timestamp_invalid",
1276
+ meaning: "History timestamp invalid condition.",
1277
+ stability: "provisional",
1278
+ exit_code: 1,
1279
+ class: "generic_failure",
1280
+ recovery: "Inspect the structured error guidance and retry the suggested command.",
1281
+ sources: ["core/history/event-index.ts", "core/history/history.ts"],
1282
+ emitting_commands: ["*"],
1283
+ canonical_code: "history_timestamp_invalid",
1284
+ aliases: [],
1285
+ },
1274
1286
  {
1275
1287
  code: "history_unknown_author_events",
1276
1288
  meaning: "History unknown author events condition.",
@@ -2162,4 +2174,4 @@ export const PM_ERROR_CODE_CATALOG_PART_1 = [
2162
2174
  },
2163
2175
  ];
2164
2176
  //# sourceMappingURL=generated-error-code-catalog-part-1.js.map
2165
- //# debugId=4734edf6-c174-50d0-b4e9-1003bc8a20bf
2177
+ //# debugId=f9059953-1d3c-5c1c-b739-4ad6cc8815a3
@@ -1,6 +1,6 @@
1
1
  /** Generated partition 2 of the exhaustive error-code catalog. */
2
2
 
3
- !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]="41e6f81d-ccb5-546c-9b26-3b78027528b5")}catch(e){}}();
3
+ !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]="f1a77960-6191-5e11-9622-4250be7b0e89")}catch(e){}}();
4
4
  export const PM_ERROR_CODE_CATALOG_PART_2 = [
5
5
  {
6
6
  code: "missing_destination",
@@ -487,6 +487,18 @@ export const PM_ERROR_CODE_CATALOG_PART_2 = [
487
487
  canonical_code: "profile_title_empty",
488
488
  aliases: [],
489
489
  },
490
+ {
491
+ code: "project_runtime_history_epoch_incompatible",
492
+ meaning: "Project runtime history epoch incompatible condition.",
493
+ stability: "provisional",
494
+ exit_code: 4,
495
+ class: "conflict",
496
+ recovery: "Inspect the structured error guidance and retry the suggested command.",
497
+ sources: ["sdk/environment/project-runtime-compatibility.ts"],
498
+ emitting_commands: ["*"],
499
+ canonical_code: "project_runtime_history_epoch_incompatible",
500
+ aliases: [],
501
+ },
490
502
  {
491
503
  code: "project_runtime_stale_mutation",
492
504
  meaning: "Project runtime stale mutation condition.",
@@ -2174,4 +2186,4 @@ export const PM_ERROR_CODE_CATALOG_PART_2 = [
2174
2186
  },
2175
2187
  ];
2176
2188
  //# sourceMappingURL=generated-error-code-catalog-part-2.js.map
2177
- //# debugId=41e6f81d-ccb5-546c-9b26-3b78027528b5
2189
+ //# debugId=f1a77960-6191-5e11-9622-4250be7b0e89
@@ -4,7 +4,7 @@
4
4
  * Implements the pm health 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]="f27cb24d-f2c8-5034-b655-84c577de7a16")}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]="9f0077a4-4f0a-540f-9951-2e8a640629c9")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import { assertInitializedTracker } from "../environment/tracker-preflight.js";
@@ -28,7 +28,6 @@ import { EXIT_CODE, PM_CORE_REQUIRED_SUBDIRS, TYPE_TO_FOLDER, } from "../../core
28
28
  import { findFirstMergeConflictMarker } from "../../core/shared/conflict-markers.js";
29
29
  import { PmCliError } from "../../core/shared/errors.js";
30
30
  import { toNonEmptyStringOrUndefined } from "../../core/shared/primitives.js";
31
- import { sha256Hex } from "../../core/shared/serialization.js";
32
31
  import { nowIso } from "../../core/shared/time.js";
33
32
  import { parseItemDocument } from "../../core/item/item-format.js";
34
33
  import { effectiveItemFormatVersion, scanItemFormatVersions, } from "../../core/item/item-format-version.js";
@@ -47,7 +46,8 @@ import { buildCapabilityContractMetadata, buildRegistrationCollisionRemediation,
47
46
  import { scanStaleInProgressItems, } from "./stale-work.js";
48
47
  import { scanTrackedRuntimeCache } from "./tracked-runtime-cache.js";
49
48
  import { auditMergeDriverConfiguration, findGitWorkspaceRoot, } from "../merge/install.js";
50
- import { inspectMergeReceiptEvidence, isSafeReceiptId, partitionMergeReceipts, } from "../merge/receipts.js";
49
+ import { inspectMergeReceiptEvidence, partitionMergeReceipts, } from "../merge/receipts.js";
50
+ import { classifyHistoryMergeReceiptReferences, extractHistoryMergeReceiptDispositions, extractHistoryMergeReceiptReferences, } from "./merge-receipt-history.js";
51
51
  import { runHistoryRepair } from "../history-repair.js";
52
52
  import { resolveWorkspaceRelationshipKindRegistry } from "../graph/assembly.js";
53
53
  import { analyzeHierarchyIntegrity, } from "../graph/hierarchy-integrity.js";
@@ -279,41 +279,13 @@ async function scanItemIntegrity(pmRoot, typeToFolder, schema) {
279
279
  }
280
280
  return { paths, unreadable, conflictMarkers, parseFailures, formatVersions };
281
281
  }
282
- function mergeReceiptIdsFromHistoryEntry(value) {
283
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
284
- return [];
285
- }
286
- const context = value.context;
287
- if (typeof context !== "object" ||
288
- context === null ||
289
- Array.isArray(context)) {
290
- return [];
291
- }
292
- const merge = context.merge;
293
- if (typeof merge !== "object" || merge === null || Array.isArray(merge)) {
294
- return [];
295
- }
296
- const receipts = merge.receipts;
297
- if (!Array.isArray(receipts))
298
- return [];
299
- return receipts.flatMap((receipt) => {
300
- if (typeof receipt !== "object" ||
301
- receipt === null ||
302
- Array.isArray(receipt)) {
303
- return [];
304
- }
305
- const receiptId = receipt.receipt_id;
306
- return typeof receiptId === "string" && receiptId.length > 0
307
- ? [receiptId]
308
- : [];
309
- });
310
- }
311
282
  async function scanHistoryIntegrity(pmRoot) {
312
283
  const historyDir = path.join(pmRoot, "history");
313
284
  const unreadable = [];
314
285
  const conflictMarkers = [];
315
286
  const invalidJson = [];
316
287
  const mergeReceiptReferences = [];
288
+ const mergeReceiptDispositions = [];
317
289
  let files = [];
318
290
  try {
319
291
  files = (await fs.readdir(historyDir))
@@ -346,11 +318,12 @@ async function scanHistoryIntegrity(pmRoot) {
346
318
  return;
347
319
  try {
348
320
  const parsed = JSON.parse(line);
349
- mergeReceiptReferences.push(...mergeReceiptIdsFromHistoryEntry(parsed).map((receiptId) => ({
321
+ mergeReceiptReferences.push(...extractHistoryMergeReceiptReferences(parsed, itemId).map((reference) => ({
350
322
  itemId,
351
323
  line: index + 1,
352
- receiptId,
324
+ ...reference,
353
325
  })));
326
+ mergeReceiptDispositions.push(...extractHistoryMergeReceiptDispositions(parsed, itemId, index + 1));
354
327
  }
355
328
  catch {
356
329
  invalidJson.push({ id: itemId, line: index + 1 });
@@ -363,6 +336,7 @@ async function scanHistoryIntegrity(pmRoot) {
363
336
  conflictMarkers,
364
337
  invalidJson,
365
338
  mergeReceiptReferences,
339
+ mergeReceiptDispositions,
366
340
  };
367
341
  }
368
342
  function buildHierarchyIntegrityWarnings(analysis) {
@@ -405,15 +379,8 @@ async function buildIntegrityCheck(pmRoot, typeToFolder, schema, requireMergeDri
405
379
  pmRoot,
406
380
  });
407
381
  const availableMergeReceiptIds = new Set(mergeReceiptEvidence.receipts.map((receipt) => receipt.id));
408
- const missingMergeReceiptReferences = historyScan.mergeReceiptReferences
409
- .filter((reference) => !availableMergeReceiptIds.has(reference.receiptId))
410
- .map((reference) => ({
411
- item_id: reference.itemId,
412
- history_line: reference.line,
413
- ...(isSafeReceiptId(reference.receiptId)
414
- ? { receipt_id: reference.receiptId }
415
- : { receipt_reference_hash: sha256Hex(reference.receiptId) }),
416
- }));
382
+ const historyReceiptClassification = classifyHistoryMergeReceiptReferences(historyScan.mergeReceiptReferences, availableMergeReceiptIds, historyScan.mergeReceiptDispositions);
383
+ const missingMergeReceiptReferences = historyReceiptClassification.missing;
417
384
  const pendingMergeReceipts = mergeReceiptEvidence.receipts.filter((receipt) => receipt.state === "pending");
418
385
  const { pendingDecisions: pendingMergeDecisions, lossless: losslessMergeReceipts, } = partitionMergeReceipts(pendingMergeReceipts);
419
386
  const mergeDriverInstallationMissing = mergeDriverAudit?.status === "missing" &&
@@ -483,6 +450,8 @@ async function buildIntegrityCheck(pmRoot, typeToFolder, schema, requireMergeDri
483
450
  lossless_merge_receipts: losslessMergeReceipts.length,
484
451
  invalid_merge_receipt_evidence: mergeReceiptEvidence.invalid_evidence_count,
485
452
  missing_merge_receipt_history_references: missingMergeReceiptReferences.length,
453
+ accepted_legacy_merge_receipt_references: historyReceiptClassification.acceptedLegacyCount,
454
+ accepted_missing_merge_receipt_dispositions: historyReceiptClassification.acceptedDispositionCount,
486
455
  },
487
456
  item_unreadable: itemScan.unreadable,
488
457
  item_conflict_markers: itemScan.conflictMarkers,
@@ -2375,4 +2344,4 @@ export const _testOnlyHealthCommand = {
2375
2344
  warningCode,
2376
2345
  };
2377
2346
  //# sourceMappingURL=health.js.map
2378
- //# debugId=f27cb24d-f2c8-5034-b655-84c577de7a16
2347
+ //# debugId=9f0077a4-4f0a-540f-9951-2e8a640629c9
@@ -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;