@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,8 +4,9 @@
4
4
  * Implements append-only history and replay behavior for Replay.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ce8dfbdf-8471-5843-8179-5608140330e1")}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]="b0230e20-93c4-531c-9cc1-85f85c1def7a")}catch(e){}}();
8
8
  import jsonPatch from "fast-json-patch";
9
+ import { findHistoryIdentityDiscontinuities } from "./identity.js";
9
10
  import { ITEM_METADATA_KEY_ORDER } from "../shared/constants.js";
10
11
  import { canonicalDocument } from "../item/item-format.js";
11
12
  import { toItemRecord } from "../item/item-record.js";
@@ -190,13 +191,12 @@ function assertHistoryEntryIntegrity(entry, index) {
190
191
  throw new TypeError(`${integrityError}:entry_${index + 1}`);
191
192
  }
192
193
  }
193
- /** Deterministically verify a history chain: each entry's before_hash must equal the prior replayed after_hash, the patch must strictly apply, and the recorded after_hash must equal the replayed result. */
194
194
  /** Verify a chain and report the explicit or auto-detected item hash epoch. */
195
195
  export function verifyHistoryChainWithVersion(entries) {
196
196
  let replay = cloneEmptyReplayDocument();
197
197
  let detectedVersion;
198
198
  let authoritativeExplicitVersion;
199
- const errors = [];
199
+ const errors = findHistoryIdentityDiscontinuities(entries).map((finding) => `verify_failed:duplicate_create:entry_${finding.repeated_create_index}:prior_${finding.prior_genesis_index}`);
200
200
  for (let index = 0; index < entries.length; index += 1) {
201
201
  const entry = entries[index];
202
202
  const explicitVersion = entry.item_hash_version;
@@ -437,4 +437,4 @@ export function historyEntriesToRaw(entries) {
437
437
  return `${entries.map((entry) => JSON.stringify(entry)).join("\n")}\n`;
438
438
  }
439
439
  //# sourceMappingURL=replay.js.map
440
- //# debugId=ce8dfbdf-8471-5843-8179-5608140330e1
440
+ //# debugId=b0230e20-93c4-531c-9cc1-85f85c1def7a
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @module core/history/version-address
3
+ * Stable ordinal addressing for streams whose retained prefix is a checkpoint.
4
+ */
5
+ import type { HistoryEntry } from "../../types/index.js";
6
+ /**
7
+ * Return the number added to physical one-based positions to obtain durable
8
+ * version addresses. Legacy checkpoints cannot prove their original ordinal;
9
+ * refusing them prevents silently selecting a different historical state.
10
+ */
11
+ export declare function historyVersionOffset(history: readonly HistoryEntry[], allowUnknown: true): number | null;
12
+ /** Resolve a required durable offset, refusing ambiguous legacy checkpoints. */
13
+ export declare function historyVersionOffset(history: readonly HistoryEntry[], allowUnknown?: false): number;
@@ -0,0 +1,33 @@
1
+
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7ad4e6c0-7545-51cb-9af7-4ba1ad4c4758")}catch(e){}}();
3
+ import { EXIT_CODE } from "../shared/constants.js";
4
+ import { PmCliError } from "../shared/errors.js";
5
+ /** Resolve the checkpoint offset with an explicit opt-in for unknown legacy addresses. */
6
+ export function historyVersionOffset(history, allowUnknown = false) {
7
+ const first = history[0];
8
+ if (first?.op !== "history_compact_baseline")
9
+ return 0;
10
+ const receipt = first.context?.history_compaction;
11
+ const offset = typeof receipt === "object" &&
12
+ receipt !== null &&
13
+ "version_offset" in receipt
14
+ ? receipt.version_offset
15
+ : undefined;
16
+ if (typeof offset === "number" &&
17
+ Number.isSafeInteger(offset) &&
18
+ offset >= 0 &&
19
+ Number.isSafeInteger(offset + history.length)) {
20
+ return offset;
21
+ }
22
+ if (allowUnknown)
23
+ return null;
24
+ throw new PmCliError("This compacted stream has no trustworthy version offset; numeric history addresses are unavailable.", EXIT_CODE.USAGE, {
25
+ code: "history_version_mapping_unavailable",
26
+ required: "Use a retained timestamp or recover the pre-compaction stream from version control.",
27
+ nextSteps: [
28
+ "Run pm history <id> --full to inspect the retained timestamps and checkpoint evidence.",
29
+ ],
30
+ });
31
+ }
32
+ //# sourceMappingURL=version-address.js.map
33
+ //# debugId=7ad4e6c0-7545-51cb-9af7-4ba1ad4c4758
@@ -1,5 +1,8 @@
1
1
  import type { RuntimeStatusRegistry } from "../schema/runtime-schema.js";
2
2
  import type { ItemMetadata, ItemStatus } from "../../types/index.js";
3
+ import { type ItemTypeRegistry } from "./type-registry.js";
4
+ /** Resolve dispatch semantics once for SDK callers, honoring custom and extension type aliases before built-in defaults. */
5
+ export declare function resolveItemExecutionRole(type: string, registry?: ItemTypeRegistry): "agent" | "human" | "gate";
3
6
  /** Built-in ordering kinds that must remain reachable by blocker resolution. */
4
7
  export declare const ACTIONABILITY_ORDERING_KINDS: readonly string[];
5
8
  /** Collects the blocker item ids declared by an item: the legacy scalar `blocked_by` field plus every `blocked_by` dependency edge. Ids are trimmed, de-duplicated, and returned in stable lexicographic order. This is the single source of truth for "what must close before this item can proceed", shared by `pm next` readiness classification and the close-time auto-unblock sweep. */
@@ -54,11 +57,28 @@ export interface ActionabilityReport {
54
57
  ready: ActionableEntry[];
55
58
  /** Active leaves with at least one open blocker — waiting to become ready. */
56
59
  blocked: ActionableEntry[];
60
+ /** Active containers with unresolved descendants, including their blocker evidence. */
61
+ containers: ActionableEntry[];
62
+ /** Unblocked leaf work that requires a human decision. */
63
+ decisions: ActionableEntry[];
64
+ /** Unblocked leaf outcome gates held out of automatic dispatch. */
65
+ gates: ActionableEntry[];
57
66
  /** Active candidates considered before the leaf/blocker split. */
58
67
  active_count: number;
59
68
  /** Active candidates skipped because they still have open descendants. */
60
69
  container_count: number;
61
70
  }
71
+ /** Explicit dispatch opt-ins; dependency and lifecycle blocking always remain enforced. */
72
+ export interface ActionabilitySelectionOptions {
73
+ /** Include human decision work in the executable selection. */
74
+ includeDecisions?: boolean;
75
+ /** Include outcome gates in the executable selection. */
76
+ includeGates?: boolean;
77
+ /** Include containers whose descendants are still unfinished. */
78
+ includeContainers?: boolean;
79
+ }
80
+ /** Select dispatch candidates from a classified report while retaining held-out worklists. Ownership and ranking remain caller responsibilities. */
81
+ export declare function selectActionableEntries(report: ActionabilityReport, statusRegistry: RuntimeStatusRegistry, options?: ActionabilitySelectionOptions, typeRegistry?: ItemTypeRegistry): Pick<ActionabilityReport, "ready" | "decisions" | "gates">;
62
82
  /**
63
83
  * Partitions a candidate set into ready vs blocked leaf work using the corpus to
64
84
  * resolve blockers, descendants, and downstream dependents.
@@ -70,4 +90,4 @@ export interface ActionabilityReport {
70
90
  * blockers and the non-terminal items it would unblock. Returned lists preserve
71
91
  * the candidate order so the caller can apply its own ranking.
72
92
  */
73
- export declare function computeActionabilityReport(candidates: ItemMetadata[], corpus: ItemMetadata[], statusRegistry: RuntimeStatusRegistry): ActionabilityReport;
93
+ export declare function computeActionabilityReport(candidates: ItemMetadata[], corpus: ItemMetadata[], statusRegistry: RuntimeStatusRegistry, typeRegistry?: ItemTypeRegistry): ActionabilityReport;
@@ -10,9 +10,15 @@
10
10
  * `blocked_by` resolution a single source of truth.
11
11
  */
12
12
 
13
- !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]="0605f770-d868-5fe9-a186-45f00d2e93b4")}catch(e){}}();
13
+ !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]="7d98ca40-57e8-5afe-8e9d-b694da0130d1")}catch(e){}}();
14
14
  import { isTerminalStatus, normalizeStatusForRegistry } from "./status.js";
