@unbrained/pm-cli 2026.8.6 → 2026.8.7

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 (209) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +30 -0
  3. package/dist/cli/main.js +4 -2
  4. package/dist/cli/register-operations.js +11 -2
  5. package/dist/cli/stats-analytics-json.d.ts +9 -0
  6. package/dist/cli/stats-analytics-json.js +69 -0
  7. package/dist/cli-bundle/bundle-manifest.json +397 -397
  8. package/dist/cli-bundle/chunks/append-7BXBFDGD.js +2 -0
  9. package/dist/cli-bundle/chunks/{chunk-TPKDJ5WL.js → chunk-2AXF3VSK.js} +2 -2
  10. package/dist/cli-bundle/chunks/{chunk-R6RKEYYW.js → chunk-2XS43CCV.js} +2 -2
  11. package/dist/cli-bundle/chunks/{chunk-T45OHXDW.js → chunk-3A6KWB72.js} +2 -2
  12. package/dist/cli-bundle/chunks/chunk-3ISTDB42.js +8 -0
  13. package/dist/cli-bundle/chunks/{chunk-SXECIECW.js → chunk-4MTI7XOV.js} +2 -2
  14. package/dist/cli-bundle/chunks/{chunk-MCS73BKB.js → chunk-6BX5UDCN.js} +2 -2
  15. package/dist/cli-bundle/chunks/{chunk-A3XQ7VPU.js → chunk-6QPO7KLR.js} +2 -2
  16. package/dist/cli-bundle/chunks/{chunk-BP6EMEDP.js → chunk-7MXHZHSQ.js} +2 -2
  17. package/dist/cli-bundle/chunks/{chunk-GU3TSEHD.js → chunk-7ZPMJW4U.js} +2 -2
  18. package/dist/cli-bundle/chunks/{chunk-343QETLI.js → chunk-AGYNSNCI.js} +2 -2
  19. package/dist/cli-bundle/chunks/chunk-B4H7FEFH.js +5 -0
  20. package/dist/cli-bundle/chunks/{chunk-CA3BURYF.js → chunk-B4KLBBMN.js} +2 -2
  21. package/dist/cli-bundle/chunks/{chunk-3ZJRFYY2.js → chunk-CALJHNBL.js} +12 -12
  22. package/dist/cli-bundle/chunks/{chunk-M357ZCOR.js → chunk-CFIGP5LY.js} +2 -2
  23. package/dist/cli-bundle/chunks/{chunk-SVV3DQES.js → chunk-CS6MRHG7.js} +2 -2
  24. package/dist/cli-bundle/chunks/{chunk-DWOAOZHZ.js → chunk-CUGNQQKH.js} +2 -2
  25. package/dist/cli-bundle/chunks/chunk-D4FPS43D.js +164 -0
  26. package/dist/cli-bundle/chunks/{chunk-L6LGKJX3.js → chunk-H5Y5YE6A.js} +2 -2
  27. package/dist/cli-bundle/chunks/{chunk-5PBP2ZP3.js → chunk-H5Y6UV6E.js} +2 -2
  28. package/dist/cli-bundle/chunks/{chunk-QJ7C3JIW.js → chunk-H7KGWPDF.js} +2 -2
  29. package/dist/cli-bundle/chunks/{chunk-D7I3TUGV.js → chunk-HFSD77TQ.js} +2 -2
  30. package/dist/cli-bundle/chunks/{chunk-AOBDLU4T.js → chunk-HX2GTA6L.js} +2 -2
  31. package/dist/cli-bundle/chunks/{chunk-4AVFKHHC.js → chunk-J2IEKAVR.js} +2 -2
  32. package/dist/cli-bundle/chunks/{chunk-OXY3SJ3N.js → chunk-K44PYFXH.js} +2 -2
  33. package/dist/cli-bundle/chunks/{chunk-M4VEE3FK.js → chunk-K4KGEEBT.js} +2 -2
  34. package/dist/cli-bundle/chunks/chunk-KFLK5TRH.js +21 -0
  35. package/dist/cli-bundle/chunks/{chunk-FDBRXV25.js → chunk-KL6IEBV2.js} +2 -2
  36. package/dist/cli-bundle/chunks/{chunk-JQ4NZ5EB.js → chunk-KWQZDZSS.js} +2 -2
  37. package/dist/cli-bundle/chunks/{chunk-UVVXHGYS.js → chunk-KZ4X3DGU.js} +2 -2
  38. package/dist/cli-bundle/chunks/chunk-LD77HJMQ.js +13 -0
  39. package/dist/cli-bundle/chunks/{chunk-AYRUGRNS.js → chunk-ME2JJ4LA.js} +2 -2
  40. package/dist/cli-bundle/chunks/chunk-NFLJ3FHD.js +2 -0
  41. package/dist/cli-bundle/chunks/{chunk-MDTH7SAE.js → chunk-NG6OXIBR.js} +8 -8
  42. package/dist/cli-bundle/chunks/{chunk-R6LSRGPS.js → chunk-NYIGHWQY.js} +2 -2
  43. package/dist/cli-bundle/chunks/{chunk-3KFVGGRE.js → chunk-NZ75GNSA.js} +2 -2
  44. package/dist/cli-bundle/chunks/{chunk-Q3VOP62W.js → chunk-PCJWJNC2.js} +2 -2
  45. package/dist/cli-bundle/chunks/{chunk-C3YABSJK.js → chunk-PD3225AM.js} +2 -2
  46. package/dist/cli-bundle/chunks/{chunk-JFZIS6JF.js → chunk-PDEGKG7P.js} +2 -2
  47. package/dist/cli-bundle/chunks/chunk-PIE5HBNA.js +2 -0
  48. package/dist/cli-bundle/chunks/{chunk-SD3YXU2U.js → chunk-PW2H7YJR.js} +20 -20
  49. package/dist/cli-bundle/chunks/{chunk-PECV7L5T.js → chunk-TPKN3S7S.js} +2 -2
  50. package/dist/cli-bundle/chunks/{chunk-F4NREH3G.js → chunk-TPXAXTCO.js} +2 -2
  51. package/dist/cli-bundle/chunks/chunk-UFWUJO4V.js +2 -0
  52. package/dist/cli-bundle/chunks/{chunk-WSI5KZQJ.js → chunk-UQLZQVFW.js} +2 -2
  53. package/dist/cli-bundle/chunks/{chunk-4OVGQW22.js → chunk-VT3Z5G7D.js} +2 -2
  54. package/dist/cli-bundle/chunks/{chunk-RUAU5OSH.js → chunk-WOD3WWUN.js} +2 -2
  55. package/dist/cli-bundle/chunks/{chunk-DQGJ2RWT.js → chunk-WSJEIGJF.js} +2 -2
  56. package/dist/cli-bundle/chunks/{chunk-RAFUN7IX.js → chunk-WYNUU7ZW.js} +49 -46
  57. package/dist/cli-bundle/chunks/{chunk-5ZKQPA44.js → chunk-YGPNCCXZ.js} +2 -2
  58. package/dist/cli-bundle/chunks/close-CMY3BAUG.js +2 -0
  59. package/dist/cli-bundle/chunks/close-many-SA4XZCTK.js +2 -0
  60. package/dist/cli-bundle/chunks/comments-EZ556ZD3.js +2 -0
  61. package/dist/cli-bundle/chunks/copy-ZSGPA52X.js +2 -0
  62. package/dist/cli-bundle/chunks/{create-TG67IVFI.js → create-I5DVV4YG.js} +2 -2
  63. package/dist/cli-bundle/chunks/delete-RL3JACSW.js +2 -0
  64. package/dist/cli-bundle/chunks/{deps-AJUGP2OH.js → deps-S7UBCECS.js} +2 -2
  65. package/dist/cli-bundle/chunks/{docs-QOCLDRKJ.js → docs-ZZNVBBYO.js} +2 -2
  66. package/dist/cli-bundle/chunks/{files-3ST5TY64.js → files-27C337VT.js} +2 -2
  67. package/dist/cli-bundle/chunks/focus-5Z2SG7LU.js +2 -0
  68. package/dist/cli-bundle/chunks/{history-compact-7BJFML4S.js → history-compact-HJQK67CZ.js} +2 -2
  69. package/dist/cli-bundle/chunks/{history-redact-WJN3HYXR.js → history-redact-PWC6PDWA.js} +2 -2
  70. package/dist/cli-bundle/chunks/{history-repair-XDNZUB7F.js → history-repair-N3CY4WBF.js} +2 -2
  71. package/dist/cli-bundle/chunks/{learnings-SZMUPVNA.js → learnings-4FH23XDT.js} +2 -2
  72. package/dist/cli-bundle/chunks/{profile-KL53JIAC.js → profile-5Y5XXH5N.js} +2 -2
  73. package/dist/cli-bundle/chunks/{register-list-query-QH7ONPKU.js → register-list-query-FJZCJ67O.js} +2 -2
  74. package/dist/cli-bundle/chunks/{register-mutation-OCRQNZK4.js → register-mutation-YGYPW3BL.js} +3 -3
  75. package/dist/cli-bundle/chunks/register-operations-WMDSUMQF.js +2 -0
  76. package/dist/cli-bundle/chunks/{register-setup-QWBQ6HBS.js → register-setup-DL7FFABC.js} +2 -2
  77. package/dist/cli-bundle/chunks/restore-6KYBV5BY.js +2 -0
  78. package/dist/cli-bundle/chunks/{schema-QJ27OTRV.js → schema-EQGKBYXJ.js} +2 -2
  79. package/dist/cli-bundle/chunks/update-QVTYOD6I.js +2 -0
  80. package/dist/cli-bundle/chunks/update-many-DJSBU525.js +2 -0
  81. package/dist/cli-bundle/focused-chunks/{chunk-MBBMTDD3.js → chunk-2ECLECMK.js} +3 -3
  82. package/dist/cli-bundle/focused-chunks/{chunk-CL3NB7VW.js → chunk-3K4XV2BF.js} +2 -2
  83. package/dist/cli-bundle/focused-chunks/{chunk-ME4XVOBJ.js → chunk-4EX25PXM.js} +2 -2
  84. package/dist/cli-bundle/focused-chunks/chunk-4VJQTS3P.js +2 -0
  85. package/dist/cli-bundle/focused-chunks/chunk-73JUDYXT.js +2 -0
  86. package/dist/cli-bundle/focused-chunks/{chunk-GSW2Y7VZ.js → chunk-CIXVQPB7.js} +2 -2
  87. package/dist/cli-bundle/focused-chunks/{chunk-7YTZ7A4E.js → chunk-DLTS3IHM.js} +2 -2
  88. package/dist/cli-bundle/focused-chunks/{chunk-YHDCGUIW.js → chunk-DQ6FKGL3.js} +10 -10
  89. package/dist/cli-bundle/focused-chunks/{chunk-YLPZHWX7.js → chunk-HNL6IFGS.js} +2 -2
  90. package/dist/cli-bundle/focused-chunks/chunk-JLG2C4EQ.js +2 -0
  91. package/dist/cli-bundle/focused-chunks/{chunk-6KDHXURF.js → chunk-MHMTKV5V.js} +2 -2
  92. package/dist/cli-bundle/focused-chunks/{chunk-GEYU23YS.js → chunk-MOTJFQ3F.js} +22 -22
  93. package/dist/cli-bundle/focused-chunks/{chunk-EYO4F74Z.js → chunk-NBJKQP4S.js} +2 -2
  94. package/dist/cli-bundle/focused-chunks/{chunk-XNVXIQ4B.js → chunk-QHRTT7WT.js} +2 -2
  95. package/dist/cli-bundle/focused-chunks/{chunk-27DK4A5O.js → chunk-R2LEMEV5.js} +2 -2
  96. package/dist/cli-bundle/focused-chunks/{chunk-4JC3AOGS.js → chunk-RPNYG5MO.js} +2 -2
  97. package/dist/cli-bundle/focused-chunks/{chunk-EAXXF2HW.js → chunk-RW5IYD4J.js} +2 -2
  98. package/dist/cli-bundle/focused-chunks/{chunk-TQMFQYXR.js → chunk-TIKDBG4D.js} +16 -16
  99. package/dist/cli-bundle/focused-chunks/{chunk-N7QN3NE6.js → chunk-VZFU2R4M.js} +2 -2
  100. package/dist/cli-bundle/focused-chunks/{chunk-GIERI4YU.js → chunk-YZEZAPJK.js} +2 -2
  101. package/dist/cli-bundle/focused-chunks/chunk-ZJIMJHDB.js +2 -0
  102. package/dist/cli-bundle/main.js +2 -2
  103. package/dist/cli-bundle/sdk-authoring.js +1 -1
  104. package/dist/cli-bundle/sdk-contracts.js +1 -1
  105. package/dist/cli-bundle/sdk-core.js +29 -28
  106. package/dist/cli-bundle/sdk-governance.js +1 -1
  107. package/dist/cli-bundle/sdk-graph.js +1 -1
  108. package/dist/cli-bundle/sdk-merge.js +1 -1
  109. package/dist/cli-bundle/sdk-query.js +1 -1
  110. package/dist/cli-bundle/sdk-runtime.js +1 -1
  111. package/dist/cli-bundle/sdk-testing.js +1 -1
  112. package/dist/cli-bundle/sdk.js +1 -1
  113. package/dist/core/extensions/reserved-host-flags.js +3 -2
  114. package/dist/core/history/workspace-history.d.ts +22 -2
  115. package/dist/core/history/workspace-history.js +60 -36
  116. package/dist/core/output/output.d.ts +2 -0
  117. package/dist/core/output/output.js +3 -2
  118. package/dist/core/shared/command-types.d.ts +2 -0
  119. package/dist/core/shared/command-types.js +2 -2
  120. package/dist/mcp/tool-definitions.js +6 -2
  121. package/dist/sdk/author-attribution.js +23 -7
  122. package/dist/sdk/cli-bootstrap.d.ts +2 -0
  123. package/dist/sdk/cli-bootstrap.js +7 -2
  124. package/dist/sdk/cli-contracts/completeness.js +51 -4
  125. package/dist/sdk/cli-contracts/flag-contracts.js +3 -2
  126. package/dist/sdk/cli-contracts/registration-helpers.js +3 -2
  127. package/dist/sdk/cli-contracts/runtime-contracts.js +14 -8
  128. package/dist/sdk/cli-contracts/tool-parameter-tables.js +116 -10
  129. package/dist/sdk/cli-contracts/tool-schema.js +18 -2
  130. package/dist/sdk/cli-program.js +3 -2
  131. package/dist/sdk/completion.js +5 -2
  132. package/dist/sdk/contracts.d.ts +1 -0
  133. package/dist/sdk/contracts.js +2 -2
  134. package/dist/sdk/core.d.ts +3 -1
  135. package/dist/sdk/core.js +4 -3
  136. package/dist/sdk/extension.js +9 -11
  137. package/dist/sdk/generated-error-code-catalog.js +112 -2
  138. package/dist/sdk/history-analytics.d.ts +141 -0
  139. package/dist/sdk/history-analytics.js +283 -0
  140. package/dist/sdk/improvement-ledger-validation.d.ts +3 -0
  141. package/dist/sdk/improvement-ledger-validation.js +63 -0
  142. package/dist/sdk/improvement-ledger.d.ts +139 -0
  143. package/dist/sdk/improvement-ledger.js +261 -0
  144. package/dist/sdk/index.d.ts +6 -2
  145. package/dist/sdk/index.js +8 -4
  146. package/dist/sdk/lifecycle/plan.js +6 -3
  147. package/dist/sdk/merge/install.js +10 -2
  148. package/dist/sdk/read-output-budget.js +24 -22
  149. package/dist/sdk/read-output-contracts.d.ts +10 -2
  150. package/dist/sdk/read-output-contracts.js +124 -65
  151. package/dist/sdk/read-output-rows.d.ts +29 -0
  152. package/dist/sdk/read-output-rows.js +100 -0
  153. package/dist/sdk/read-output-session.d.ts +69 -0
  154. package/dist/sdk/read-output-session.js +200 -0
  155. package/dist/sdk/runtime-input.d.ts +2 -0
  156. package/dist/sdk/runtime-input.js +14 -2
  157. package/dist/sdk/runtime-primitives.d.ts +1 -1
  158. package/dist/sdk/runtime-primitives.js +3 -3
  159. package/dist/sdk/runtime-stats-options.d.ts +9 -0
  160. package/dist/sdk/runtime-stats-options.js +38 -0
  161. package/dist/sdk/runtime.d.ts +1 -0
  162. package/dist/sdk/runtime.js +6 -27
  163. package/dist/sdk/stats.d.ts +40 -0
  164. package/dist/sdk/stats.js +112 -29
  165. package/docs/IMPROVEMENT_ANALYTICS.md +103 -0
  166. package/docs/OUTPUT_PROJECTION_CONTRACTS.md +5 -5
  167. package/docs/README.md +1 -0
  168. package/docs/READ_OUTPUT_CONTRACTS.md +60 -1
  169. package/marketplace.json +2 -2
  170. package/package.json +3 -3
  171. package/packages/pm-beads/package.json +1 -1
  172. package/packages/pm-calendar/package.json +1 -1
  173. package/packages/pm-command-kit/package.json +1 -1
  174. package/packages/pm-digital-twin/package.json +1 -1
  175. package/packages/pm-governance-audit/package.json +1 -1
  176. package/packages/pm-guide-shell/package.json +1 -1
  177. package/packages/pm-kanban/package.json +1 -1
  178. package/packages/pm-lifecycle-hooks/package.json +1 -1
  179. package/packages/pm-linked-test-adapters/package.json +1 -1
  180. package/packages/pm-search-advanced/package.json +1 -1
  181. package/packages/pm-templates/package.json +1 -1
  182. package/packages/pm-todos/package.json +1 -1
  183. package/packages/pm-vcs/package.json +1 -1
  184. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  185. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  186. package/sdk/public-surface.json +374 -821
  187. package/dist/cli-bundle/chunks/append-XAJ5Z4XS.js +0 -2
  188. package/dist/cli-bundle/chunks/chunk-AJE3AHPD.js +0 -8
  189. package/dist/cli-bundle/chunks/chunk-E7BFPLUZ.js +0 -5
  190. package/dist/cli-bundle/chunks/chunk-HS7OVAUN.js +0 -164
  191. package/dist/cli-bundle/chunks/chunk-SV3YQ4RY.js +0 -2
  192. package/dist/cli-bundle/chunks/chunk-V663653R.js +0 -20
  193. package/dist/cli-bundle/chunks/chunk-XPOQQJTX.js +0 -13
  194. package/dist/cli-bundle/chunks/chunk-YCCDXBNU.js +0 -2
  195. package/dist/cli-bundle/chunks/chunk-ZFBWCKYF.js +0 -2
  196. package/dist/cli-bundle/chunks/close-DI66JMSB.js +0 -2
  197. package/dist/cli-bundle/chunks/close-many-VFKT6U3O.js +0 -2
  198. package/dist/cli-bundle/chunks/comments-E73HIEZJ.js +0 -2
  199. package/dist/cli-bundle/chunks/copy-WBYVLCPC.js +0 -2
  200. package/dist/cli-bundle/chunks/delete-6XKUVVQN.js +0 -2
  201. package/dist/cli-bundle/chunks/focus-R2AWS63Y.js +0 -2
  202. package/dist/cli-bundle/chunks/register-operations-HIBJXRGB.js +0 -2
  203. package/dist/cli-bundle/chunks/restore-FXA5QPM7.js +0 -2
  204. package/dist/cli-bundle/chunks/update-7GBO4SXG.js +0 -2
  205. package/dist/cli-bundle/chunks/update-many-VF6ZKQUO.js +0 -2
  206. package/dist/cli-bundle/focused-chunks/chunk-74CWP3A4.js +0 -2
  207. package/dist/cli-bundle/focused-chunks/chunk-7AZDTGPA.js +0 -2
  208. package/dist/cli-bundle/focused-chunks/chunk-LKQXXO62.js +0 -2
  209. package/dist/cli-bundle/focused-chunks/chunk-QL5H3AQH.js +0 -2
