@unbrained/pm-cli 2026.8.7 → 2026.8.9

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 (288) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +54 -0
  3. package/dist/cli/main.js +4 -3
  4. package/dist/cli/register-annotations.d.ts +11 -0
  5. package/dist/cli/register-annotations.js +195 -0
  6. package/dist/cli/register-history-author.js +7 -30
  7. package/dist/cli/register-mutation.js +25 -206
  8. package/dist/cli/runtime-compatibility-boundary.d.ts +17 -0
  9. package/dist/cli/runtime-compatibility-boundary.js +43 -0
  10. package/dist/cli-bundle/bundle-manifest.json +158 -694
  11. package/dist/cli-bundle/chunks/chunk-2DTCZXSD.js +13 -0
  12. package/dist/cli-bundle/chunks/chunk-5JO6R4BS.js +3 -0
  13. package/dist/cli-bundle/chunks/chunk-5KN4DZYV.js +194 -0
  14. package/dist/cli-bundle/chunks/chunk-EF43KODO.js +2 -0
  15. package/dist/cli-bundle/chunks/chunk-GMX5YOI3.js +77 -0
  16. package/dist/cli-bundle/chunks/chunk-HUV2Z7IS.js +28 -0
  17. package/dist/cli-bundle/chunks/chunk-MHBVCUF2.js +2 -0
  18. package/dist/cli-bundle/chunks/chunk-PYO5GZU6.js +5 -0
  19. package/dist/cli-bundle/chunks/chunk-QWRRFYK3.js +2 -0
  20. package/dist/cli-bundle/chunks/chunk-RJC7TPF4.js +8 -0
  21. package/dist/cli-bundle/chunks/chunk-YC3UF2IO.js +2068 -0
  22. package/dist/cli-bundle/chunks/{register-list-query-FJZCJ67O.js → register-list-query-BUE7PTCU.js} +8 -8
  23. package/dist/cli-bundle/chunks/register-mutation-FC3XLVIK.js +20 -0
  24. package/dist/cli-bundle/chunks/register-operations-YH2WAOXU.js +2 -0
  25. package/dist/cli-bundle/chunks/register-setup-UQDTNTLJ.js +2 -0
  26. package/dist/cli-bundle/focused-chunks/chunk-2VVP5RAA.js +153 -0
  27. package/dist/cli-bundle/focused-chunks/{chunk-4VJQTS3P.js → chunk-3GSFUDAI.js} +2 -2
  28. package/dist/cli-bundle/focused-chunks/chunk-3WVHTUAW.js +5 -0
  29. package/dist/cli-bundle/focused-chunks/chunk-4H6MVCK3.js +16 -0
  30. package/dist/cli-bundle/focused-chunks/{chunk-73JUDYXT.js → chunk-54TZJ4BM.js} +2 -2
  31. package/dist/cli-bundle/focused-chunks/chunk-5NK5TJ5D.js +2 -0
  32. package/dist/cli-bundle/focused-chunks/{chunk-HNL6IFGS.js → chunk-6DO4YQWZ.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/chunk-73FIJONU.js +2 -0
  34. package/dist/cli-bundle/focused-chunks/{chunk-TIKDBG4D.js → chunk-C3GCHDSQ.js} +29 -27
  35. package/dist/cli-bundle/focused-chunks/chunk-JGRSQZJT.js +18 -0
  36. package/dist/cli-bundle/focused-chunks/{chunk-YZEZAPJK.js → chunk-KNEHLPBF.js} +2 -2
  37. package/dist/cli-bundle/focused-chunks/chunk-MRWVJ3ZG.js +2 -0
  38. package/dist/cli-bundle/focused-chunks/chunk-NL57J7BZ.js +4 -0
  39. package/dist/cli-bundle/focused-chunks/{chunk-NBJKQP4S.js → chunk-P6BBIQRG.js} +2 -2
  40. package/dist/cli-bundle/focused-chunks/{chunk-QHRTT7WT.js → chunk-PZAGVQNN.js} +2 -2
  41. package/dist/cli-bundle/focused-chunks/chunk-QDAO3XEK.js +14 -0
  42. package/dist/cli-bundle/focused-chunks/chunk-T4IGQCSY.js +2 -0
  43. package/dist/cli-bundle/focused-chunks/chunk-U46GQJNY.js +2 -0
  44. package/dist/cli-bundle/focused-chunks/{chunk-RPNYG5MO.js → chunk-VRXJSGIT.js} +6 -6
  45. package/dist/cli-bundle/focused-chunks/{chunk-R2LEMEV5.js → chunk-XC2ZW3CJ.js} +2 -2
  46. package/dist/cli-bundle/focused-chunks/chunk-ZG54B4XG.js +2 -0
  47. package/dist/cli-bundle/main.js +13 -13
  48. package/dist/cli-bundle/sdk-authoring.js +1 -1
  49. package/dist/cli-bundle/sdk-contracts.js +1 -1
  50. package/dist/cli-bundle/sdk-core.js +38 -38
  51. package/dist/cli-bundle/sdk-governance.js +1 -1
  52. package/dist/cli-bundle/sdk-graph.js +1 -1
  53. package/dist/cli-bundle/sdk-merge.js +1 -1
  54. package/dist/cli-bundle/sdk-query.js +1 -1
  55. package/dist/cli-bundle/sdk-runtime.js +1 -1
  56. package/dist/cli-bundle/sdk-testing.js +1 -1
  57. package/dist/cli-bundle/sdk.js +2 -1
  58. package/dist/cli.js +14 -4
  59. package/dist/core/diagnostics/remediation.js +12 -2
  60. package/dist/core/history/history.js +13 -4
  61. package/dist/core/item/actionability.d.ts +7 -1
  62. package/dist/core/item/actionability.js +71 -15
  63. package/dist/core/output/output.js +9 -2
  64. package/dist/core/sentry/helpers.d.ts +10 -0
  65. package/dist/core/sentry/helpers.js +59 -4
  66. package/dist/core/shared/author.d.ts +25 -0
  67. package/dist/core/shared/author.js +114 -9
  68. package/dist/core/shared/constants.d.ts +2 -0
  69. package/dist/core/shared/constants.js +4 -2
  70. package/dist/sdk/actionability.d.ts +1 -1
  71. package/dist/sdk/actionability.js +3 -3
  72. package/dist/sdk/annotations.d.ts +40 -0
  73. package/dist/sdk/annotations.js +61 -9
  74. package/dist/sdk/author-attribution.d.ts +12 -0
  75. package/dist/sdk/author-attribution.js +73 -11
  76. package/dist/sdk/cli-contracts/command-exit-contracts.d.ts +118 -0
  77. package/dist/sdk/cli-contracts/command-exit-contracts.js +152 -0
  78. package/dist/sdk/cli-contracts/completeness.js +5 -3
  79. package/dist/sdk/cli-contracts/flag-contracts.js +5 -2
  80. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +19 -0
  81. package/dist/sdk/cli-contracts/runtime-contracts.js +44 -2
  82. package/dist/sdk/cli-contracts/tool-parameter-tables.js +15 -2
  83. package/dist/sdk/cli-contracts/tool-schema.d.ts +1 -1
  84. package/dist/sdk/cli-contracts/tool-schema.js +6 -3
  85. package/dist/sdk/comments.d.ts +7 -0
  86. package/dist/sdk/comments.js +2 -2
  87. package/dist/sdk/completion.js +9 -5
  88. package/dist/sdk/contracts.d.ts +1 -0
  89. package/dist/sdk/contracts.js +3 -2
  90. package/dist/sdk/core-governance.d.ts +1 -1
  91. package/dist/sdk/core-governance.js +3 -3
  92. package/dist/sdk/dependencies.d.ts +2 -0
  93. package/dist/sdk/dependencies.js +7 -6
  94. package/dist/sdk/environment/host-environment-errors.d.ts +27 -0
  95. package/dist/sdk/environment/host-environment-errors.js +124 -0
  96. package/dist/sdk/environment/project-runtime-compatibility.d.ts +65 -0
  97. package/dist/sdk/environment/project-runtime-compatibility.js +385 -0
  98. package/dist/sdk/environment/source-context.d.ts +23 -0
  99. package/dist/sdk/environment/source-context.js +29 -0
  100. package/dist/sdk/error-code-catalog.d.ts +6 -0
  101. package/dist/sdk/error-code-catalog.js +62 -8
  102. package/dist/sdk/extension/bundled-catalog.js +19 -6
  103. package/dist/sdk/generated-error-code-catalog.js +665 -3
  104. package/dist/sdk/governance/health.d.ts +11 -3
  105. package/dist/sdk/governance/health.js +32 -13
  106. package/dist/sdk/governance/provenance-health.d.ts +26 -0
  107. package/dist/sdk/governance/provenance-health.js +139 -0
  108. package/dist/sdk/governance/validate.js +13 -8
  109. package/dist/sdk/governance.d.ts +1 -0
  110. package/dist/sdk/governance.js +3 -2
  111. package/dist/sdk/graph/assembly.d.ts +4 -0
  112. package/dist/sdk/graph/assembly.js +22 -2
  113. package/dist/sdk/graph/run.d.ts +2 -0
  114. package/dist/sdk/graph/run.js +3 -2
  115. package/dist/sdk/index.d.ts +7 -3
  116. package/dist/sdk/index.js +9 -5
  117. package/dist/sdk/learnings.d.ts +15 -0
  118. package/dist/sdk/learnings.js +2 -2
  119. package/dist/sdk/lifecycle/close-many.d.ts +6 -1
  120. package/dist/sdk/lifecycle/close-many.js +43 -5
  121. package/dist/sdk/lifecycle/close.js +13 -8
  122. package/dist/sdk/lifecycle/create.js +6 -12
  123. package/dist/sdk/lifecycle/plan.js +6 -3
  124. package/dist/sdk/lifecycle/update-many.d.ts +2 -1
  125. package/dist/sdk/lifecycle/update-many.js +29 -5
  126. package/dist/sdk/lifecycle/update.js +6 -20
  127. package/dist/sdk/merge/driver.d.ts +2 -1
  128. package/dist/sdk/merge/driver.js +7 -4
  129. package/dist/sdk/merge/index.d.ts +1 -1
  130. package/dist/sdk/merge/index.js +3 -3
  131. package/dist/sdk/merge/install.d.ts +21 -0
  132. package/dist/sdk/merge/install.js +51 -21
  133. package/dist/sdk/merge/receipts.d.ts +14 -1
  134. package/dist/sdk/merge/receipts.js +36 -8
  135. package/dist/sdk/merge/reconcile.js +21 -4
  136. package/dist/sdk/merge/three-way.d.ts +6 -2
  137. package/dist/sdk/merge/three-way.js +24 -10
  138. package/dist/sdk/notes.d.ts +7 -0
  139. package/dist/sdk/notes.js +2 -2
  140. package/dist/sdk/query/get.d.ts +11 -0
  141. package/dist/sdk/query/get.js +37 -3
  142. package/dist/sdk/read-output-contracts.d.ts +1 -1
  143. package/dist/sdk/read-output-contracts.js +103 -5
  144. package/dist/sdk/relationship-kinds/contract.d.ts +48 -0
  145. package/dist/sdk/relationship-kinds/contract.js +22 -0
  146. package/dist/sdk/relationships.d.ts +6 -41
  147. package/dist/sdk/relationships.js +12 -126
  148. package/dist/sdk/runtime-primitives.d.ts +1 -1
  149. package/dist/sdk/runtime-primitives.js +3 -3
  150. package/dist/sdk/runtime.d.ts +1 -1
  151. package/dist/sdk/runtime.js +9 -25
  152. package/dist/sdk/similarity.d.ts +5 -0
  153. package/dist/sdk/similarity.js +40 -10
  154. package/dist/sdk/structured-mutations.js +5 -2
  155. package/dist/sdk/test/execution.js +4 -2
  156. package/dist/sdk/test/linked-command-detection.d.ts +2 -7
  157. package/dist/sdk/test/linked-command-detection.js +22 -9
  158. package/dist/sdk/test/parsers.js +5 -2
  159. package/dist/sdk/workspace-snapshot.d.ts +9 -0
  160. package/dist/sdk/workspace-snapshot.js +48 -16
  161. package/docs/AGENT_GUIDE.md +2 -1
  162. package/docs/AGENT_RUNTIME_PRIMITIVES.md +11 -4
  163. package/docs/COMMANDS.md +19 -1
  164. package/docs/DEPENDENCY_KIND_CONTRACT.md +29 -0
  165. package/docs/ITEM_READ_PROJECTIONS.md +26 -0
  166. package/docs/MERGE_SAFETY.md +10 -3
  167. package/docs/README.md +1 -0
  168. package/docs/RELATIONSHIP_GRAPH.md +1 -1
  169. package/docs/RELEASING.md +27 -2
  170. package/docs/SCRIPTING.md +27 -1
  171. package/docs/SDK_AGENT_SESSION_CONTEXT.md +35 -2
  172. package/docs/SDK_CONTEXT_INTEGRITY.md +81 -0
  173. package/docs/SDK_RUNTIME_BOUNDARIES.md +58 -0
  174. package/docs/SELF_DESCRIBING_CONTEXT_CONTRACTS.md +13 -0
  175. package/docs/SENTRY_CONTRACT_EPOCHS.md +20 -0
  176. package/docs/TESTING.md +17 -0
  177. package/docs/agent-task-token-baseline.json +2 -2
  178. package/marketplace.json +2 -2
  179. package/package.json +5 -3
  180. package/packages/pm-beads/package.json +1 -1
  181. package/packages/pm-calendar/package.json +1 -1
  182. package/packages/pm-command-kit/package.json +1 -1
  183. package/packages/pm-digital-twin/package.json +1 -1
  184. package/packages/pm-governance-audit/package.json +1 -1
  185. package/packages/pm-guide-shell/package.json +1 -1
  186. package/packages/pm-kanban/package.json +1 -1
  187. package/packages/pm-lifecycle-hooks/package.json +1 -1
  188. package/packages/pm-linked-test-adapters/package.json +1 -1
  189. package/packages/pm-search-advanced/package.json +1 -1
  190. package/packages/pm-templates/package.json +1 -1
  191. package/packages/pm-todos/package.json +1 -1
  192. package/packages/pm-vcs/package.json +1 -1
  193. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  194. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  195. package/sdk/public-surface.json +756 -57
  196. package/dist/cli-bundle/chunks/append-7BXBFDGD.js +0 -2
  197. package/dist/cli-bundle/chunks/chunk-2AXF3VSK.js +0 -2
  198. package/dist/cli-bundle/chunks/chunk-2XS43CCV.js +0 -2
  199. package/dist/cli-bundle/chunks/chunk-3A6KWB72.js +0 -8
  200. package/dist/cli-bundle/chunks/chunk-3ISTDB42.js +0 -8
  201. package/dist/cli-bundle/chunks/chunk-4MTI7XOV.js +0 -5
  202. package/dist/cli-bundle/chunks/chunk-6BX5UDCN.js +0 -3
  203. package/dist/cli-bundle/chunks/chunk-6QPO7KLR.js +0 -2
  204. package/dist/cli-bundle/chunks/chunk-7MXHZHSQ.js +0 -5
  205. package/dist/cli-bundle/chunks/chunk-7ZPMJW4U.js +0 -2
  206. package/dist/cli-bundle/chunks/chunk-A6KGKEWT.js +0 -2
  207. package/dist/cli-bundle/chunks/chunk-AGYNSNCI.js +0 -2
  208. package/dist/cli-bundle/chunks/chunk-B4H7FEFH.js +0 -5
  209. package/dist/cli-bundle/chunks/chunk-B4KLBBMN.js +0 -2
  210. package/dist/cli-bundle/chunks/chunk-BXCSXK4J.js +0 -2
  211. package/dist/cli-bundle/chunks/chunk-CALJHNBL.js +0 -23
  212. package/dist/cli-bundle/chunks/chunk-CFIGP5LY.js +0 -2
  213. package/dist/cli-bundle/chunks/chunk-CHOQ2VAW.js +0 -2
  214. package/dist/cli-bundle/chunks/chunk-CS6MRHG7.js +0 -2
  215. package/dist/cli-bundle/chunks/chunk-CUGNQQKH.js +0 -2
  216. package/dist/cli-bundle/chunks/chunk-D4FPS43D.js +0 -164
  217. package/dist/cli-bundle/chunks/chunk-E2ZSLTOP.js +0 -2
  218. package/dist/cli-bundle/chunks/chunk-FB7G2HY2.js +0 -2
  219. package/dist/cli-bundle/chunks/chunk-H5Y5YE6A.js +0 -2
  220. package/dist/cli-bundle/chunks/chunk-H5Y6UV6E.js +0 -2
  221. package/dist/cli-bundle/chunks/chunk-H7KGWPDF.js +0 -2
  222. package/dist/cli-bundle/chunks/chunk-HFSD77TQ.js +0 -2
  223. package/dist/cli-bundle/chunks/chunk-HX2GTA6L.js +0 -2
  224. package/dist/cli-bundle/chunks/chunk-J2IEKAVR.js +0 -2
  225. package/dist/cli-bundle/chunks/chunk-JC6FKIFM.js +0 -2
  226. package/dist/cli-bundle/chunks/chunk-K44PYFXH.js +0 -2
  227. package/dist/cli-bundle/chunks/chunk-K4KGEEBT.js +0 -2
  228. package/dist/cli-bundle/chunks/chunk-KFLK5TRH.js +0 -21
  229. package/dist/cli-bundle/chunks/chunk-KL6IEBV2.js +0 -2
  230. package/dist/cli-bundle/chunks/chunk-KWQZDZSS.js +0 -2
  231. package/dist/cli-bundle/chunks/chunk-KZ4X3DGU.js +0 -3
  232. package/dist/cli-bundle/chunks/chunk-LD77HJMQ.js +0 -13
  233. package/dist/cli-bundle/chunks/chunk-LEPJJ6QC.js +0 -2
  234. package/dist/cli-bundle/chunks/chunk-ME2JJ4LA.js +0 -3
  235. package/dist/cli-bundle/chunks/chunk-NE5VRDAI.js +0 -2
  236. package/dist/cli-bundle/chunks/chunk-NFLJ3FHD.js +0 -2
  237. package/dist/cli-bundle/chunks/chunk-NG6OXIBR.js +0 -19
  238. package/dist/cli-bundle/chunks/chunk-NYIGHWQY.js +0 -8
  239. package/dist/cli-bundle/chunks/chunk-NZ75GNSA.js +0 -2
  240. package/dist/cli-bundle/chunks/chunk-PCJWJNC2.js +0 -2
  241. package/dist/cli-bundle/chunks/chunk-PD3225AM.js +0 -2
  242. package/dist/cli-bundle/chunks/chunk-PDEGKG7P.js +0 -2
  243. package/dist/cli-bundle/chunks/chunk-PIE5HBNA.js +0 -2
  244. package/dist/cli-bundle/chunks/chunk-PW2H7YJR.js +0 -56
  245. package/dist/cli-bundle/chunks/chunk-RSIC5OPE.js +0 -2
  246. package/dist/cli-bundle/chunks/chunk-TPKN3S7S.js +0 -2
  247. package/dist/cli-bundle/chunks/chunk-TPXAXTCO.js +0 -2
  248. package/dist/cli-bundle/chunks/chunk-UFWUJO4V.js +0 -2
  249. package/dist/cli-bundle/chunks/chunk-UQLZQVFW.js +0 -55
  250. package/dist/cli-bundle/chunks/chunk-VT3Z5G7D.js +0 -2
  251. package/dist/cli-bundle/chunks/chunk-WOD3WWUN.js +0 -2
  252. package/dist/cli-bundle/chunks/chunk-WSJEIGJF.js +0 -3
  253. package/dist/cli-bundle/chunks/chunk-WYNUU7ZW.js +0 -2008
  254. package/dist/cli-bundle/chunks/chunk-YGPNCCXZ.js +0 -2
  255. package/dist/cli-bundle/chunks/close-CMY3BAUG.js +0 -2
  256. package/dist/cli-bundle/chunks/close-many-SA4XZCTK.js +0 -2
  257. package/dist/cli-bundle/chunks/comments-EZ556ZD3.js +0 -2
  258. package/dist/cli-bundle/chunks/copy-ZSGPA52X.js +0 -2
  259. package/dist/cli-bundle/chunks/create-I5DVV4YG.js +0 -2
  260. package/dist/cli-bundle/chunks/delete-RL3JACSW.js +0 -2
  261. package/dist/cli-bundle/chunks/deps-S7UBCECS.js +0 -2
  262. package/dist/cli-bundle/chunks/docs-ZZNVBBYO.js +0 -2
  263. package/dist/cli-bundle/chunks/files-27C337VT.js +0 -2
  264. package/dist/cli-bundle/chunks/focus-5Z2SG7LU.js +0 -2
  265. package/dist/cli-bundle/chunks/history-compact-HJQK67CZ.js +0 -2
  266. package/dist/cli-bundle/chunks/history-redact-PWC6PDWA.js +0 -2
  267. package/dist/cli-bundle/chunks/history-repair-N3CY4WBF.js +0 -2
  268. package/dist/cli-bundle/chunks/learnings-4FH23XDT.js +0 -2
  269. package/dist/cli-bundle/chunks/profile-5Y5XXH5N.js +0 -2
  270. package/dist/cli-bundle/chunks/register-mutation-YGYPW3BL.js +0 -20
  271. package/dist/cli-bundle/chunks/register-operations-WMDSUMQF.js +0 -2
  272. package/dist/cli-bundle/chunks/register-setup-DL7FFABC.js +0 -2
  273. package/dist/cli-bundle/chunks/restore-6KYBV5BY.js +0 -2
  274. package/dist/cli-bundle/chunks/schema-EQGKBYXJ.js +0 -2
  275. package/dist/cli-bundle/chunks/update-QVTYOD6I.js +0 -2
  276. package/dist/cli-bundle/chunks/update-many-DJSBU525.js +0 -2
  277. package/dist/cli-bundle/focused-chunks/chunk-2ECLECMK.js +0 -12
  278. package/dist/cli-bundle/focused-chunks/chunk-3K4XV2BF.js +0 -16
  279. package/dist/cli-bundle/focused-chunks/chunk-4EX25PXM.js +0 -8
  280. package/dist/cli-bundle/focused-chunks/chunk-CIXVQPB7.js +0 -5
  281. package/dist/cli-bundle/focused-chunks/chunk-DLTS3IHM.js +0 -2
  282. package/dist/cli-bundle/focused-chunks/chunk-DQ6FKGL3.js +0 -14
  283. package/dist/cli-bundle/focused-chunks/chunk-JLG2C4EQ.js +0 -2
  284. package/dist/cli-bundle/focused-chunks/chunk-MHMTKV5V.js +0 -2
  285. package/dist/cli-bundle/focused-chunks/chunk-MOTJFQ3F.js +0 -153
  286. package/dist/cli-bundle/focused-chunks/chunk-RW5IYD4J.js +0 -4
  287. package/dist/cli-bundle/focused-chunks/chunk-VZFU2R4M.js +0 -2
  288. package/dist/cli-bundle/focused-chunks/chunk-ZJIMJHDB.js +0 -2
@@ -5,10 +5,12 @@
5
5
  * governance and package-owned duplicate analysis.
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]="078456b8-ed61-5c47-afc7-7553833934e1")}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]="a2fad90a-3575-5f3e-8cbe-ac380ac45591")}catch(e){}}();
9
9
  import { EXIT_CODE } from "../core/shared/constants.js";