15
+ import { BUILTIN_ITEM_EXECUTION_ROLES, resolveTypeDefinition } from "./type-registry.js";
15
16
  import { isExternalDependencyReference, isExternalDependencySourceKind, } from "./dependency-reference.js";
17
+ /** Resolve dispatch semantics once for SDK callers, honoring custom and extension type aliases before built-in defaults. */
18
+ export function resolveItemExecutionRole(type, registry) {
19
+ const definition = registry === undefined ? undefined : resolveTypeDefinition(type, registry);
20
+ return definition?.execution_role ?? BUILTIN_ITEM_EXECUTION_ROLES[type.trim().toLowerCase()] ?? "agent";
21
+ }
16
22
  /** Dependency kind that marks "this item is blocked by the referenced item". */
17
23
  const BLOCKED_BY_DEPENDENCY_KIND = "blocked_by";
18
24
  /** Reverse dependency kind that marks "this item blocks the referenced item". */
@@ -177,6 +183,24 @@ export function collectDependencyBlockedIds(corpus, statusRegistry) {
177
183
  }
178
184
  return blocked;
179
185
  }
186
+ /** Select dispatch candidates from a classified report while retaining held-out worklists. Ownership and ranking remain caller responsibilities. */
187
+ export function selectActionableEntries(report, statusRegistry, options = {}, typeRegistry) {
188
+ const candidates = [...report.ready, ...report.decisions, ...report.gates];
189
+ if (options.includeContainers === true) {
190
+ candidates.push(...report.containers.filter((entry) => entry.open_blockers.length === 0 && !statusRegistry.blocked_statuses.has(normalizeStatusForRegistry(entry.item.status, statusRegistry))));
191
+ }
192
+ const selected = { ready: [], decisions: [], gates: [] };
193
+ for (const entry of candidates) {
194
+ const role = resolveItemExecutionRole(entry.item.type, typeRegistry);
195
+ if (role === "human" && options.includeDecisions !== true)
196
+ selected.decisions.push(entry);
197
+ else if (role === "gate" && options.includeGates !== true)
198
+ selected.gates.push(entry);
199
+ else
200
+ selected.ready.push(entry);
201
+ }
202
+ return selected;
203
+ }
180
204
  /** Resolves the registry's active status set, falling back to just the canonical open status when a custom schema declares none — the same safety net `pm context` applies so the report never misclassifies every item as inactive. */