@@ -5,10 +5,12 @@
5
5
  * surface without coupling package authors to command-specific option names.
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]="27431a6b-6f2e-5020-b4f1-b94cfa8a1c26")}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]="0bccb953-bd78-5eee-a78d-8af3e250fa55")}catch(e){}}();
9
9
  import { EXIT_CODE } from "../core/shared/constants.js";
10
10
  import { PmCliError } from "../core/shared/errors.js";
11
- import { compactReadOutputToBudget, updateReadOutputReceiptEstimate } from "./read-output-budget.js";
11
+ import { compactReadOutputToBudget, updateReadOutputReceiptEstimate, } from "./read-output-budget.js";
12
+ import { boundReadOutputRows, countReadOutputRows, mapReadOutputRows, readOutputRowPaths, } from "./read-output-rows.js";
13
+ import { applyReadOutputSessionReferences, attachReadOutputSessionReceipt, parseReadOutputSession, readOutputSessionRemainingTokens, } from "./read-output-session.js";
12
14
  /** Stable output dimensions shared by every read surface. */
13
15
  export const PM_READ_OUTPUT_DIMENSIONS = [
14
16
  "include",
@@ -52,6 +54,10 @@ const CANONICAL_OPTIONS = {
52
54
  };
53
55
  /** Canonical CLI flags that opt a read invocation into universal output shaping. */
54
56
  export const PM_READ_OUTPUT_OPTION_FLAGS = Object.freeze(PM_READ_OUTPUT_DIMENSIONS.map((dimension) => CANONICAL_OPTIONS[dimension]));
57
+ /** Canonical control that composes the four per-call dimensions across reads. */
58
+ export const PM_READ_OUTPUT_COMPOSITION_OPTION_FLAGS = Object.freeze([
59
+ "--output-session",
60
+ ]);
55
61
  const LEGACY_FLAGS_BY_COMMAND = {
56
62
  list: {
57
63
  include: ["--brief", "--compact", "--fields", "--full"],
@@ -166,7 +172,11 @@ function buildSurfaceContract(command) {
166
172
  }))),