10
10
  import { PmCliError } from "../core/shared/errors.js";
11
11
  import { resolveItemTypeRegistry } from "../core/item/type-registry.js";
12
+ import { normalizeStatusInput } from "../core/item/status.js";
13
+ import { resolveRuntimeStatusRegistry } from "../core/schema/runtime-schema.js";
12
14
  import { listAllItemMetadataLight } from "../core/store/item-store.js";
13
15
  import { resolvePmRoot } from "../core/store/paths.js";
14
16
  import { readSettings } from "../core/store/settings.js";
@@ -62,14 +64,38 @@ async function loadPreparedDuplicateItems(options, since) {
62
64
  const pmRoot = resolvePmRoot(options.cwd ?? process.cwd(), options.pmRoot);
63
65
  const settings = await readSettings(pmRoot);
64
66
  const typeRegistry = resolveItemTypeRegistry(settings);
65
- const allowedStatuses = options.statuses
66
- ? new Set(options.statuses.map((status) => status.trim()).filter(Boolean))
67
+ const requestedStatuses = options.statuses
68
+ ?.map((status) => status.trim().toLowerCase())
69
+ .filter(Boolean);
70
+ if (options.statuses !== undefined && requestedStatuses?.length === 0) {
71
+ throw new PmCliError("Duplicate cluster statuses must include at least one lifecycle status or all.", EXIT_CODE.USAGE);
72
+ }
73
+ const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
74
+ const normalizedStatuses = requestedStatuses?.map((status) => {
75
+ if (status === "all")
76
+ return status;
77
+ const normalized = normalizeStatusInput(status, statusRegistry);
78
+ if (!normalized) {
79
+ throw new PmCliError(`Unknown duplicate-cluster status "${status}". Allowed: all, ${statusRegistry.definitions.map((entry) => entry.id).join(", ")}.`, EXIT_CODE.USAGE);
80
+ }
81
+ return normalized;
82
+ });
83
+ const hasAll = normalizedStatuses?.includes("all") === true;
84
+ if (hasAll && normalizedStatuses?.some((status) => status !== "all")) {
85
+ throw new PmCliError('The "all" status cannot be combined with other statuses.', EXIT_CODE.USAGE);
86
+ }
87
+ const effectiveStatuses = hasAll ? undefined : normalizedStatuses;
88
+ const allowedStatuses = effectiveStatuses
89
+ ? new Set(effectiveStatuses)
67
90
  : undefined;
68
- return (await listAllItemMetadataLight(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema))
69
- .filter((item) => (!allowedStatuses || allowedStatuses.has(item.status)) &&
70
- (!since || new Date(item.created_at).getTime() >= since.getTime()))
71
- .sort((left, right) => left.id.localeCompare(right.id))
72
- .map((item) => ({ item, prepared: prepareSimilarityText(item.title) }));
91
+ return {
92
+ items: (await listAllItemMetadataLight(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema))
93
+ .filter((item) => (!allowedStatuses || allowedStatuses.has(item.status)) &&
94
+ (!since || new Date(item.created_at).getTime() >= since.getTime()))
95
+ .sort((left, right) => left.id.localeCompare(right.id))
96
+ .map((item) => ({ item, prepared: prepareSimilarityText(item.title) })),
97
+ statuses: effectiveStatuses,
98
+ };
73
99
  }