181
205
  function resolveActiveStatusSet(statusRegistry) {
182
206
  /* c8 ignore start -- fallback applies only to custom schemas that intentionally define zero active statuses */
@@ -242,7 +266,7 @@ function indexCorpus(corpus) {
242
266
  * blockers and the non-terminal items it would unblock. Returned lists preserve
243
267
  * the candidate order so the caller can apply its own ranking.
244
268
  */
245
- export function computeActionabilityReport(candidates, corpus, statusRegistry) {
269
+ export function computeActionabilityReport(candidates, corpus, statusRegistry, typeRegistry) {
246
270
  const { itemsById, childrenByParent, blockedByReverse, blockerIdsByItem } = indexCorpus(corpus);
247
271
  const activeStatuses = new Set([
248
272
  ...resolveActiveStatusSet(statusRegistry),
@@ -255,16 +279,14 @@ export function computeActionabilityReport(candidates, corpus, statusRegistry) {
255
279
  .map((entry) => normalizeItemId(entry.id)));
256
280
  const ready = [];
257
281
  const blocked = [];
282
+ const containers = [];
283
+ const decisions = [];
284
+ const gates = [];
258
285
  let activeCount = 0;
259
- let containerCount = 0;
260
286
  for (const item of candidates) {
261
287
  if (!activeStatuses.has(normalizeStatusForRegistry(item.status, statusRegistry)))
262
288
  continue;
263
289
  activeCount += 1;
264
- if (hasOpenDescendant(item.id, childrenByParent, statusRegistry)) {
265
- containerCount += 1;
266
- continue;
267
- }
268
290
  const openBlockers = resolveItemBlockersWithIndex(item, itemsById, statusRegistry, blockerIdsByItem).filter((blocker) => !blocker.resolved);
269
291
  const unblocks = (blockedByReverse.get(normalizeItemId(item.id)) ?? [])
270
292
  .filter((dependentId) => nonTerminalIds.has(normalizeItemId(dependentId)))
@@ -274,9 +296,19 @@ export function computeActionabilityReport(candidates, corpus, statusRegistry) {
274
296
  open_blockers: openBlockers,
275
297
  unblocks,
276
298
  };
299
+ if (hasOpenDescendant(item.id, childrenByParent, statusRegistry)) {
300
+ containers.push(entry);
301
+ continue;
302
+ }
277
303
  const lifecycleBlocked = statusRegistry.blocked_statuses.has(normalizeStatusForRegistry(item.status, statusRegistry));
278
304
  if (openBlockers.length === 0 && !lifecycleBlocked) {
279
- ready.push(entry);
305
+ const role = resolveItemExecutionRole(item.type, typeRegistry);
306
+ if (role === "human")
307
+ decisions.push(entry);
308
+ else if (role === "gate")
309
+ gates.push(entry);
310
+ else
311
+ ready.push(entry);
280
312
  }
281
313
  else {
282
314
  blocked.push(entry);
@@ -285,9 +317,12 @@ export function computeActionabilityReport(candidates, corpus, statusRegistry) {
285
317
  return {
286
318
  ready,
287
319
  blocked,
320
+ containers,
321
+ decisions,
322
+ gates,
288
323
  active_count: activeCount,
289
- container_count: containerCount,
324
+ container_count: containers.length,
290
325
  };
291
326
  }
292
327
  //# sourceMappingURL=actionability.js.map
293
- //# debugId=0605f770-d868-5fe9-a186-45f00d2e93b4
328
+ //# debugId=7d98ca40-57e8-5afe-8e9d-b694da0130d1
@@ -4,7 +4,7 @@
4
4
  * Defines item parsing, formatting, and lifecycle helpers for Id.
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]="6b3f1585-ab12-57ca-80eb-d3cebc384c52")}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]="04f02467-a4ee-5616-9fbf-3df1141efccf")}catch(e){}}();
8
8
  import crypto from "node:crypto";
9
9
  import path from "node:path";
10
10
  import { TYPE_TO_FOLDER } from "../shared/constants.js";
@@ -60,11 +60,13 @@ function randomToken(length) {
60
60
  }
61
61
  return token;
62
62
  }