167
173
  }),
168
174
  ])));
169
- return Object.freeze({ command, dimensions, precedence: READ_OUTPUT_PRECEDENCE });
175
+ return Object.freeze({
176
+ command,
177
+ dimensions,
178
+ precedence: READ_OUTPUT_PRECEDENCE,
179
+ });
170
180
  }
171
181
  /** Universal output contract for every built-in read surface. */
172
182
  export const PM_READ_OUTPUT_SURFACE_CONTRACTS = Object.freeze(PM_READ_OUTPUT_SURFACES.map(buildSurfaceContract));
@@ -195,6 +205,8 @@ const CANONICAL_OPTION_KEYS = [
195
205
  "output_budget",
196
206
  "outputFormat",
197
207
  "output_format",
208
+ "outputSession",
209
+ "output_session",
198
210
  ];
199
211
  const HYBRID_READ_MUTATION_KEYS = {
200
212
  comments: ["add", "body", "stdin", "file", "edit", "delete"],
@@ -226,6 +238,14 @@ const READ_OUTPUT_VALUE_VALIDATORS = [
226
238
  valid: (value) => value === "toon" || value === "json",
227
239
  message: "--output-format must be toon or json.",
228
240
  },
241
+ {
242
+ keys: ["outputSession", "output_session"],
243
+ valid: (value) => {
244
+ parseReadOutputSession(value);
245
+ return true;
246
+ },
247
+ message: "--output-session must be a valid session-state object.",
248
+ },
229
249
  ];
