@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
@@ -1,5 +1,6 @@
1
1
  import type { GlobalOptions } from "../../core/shared/command-types.js";
2
2
  import { readSettings } from "../../core/store/settings.js";
3
+ import { resolveSourceContextWritePolicy } from "../environment/source-context.js";
3
4
  /** Opening marker for the pm-owned merge-driver `.gitattributes` block. */
4
5
  export declare const PM_GITATTRIBUTES_START = "# pm-cli:merge-drivers:start";
5
6
  /** Closing marker for the pm-owned merge-driver `.gitattributes` block. */
@@ -37,6 +38,26 @@ export interface MergeInstallResult {
37
38
  /** ISO 8601 timestamp recording when generated occurred. */
38
39
  generated_at: string;
39
40
  }
41
+ /** Resolved tracker and workspace selection for one merge-install invocation. */
42
+ export interface MergeInstallContextResolution {
43
+ /** Tracker root selected without performing filesystem writes. */
44
+ pm_root: string;
45
+ /** Starting path used to discover the enclosing Git workspace. */
46
+ workspace_start: string;
47
+ /** Whether complete inherited source coordinates were present. */
48
+ source_coordinates_available: boolean;
49
+ /** Whether inherited source coordinates were selected. */
50
+ source_context_selected: boolean;
51
+ /** Source-coordinate write policy active for the invocation. */
52
+ source_policy: ReturnType<typeof resolveSourceContextWritePolicy>;
53
+ }
54
+ /** Resolve explicit, inherited-source, and current-workspace precedence without I/O. */
55
+ export declare function resolveMergeInstallContext(options: {
56
+ cwd: string;
57
+ explicitPath?: string;
58
+ dryRun: boolean;
59
+ environment: Readonly<Record<string, string | undefined>>;
60
+ }): MergeInstallContextResolution;
40
61
  /** Result of auditing clone-local driver definitions behind a committed fence. */
41
62
  export interface MergeDriverConfigurationAuditResult {
42
63
  /** Whether every required driver definition exactly matches this installation. */
@@ -8,7 +8,7 @@
8
8
  * mutations refresh the fenced block automatically once it is installed.
9
9
  */
10
10
 
11
- !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]="a250384a-0279-5d01-ade4-f64be3119ed9")}catch(e){}}();
11
+ !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]="cb6dc38e-b317-5739-83ff-cf459b8bb31e")}catch(e){}}();
12
12
  import { readFile, realpath, writeFile } from "node:fs/promises";
13
13
  import { execFile } from "node:child_process";
14
14
  import path from "node:path";
@@ -24,6 +24,7 @@ import { nowIso } from "../../core/shared/time.js";
24
24
  import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
25
25
  import { readSettings, resolveGovernanceKnobs, } from "../../core/store/settings.js";
26
26
  import { isPathOutsideRoot } from "../workspace.js";
27
+ import { resolveSourceContextWritePolicy } from "../environment/source-context.js";
27
28
  const execFileAsync = promisify(execFile);
28
29
  /** Opening marker for the pm-owned merge-driver `.gitattributes` block. */
29
30
  export const PM_GITATTRIBUTES_START = "# pm-cli:merge-drivers:start";
@@ -80,6 +81,45 @@ const MERGE_DRIVER_DEFINITIONS = [
80
81
  itemPath: undefined,
81
82
  },
82
83
  ];
84
+ /** Resolve explicit, inherited-source, and current-workspace precedence without I/O. */
85
+ export function resolveMergeInstallContext(options) {
86
+ const explicitPath = options.explicitPath?.trim();
87
+ const sourceWorkspaceRoot = options.environment.PM_SOURCE_WORKSPACE_ROOT?.trim();
88
+ const sourcePmRoot = options.environment.PM_SOURCE_PM_PATH?.trim();
89
+ const sourcePolicy = resolveSourceContextWritePolicy(options.environment);
90
+ const sourceCoordinatesAvailable = Boolean(sourceWorkspaceRoot && sourcePmRoot);
91
+ const sourceContextSelected = explicitPath === undefined &&
92
+ sourceCoordinatesAvailable &&
93
+ (options.dryRun || sourcePolicy.source_writes_allowed);
94
+ if (explicitPath !== undefined) {
95
+ const pmRoot = resolvePmRoot(options.cwd, explicitPath);
96
+ return {
97
+ pm_root: pmRoot,
98
+ workspace_start: pmRoot,
99
+ source_coordinates_available: sourceCoordinatesAvailable,
100
+ source_context_selected: false,
101
+ source_policy: sourcePolicy,
102
+ };
103
+ }
104
+ if (sourceContextSelected) {
105
+ return {
106
+ pm_root: path.resolve(sourcePmRoot),
107
+ workspace_start: path.resolve(sourceWorkspaceRoot),
108
+ source_coordinates_available: true,
109
+ source_context_selected: true,
110
+ source_policy: sourcePolicy,
111
+ };
112
+ }
113
+ return {
114
+ pm_root: sourceCoordinatesAvailable
115
+ ? resolvePmRoot(options.cwd, ".agents/pm")
116
+ : resolvePmRoot(options.cwd),
117
+ workspace_start: options.cwd,
118
+ source_coordinates_available: sourceCoordinatesAvailable,
119
+ source_context_selected: false,
120
+ source_policy: sourcePolicy,
121
+ };
122
+ }
83
123
  /** Resolve the enclosing Git worktree root or return null outside Git. */