63
+ /** Reserve an identity when either a live item path or its retained history exists. */
63
64
  async function idExists(pmRoot, id, typeToFolder) {
64
65
  const checks = [...new Set(Object.values(typeToFolder))].flatMap((folder) => [
65
66
  path.join(pmRoot, folder, `${id}.md`),
66
67
  path.join(pmRoot, folder, `${id}.toon`),
67
68
  ]);
69
+ checks.push(path.join(pmRoot, "history", `${id}.jsonl`));
68
70
  return (await Promise.all(checks.map((target) => pathExists(target)))).some(Boolean);
69
71
  }
70
72
  /** Bounds accepted for the configurable random id token length (`ids.token_length`). */
@@ -95,8 +97,10 @@ export async function generateItemId(pmRoot, prefix, options = {}) {
95
97
  while (tokenLength <= maxTokenLength) {
96
98
  for (let i = 0; i < 32; i += 1) {
97
99
  const id = `${normalizePrefix(prefix)}${randomToken(tokenLength)}`;
98
- if (options.probeExisting === false ||
99
- !(await idExists(pmRoot, id, options.typeToFolder ?? TYPE_TO_FOLDER))) {
100
+ const occupied = await (options.probeExisting === false
101
+ ? pathExists(path.join(pmRoot, "history", `${id}.jsonl`))
102
+ : idExists(pmRoot, id, options.typeToFolder ?? TYPE_TO_FOLDER));
103
+ if (!occupied) {
100
104
  return id;
101
105
  }
102
106
  attempts += 1;
@@ -106,4 +110,4 @@ export async function generateItemId(pmRoot, prefix, options = {}) {
106
110
  throw new Error(`Unable to generate unique id after ${attempts} attempts`);
107
111
  }
108
112
  //# sourceMappingURL=id.js.map
109
- //# debugId=6b3f1585-ab12-57ca-80eb-d3cebc384c52
113
+ //# debugId=04f02467-a4ee-5616-9fbf-3df1141efccf
@@ -38,6 +38,8 @@ export interface NormalizeItemTypeDefinitionOptions {
38
38
  /** How to resolve a raw policy `command` value (defaults to {@link keepPolicyCommand}). */
39
39
  resolvePolicyCommand?: ResolvePolicyCommand;
40
40
  }
41
+ /** Validate an execution role before a settings or extension definition enters scheduling. Unknown values fail instead of silently enabling dispatch. */
42
+ export declare function parseItemExecutionRole(value: unknown): ItemTypeDefinition["execution_role"];
41
43
  /**
42
44
  * Normalize a full {@link ItemTypeDefinition}, returning null when the name is blank.
43
45
  *
@@ -15,7 +15,7 @@
15
15
  */
16
16
  /** Dedupe + sort a string list: trim, drop blanks, unique, locale-sorted. */
17
17
 
18
- !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]="815165a9-27a7-5933-adae-c7e55330c8e4")}catch(e){}}();
18
+ !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]="f02cb2e7-2d5f-5cc8-8a60-18db78b50da0")}catch(e){}}();
19
19
  export function normalizeItemTypeStringList(values) {
20
20
  return [
21
21
  ...new Set((values ?? [])
@@ -85,6 +85,12 @@ function optionalNonEmptyString(value) {
85
85
  const normalized = value?.trim();
86
86
  return normalized && normalized.length > 0 ? normalized : undefined;
87
87
  }
88
+ /** Validate an execution role before a settings or extension definition enters scheduling. Unknown values fail instead of silently enabling dispatch. */
89
+ export function parseItemExecutionRole(value) {
90
+ if (value === undefined || value === "agent" || value === "human" || value === "gate")
91
+ return value;
92
+ throw new Error("Item type execution_role must be agent, human, or gate.");
93
+ }
88
94
  /**
89
95
  * Normalize a full {@link ItemTypeDefinition}, returning null when the name is blank.
90
96
  *
@@ -113,6 +119,7 @@ export function normalizeItemTypeDefinition(definition, options = {}) {
113
119
  name,
114
120
  description: optionalNonEmptyString(definition.description),
115
121
  default_status: optionalNonEmptyString(definition.default_status),
122
+ ...(definition.execution_role === undefined ? {} : { execution_role: parseItemExecutionRole(definition.execution_role) }),
116
123
  folder: optionalNonEmptyString(definition.folder),
117
124
  aliases: aliases.length > 0 ? aliases : undefined,
118
125
  required_create_fields: normalizeOptionalStringList(definition.required_create_fields, hasRequiredCreateFields),
@@ -124,4 +131,4 @@ export function normalizeItemTypeDefinition(definition, options = {}) {
124
131
  };
125
132
  }
126
133
  //# sourceMappingURL=item-type-definition.js.map
127
- //# debugId=815165a9-27a7-5933-adae-c7e55330c8e4
134
+ //# debugId=f02cb2e7-2d5f-5cc8-8a60-18db78b50da0
@@ -1,5 +1,7 @@
1
1
  import type { ExtensionRegistrationRegistry } from "../extensions/loader.js";
2
- import type { ItemTypeCommandOptionPolicy, ItemTypeOptionDefinition, PmSettings } from "../../types/index.js";
2
+ import type { ItemTypeCommandOptionPolicy, ItemTypeDefinition, ItemTypeOptionDefinition, PmSettings } from "../../types/index.js";
3
+ /** Default dispatch roles for built-in types whose work requires human input or outcome verification. Custom definitions can override these through the same registry. */
4
+ export declare const BUILTIN_ITEM_EXECUTION_ROLES: Readonly<Record<string, "human" | "gate">>;
3
5
  /** Fallback required create fields used when callers do not provide an override. */
4
6
  export declare const DEFAULT_REQUIRED_CREATE_FIELDS: readonly ["title", "description", "status", "priority", "tags", "body", "deadline", "estimatedMinutes", "acceptanceCriteria", "author", "message", "assignee"];
5
7
  /** Fallback required create repeatables used when callers do not provide an override. */
@@ -31,6 +33,8 @@ export interface ResolvedItemTypeDefinition {
31
33
  aliases: string[];
32
34
  /** Optional per-type status applied at create time when `--status` is omitted. */
33
35
  default_status?: string;
36
+ /** Effective dispatch role; absent legacy definitions are resolved through the built-in defaults. */
37
+ execution_role?: ItemTypeDefinition["execution_role"];
34
38
  /** Value that configures or reports required create fields for this contract. */
35
39
  required_create_fields: string[];
36
40
  /** Value that configures or reports required create repeatables for this contract. */
@@ -4,11 +4,13 @@
4
4
  * Defines item parsing, formatting, and lifecycle helpers for Type Registry.
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]="88b2ed4e-b5fd-5014-abf1-c163db033abf")}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]="506efdc7-b04e-5023-ab59-57ede87558f9")}catch(e){}}();
8
8
  import path from "node:path";