230
250
  /** Reject malformed or mutation-scoped universal output controls before command execution. */
231
251
  export function validateReadOutputOptions(command, options) {
@@ -403,29 +423,24 @@ const ENVELOPE_KEYS = new Set([
403
423
  "total",
404
424
  "truncated",
405
425
  ]);
406
- function rowKeys(result) {
407
- const contract = result.row_contract;
408
- if (isRecord(contract) && Array.isArray(contract.row_keys)) {
409
- return contract.row_keys.filter((entry) => typeof entry === "string");
410
- }
411
- return Object.entries(result)
412
- .filter(([, value]) => Array.isArray(value))
413
- .map(([key]) => key);
414
- }
415
426
  function projectRecordFields(value, selectors) {
416
427
  const selected = new Set(selectors.map((selector) => selector.split(".")[0]));
417
428
  return Object.fromEntries(Object.entries(value).filter(([key]) => selected.has(key)));
418
429
  }
419
430
  function applyIncludeProjection(result, selectors) {
420
- const rows = rowKeys(result);
421
- const selectedRoot = selectors.some((selector) => Object.hasOwn(result, selector.split(".")[0]));
422
- if (rows.length > 0 && !selectedRoot) {
423
- return Object.fromEntries(Object.entries(result).map(([key, value]) => [
424
- key,
425
- rows.includes(key) && Array.isArray(value)
426
- ? value.map((entry) => isRecord(entry) ? projectRecordFields(entry, selectors) : entry)
427
- : value,
428
- ]));
431
+ const rows = readOutputRowPaths(result);
432
+ const qualifiedRowSelectors = selectors.flatMap((selector) => rows.flatMap((rowPath) => selector.startsWith(`${rowPath}.`)
433
+ ? [selector.slice(rowPath.length + 1)]
434
+ : []));
435
+ const selectedRoot = selectors.some((selector) => Object.hasOwn(result, selector.split(".")[0]) &&
436
+ !rows.some((rowPath) => selector.startsWith(`${rowPath}.`)));
437
+ if (rows.length > 0 && (!selectedRoot || qualifiedRowSelectors.length > 0)) {
438
+ const projected = { ...result };
439
+ return mapReadOutputRows(projected, (entry) => isRecord(entry)
440
+ ? projectRecordFields(entry, qualifiedRowSelectors.length > 0
441
+ ? qualifiedRowSelectors
442
+ : selectors)
443
+ : entry);
429
444
  }
430
445
  return Object.fromEntries(Object.entries(result).filter(([key]) => selectors.some((selector) => selector.split(".")[0] === key) ||
431
446
  ENVELOPE_KEYS.has(key)));
@@ -433,22 +448,13 @@ function applyIncludeProjection(result, selectors) {
433
448
  function applyAmountBound(result, amount) {
434
449
  if (amount === "unbounded")
435
450
  return result;
436
- let truncated = false;
437
- const rowKeyList = rowKeys(result);
438
- const rows = new Set(rowKeyList);
439
- const bounded = Object.fromEntries(Object.entries(result).map(([key, value]) => {
440
- if (!rows.has(key) || !Array.isArray(value) || value.length <= amount) {
441
- return [key, value];
442
- }
443
- truncated = true;
444
- return [key, value.slice(0, amount)];
445
- }));
451
+ const { result: bounded, truncated } = boundReadOutputRows(result, amount);
446
452
  if (!truncated)
447
453
  return bounded;
448
454
  bounded.has_more = true;
449
455
  bounded.truncated = true;
450
456
  if (typeof bounded.count === "number") {
451
- bounded.count = rowKeyList.reduce((total, key) => total + (Array.isArray(bounded[key]) ? bounded[key].length : 0), 0);
457
+ bounded.count = countReadOutputRows(bounded);
452
458
  }
453
459
  bounded.applied_bound = {
454
460
  kind: "output_limit",
@@ -460,23 +466,91 @@ function applyAmountBound(result, amount) {
460
466
  function requestedDimensions(resolved) {
461
467
  return PM_READ_OUTPUT_DIMENSIONS.filter((dimension) => resolved[dimension] !== undefined);
462
468
  }
469
+ /** Stabilize the per-call and cross-call receipts in one complete envelope. */
470
+ function attachReadOutputSessionContracts(result, state, receipt) {
471
+ let withSession = attachReadOutputSessionReceipt(result, state);
472
+ for (let iteration = 0; iteration < 8; iteration += 1) {
473
+ const previousReadEstimate = receipt.estimated_tokens;
474
+ const previousSessionEstimate = withSession.read_session.spent_this_call_tokens;
475
+ updateReadOutputReceiptEstimate(withSession, receipt);
476
+ withSession = attachReadOutputSessionReceipt(withSession, state);
477
+ const sessionEstimate = withSession.read_session.spent_this_call_tokens;
478
+ if (receipt.estimated_tokens === previousReadEstimate &&
479
+ sessionEstimate === previousSessionEstimate) {
480
+ return withSession;
481
+ }
482
+ }
483
+ return withSession;
484
+ }
485
+ /** Apply field, amount, and repeat projections to every declared row path. */
486
+ function projectReadOutputRows(result, resolved, session) {
487
+ let projected = { ...result };
488
+ if (resolved.include?.source === "canonical") {
489
+ projected = applyIncludeProjection(projected, resolved.include.value);
490
+ }
491
+ if (resolved.amount?.source === "canonical") {
492
+ projected = applyAmountBound(projected, resolved.amount.value);
493
+ }
494
+ return session === undefined
495
+ ? projected
496
+ : applyReadOutputSessionReferences(projected, session);
497
+ }
498
+ /** Resolve the smallest binding per-call or remaining cross-call ceiling. */
499
+ function resolveBindingReadOutputBudget(resolved, session) {
500
+ const budgets = [
501
+ ...(resolved.cost?.source === "canonical" ? [resolved.cost.value] : []),
502
+ ...(session === undefined
503
+ ? []
504
+ : [readOutputSessionRemainingTokens(session)]),
505
+ ];
506
+ return budgets.length === 0 ? undefined : Math.min(...budgets);
507
+ }
508
+ /** Build the smallest truthful omission envelope or reject an exhausted session. */
509
+ function omitReadOutputForBudget(resolved, requested, session, budget) {
510
+ const minimalReceipt = {
511
+ contract_version: 1,
512
+ command: resolved.command,
513
+ requested_dimensions: requested,
514
+ precedence: resolved.precedence,
515
+ legacy_aliases_used: [],
516
+ migration_hints: [],
517
+ estimated_tokens: 0,
518
+ within_budget: false,
519
+ strings_compacted: false,
520
+ rows_compacted: false,
521
+ result_omitted: true,
522
+ };
523
+ const omitted = {
524
+ output_budget_exceeded: {
525
+ omitted_result: true,
526
+ reason: "requested_budget_infeasible",
527
+ restore_with: "Increase --output-budget or narrow the read.",
528
+ },
529
+ read_output: minimalReceipt,
530
+ };
531
+ const boundedOmission = session === undefined
532
+ ? omitted
533
+ : attachReadOutputSessionContracts(omitted, session, minimalReceipt);
534
+ if (session === undefined) {
535
+ updateReadOutputReceiptEstimate(boundedOmission, minimalReceipt);
536
+ }
537
+ if (session !== undefined && minimalReceipt.estimated_tokens > budget) {
538
+ throw new PmCliError("The remaining output-session budget cannot fit its mandatory receipts; start a new session with a larger token_budget.", EXIT_CODE.USAGE);
539
+ }
540
+ return boundedOmission;
541
+ }
463
542
  /** Apply universal field, row, and token bounds and attach an exact receipt. */
464
543
  export function applyReadOutputDimensions(command, options, result) {
465
544
  const resolved = resolveReadOutputDimensions(command, options);
466
545
  if (!resolved)
467
546
  return result;
547
+ const session = parseReadOutputSession(options.outputSession ?? options.output_session);
468
548
  const requested = requestedDimensions(resolved);
469
549
  const canonicalRequested = requested.filter((dimension) => resolved[dimension]?.source === "canonical");
470
- if (canonicalRequested.length === 0) {
550
+ if (canonicalRequested.length === 0 && session === undefined) {
471
551
  return result;
472
552
  }
473
- let projected = { ...result };
474
- if (resolved.include?.source === "canonical") {
475
- projected = applyIncludeProjection(projected, resolved.include.value);
476
- }
477
- if (resolved.amount?.source === "canonical") {
478
- projected = applyAmountBound(projected, resolved.amount.value);
479
- }
553
+ let projected = projectReadOutputRows(result, resolved, session);
480
554
  const receipt = {
481
555
  contract_version: 1,
482
556
  command: resolved.command,
@@ -491,35 +565,20 @@ export function applyReadOutputDimensions(command, options, result) {
491
565
  result_omitted: false,
492
566
  };
493
567
  projected.read_output = receipt;
568
+ projected =
569
+ session === undefined
570
+ ? projected
571
+ : attachReadOutputSessionContracts(projected, session, receipt);
494
572
  updateReadOutputReceiptEstimate(projected, receipt);
495
- const budget = resolved.cost?.source === "canonical" ? resolved.cost.value : undefined;
573
+ const budget = resolveBindingReadOutputBudget(resolved, session);
496
574
  if (budget !== undefined && receipt.estimated_tokens > budget) {
497
575
  projected = compactReadOutputToBudget(projected, receipt, budget);
576
+ if (session !== undefined) {
577
+ projected = attachReadOutputSessionContracts(projected, session, receipt);
578
+ }
498
579
  }
499
580
  if (budget !== undefined && receipt.estimated_tokens > budget) {
500
- const minimalReceipt = {
501
- contract_version: 1,
502
- command: resolved.command,
503
- requested_dimensions: requested,
504
- precedence: resolved.precedence,
505
- legacy_aliases_used: [],
506
- migration_hints: [],
507
- estimated_tokens: 0,
508
- within_budget: false,
509
- strings_compacted: false,
510
- rows_compacted: false,
511
- result_omitted: true,
512
- };
513
- const omitted = {
514
- output_budget_exceeded: {
515
- omitted_result: true,
516
- reason: "requested_budget_infeasible",
517
- restore_with: "Increase --output-budget or narrow the read.",
518
- },
519
- read_output: minimalReceipt,
520
- };
521
- updateReadOutputReceiptEstimate(omitted, minimalReceipt);
522
- return omitted;
581
+ return omitReadOutputForBudget(resolved, requested, session, budget);
523
582
  }
524
583
  return projected;
525
584
  }
@@ -538,4 +597,4 @@ export function resolveReadOutputEncoding(command, options) {
538
597
  : undefined;
539
598
  }
540
599
  //# sourceMappingURL=read-output-contracts.js.map
541
- //# debugId=27431a6b-6f2e-5020-b4f1-b94cfa8a1c26
600
+ //# debugId=0bccb953-bd78-5eee-a78d-8af3e250fa55
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @module sdk/read-output-rows
3
+ *
4
+ * Resolves and transforms the row collections declared by universal read
5
+ * envelopes, including dot-delimited nested paths used by graph projections.
6
+ */
7
+ /** One declared array or object-map row collection in a read envelope. */
8
+ export interface PmReadOutputRowCollection {
9
+ /** Dot-delimited path published by the envelope row contract. */
10
+ path: string;
11
+ /** Array rows or a keyed row map stored at {@link path}. */
12
+ value: unknown[] | Record<string, unknown>;
13
+ }
14
+ /** Resolve declared row paths, falling back to top-level array properties. */
15
+ export declare function readOutputRowPaths(result: Record<string, unknown>): string[];
16
+ /** Resolve every declared row path that currently contains iterable rows. */
17
+ export declare function readOutputRowCollections(result: Record<string, unknown>): PmReadOutputRowCollection[];
18
+ /** Count array entries and object-map values across declared row collections. */
19
+ export declare function countReadOutputRows(result: Record<string, unknown>): number;
20
+ /**
21
+ * Transform every declared row while preserving collection keys and cloning
22
+ * only the owner objects along paths that changed.
23
+ */
24
+ export declare function mapReadOutputRows(result: Record<string, unknown>, transform: (row: unknown, path: string, index: number) => unknown): Record<string, unknown>;
25
+ /** Bound every declared row collection independently and report truncation. */
26
+ export declare function boundReadOutputRows(result: Record<string, unknown>, amount: number): {
27
+ result: Record<string, unknown>;
28
+ truncated: boolean;
29
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @module sdk/read-output-rows
3
+ *
4
+ * Resolves and transforms the row collections declared by universal read
5
+ * envelopes, including dot-delimited nested paths used by graph projections.
6
+ */
7
+
8
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ae6fbd4a-6c4e-5639-93ac-f107a336e95b")}catch(e){}}();
9
+ function isRecord(value) {
10
+ return value !== null && typeof value === "object" && !Array.isArray(value);
11
+ }
12
+ /** Read one dot-delimited path without treating missing segments as rows. */
13
+ function valueAtPath(result, rowPath) {
14
+ let value = result;
15
+ for (const segment of rowPath.split(".")) {
16
+ if (!isRecord(value))
17
+ return undefined;
18
+ value = value[segment];
19
+ }
20
+ return value;
21
+ }
22
+ /** Clone the owners along one row path and replace only its terminal value. */
23
+ function replaceValueAtPath(result, rowPath, replacement) {
24
+ const segments = rowPath.split(".");
25
+ const root = { ...result };
26
+ let source = result;
27
+ let target = root;
28
+ for (const segment of segments.slice(0, -1)) {
29
+ const sourceChild = source[segment];
30
+ const targetChild = { ...sourceChild };
31
+ target[segment] = targetChild;
32
+ source = sourceChild;
33
+ target = targetChild;
34
+ }
35
+ target[segments.at(-1)] = replacement;
36
+ return root;
37
+ }
38
+ /** Resolve declared row paths, falling back to top-level array properties. */
39
+ export function readOutputRowPaths(result) {
40
+ const contract = result.row_contract;
41
+ if (isRecord(contract) && Array.isArray(contract.row_keys)) {
42
+ return contract.row_keys.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
43
+ }
44
+ return Object.entries(result)
45
+ .filter(([, value]) => Array.isArray(value))
46
+ .map(([key]) => key);
47
+ }
48
+ /** Resolve every declared row path that currently contains iterable rows. */
49
+ export function readOutputRowCollections(result) {
50
+ return readOutputRowPaths(result).flatMap((rowPath) => {
51
+ const value = valueAtPath(result, rowPath);
52
+ return Array.isArray(value) || isRecord(value)
53
+ ? [{ path: rowPath, value }]
54
+ : [];
55
+ });
56
+ }
57
+ /** Count array entries and object-map values across declared row collections. */
58
+ export function countReadOutputRows(result) {
59
+ return readOutputRowCollections(result).reduce((total, collection) => total +
60
+ (Array.isArray(collection.value)
61
+ ? collection.value.length
62
+ : Object.keys(collection.value).length), 0);
63
+ }
64
+ /**
65
+ * Transform every declared row while preserving collection keys and cloning
66
+ * only the owner objects along paths that changed.
67
+ */
68
+ export function mapReadOutputRows(result, transform) {
69
+ let projected = result;
70
+ for (const collection of readOutputRowCollections(projected)) {
71
+ const replacement = Array.isArray(collection.value)
72
+ ? collection.value.map((row, index) => transform(row, collection.path, index))
73
+ : Object.fromEntries(Object.entries(collection.value).map(([key, row], index) => [
74
+ key,
75
+ transform(row, collection.path, index),
76
+ ]));
77
+ projected = replaceValueAtPath(projected, collection.path, replacement);
78
+ }
79
+ return projected;
80
+ }
81
+ /** Bound every declared row collection independently and report truncation. */
82
+ export function boundReadOutputRows(result, amount) {
83
+ let projected = result;
84
+ let truncated = false;
85
+ for (const collection of readOutputRowCollections(projected)) {
86
+ const entries = Array.isArray(collection.value)
87
+ ? collection.value
88
+ : Object.entries(collection.value);
89
+ if (entries.length <= amount)
90
+ continue;
91
+ truncated = true;
92
+ const replacement = Array.isArray(collection.value)
93
+ ? entries.slice(0, amount)
94
+ : Object.fromEntries(entries.slice(0, amount));
95
+ projected = replaceValueAtPath(projected, collection.path, replacement);
96
+ }
97
+ return { result: projected, truncated };
98
+ }
99
+ //# sourceMappingURL=read-output-rows.js.map
100
+ //# debugId=ae6fbd4a-6c4e-5639-93ac-f107a336e95b
@@ -0,0 +1,69 @@
1
+ /** Versioned state supplied to a sequence of related read invocations. */
2
+ export interface PmReadOutputSessionState {
3
+ /** Session-state schema version. */
4
+ version: 1;
5
+ /** Caller-selected request-group identity. */
6
+ id: string;
7
+ /** Binding token ceiling shared by every invocation in the group. */
8
+ token_budget: number;
9
+ /** Tokens already spent by earlier invocations. */
10
+ spent_tokens: number;
11
+ /** Item facts already serialized in full during this session. */
12
+ seen_item_ids: string[];
13
+ }
14
+ /** Lightweight row emitted instead of repeating a previously served item. */
15
+ export interface PmReadOutputSessionReference {
16
+ /** Stable item identity retained for joins and follow-up reads. */
17
+ id: string;
18
+ /** Resolvable reference to the session fact already in caller context. */
19
+ context_ref: string;
20
+ }
21
+ /** Receipt proving cross-call suppression and budget accounting. */
22
+ export interface PmReadOutputSessionReceipt {
23
+ /** Session-receipt schema version. */
24
+ contract_version: 1;
25
+ /** Caller-selected request-group identity. */
26
+ id: string;
27
+ /** Accounting scope, including this receipt and the read-output receipt. */
28
+ measurement_scope: "complete_read_envelope";
29
+ /** Canonical estimator shared with per-call output budgets. */
30
+ estimator: "ceil(utf8_bytes / 4)";
31
+ /** Group ceiling supplied in the session state. */
32
+ token_budget: number;
33
+ /** Spend carried into this invocation. */
34
+ spent_before_tokens: number;
35
+ /** Exact fixed-point estimate emitted by this invocation. */
36
+ spent_this_call_tokens: number;
37
+ /** Portion of this invocation charged before the ceiling was exhausted. */
38
+ charged_this_call_tokens: number;
39
+ /** Accumulated spend after this invocation. */
40
+ spent_total_tokens: number;
41
+ /** Unspent group capacity after this invocation. */
42
+ remaining_tokens: number;
43
+ /** Whether no further useful read envelope fits the group ceiling. */
44
+ exhausted: boolean;
45
+ /** Number of full item facts known before this invocation. */
46
+ seen_before_count: number;
47
+ /** Number of newly delivered item facts retained in this envelope. */
48
+ new_item_count: number;
49
+ /** Number of repeated item rows replaced by references. */
50
+ suppressed_repeat_count: number;
51
+ /** Stable reference syntax used by suppressed rows. */
52
+ reference_format: "session:<session-id>:<item-id>";
53
+ /** Command that restores a referenced item when prior context is unavailable. */
54
+ restore_reference_with: "pm get <item-id> --brief";
55
+ /** Caller-carried state for the next read in the same request group. */
56
+ next_state: PmReadOutputSessionState;
57
+ }
58
+ /** Smallest session ceiling that can carry a useful result and both receipts. */
59
+ export declare const PM_READ_OUTPUT_SESSION_MIN_TOKENS = 256;
60
+ /** Maximum caller-carried served-item identities accepted in one session state. */
61
+ export declare const PM_READ_OUTPUT_SESSION_MAX_SEEN_ITEM_IDS = 10000;
62
+ /** Parse and strictly validate a JSON string or typed session-state object. */
63
+ export declare function parseReadOutputSession(value: unknown): PmReadOutputSessionState | undefined;
64
+ /** Replace previously served item rows with compact, resolvable references. */
65
+ export declare function applyReadOutputSessionReferences(result: Record<string, unknown>, state: PmReadOutputSessionState): Record<string, unknown>;
66
+ /** Attach a fixed-point session receipt and return the exact charged tokens. */
67
+ export declare function attachReadOutputSessionReceipt(result: Record<string, unknown>, state: PmReadOutputSessionState): Record<string, unknown>;
68
+ /** Return the unspent group budget available to the current invocation. */
69
+ export declare function readOutputSessionRemainingTokens(state: PmReadOutputSessionState): number;