74
100
  function collectDuplicateCandidatePairs(items, maxPairEvaluations = MAX_BATCH_PAIR_EVALUATIONS) {
75
101
  const candidates = new Set();
@@ -233,7 +259,7 @@ export async function findDuplicateClusters(options = {}) {
233
259
  limit: undefined,
234
260
  });
235
261
  const { limit, since } = validateDuplicateClusterOptions(options);
236
- const items = await loadPreparedDuplicateItems(options, since);
262
+ const { items, statuses } = await loadPreparedDuplicateItems(options, since);
237
263
  const candidates = collectDuplicateCandidatePairs(items);
238
264
  const union = createDuplicateUnionFind(items.length);
239
265
  const matches = scoreDuplicateCandidates(items, candidates, threshold, union);
@@ -243,6 +269,10 @@ export async function findDuplicateClusters(options = {}) {
243
269
  count: clusters.length,
244
270
  threshold,
245
271
  source: "metadata_scan",
272
+ filters: {
273
+ statuses: statuses ?? null,
274
+ since: options.since ?? null,
275
+ },
246
276
  cost: {
247
277
  item_count: items.length,
248
278
  candidate_pairs: candidates.size,
@@ -273,4 +303,4 @@ export async function evaluateSimilarityGovernance(candidate, options) {
273
303
  return { mode: options.mode, bypassed, result };
274
304
  }
275
305
  //# sourceMappingURL=similarity.js.map
276
- //# debugId=078456b8-ed61-5c47-afc7-7553833934e1
306
+ //# debugId=a2fad90a-3575-5f3e-8cbe-ac380ac45591
@@ -5,7 +5,7 @@
5
5
  * transaction contract and normalizes full item documents for CLI round trips.
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]="91be2c5d-c495-54bc-ac79-b4c645ad2c6e")}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]="07876c03-63a8-5c69-9c6c-c3446076a382")}catch(e){}}();
9
9
  import crypto from "node:crypto";