9
9
  import { TYPE_TO_FOLDER } from "../shared/constants.js";
10
10
  import { ITEM_TYPE_VALUES } from "../../types/index.js";
11
- import { normalizeItemTypeDefinition as normalizeSharedItemTypeDefinition, normalizeItemTypeStringList, strictPolicyCommand, } from "./item-type-definition.js";
11
+ import { normalizeItemTypeDefinition as normalizeSharedItemTypeDefinition, normalizeItemTypeStringList, strictPolicyCommand, parseItemExecutionRole, } from "./item-type-definition.js";
12
+ /** Default dispatch roles for built-in types whose work requires human input or outcome verification. Custom definitions can override these through the same registry. */
13
+ export const BUILTIN_ITEM_EXECUTION_ROLES = Object.freeze({ decision: "human", milestone: "gate" });
12
14
  /** Fallback required create fields used when callers do not provide an override. */
13
15
  export const DEFAULT_REQUIRED_CREATE_FIELDS = [
14
16
  "title",
@@ -421,6 +423,7 @@ function coerceTypeDefinitionFromUnknown(raw) {
421
423
  name,
422
424
  description,
423
425
  default_status: defaultStatus,
426
+ execution_role: parseItemExecutionRole(record.execution_role),
424
427
  folder,
425
428
  aliases: readStringArray(record, "aliases"),
426
429
  required_create_fields: readStringArray(record, "required_create_fields"),
@@ -462,6 +465,7 @@ function buildResolvedTypeDefinition(normalizedDefinition, existing) {
462
465
  toDefaultFolder(keepName));
463
466
  const resolvedDefinition = {
464
467
  name: keepName,
468
+ execution_role: normalizedDefinition.execution_role,
465
469
  folder,
466
470
  aliases: normalizeItemTypeStringList([
467
471
  ...(existing?.aliases ?? []),
@@ -488,7 +492,7 @@ function applyTypeDefinitions(source, target) {
488
492
  }
489
493
  const lowerName = normalizedDefinition.name.toLowerCase();
490
494
  const existing = target.get(lowerName);
491
- target.set(lowerName, buildResolvedTypeDefinition(normalizedDefinition, existing));
495
+ target.set(lowerName, buildResolvedTypeDefinition({ ...normalizedDefinition, execution_role: normalizedDefinition.execution_role ?? existing?.execution_role }, existing));
492
496
  }
493
497
  }
494
498
  function collectExtensionTypeDefinitions(registrations) {
@@ -516,6 +520,7 @@ export function resolveItemTypeRegistry(settings, extensionRegistrations = null)
516
520
  for (const builtin of ITEM_TYPE_VALUES) {
517
521
  byLowerName.set(builtin.toLowerCase(), {
518
522
  name: builtin,
523
+ execution_role: BUILTIN_ITEM_EXECUTION_ROLES[builtin.toLowerCase()] ?? "agent",
519
524
  folder: TYPE_TO_FOLDER[builtin],
520
525
  aliases: [],
521
526
  required_create_fields: [...DEFAULT_REQUIRED_CREATE_FIELDS],
@@ -708,4 +713,4 @@ export function validateTypeOptions(typeName, rawTypeOptions, registry) {
708
713
  };
709
714
  }
710
715
  //# sourceMappingURL=type-registry.js.map
711
- //# debugId=88b2ed4e-b5fd-5014-abf1-c163db033abf
716
+ //# debugId=506efdc7-b04e-5023-ab59-57ede87558f9
@@ -19,7 +19,7 @@
19
19
  * MCP server, and returns the original reference unchanged when nothing is compacted.
20
20
  */
21
21
 
22
- !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]="a3e0573a-01fd-54fb-a568-51c5287b696c")}catch(e){}}();
22
+ !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]="d6a389b0-7a14-56e7-ac2c-17fcdecc7b29")}catch(e){}}();
23
23
  const CHANGED_FIELDS_KEY = "changed_fields";