84
124
  export async function findGitWorkspaceRoot(cwd) {
85
125
  try {
@@ -393,27 +433,17 @@ export async function refreshMergeAttributeFenceIfInstalled(pmRoot) {
393
433
  * per checkout). Requires an initialized tracker and a git repository.
394
434
  */
395
435
  export async function runMergeInstall(options, global) {
396
- const explicitPath = global.path?.trim();
397
- const sourceWorkspaceRoot = process.env.PM_SOURCE_WORKSPACE_ROOT?.trim();
398
- const sourcePmRoot = process.env.PM_SOURCE_PM_PATH?.trim();
399
- const usesLinkedTestSourceContext = explicitPath === undefined &&
400
- sourceWorkspaceRoot !== undefined &&
401
- sourceWorkspaceRoot.length > 0 &&
402
- sourcePmRoot !== undefined &&
403
- sourcePmRoot.length > 0;
404
- const pmRoot = explicitPath !== undefined
405
- ? resolvePmRoot(process.cwd(), explicitPath)
406
- : usesLinkedTestSourceContext
407
- ? path.resolve(sourcePmRoot)
408
- : resolvePmRoot(process.cwd());
436
+ const context = resolveMergeInstallContext({
437
+ cwd: process.cwd(),
438
+ explicitPath: global.path,
439
+ dryRun: options.dryRun === true,
440
+ environment: process.env,
441
+ });
442
+ const pmRoot = context.pm_root;
409
443
  if (!(await pathExists(getSettingsPath(pmRoot)))) {
410
444
  throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
411
445
  }
412
- const workspaceRoot = await resolveGitWorkspaceRoot(explicitPath !== undefined
413
- ? pmRoot
414
- : usesLinkedTestSourceContext
415
- ? path.resolve(sourceWorkspaceRoot)
416
- : process.cwd());
446
+ const workspaceRoot = await resolveGitWorkspaceRoot(context.workspace_start);
417
447
  return installMergeFence({
418
448
  pmRoot,
419
449
  workspaceRoot,
@@ -511,11 +541,11 @@ export async function installMergeFence(options) {
511
541
  guidance: [
512
542
  "Commit .gitattributes so every branch and collaborator shares the merge mapping.",
513
543
  'git config is per-clone: each collaborator (and each fresh worktree/clone) runs "pm merge install" once.',
514
- 'After merging branches, run "pm validate" and, if history drift is reported, "pm history-repair --all" to reconcile item state with merged history.',
544
+ 'After merging branches, run "pm merge reconcile --dry-run" to inspect the complete receipt and history repair, then apply "pm merge reconcile"; use --force only after explicitly accepting any discarded values.',
515
545
  "Custom item types registered later refresh this fence automatically (pm schema add-type/remove-type); rerun pm merge install only after out-of-band type-folder edits.",
516
546
  ],
517
547
  generated_at: nowIso(),
518
548
  };
519
549
  }
520
550
  //# sourceMappingURL=install.js.map
521
- //# debugId=a250384a-0279-5d01-ade4-f64be3119ed9
551
+ //# debugId=cb6dc38e-b317-5739-83ff-cf459b8bb31e
@@ -11,6 +11,8 @@ export interface MergeDecisionReceipt {
11
11
  item_id: string;
12
12
  /** Preferred side used for scalar conflicts. */
13
13
  preferred: MergePreferredSide;
14
+ /** Scalar-conflict selection contract used by the item driver. */
15
+ conflict_resolution: "preferred_side" | "stable_value_order";
14
16
  /** Fields selected cleanly from the other branch. */
15
17
  fields_from_theirs: string[];
16
18
  /** Collections combined from both branches. */
@@ -40,6 +42,8 @@ export interface MergeDecisionReceiptSummary {
40
42
  union_fields: string[];
41
43
  /** Preferred side used for scalar conflicts. */
42
44
  preferred: MergePreferredSide;
45
+ /** Scalar-conflict selection contract used by the item driver. */
46
+ conflict_resolution: "preferred_side" | "stable_value_order";
43
47
  /** Hashes proving the retained and discarded values without publishing them. */
44
48
  decisions: Array<{
45
49
  field: string;
@@ -65,14 +69,23 @@ export declare function writeMergeReceipt(params: {
65
69
  cwd: string;
66
70
  itemPath: string;
67
71
  preferred: MergePreferredSide;
72
+ conflictResolution?: "preferred_side" | "stable_value_order";
68
73
  fieldsFromTheirs: string[];
69
74
  unionFields: string[];
70
75
  decisions: ItemMergeConflictDecision[];
71
76
  }): Promise<MergeDecisionReceipt | null>;
72
- /** Read all clone-local receipts, optionally including reconciled history. */
77
+ /** Read clone-local receipts with explicit reconciled/lossless classification controls. */
73
78
  export declare function listMergeReceipts(cwd: string, options?: {
74
79
  includeReconciled?: boolean;
80
+ includeLossless?: boolean;
75
81
  }): Promise<MergeDecisionReceipt[]>;
82
+ /** Split merge provenance into receipts with discarded values and receipts whose composition was lossless. */
83
+ export declare function partitionMergeReceipts(receipts: MergeDecisionReceipt[]): {
84
+ /** Receipts that require an explicit decision because at least one competing scalar value was discarded. */
85
+ pendingDecisions: MergeDecisionReceipt[];
86
+ /** Receipts that record provenance without a discarded competing scalar value. */
87
+ lossless: MergeDecisionReceipt[];
88
+ };
76
89
  /** Mark a receipt as represented by a committed merge history event. */
77
90
  export declare function markMergeReceiptReconciled(cwd: string, receipt: MergeDecisionReceipt): Promise<void>;
78
91
  /** Report pending or historical clone-local merge decisions. */
@@ -7,7 +7,7 @@
7
7
  * value for the coordinator that performed the merge.
8
8
  */
9
9
 
10
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c4721ede-e557-5720-a9c2-4b2b344cc6cc")}catch(e){}}();
10
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3ccde5c2-f743-52ac-a3fd-9590f720e1b3")}catch(e){}}();
11
11
  import { execFile } from "node:child_process";
12
12
  import { randomUUID } from "node:crypto";
13
13
  import { readdir, readFile } from "node:fs/promises";
@@ -19,7 +19,12 @@ import { nowIso } from "../../core/shared/time.js";
19
19
  const execFileAsync = promisify(execFile);
20
20
  async function resolveReceiptDirectory(cwd) {
21
21
  try {
22
- const { stdout } = await execFileAsync("git", ["rev-parse", "--path-format=absolute", "--git-path", "pm-merge-receipts"], { cwd, encoding: "utf8", windowsHide: true, timeout: 10_000 });
22
+ const { stdout } = await execFileAsync("git", [
23
+ "rev-parse",
24
+ "--path-format=absolute",
25
+ "--git-path",
26
+ "pm-merge-receipts",
27
+ ], { cwd, encoding: "utf8", windowsHide: true, timeout: 10_000 });
23
28
  return stdout.trim();
24
29
  }
25
30
  catch {
@@ -39,6 +44,7 @@ export function summarizeMergeReceipt(receipt) {
39
44
  fields_from_theirs: receipt.fields_from_theirs,
40
45
  union_fields: receipt.union_fields,
41
46
  preferred: receipt.preferred,
47
+ conflict_resolution: receipt.conflict_resolution,
42
48
  decisions: receipt.decisions.map((decision) => ({
43
49
  field: decision.field,
44
50
  retained_hash: sha256Hex(stableStringify(decision.retained)),
@@ -65,6 +71,7 @@ export async function writeMergeReceipt(params) {
65
71
  item_path: itemPath.replaceAll("\\", "/"),
66
72
  item_id: itemId,
67
73
  preferred: params.preferred,
74
+ conflict_resolution: params.conflictResolution ?? "preferred_side",
68
75
  fields_from_theirs: [...params.fieldsFromTheirs],
69
76
  union_fields: [...params.unionFields],
70
77
  decisions: structuredClone(params.decisions),
@@ -75,7 +82,7 @@ export async function writeMergeReceipt(params) {
75
82
  await writeFileAtomic(path.join(directory, receiptFileName(receipt.id)), `${JSON.stringify(receipt, null, 2)}\n`);
76
83
  return receipt;
77
84
  }
78
- /** Read all clone-local receipts, optionally including reconciled history. */
85
+ /** Read clone-local receipts with explicit reconciled/lossless classification controls. */
79
86
  export async function listMergeReceipts(cwd, options = {}) {
80
87
  const directory = await resolveReceiptDirectory(cwd);
81
88
  if (directory === null || !(await pathExists(directory))) {
@@ -95,9 +102,16 @@ export async function listMergeReceipts(cwd, options = {}) {
95
102
  }
96
103
  try {
97
104
  const parsed = JSON.parse(await readFile(path.join(directory, name), "utf8"));
98
- if (parsed.version === 1 &&
99
- (options.includeReconciled || parsed.state === "pending")) {
100
- receipts.push(parsed);
105
+ const normalizedReceipt = {
106
+ ...parsed,
107
+ conflict_resolution: parsed.conflict_resolution ?? "preferred_side",
108
+ };
109
+ if (normalizedReceipt.version === 1 &&
110
+ (options.includeReconciled || normalizedReceipt.state === "pending") &&
111
+ (options.includeLossless !== false ||
112
+ (Array.isArray(normalizedReceipt.decisions) &&
113
+ normalizedReceipt.decisions.length > 0))) {
114
+ receipts.push(normalizedReceipt);
101
115
  }
102
116
  }
103
117
  catch {
@@ -107,6 +121,17 @@ export async function listMergeReceipts(cwd, options = {}) {
107
121
  }
108
122
  return receipts.sort((left, right) => left.created_at.localeCompare(right.created_at));
109
123
  }
124
+ /** Split merge provenance into receipts with discarded values and receipts whose composition was lossless. */
125
+ export function partitionMergeReceipts(receipts) {
126
+ const pendingDecisions = [];
127
+ const lossless = [];
128
+ for (const receipt of receipts) {
129
+ (Array.isArray(receipt.decisions) && receipt.decisions.length > 0
130
+ ? pendingDecisions
131
+ : lossless).push(receipt);
132
+ }
133
+ return { pendingDecisions, lossless };
134
+ }
110
135
  /** Mark a receipt as represented by a committed merge history event. */
111
136
  export async function markMergeReceiptReconciled(cwd, receipt) {
112
137
  const directory = await resolveReceiptDirectory(cwd);
@@ -117,7 +142,10 @@ export async function markMergeReceiptReconciled(cwd, receipt) {
117
142
  }
118
143
  /** Report pending or historical clone-local merge decisions. */
119
144
  export async function runMergeReceiptReport(options) {
120
- const receipts = await listMergeReceipts(options.cwd ?? process.cwd(), options);
145
+ const receipts = await listMergeReceipts(options.cwd ?? process.cwd(), {
146
+ ...options,
147
+ includeLossless: true,
148
+ });
121
149
  return {
122
150
  ok: true,
123
151
  count: receipts.length,
@@ -126,4 +154,4 @@ export async function runMergeReceiptReport(options) {
126
154
  };
127
155
  }
128
156
  //# sourceMappingURL=receipts.js.map
129
- //# debugId=c4721ede-e557-5720-a9c2-4b2b344cc6cc
157
+ //# debugId=3ccde5c2-f743-52ac-a3fd-9590f720e1b3
@@ -1,8 +1,10 @@
1
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]="b2f34565-7664-5612-815d-949b8b1d4f90")}catch(e){}}();
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]="c5620467-6c8c-5702-b742-57fba9e302c5")}catch(e){}}();
3
+ import { EXIT_CODE } from "../../core/shared/constants.js";
4
+ import { PmCliError } from "../../core/shared/errors.js";
3
5
  import { runHistoryRepair, runHistoryRepairAll, } from "../history-repair.js";
4
6
  import { runValidate } from "../governance/validate.js";
5
- import { listMergeReceipts, markMergeReceiptReconciled, summarizeMergeReceipt, } from "./receipts.js";
7
+ import { listMergeReceipts, markMergeReceiptReconciled, partitionMergeReceipts, summarizeMergeReceipt, } from "./receipts.js";
6
8
  /**
7
9
  * Preview or apply post-merge history reconciliation and immediately validate
8
10
  * the two merge-critical invariants. The default remains explicit and safe:
@@ -11,7 +13,22 @@ import { listMergeReceipts, markMergeReceiptReconciled, summarizeMergeReceipt, }
11
13
  */
12
14
  export async function runMergeReconcile(options, global) {
13
15
  const dryRun = options.dryRun === true;
14
- const pendingReceipts = await listMergeReceipts(process.cwd());
16
+ const pendingReceipts = await listMergeReceipts(process.cwd(), {
17
+ includeLossless: true,
18
+ });
19
+ const { pendingDecisions: discardedReceipts } = partitionMergeReceipts(pendingReceipts);
20
+ if (!dryRun && options.force !== true && discardedReceipts.length > 0) {
21
+ throw new PmCliError(`Merge reconciliation would accept ${discardedReceipts.length} receipt(s) containing discarded scalar values. Review pm merge report and rerun with --force only after deciding which values to retain or re-apply.`, EXIT_CODE.CONFLICT, {
22
+ code: "merge_reconcile_discards_require_acceptance",
23
+ required: "Explicitly review every discarded field before accepting reconciliation.",
24
+ nextSteps: discardedReceipts.map((receipt) => `Review receipt ${receipt.id} for ${receipt.item_id}: ${receipt.decisions
25
+ .map((decision) => decision.field)
26
+ .join(", ")}.`),
27
+ recovery: {
28
+ suggested_retry: "pm merge reconcile --dry-run",
29
+ },
30
+ });
31
+ }
15
32
  const receiptsByItem = pendingReceipts.reduce((groups, receipt) => {
16
33
  (groups[receipt.item_id] ??= []).push(receipt);
17
34
  return groups;
@@ -106,4 +123,4 @@ export async function runMergeReconcile(options, global) {
106
123
  };
107
124
  }
108
125
  //# sourceMappingURL=reconcile.js.map
109
- //# debugId=b2f34565-7664-5612-815d-949b8b1d4f90
126
+ //# debugId=c5620467-6c8c-5702-b742-57fba9e302c5
@@ -100,6 +100,8 @@ export interface ItemDocumentMergeResult {
100
100
  conflict_decisions: ItemMergeConflictDecision[];
101
101
  /** Which side unresolvable conflicts were resolved toward. */
102
102
  preferred: MergePreferredSide;
103
+ /** Scalar-conflict selection contract used for this merge. */
104
+ conflict_resolution: "preferred_side" | "stable_value_order";
103
105
  }
104
106
  /**
105
107
  * Field-aware three-way merge of one tracker item document. Commutative
@@ -107,8 +109,8 @@ export interface ItemDocumentMergeResult {
107
109
  * concurrent appends never conflict; `updated_at` resolves to the latest
108
110
  * timestamp so disjoint-field edits never collide on the shared freshness
109
111
  * scalar; every other metadata field and the body use classic three-way
110
- * resolution. Unresolvable both-sides-changed conflicts are resolved toward
111
- * the preferred side but reported in `conflict_fields`, and the merged output
112
+ * resolution. Unresolvable both-sides-changed conflicts use the configured
113
+ * scalar policy but remain reported in `conflict_fields`, and the merged output
112
114
  * is always canonically serialized — count-prefixed TOON array headers are
113
115
  * recomputed, so the hand-resolution corruption class (stale `notes[N]`
114
116
  * headers) cannot be produced by this merge.
@@ -116,6 +118,8 @@ export interface ItemDocumentMergeResult {
116
118
  export declare function mergeItemDocuments(baseRaw: string, oursRaw: string, theirsRaw: string, options?: ItemDocumentFormatOptions & {
117
119
  /** Side that wins unresolvable conflicts (default "ours"). */
118
120
  preferred?: MergePreferredSide;
121
+ /** Direction-independent scalar selection used by the Git driver. */
122
+ conflictResolution?: "preferred_side" | "stable_value_order";
119
123
  }): ItemDocumentMergeResult;
120
124
  /** Documents the JSON document merge result payload exchanged by command, SDK, and package integrations. */
121
125
  export interface JsonDocumentMergeResult {
@@ -9,7 +9,7 @@
9
9
  * definition for multi-branch agent workflows.
10
10
  */
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]="582576df-8dbe-5f93-890b-5d872669dfe8")}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]="f6f04eec-0698-5e5b-a40e-de3a4be89f95")}catch(e){}}();
13
13
  import { historyEntriesToRaw, reanchorHistoryEntries, } from "../../core/history/replay.js";
14
14
  import { canonicalDocument, parseItemDocument, serializeItemDocument, } from "../../core/item/item-format.js";
15
15
  import { EXIT_CODE } from "../../core/shared/constants.js";
@@ -339,6 +339,18 @@ function mergeScalarThreeWay(base, ours, theirs, preferred) {
339
339
  conflict: true,
340
340
  };
341
341
  }
342
+ function mergeItemScalarThreeWay(base, ours, theirs, preferred, conflictResolution) {
343
+ const outcome = mergeScalarThreeWay(base, ours, theirs, preferred);
344
+ if (!outcome.conflict || conflictResolution === "preferred_side") {
345
+ return outcome;
346
+ }
347
+ const retainTheirs = stableStringify(theirs).localeCompare(stableStringify(ours)) < 0;
348
+ return {
349
+ value: retainTheirs ? theirs : ours,
350
+ from_theirs: retainTheirs,
351
+ conflict: true,
352
+ };
353
+ }
342
354
  function toMetadataRecord(document) {
343
355
  return { ...document.metadata };
344
356
  }
@@ -350,7 +362,7 @@ function parseItemMergeSide(raw, label, options) {
350
362
  throw new PmCliError(`Item merge input (${label}) is not a readable item document: ${String(error)}`, EXIT_CODE.GENERIC_FAILURE);
351
363
  }
352
364
  }
353
- function mergeItemMetadataRecords(baseRecord, oursRecord, theirsRecord, preferred) {
365
+ function mergeItemMetadataRecords(baseRecord, oursRecord, theirsRecord, preferred, conflictResolution) {
354
366
  const unionFieldSet = new Set(ITEM_UNION_COLLECTION_FIELDS);
355
367
  const latestFieldSet = new Set(ITEM_LATEST_TIMESTAMP_FIELDS);
356
368
  const fieldNames = [
@@ -382,7 +394,7 @@ function mergeItemMetadataRecords(baseRecord, oursRecord, theirsRecord, preferre
382
394
  accumulator.merged[field] = latestTimestamp(oursValue, theirsValue);
383
395
  continue;
384
396
  }
385
- const outcome = mergeScalarThreeWay(baseValue, oursValue, theirsValue, preferred);
397
+ const outcome = mergeItemScalarThreeWay(baseValue, oursValue, theirsValue, preferred, conflictResolution);
386
398
  if (outcome.value !== undefined) {
387
399
  accumulator.merged[field] = outcome.value;
388
400
  }
@@ -394,7 +406,7 @@ function mergeItemMetadataRecords(baseRecord, oursRecord, theirsRecord, preferre
394
406
  ours: oursValue,
395
407
  theirs: theirsValue,
396
408
  retained: outcome.value,
397
- discarded: preferred === "theirs" ? oursValue : theirsValue,
409
+ discarded: outcome.from_theirs ? oursValue : theirsValue,
398
410
  });
399
411
  }
400
412
  else if (outcome.from_theirs) {
@@ -409,14 +421,15 @@ function mergeItemMetadataRecords(baseRecord, oursRecord, theirsRecord, preferre
409
421
  * concurrent appends never conflict; `updated_at` resolves to the latest
410
422
  * timestamp so disjoint-field edits never collide on the shared freshness
411
423
  * scalar; every other metadata field and the body use classic three-way
412
- * resolution. Unresolvable both-sides-changed conflicts are resolved toward
413
- * the preferred side but reported in `conflict_fields`, and the merged output
424
+ * resolution. Unresolvable both-sides-changed conflicts use the configured
425
+ * scalar policy but remain reported in `conflict_fields`, and the merged output
414
426
  * is always canonically serialized — count-prefixed TOON array headers are
415
427
  * recomputed, so the hand-resolution corruption class (stale `notes[N]`
416
428
  * headers) cannot be produced by this merge.
417
429
  */
418
430
  export function mergeItemDocuments(baseRaw, oursRaw, theirsRaw, options = {}) {
419
431
  const preferred = options.preferred ?? "ours";
432
+ const conflictResolution = options.conflictResolution ?? "preferred_side";
420
433
  // An empty base means both branches created the file independently
421
434
  // (add/add); three-way falls back to treating every differing field as an
422
435
  // ours/theirs decision, which the scalar resolver already models.
@@ -429,8 +442,8 @@ export function mergeItemDocuments(baseRaw, oursRaw, theirsRaw, options = {}) {
429
442
  : {};
430
443
  const oursRecord = toMetadataRecord(ours);
431
444
  const theirsRecord = toMetadataRecord(theirs);
432
- const { merged, conflictFields, fieldsFromTheirs, unionFields, conflictDecisions, } = mergeItemMetadataRecords(baseRecord, oursRecord, theirsRecord, preferred);
433
- const bodyOutcome = mergeScalarThreeWay(hasBase ? base.body : "", ours.body, theirs.body, preferred);
445
+ const { merged, conflictFields, fieldsFromTheirs, unionFields, conflictDecisions, } = mergeItemMetadataRecords(baseRecord, oursRecord, theirsRecord, preferred, conflictResolution);
446
+ const bodyOutcome = mergeItemScalarThreeWay(hasBase ? base.body : "", ours.body, theirs.body, preferred, conflictResolution);
434
447
  if (bodyOutcome.conflict) {
435
448
  conflictFields.push("body");
436
449
  conflictDecisions.push({
@@ -439,7 +452,7 @@ export function mergeItemDocuments(baseRaw, oursRaw, theirsRaw, options = {}) {
439
452
  ours: ours.body,
440
453
  theirs: theirs.body,
441
454
  retained: bodyOutcome.value,
442
- discarded: preferred === "theirs" ? ours.body : theirs.body,
455
+ discarded: bodyOutcome.from_theirs ? ours.body : theirs.body,
443
456
  });
444
457
  }
445
458
  else if (bodyOutcome.from_theirs) {
@@ -456,6 +469,7 @@ export function mergeItemDocuments(baseRaw, oursRaw, theirsRaw, options = {}) {
456
469
  union_fields: unionFields,
457
470
  conflict_decisions: conflictDecisions,
458
471
  preferred,
472
+ conflict_resolution: conflictResolution,
459
473
  };
460
474
  }
461
475
  function isPlainObject(value) {
@@ -611,4 +625,4 @@ export function mergeJsonDocuments(baseRaw, oursRaw, theirsRaw, options = {}) {
611
625
  };
612
626
  }
613
627
  //# sourceMappingURL=three-way.js.map
614
- //# debugId=582576df-8dbe-5f93-890b-5d872669dfe8
628
+ //# debugId=f6f04eec-0698-5e5b-a40e-de3a4be89f95
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { type GlobalOptions } from "./runtime-primitives.js";
7
7
  import type { LogNote } from "../types/index.js";
8
+ import { type AnnotationMutationReceipt, type AnnotationOmissionReceipt } from "./annotations.js";
8
9
  /** Documents the notes command options payload exchanged by command, SDK, and package integrations. */
9
10
  export interface NotesCommandOptions {
10
11
  /** Value that configures or reports add for this contract. */
@@ -27,6 +28,8 @@ export interface NotesCommandOptions {
27
28
  eventType?: string;
28
29
  /** Include total, returned, and truncation metadata. */
29
30
  includeMeta?: boolean;
31
+ /** Return complete note history after a mutation instead of a bounded receipt. */
32
+ fullHistory?: boolean;
30
33
  /** Value that configures or reports author for this contract. */
31
34
  author?: string;
32
35
  /** Human-readable explanation suitable for logs and agent-facing output. */
@@ -52,6 +55,10 @@ export interface NotesResult {
52
55
  limit?: number;
53
56
  /** Number of structured context events in the returned projection. */
54
57
  structured_event_count?: number;
58
+ /** Mutation identity when this result changed the collection. */
59
+ mutation_receipt?: AnnotationMutationReceipt;
60
+ /** Declares whether older notes were withheld from a mutation response. */
61
+ omission_receipt?: AnnotationOmissionReceipt;
55
62
  }
56
63
  /** Implements run notes for the public runtime surface of this module. */
57
64
  export declare function runNotes(id: string, options: NotesCommandOptions, global: GlobalOptions): Promise<NotesResult>;
package/dist/sdk/notes.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Implements the pm notes 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]="973fe868-d08e-5a45-83c5-b7ecb959f680")}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]="ebd9f151-593f-5081-97da-d78f83de4914")}catch(e){}}();
8
8
  import { EXIT_CODE, PmCliError, parseLimit, stableStringify, } from "./runtime-primitives.js";
9
9
  import { limitAnnotationEntries, parseAnnotationTextInput, resolveAnnotationInput, runAnnotationCommand, } from "./annotations.js";
10
10
  function parseStructuredEventPayload(raw) {
@@ -137,4 +137,4 @@ export async function runNotes(id, options, global) {
137
137
  };
138
138
  }
139
139
  //# sourceMappingURL=notes.js.map
140
- //# debugId=973fe868-d08e-5a45-83c5-b7ecb959f680
140
+ //# debugId=ebd9f151-593f-5081-97da-d78f83de4914
@@ -24,6 +24,17 @@ type GetItemProjection = Partial<ItemMetadata> & {
24
24
  notes_count?: number;
25
25
  /** Number of linked tests omitted by a token-bounded projection. */
26
26
  tests_count?: number;
27
+ /** Stable cardinalities for every collection mutation surface. */
28
+ collection_counts?: Readonly<{
29
+ comments: number;
30
+ notes: number;
31
+ learnings: number;
32
+ files: number;
33
+ tests: number;
34
+ docs: number;
35
+ reminders: number;
36
+ events: number;
37
+ }>;
27
38
  };
28
39
  /** Documents the get result payload exchanged by command, SDK, and package integrations. */
29
40
  export interface GetResult {
@@ -4,7 +4,7 @@
4
4
  * Implements the SDK-owned item query shared by every surface.
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]="5536c6eb-5d51-5b67-879d-c1d0bfa5b692")}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]="f68f4074-51ba-5065-8cca-fe16acd48927")}catch(e){}}();
8
8
  import { pathExists, getActiveExtensionRegistrations, toItemRecord, resolveItemTypeRegistry, resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, EXIT_CODE, ITEM_METADATA_KEY_ORDER, TYPE_TO_FOLDER, PmCliError, buildItemNotFoundError, listAllItemMetadataLight, locateItem, readLocatedItem, getHistoryPath, getSettingsPath, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
9
9
  import { readHistoryEntries } from "../history-read.js";
10
10
  import { recordContextUsageTouches } from "../context-usage.js";
@@ -21,6 +21,23 @@ const AUTOMATIC_CHILD_ROLLUP_TYPES = new Set([
21
21
  "plan",
22
22
  ]);
23
23
  const BUILTIN_ITEM_TYPES = new Set(Object.keys(TYPE_TO_FOLDER).map((type) => type.toLowerCase()));
24
+ function itemCollectionCounts(item) {
25
+ const lengths = Object.fromEntries([
26
+ "comments",
27
+ "notes",
28
+ "learnings",
29
+ "files",
30
+ "tests",
31
+ "docs",
32
+ "reminders",
33
+ "events",
34
+ ].map((key) => [
35
+ key,
36
+ item[key]
37
+ ?.length ?? 0,
38
+ ]));
39
+ return lengths;
40
+ }
24
41
  /** Decide whether a normal read should pay for a workspace-wide child projection. */
25
42
  function shouldAutoIncludeGetChildren(itemType) {
26
43
  const normalizedType = itemType.trim().toLowerCase();
@@ -65,14 +82,29 @@ function parseGetDepth(raw) {
65
82
  throw new PmCliError("Get --depth must be one of brief|standard|deep|full", EXIT_CODE.USAGE);
66
83
  }
67
84
  function projectItemForDepth(item, depth) {
85
+ const collectionCounts = itemCollectionCounts(item);
68
86
  if (depth === "deep") {
69
- return item;
87
+ return {
88
+ ...item,
89
+ comments: item.comments ?? [],
90
+ notes: item.notes ?? [],
91
+ learnings: item.learnings ?? [],
92
+ files: item.files ?? [],
93
+ tests: item.tests ?? [],
94
+ docs: item.docs ?? [],
95
+ reminders: item.reminders ?? [],
96
+ events: item.events ?? [],
97
+ notes_count: collectionCounts.notes,
98
+ tests_count: collectionCounts.tests,
99
+ collection_counts: collectionCounts,
100
+ };
70
101
  }
71
102
  const { comments: _comments, notes: _notes, learnings: _learnings, files: _files, tests: _tests, docs: _docs, reminders: _reminders, events: _events, ...projected } = item;
72
103
  return {
73
104
  ...projected,
74
105
  notes_count: item.notes?.length ?? 0,
75
106
  tests_count: item.tests?.length ?? 0,
107
+ collection_counts: collectionCounts,
76
108
  };
77
109
  }
78
110
  function parseGetFields(raw) {
@@ -100,6 +132,7 @@ function validateGetFields(fields, runtimeMetadataKeys) {
100
132
  ...runtimeMetadataKeys,
101
133
  "notes_count",
102
134
  "tests_count",
135
+ "collection_counts",
103
136
  ]);
104
137
  const allowedRootFields = new Set([
105
138
  "body",
@@ -151,6 +184,7 @@ function projectItemForFields(item, fields) {
151
184
  const omittedCounts = {
152
185
  notes_count: item.notes?.length ?? 0,
153
186
  tests_count: item.tests?.length ?? 0,
187
+ collection_counts: itemCollectionCounts(item),
154
188
  };
155
189
  const projected = {};
156
190
  for (const field of fields) {
@@ -387,4 +421,4 @@ export const _testOnlyGetCommand = {
387
421
  shouldAutoIncludeGetChildren,
388
422
  };
389
423
  //# sourceMappingURL=get.js.map
390
- //# debugId=5536c6eb-5d51-5b67-879d-c1d0bfa5b692
424
+ //# debugId=f68f4074-51ba-5065-8cca-fe16acd48927
@@ -4,7 +4,7 @@ export declare const PM_READ_OUTPUT_DIMENSIONS: readonly ["include", "amount", "
4
4
  /** One member of the universal read-output dimension set. */
5
5
  export type PmReadOutputDimension = (typeof PM_READ_OUTPUT_DIMENSIONS)[number];
6
6
  /** Built-in command roots whose primary operation is a read. */
7
- export declare const PM_READ_OUTPUT_SURFACES: readonly ["list", "context", "search", "get", "next", "health", "deps", "graph", "history", "activity", "validate", "events", "contracts", "comments", "notes", "files", "docs", "stats", "aggregate"];
7
+ export declare const PM_READ_OUTPUT_SURFACES: readonly ["list", "context", "search", "get", "next", "health", "deps", "graph", "history", "activity", "validate", "events", "contracts", "comments", "notes", "files", "docs", "stats", "aggregate", "package-manage"];
8
8
  /** Built-in read command supported by the universal output contract. */
9
9
  export type PmReadOutputSurface = (typeof PM_READ_OUTPUT_SURFACES)[number];
10
10
  /** Canonical output controls accepted by every built-in read action. */