10
10
  import { normalizeItemId, normalizePrefix } from "../core/item/id.js";
11
11
  import { EXIT_CODE, ITEM_PROJECT_CONTEXT_KEYS, } from "../core/shared/constants.js";
@@ -43,6 +43,9 @@ const READ_ONLY_ITEM_KEYS = new Set([
43
43
  "format_version",
44
44
  "path",
45
45
  "author",
46
+ "collection_counts",
47
+ "notes_count",
48
+ "tests_count",
46
49
  ]);
47
50
  const UPDATE_READ_ONLY_ITEM_KEYS = new Set([
48
51
  ...READ_ONLY_ITEM_KEYS,
@@ -568,4 +571,4 @@ export function validateItemMutationRows(value) {
568
571
  return parseItemMutationBatch(JSON.stringify(value));
569
572
  }
570
573
  //# sourceMappingURL=structured-mutations.js.map
571
- //# debugId=91be2c5d-c495-54bc-ac79-b4c645ad2c6e
574
+ //# debugId=07876c03-63a8-5c69-9c6c-c3446076a382
@@ -4,7 +4,7 @@
4
4
  * Implements the pm test 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]="7d05534b-3cf7-506c-8626-4bd4a42cbc80")}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]="2c0646bf-44d7-521f-aea1-b0683d88a8fa")}catch(e){}}();
8
8
  import { spawn } from "node:child_process";
9
9
  import { cp, mkdir, mkdtemp, open, readdir, rm } from "node:fs/promises";
10
10
  import { tmpdir } from "node:os";