24
24
  const CHANGED_FIELD_COUNT_KEY = "changed_field_count";
25
25
  const ROWS_KEY = "rows";
@@ -115,6 +115,7 @@ function projectIdOnlyResult(result) {
115
115
  }
116
116
  : { id };
117
117
  }
118
+ /** Project a recognized item mutation to identity and change counts while preserving warnings and executable recovery. */
118
119
  function projectCompactMutationEnvelope(result) {
119
120
  if (!isPlainObject(result) || !isPlainObject(result.item))
120
121
  return null;
@@ -137,10 +138,15 @@ function projectCompactMutationEnvelope(result) {
137
138
  : {}),
138
139
  changed_field_count: changedFields.length,
139
140
  };
141
+ appendCompactMutationEvidence(result, result.item, compact);
142
+ return compact;
143
+ }
144
+ /** Keep lifecycle context, warnings, and executable recovery alongside the compact identity. */
145
+ function appendCompactMutationEvidence(result, item, compact) {
140
146
  const closeReason = typeof result.close_reason === "string"
141
147
  ? result.close_reason
142
- : typeof result.item.close_reason === "string"
143
- ? result.item.close_reason
148
+ : typeof item.close_reason === "string"
149
+ ? item.close_reason
144
150
  : undefined;
145
151
  if (closeReason !== undefined)
146
152
  compact.close_reason = closeReason;
@@ -149,7 +155,8 @@ function projectCompactMutationEnvelope(result) {
149
155
  compact.recurrence = recurrence;
150
156
  if (Array.isArray(result.warnings) && result.warnings.length > 0)
151
157
  compact.warnings = result.warnings;
152
- return compact;
158
+ if (isPlainObject(result.recovery))
159
+ compact.recovery = result.recovery;
153
160
  }
154
161
  function compactUpdateManyRows(envelope) {
155
162
  const rows = isUpdateManyMutationEnvelope(envelope)
@@ -208,4 +215,4 @@ export function projectMutationResult(result, options = {}) {
208
215
  return changed ? projected : result;
209
216
  }
210
217
  //# sourceMappingURL=mutation-projection.js.map
211
- //# debugId=a3e0573a-01fd-54fb-a568-51c5287b696c
218
+ //# debugId=d6a389b0-7a14-56e7-ac2c-17fcdecc7b29
@@ -53,6 +53,14 @@ export interface PmCliErrorRecoveryPayload {
53
53
  export interface PmCliErrorContext {
54
54
  /** Value that configures or reports code for this contract. */
55
55
  code?: string;
56
+ /** Item whose document could not be decoded or parsed. */
57
+ item_id?: string;
58
+ /** Exact filesystem path of the unreadable item document. */
59
+ item_path?: string;
60
+ /** Original document size before decoding or parsing. */
61
+ byte_length?: number;
62
+ /** Whether the original item document contained no bytes. */
63
+ empty?: boolean;
56
64
  /** Stable failure class within the operation-specific error code. */
57
65
  reason?: string;
58
66
  /** Metadata field responsible for a validation failure, when known. */
@@ -1,6 +1,6 @@
1
1
  /** Implements the exported pm cli error runtime abstraction for core/shared/errors.ts. */
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]="922e2e27-1499-5466-98e4-322d0d742e40")}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]="9ab4b378-900c-5a2a-9237-b1d8d4f2ae13")}catch(e){}}();
4
4
  export class PmCliError extends Error {
5
5
  /** Value that configures or reports exit code for this contract. */
6
6
  exitCode;
@@ -18,4 +18,4 @@ export class PmCliError extends Error {
18
18
  }
19
19
  }
20
20
  //# sourceMappingURL=errors.js.map
21
- //# debugId=922e2e27-1499-5466-98e4-322d0d742e40
21
+ //# debugId=9ab4b378-900c-5a2a-9237-b1d8d4f2ae13
@@ -4,13 +4,13 @@
4
4
  * Maintains a rebuildable SQLite projection for bounded metadata queries.
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]="97cfeab2-8e3f-5b70-9f64-10494158d141")}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]="530ad63f-f7c5-52c9-9f81-a74b1cd4c36e")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import { randomUUID } from "node:crypto";
11
11
  import { createRequire } from "node:module";
12
12
  const QUERY_INDEX_FILENAME = "metadata-query-index.sqlite";
13
- const QUERY_INDEX_VERSION = "4";
13
+ const QUERY_INDEX_VERSION = "5";
14
14
  function loadDatabaseSync(loadModule) {
15
15
  try {
16
16
  const loaded = loadModule(["node", "sqlite"].join(":"));
@@ -102,6 +102,7 @@ function writeMetadata(database, key, value) {
102
102
  .prepare("INSERT INTO metadata(key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value")
103
103
  .run(key, value);
104
104
  }
105
+ /** Upsert authoritative metadata and replace dependent search, key and linked-file rows in the caller transaction. */
105
106
  function insertRow(database, row) {
106
107
  const metadata = row.metadata;
107
108
  database
@@ -128,10 +129,12 @@ function insertRow(database, row) {
128
129
  database
129
130
  .prepare("DELETE FROM item_linked_files WHERE item_id = ?")
130
131
  .run(metadata.id);
131
- database.prepare("DELETE FROM item_search WHERE id = ?").run(metadata.id);
132
+ // FTS UNINDEXED columns cannot provide identity lookup. Share the items rowid
133
+ // so both rebuilding and incremental maintenance use a single indexed row.
134
+ database.prepare("DELETE FROM item_search WHERE rowid = (SELECT rowid FROM items WHERE id = ?)").run(metadata.id);
132
135
  database
133
- .prepare("INSERT INTO item_search(id, title, description, tags) VALUES (?, ?, ?, ?)")
134
- .run(metadata.id, metadata.title, metadata.description, metadata.tags.join(" "));
136
+ .prepare("INSERT INTO item_search(rowid, id, title, description, tags) SELECT rowid, ?, ?, ?, ? FROM items WHERE id = ?")
137
+ .run(metadata.id, metadata.title, metadata.description, metadata.tags.join(" "), metadata.id);
135
138
  const insertMetadataKey = database.prepare("INSERT INTO item_metadata_keys(item_id, key) VALUES (?, ?)");
136
139
  for (const key of Object.keys(metadata)) {
137
140
  insertMetadataKey.run(metadata.id, key);
@@ -203,13 +206,13 @@ export async function updateItemMetadataQueryIndex(options) {
203
206
  }
204
207
  database.exec("BEGIN IMMEDIATE");
205
208
  const deleteByPath = database.prepare("DELETE FROM items WHERE relative_path = ?");
206
- const findIdByPath = database.prepare("SELECT id FROM items WHERE relative_path = ?");
207
- const deleteSearchById = database.prepare("DELETE FROM item_search WHERE id = ?");
209
+ const findRowidByPath = database.prepare("SELECT rowid FROM items WHERE relative_path = ?");
210
+ const deleteSearchByRowid = database.prepare("DELETE FROM item_search WHERE rowid = ?");
208
211
  for (const relativePath of options.deletedRelativePaths ?? []) {
209
- const deleted = findIdByPath.get(relativePath);
212
+ const deleted = findRowidByPath.get(relativePath);
210
213
  deleteByPath.run(relativePath);
211
214
  if (deleted)
212
- deleteSearchById.run(deleted.id);
215
+ deleteSearchByRowid.run(deleted.rowid);
213
216
  }
214
217
  if (options.row)
215
218
  insertRow(database, options.row);
@@ -470,4 +473,4 @@ export const _testOnly = {
470
473
  },
471
474
  };
472
475
  //# sourceMappingURL=item-metadata-query-index.js.map
473
- //# debugId=97cfeab2-8e3f-5b70-9f64-10494158d141
476
+ //# debugId=530ad63f-f7c5-52c9-9f81-a74b1cd4c36e
@@ -0,0 +1,19 @@
1
+ /** Logical metadata work, independent of output projection and cache hit rate. */
2
+ export interface ItemMetadataReadWork {
3
+ /** Completed full, light, or body-bearing item-store enumeration calls. */
4
+ enumeration_calls: number;
5
+ /** Metadata rows returned by those calls, counting repeated enumeration. */
6
+ metadata_rows: number;
7
+ }
8
+ /** Record completed enumeration in each enclosing measurement, without retaining item data. */
9
+ export declare function recordItemMetadataEnumeration(rowCount: number): void;
10
+ /**
11
+ * Measure an awaited operation without changing its result or failure semantics.
12
+ * Concurrent roots remain isolated; nested measurements also contribute to their
13
+ * parents. The returned snapshot excludes work completed after the operation.
14
+ * Counters cover filesystem item-store enumeration APIs, not arbitrary host I/O.
15
+ */
16
+ export declare function measureItemMetadataReadWork<T>(operation: () => T | Promise<T>): Promise<{
17
+ result: T;
18
+ work: Readonly<ItemMetadataReadWork>;
19
+ }>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @module core/store/item-metadata-read-work
3
+ *
4
+ * Measures successful filesystem metadata enumerations within one async SDK
5
+ * operation. Cache hits count too: materializing a cached corpus is still work.
6
+ */
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]="1cd39e2f-41c7-5005-925d-d4539cda15d3")}catch(e){}}();
9
+ import { AsyncLocalStorage } from "node:async_hooks";
10
+ import { channel } from "node:diagnostics_channel";
11
+ const observers = new AsyncLocalStorage();
12
+ const enumerations = channel("@unbrained/pm-cli/item-metadata-enumeration/v1");
13
+ /** Record completed enumeration in each enclosing measurement, without retaining item data. */
14
+ export function recordItemMetadataEnumeration(rowCount) {
15
+ enumerations.publish(rowCount);
16
+ }
17
+ /**
18
+ * Measure an awaited operation without changing its result or failure semantics.
19
+ * Concurrent roots remain isolated; nested measurements also contribute to their
20
+ * parents. The returned snapshot excludes work completed after the operation.
21
+ * Counters cover filesystem item-store enumeration APIs, not arbitrary host I/O.
22
+ */
23
+ export async function measureItemMetadataReadWork(operation) {
24
+ const work = { enumeration_calls: 0, metadata_rows: 0 };
25
+ // A named channel crosses the published query/bundled runtime boundary;
26
+ // async membership prevents concurrent roots from counting each other's work.
27
+ /** Count notifications only while this measurement belongs to the active async scope. */
28
+ const observe = (message) => {
29
+ if (observers.getStore()?.includes(work)) {
30
+ work.enumeration_calls += 1;
31
+ work.metadata_rows += message;
32
+ }
33
+ };
34
+ enumerations.subscribe(observe);
35
+ try {
36
+ const result = await observers.run([...(observers.getStore() ?? []), work], operation);
37
+ return { result, work: { ...work } };
38
+ }
39
+ finally {
40
+ enumerations.unsubscribe(observe);
41
+ }
42
+ }
43
+ //# sourceMappingURL=item-metadata-read-work.js.map
44
+ //# debugId=1cd39e2f-41c7-5005-925d-d4539cda15d3
@@ -25,6 +25,20 @@ export declare function readLocatedItem(item: LocatedItem, options?: {
25
25
  raw: string;
26
26
  document: ItemDocument;
27
27
  }>;
28
+ /**
29
+ * Read once and retain a recoverable parse failure beside its exact text snapshot.
30
+ * Filesystem and merge-conflict errors still throw; callers must explicitly
31
+ * reconstruct an invalid document before performing any mutation.
32
+ */
33
+ export declare function readLocatedItemSnapshot(item: LocatedItem, options?: Parameters<typeof readLocatedItem>[1]): Promise<{
34
+ raw: string;
35
+ document: ItemDocument;
36
+ error: null;
37
+ } | {
38
+ raw: string;
39
+ document: null;
40
+ error: PmCliError;
41
+ }>;
28
42
  /** Implements list all item metadata for the public runtime surface of this module. */
29
43
  export declare function listAllItemMetadata(pmRoot: string, preferredFormat?: ItemFormat, typeToFolder?: Record<string, string>, warnings?: string[], schema?: RuntimeSchemaSettings): Promise<ItemMetadata[]>;
30
44
  /**