@@ -28,6 +28,7 @@ import { LINKED_TEST_PM_CONTEXT_MODE_VALUES as PM_CONTEXT_MODE_VALUES, LINKED_TE
28
28
  import { parseOnlyIndexValue, resolveLinkedTestRunSelection, } from "../../core/test/run-selectors.js";
29
29
  import { SCOPE_VALUES } from "../../types/index.js";
30
30
  import { diffTestRunMeasurements, parseTestRunMeasurements, queryTestRunMeasurementsBelow, } from "./measurements.js";
31
+ import { SOURCE_CONTEXT_ACCESS_ENV } from "../environment/source-context.js";
31
32
  const TEST_OUTPUT_MAX_BUFFER_BYTES = 20 * 1024 * 1024;
32
33
  const DEFAULT_LINKED_TEST_TIMEOUT_FORCE_KILL_DELAY_MS = 3000;
33
34
  const DEFAULT_LINKED_TEST_HEARTBEAT_INTERVAL_MS = 10000;
@@ -1398,6 +1399,7 @@ function buildLinkedTestExecutionEnv(params) {
1398
1399
  process.env.PM_SOURCE_WORKSPACE_ROOT ?? process.cwd();
1399
1400
  executionEnv.PM_SOURCE_PM_PATH =
1400
1401
  params.executionContext.source_project_pm_path;
1402
+ executionEnv[SOURCE_CONTEXT_ACCESS_ENV] = "read_only";
1401
1403
  return executionEnv;
1402
1404
  }
1403
1405
  function buildLinkedTestPassedResult(linkedTest, executionContext, execution) {
@@ -1872,4 +1874,4 @@ export const _testOnlyTestCommand = {
1872
1874
  summarizeRunResultStatuses,
1873
1875
  };
1874
1876
  //# sourceMappingURL=execution.js.map
1875
- //# debugId=7d05534b-3cf7-506c-8626-4bd4a42cbc80
1877
+ //# debugId=2c0646bf-44d7-521f-aea1-b0683d88a8fa
@@ -1,8 +1,3 @@
1
- /**
2
- * @module sdk/test/linked-command-detection
3
- *
4
- * Parses linked-test command invocations for sandbox and context-safety checks.
5
- */
6
1
  /** Public contract for pm global flags with value, shared by SDK and presentation-layer consumers. */
7
2
  export declare const PM_GLOBAL_FLAGS_WITH_VALUE: Set<string>;
8
3
  /** Value-bearing flags accepted before item positionals by item-referencing commands. */
@@ -28,7 +23,7 @@ export declare const SCRIPT_RUN_FLAGS_WITH_VALUE: Set<string>;
28
23
  /** Implements split normalized command segments for the public runtime surface of this module. */
29
24
  export declare function splitNormalizedCommandSegments(normalizedCommand: string): string[];
30
25
  /** Extract pm CLI arguments from one normalized shell-command segment. */
31
- export declare function extractPmInvocationArgsFromSegment(segment: string): string[] | null;
26
+ export declare function extractPmInvocationArgsFromSegment(segment: string, cwd?: string): string[] | null;
32
27
  /** Extract referenced item IDs from pm CLI invocations embedded in one command. */
33
28
  export declare const extractReferencedPmItemIdsFromCommand: (command: string, idPrefix?: string) => string[];
34
29
  /** Implements strip leading env assignments for the public runtime surface of this module. */
@@ -42,7 +37,7 @@ export declare function normalizePackageSpecifier(token: string): string;
42
37
  /** Implements check whether pm cli package token for the public runtime surface of this module. */
43
38
  export declare function isPmCliPackageToken(token: string): boolean;
44
39
  /** Implements check whether pm cli script token for the public runtime surface of this module. */
45
- export declare function isPmCliScriptToken(token: string): boolean;
40
+ export declare function isPmCliScriptToken(token: string, cwd?: string): boolean;
46
41
  /** Implements parse npx command for the public runtime surface of this module. */
47
42
  export declare function parseNpxCommand(tokens: string[]): {
48
43
  command: string;
@@ -9,7 +9,9 @@
9
9
  // normalized command string. Kept in core so SDK governance and CLI test
10
10
  // execution share one dependency-direction-safe parser.
11
11
 
12
- !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]="8c4d45cf-6b97-5151-a325-db09d31962a7")}catch(e){}}();
12
+ !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]="673a5a26-6214-58d6-af19-baee5a8359f0")}catch(e){}}();
13
+ import { readFileSync } from "node:fs";
14
+ import path from "node:path";
13
15
  const PM_SUBCOMMANDS_WITH_ITEM_REFERENCE = new Set([
14
16
  "get",
15
17
  "history",
@@ -277,15 +279,15 @@ export function splitNormalizedCommandSegments(normalizedCommand) {
277
279
  .filter((segment) => segment.length > 0);
278
280
  }
279
281
  /** Extract pm CLI arguments from one normalized shell-command segment. */
280
- export function extractPmInvocationArgsFromSegment(segment) {
282
+ export function extractPmInvocationArgsFromSegment(segment, cwd = process.cwd()) {
281
283
  const tokens = stripLeadingEnvAssignments(segment.split(" ").filter((token) => token.length > 0));
282
284
  if (tokens.length === 0)
283
285
  return null;
284
286
  const [executable, ...args] = tokens;
285
- if (isPmExecutableToken(executable) || isPmCliScriptToken(executable)) {
287
+ if (isPmExecutableToken(executable) || isPmCliScriptToken(executable, cwd)) {
286
288
  return args;
287
289
  }
288
- if (executable === "node" && args[0] && isPmCliScriptToken(args[0])) {
290
+ if (executable === "node" && args[0] && isPmCliScriptToken(args[0], cwd)) {
289
291
  return args.slice(1);
290
292
  }
291
293
  const invocation = executable === "npx" || executable === "bunx"
@@ -408,10 +410,21 @@ export function isPmCliPackageToken(token) {
408
410
  token.endsWith("/pm-cli"));
409
411
  }
410
412
  /** Implements check whether pm cli script token for the public runtime surface of this module. */
411
- export function isPmCliScriptToken(token) {
412
- return (token === "dist/cli.js" ||
413
- token === "./dist/cli.js" ||
414
- token.endsWith("/dist/cli.js"));
413
+ export function isPmCliScriptToken(token, cwd = process.cwd()) {
414
+ const normalized = token.replaceAll("\\", "/");
415
+ if (normalized !== "dist/cli.js" &&
416
+ normalized !== "./dist/cli.js" &&
417
+ !normalized.endsWith("/dist/cli.js")) {
418
+ return false;
419
+ }
420
+ const scriptPath = path.resolve(cwd, token);
421
+ try {
422
+ const packageJson = JSON.parse(readFileSync(path.join(path.dirname(path.dirname(scriptPath)), "package.json"), "utf8"));
423
+ return packageJson.name === "@unbrained/pm-cli";
424
+ }
425
+ catch {
426
+ return false;
427
+ }
415
428
  }
416
429
  /** Implements parse npx command for the public runtime surface of this module. */
417
430
  export function parseNpxCommand(tokens) {
@@ -531,4 +544,4 @@ export function firstPositionalToken(tokens, flagsWithValue = new Set()) {
531
544
  return undefined;
532
545
  }
533
546
  //# sourceMappingURL=linked-command-detection.js.map
534
- //# debugId=8c4d45cf-6b97-5151-a325-db09d31962a7
547
+ //# debugId=673a5a26-6214-58d6-af19-baee5a8359f0
@@ -4,13 +4,14 @@
4
4
  * Implements the pm linked test parsers 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]="f592ba2b-fc8d-5930-a2a5-d02835c457a3")}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]="74163bed-a473-543e-ae6a-0d5091b3b3a9")}catch(e){}}();
8
8
  import { parseOptionalNumber } from "../../core/item/parse.js";
9
9
  import { EXIT_CODE } from "../../core/shared/constants.js";
10
10
  import { PmCliError } from "../../core/shared/errors.js";
11
11
  import { splitCommaList } from "../../core/shared/split-comma-list.js";
12
12
  import { STRUCTURED_LINKED_TEST_KEYS } from "./entry.js";
13
13
  import { SCOPE_VALUES } from "../../types/index.js";
14
+ import { SOURCE_CONTEXT_ACCESS_ENV, SOURCE_CONTEXT_WRITE_OVERRIDE_ENV, } from "../environment/source-context.js";
14
15
  /**
15
16
  * Shared linked-test field parsers used by the `create` and `test` commands.
16
17
  *
@@ -30,6 +31,8 @@ export const LINKED_TEST_PROTECTED_ENV_KEYS = new Set([
30
31
  "PM_GLOBAL_PATH",
31
32
  "PM_SOURCE_PM_PATH",
32
33
  "PM_SOURCE_WORKSPACE_ROOT",
34
+ SOURCE_CONTEXT_ACCESS_ENV,
35
+ SOURCE_CONTEXT_WRITE_OVERRIDE_ENV,
33
36
  "FORCE_COLOR",
34
37
  ]);
35
38
  /** Public contract for linked test env name pattern, shared by SDK and presentation-layer consumers. */
@@ -521,4 +524,4 @@ export const _testOnlyLinkedTestParsers = {
521
524
  parseLinkedTestJsonEntry,
522
525
  };
523
526
  //# sourceMappingURL=parsers.js.map
524
- //# debugId=f592ba2b-fc8d-5930-a2a5-d02835c457a3
527
+ //# debugId=74163bed-a473-543e-ae6a-0d5091b3b3a9
@@ -29,6 +29,7 @@ declare class WorkspaceLockHeartbeat {
29
29
  /** Internal heartbeat constructor exposed only for deterministic lock tests. */
30
30
  export declare const _testOnlyWorkspaceSnapshot: {
31
31
  WorkspaceLockHeartbeat: typeof WorkspaceLockHeartbeat;
32
+ withSnapshotFilesystemGuard: typeof withSnapshotFilesystemGuard;
32
33
  };
33
34
  /** Immutable manifest stored with every content-addressed snapshot object. */
34
35
  export interface WorkspaceSnapshotManifest {
@@ -117,6 +118,14 @@ export interface RestoreWorkspaceSnapshotResult {
117
118
  /** Stable audit operation appended after staging and before activation. */
118
119
  audit_operation: "workspace_snapshot_restore";
119
120
  }
121
+ /**
122
+ * Runs a bounded snapshot filesystem stage, converting host environment faults
123
+ * into declared refusals.
124
+ *
125
+ * The operation label is a fixed identifier, never a path: snapshot failures
126
+ * are reported without disclosing workspace topology.
127
+ */
128
+ declare function withSnapshotFilesystemGuard<T>(operation: string, run: () => Promise<T>): Promise<T>;
120
129
  /**
121
130
  * Publish a prepared immutable object, treating a concurrent winning publish
122
131
  * as successful deduplication.
@@ -5,7 +5,7 @@
5
5
  * state while excluding clone-local caches, locks, and recovery journals.
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]="3e32be7c-f8a4-547d-8c19-456b4567982e")}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]="cdde844a-a14a-501d-a45b-18cbd1dd9008")}catch(e){}}();
9
9
  import crypto from "node:crypto";
10
10
  import { cp, lstat, mkdir, readFile, readdir, rename, rm, writeFile, } from "node:fs/promises";
11
11
  import path from "node:path";
@@ -15,6 +15,7 @@ import { acquireLock } from "../core/lock/lock.js";
15
15
  import { getLockPath } from "../core/store/paths.js";
16
16
  import { EXIT_CODE } from "../core/shared/constants.js";
17
17
  import { PmCliError } from "../core/shared/errors.js";
18
+ import { withHostEnvironmentBoundary } from "./environment/host-environment-errors.js";
18
19
  /** Current content-addressed workspace snapshot manifest schema identifier. */
19
20
  export const SNAPSHOT_SCHEMA = "https://schema.unbrained.dev/pm/workspace-snapshot/v1";
20
21
  const SNAPSHOT_RUNTIME_PATH = path.join("runtime", "workspace-snapshots");
@@ -27,6 +28,11 @@ const EXCLUDED_ROOT_NAMES = new Set([
27
28
  ]);
28
29
  const SNAPSHOT_TARGET_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
29
30
  const WORKSPACE_WRITER_LOCK_ID = "sdk-workspace-transaction";
31
+ const SNAPSHOT_HOST_FAULT_CODES = {
32
+ capacity: { code: "workspace_snapshot_storage_exhausted" },
33
+ permission: { code: "workspace_snapshot_permission_denied" },
34
+ resource: { code: "workspace_snapshot_resource_exhausted" },
35
+ };
30
36
  const DEFAULT_ATOMIC_OPERATIONS = {
31
37
  renameEntry: rename,
32
38
  removeEntry: async (target) => {
@@ -97,6 +103,7 @@ class WorkspaceLockHeartbeat {
97
103
  /** Internal heartbeat constructor exposed only for deterministic lock tests. */
98
104
  export const _testOnlyWorkspaceSnapshot = {
99
105
  WorkspaceLockHeartbeat,
106
+ withSnapshotFilesystemGuard,
100
107
  };
101
108
  async function collectAuthoritativeFiles(root, relative = "") {
102
109
  const entries = await readdir(path.join(root, relative), {
@@ -193,6 +200,27 @@ function isErrno(error, code) {
193
200
  "code" in error &&
194
201
  error.code === code);
195
202
  }
203
+ /**
204
+ * Runs a bounded snapshot filesystem stage, converting host environment faults
205
+ * into declared refusals.
206
+ *
207
+ * The operation label is a fixed identifier, never a path: snapshot failures
208
+ * are reported without disclosing workspace topology.
209
+ */
210
+ async function withSnapshotFilesystemGuard(operation, run) {
211
+ return withHostEnvironmentBoundary(`workspace_snapshot_${operation}`, run, {
212
+ codes: {
213
+ capacity: SNAPSHOT_HOST_FAULT_CODES.capacity.code,
214
+ permission: SNAPSHOT_HOST_FAULT_CODES.permission.code,
215
+ resource: SNAPSHOT_HOST_FAULT_CODES.resource.code,
216
+ },
217
+ why: "Snapshot create and restore copy authoritative tracker state before activation, so the stage needs capacity and write access up front.",
218
+ nextSteps: [
219
+ "Reclaim rebuildable tracker cache space with pm gc, then retry.",
220
+ ],
221
+ suggestedRetry: "pm gc --json",
222
+ });
223
+ }
196
224
  function snapshotStore(pmRoot) {
197
225
  return path.join(pmRoot, SNAPSHOT_RUNTIME_PATH);
198
226
  }
@@ -302,14 +330,16 @@ export async function createWorkspaceSnapshot(pmRoot, options = {}) {
302
330
  }
303
331
  if (!deduplicated) {
304
332
  const temporaryRoot = path.join(store, "objects", `.create-${process.pid}-${crypto.randomUUID()}`);
305
- await mkdir(path.join(temporaryRoot, "files"), { recursive: true });
306
- for (const [index, file] of manifest.files.entries()) {
307
- const target = path.join(temporaryRoot, "files", file);
308
- await mkdir(path.dirname(target), { recursive: true });
309
- await writeFile(target, contents[index]);
310
- }
311
- await writeFile(path.join(temporaryRoot, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
312
- await mkdir(path.dirname(objectRoot), { recursive: true });
333
+ await withSnapshotFilesystemGuard("create_object", async () => {
334
+ await mkdir(path.join(temporaryRoot, "files"), { recursive: true });
335
+ for (const [index, file] of manifest.files.entries()) {
336
+ const target = path.join(temporaryRoot, "files", file);
337
+ await mkdir(path.dirname(target), { recursive: true });
338
+ await writeFile(target, contents[index]);
339
+ }
340
+ await writeFile(path.join(temporaryRoot, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
341
+ await mkdir(path.dirname(objectRoot), { recursive: true });
342
+ });
313
343
  deduplicated = await publishWorkspaceSnapshotObject(temporaryRoot, objectRoot);
314
344
  }
315
345
  if (options.name !== undefined) {
@@ -467,12 +497,14 @@ export async function restoreWorkspaceSnapshotWithRecovery(pmRoot, target, optio
467
497
  const base = path.basename(pmRoot);
468
498
  staging = path.join(parent, `.${base}.restore-${crypto.randomUUID()}`);
469
499
  const backup = path.join(parent, `.${base}.backup-${crypto.randomUUID()}`);
470
- await mkdir(staging, { recursive: true });
471
- await cp(source, staging, { recursive: true, force: false });
472
- await mkdir(path.join(staging, "runtime"), { recursive: true });
473
- await cp(store, path.join(staging, SNAPSHOT_RUNTIME_PATH), {
474
- recursive: true,
475
- force: false,
500
+ await withSnapshotFilesystemGuard("restore_stage", async () => {
501
+ await mkdir(staging, { recursive: true });
502
+ await cp(source, staging, { recursive: true, force: false });
503
+ await mkdir(path.join(staging, "runtime"), { recursive: true });
504
+ await cp(store, path.join(staging, SNAPSHOT_RUNTIME_PATH), {
505
+ recursive: true,
506
+ force: false,
507
+ });
476
508
  });
477
509
  const audit = await appendWorkspaceAuditEvent({
478
510
  pmRoot: staging,
@@ -564,4 +596,4 @@ export async function deleteWorkspaceSnapshot(pmRoot, target) {
564
596
  return { deleted: "object", target };
565
597
  }
566
598
  //# sourceMappingURL=workspace-snapshot.js.map
567
- //# debugId=3e32be7c-f8a4-547d-8c19-456b4567982e
599
+ //# debugId=cdde844a-a14a-501d-a45b-18cbd1dd9008
@@ -189,6 +189,7 @@ Use these defaults unless the task requires otherwise:
189
189
  - `pm validate --check-resolution --check-history-drift` before closing broad work.
190
190
  - `pm history-redact <id> --dry-run` before rewriting sensitive history payloads, then rerun without `--dry-run` once scope is confirmed.
191
191
  - `pm history-repair <id> --dry-run` when `pm health` or `pm validate --check-history-drift` report drifted streams; it re-anchors the hash chain and reconciles with the on-disk item without touching item content. Rerun without `--dry-run` to apply.
192
+ - `pm merge reconcile --dry-run --json` after a branch merge that touched tracker data. Review every discarded-value receipt before applying; a lossy reconciliation requires the explicit `--force` acceptance flag. `history-repair` alone does not settle merge receipts.
192
193
  - `pm schema list` and `pm schema show <Type>` before creating custom-domain work; they show built-in, persisted custom, and extension-provided item types without reading schema files by hand.
193
194
  - `pm schema add-type <Name>` when `pm create`/`pm update` reject a project-specific type as invalid; it registers the type in `.agents/pm/schema/types.json` so `pm create <Name> "..."` works. Built-in types are reserved; the upsert is idempotent. `pm schema remove-type <Name>` removes a custom type (warns, non-blocking, if items still use it).
194
195
  - `pm schema add-status <id> --role <role>` / `pm schema remove-status <id>` manage custom lifecycle statuses in `.agents/pm/schema/statuses.json`; roles come from the runtime status-role vocabulary, the upsert is idempotent, and built-in default statuses cannot be removed. `pm schema list` now reports statuses (builtin vs custom) alongside types.
@@ -204,7 +205,7 @@ Use these defaults unless the task requires otherwise:
204
205
  Concurrent agents work on ordinary Git branches/worktrees; tracker artifacts need the semantic merge contract from [Merge Safety](MERGE_SAFETY.md). The short loop:
205
206
 
206
207
  - After a fresh clone or new worktree, run `pm merge install` once so the field-aware merge drivers back the committed `.gitattributes` fence.
207
- - After every merge that touches `.agents/pm`, run `pm validate --check-storage-integrity` and `pm history --verify --strict-exit`; follow the remediation output (`pm history-repair` wiring included).
208
+ - After every merge that touches `.agents/pm`, run `pm merge reconcile --dry-run --json`, review the receipt classification, then apply `pm merge reconcile`. Add `--force` only after explicitly accepting or re-applying every discarded scalar value. Finish with `pm validate --check-storage-integrity` and `pm history --verify --strict-exit`.
208
209
  - Repositories fanning out many branches between merges should raise id entropy: `pm config project set ids_token_length 6`.
209
210
  - Use `--add-ac`/`--remove-ac` (not `--ac`) so concurrent acceptance-criteria edits merge instead of clobbering.
210
211
 
@@ -25,6 +25,8 @@ historical projections, and versioned legacy identity are tracked by
25
25
  [pm-ffz0a9](../.agents/pm/issues/pm-ffz0a9.toon),
26
26
  [pm-v8gfi7](../.agents/pm/issues/pm-v8gfi7.toon), and
27
27
  [pm-3yxwv5](../.agents/pm/issues/pm-3yxwv5.toon).
28
+ [pm-alhqbz](../.agents/pm/issues/pm-alhqbz.toon) governs the nested source-write
29
+ boundary retained by linked-test package lifecycles.
28
30
 
29
31
  `pm` treats project management as context management. These primitives keep
30
32
  mutation provenance, source-workspace identity, extension flags, and bounded
@@ -198,10 +200,15 @@ Every extension command, parser, preflight hook, renderer, and service receives:
198
200
  Linked tests set `PM_SOURCE_WORKSPACE_ROOT` before replacing `PM_PATH` and
199
201
  `PM_GLOBAL_PATH`, and protect `PM_SOURCE_PM_PATH` as the read-only source
200
202
  tracker coordinate for source-repository lifecycle commands such as
201
- `pm merge install`. Extensions can therefore inspect source VCS metadata
202
- without writing real tracker state. Package code should prefer `pm_root_rel`
203
- in output and persisted evidence to avoid leaking host-specific absolute
204
- paths.
203
+ `pm merge install`. They also set `PM_SOURCE_CONTEXT_ACCESS=read_only`.
204
+ Validation may continue to inspect the source coordinates, but a nested
205
+ non-dry-run `pm merge install` selects the current package repository instead
206
+ of the source workspace. A maintainer can deliberately opt into the legacy
207
+ source mutation for one invocation with `PM_ALLOW_SOURCE_CONTEXT_WRITES=1`;
208
+ `resolveMergeInstallContext()` reports whether that override selects the source.
209
+ Both variables are protected from linked-test `env_set` and `env_clear`
210
+ metadata. Package code should prefer `pm_root_rel` in output and persisted
211
+ evidence to avoid leaking host-specific absolute paths.
205
212
 
206
213
  ## Strict extension flag descriptors
207
214
 
package/docs/COMMANDS.md CHANGED
@@ -78,6 +78,7 @@ Use `--with-packages` for one-step agent setup when bundled package commands sho
78
78
  pm package # bare command defaults to --explore (list installed)
79
79
  pm install '*' --project
80
80
  pm package catalog --project
81
+ pm package manage --project --output-format json
81
82
  pm install npm:@scope/pm-package --project
82
83
  pm package describe --project # by-name surface map of every loaded package
83
84
  pm package describe my-package --markdown --output docs/my-package-reference.md
@@ -90,6 +91,11 @@ pm upgrade --cli-only --repair
90
91
  ```
91
92
 
92
93
  `pm install` and `pm package` are the preferred package-first workflow. `pm package` and `pm extension` bare invocations default to `--explore` so agents can list installed packages without remembering an action flag. `pm install '*'`, shell-expanded `pm install *`, and `pm install all` install bundled first-party packages. `pm extension` remains as a compatibility command for direct extension lifecycle operations.
94
+ `pm package catalog` emits one row per package, with every resolvable bundled
95
+ alias preserved in `aliases`; totals therefore measure packages rather than
96
+ alias-index entries. `pm package manage` participates in the universal read
97
+ output contract, so `--output-include`, `--output-limit`, `--output-budget`, and
98
+ `--output-format` behave like the same controls on other SDK-backed reads.
93
99
  Install output includes a light `verification` summary with target tracker root, activation state, registered commands/actions/item types, and an `ok|degraded` health verdict. Runtime activation failure sets the command result and process exit status to failure; inspect `activation_diagnostics` and `command_discovery.next_steps` for the exact recovery path.
94
100
  Bare install names use bundled aliases before installed npm packages. Every
95
101
  install result reports `source_resolution`; when both candidates exist it marks
@@ -113,6 +119,7 @@ pm list-open --type Task --priority 1 --limit 20
113
119
  pm list-in-progress --limit 20
114
120
  pm aggregate --group-by parent,type --status open
115
121
  pm aggregate --group-by parent,type --completion --include-unparented
122
+ pm duplicates --status all --threshold 0.8
116
123
  ```
117
124
 
118
125
  Use `pm next` when the only question is "what should I work on now?" It computes dependency-aware readiness, keeps dangling dependency ids blocked until repaired, and combines lifecycle-blocked plus graph-blocked work in the companion queue. The `recommended` projection is excluded from the `ready` tail; every actionable row carries its one-based `rank`, and the tail preserves the exact recommendation order. Foreign-owned in-progress work is summarized under `held_by_others`. Human-gated `Decision` records remain visible under `decision_needed` but are excluded from agent recommendations by default.
@@ -126,6 +133,10 @@ pm next --ready-only --limit 3 --json # tightest agent-loop projection
126
133
  ```
127
134
 
128
135
  Use `context` first for a compact active-work snapshot. Use `search` when the request names a concept, component, or prior issue.
136
+ Use `duplicates --status all` for a true whole-history duplicate check. The
137
+ result echoes `filters.statuses: null` for the unrestricted corpus; named or
138
+ custom statuses are normalized through the runtime status registry and an
139
+ unknown status fails instead of returning a false-clean result.
129
140
  Use `pm get <id>` to read a single item by ID — the single-item read primitive used throughout the agent loop. It accepts `--fields <list>` and `--depth brief|standard|deep|full` for token-minimal projections, and `--tree`/`--tree-depth <n>` to include descendants. Standard/deep reads expose a normalized `schedule` facet (`deadline`, `start_at`, `end_at`, `location`, reminders, and events) when scheduling metadata exists. Container-oriented built-ins (Epic, Feature, Milestone, and Plan) plus custom types automatically expose type-agnostic child counts and continuation metadata. Standard depth keeps that rollup counts-only; `--depth deep|full` or an explicit `--fields id,children` request adds the deterministic bounded child sample. Built-in leaf reads avoid a workspace scan unless children are explicitly requested. `pm get <id> --json` returns the `body` inside the `item` object (`.item.body`); see [Full results, totals, and bodies](#full-results-totals-and-bodies). To duplicate an existing item as a starting point, `pm copy <id> --title "New title"` clones it into a fresh id with lifecycle fields reset.
130
141
 
131
142
  Add `--at <version|ISO-timestamp>` for a verified point-in-time read. It replays the same hash-checked history kernel used by restore but never acquires a lock, writes the item, or appends history. The result always includes `reconstructed: true`, `as_of_version`, and `as_of_timestamp`. Future/out-of-range targets fail with structured `valid_range` metadata. `--at` cannot be combined with `--tree`; workspace-wide historical graph projections require a future indexed primitive.
@@ -891,12 +902,19 @@ one-command reconciliation gate:
891
902
  ```bash
892
903
  pm merge reconcile --dry-run --json
893
904
  pm merge reconcile --message "Reconcile branch histories" --json
905
+ # Only after reviewing every discarded-value receipt:
906
+ pm merge reconcile --force --message "Accept reviewed merge decisions" --json
894
907
  ```
895
908
 
896
909
  The command scans every history stream, delegates repairs to the audited
897
910
  `history-repair --all` engine, then runs the history-drift and storage-integrity
898
911
  validation checks. Dry-run leaves drift intact and reports it in `validation`;
899
- apply exits nonzero if any stream fails or either invariant stays red. No Git
912
+ apply exits nonzero if any stream fails or either invariant stays red. Lossless
913
+ receipts remain visible in `pm merge report` but do not count as discarded-value
914
+ decisions. When a receipt contains a discarded scalar value, apply refuses with
915
+ `merge_reconcile_discards_require_acceptance` until the coordinator reviews or
916
+ re-applies the value and passes `--force`. `pm history-repair` is the narrower
917
+ drift-only tool and never substitutes for receipt reconciliation. No Git
900
918
  hook is installed automatically—teams may call this command from an explicit
901
919
  post-merge hook after opting into that policy.
902
920
 
@@ -0,0 +1,29 @@
1
+ # Dependency-kind contract
2
+
3
+ Tracker: [pm-4020c5](../.agents/pm/issues/pm-4020c5.toon), [pm-jkbqt8](../.agents/pm/issues/pm-jkbqt8.toon)
4
+
5
+ Dependency rows have one canonical stored spelling per relationship meaning. Command inputs remain compatibility-friendly: hyphens normalize to underscores and the aliases below are accepted, but `pm create` and `pm update` persist the canonical kind. Existing historical rows are never rewritten implicitly.
6
+
7
+ | Canonical kind | Accepted legacy aliases |
8
+ | --- | --- |
9
+ | `blocked_by` | `depends_on`, `depends-on` |
10
+ | `related` | `related_to`, `related-to` |
11
+ | `parent` | `child_of`, `child-of`, `epic` |
12
+ | `child` | `parent_child`, `parent-child`, `task` |
13
+
14
+ `epic` and `task` are compatibility aliases, not item types embedded in the relationship ontology. New integrations should use `parent` or `child` and express the work classification through the item `type` field.
15
+
16
+ The SDK relationship registry is authoritative. `canonicalizeRelationshipKind()` rejects unknown spellings, while `resolveCanonicalRelationshipKind()` supports validation flows that need an undefined result. `pm contracts` publishes `relationship_kind_contracts` with canonical names, aliases, inverses, and ordering/hierarchy semantics.
17
+
18
+ ## Direction and actionability
19
+
20
+ `blocked_by` and `blocks` are inverse storage directions with identical scheduling meaning:
21
+
22
+ - `A --blocked_by--> B` means A waits for B.
23
+ - `B --blocks--> A` means A waits for B.
24
+
25
+ Readiness, `pm next`, context blocker summaries, `pm list-blocked`, downstream `unblocks` projections, and close-time auto-unblock use that shared interpretation. This applies to mixed-direction corpora without migrating existing rows.
26
+
27
+ ## Legacy observability
28
+
29
+ `pm deps` returns `legacy_alias_counts` for the workspace. `pm graph audit` returns the same field beside the canonical `profile.edges_by_kind` counts. Empty objects mean no stored alias debt. These diagnostics are read-only; terminal history remains untouched until an explicitly governed migration is requested.
@@ -0,0 +1,26 @@
1
+ # Stable Item Read Projections
2
+
3
+ Tracker reference: [pm-b1w8vr](../.agents/pm/issues/pm-b1w8vr.toon).
4
+
5
+ Item mutation and read-back surfaces share one collection vocabulary:
6
+ `comments`, `notes`, `learnings`, `files`, `tests`, `docs`, `reminders`, and
7
+ `events`. Every normal `pm get` and SDK `runGet` result carries
8
+ `item.collection_counts` with all eight keys, including zero values. This gives
9
+ agents a stable, low-token way to verify a write without requesting complete
10
+ collection payloads.
11
+
12
+ `brief` and `standard` omit the collection arrays but retain the stable counts.
13
+ `deep`, `full`, and `--full` include every collection array, normalizing absent
14
+ collections to `[]`, and retain `notes_count`, `tests_count`, and
15
+ `collection_counts`. A full projection is therefore a structural superset of
16
+ the standard item projection rather than a different shape.
17
+
18
+ Field projections can request `collection_counts` directly:
19
+
20
+ ```bash
21
+ pm get pm-example --fields id,updated_at,collection_counts
22
+ ```
23
+
24
+ Package authors receive the same contract from `runGet`. Do not infer whether
25
+ a collection exists by checking for an omitted key; use the count projection,
26
+ or request a full projection when the entries themselves are needed.