@unbrained/pm-cli 2026.8.13 → 2026.8.15

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 (194) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +165 -113
  3. package/dist/cli/commander-usage.js +17 -4
  4. package/dist/cli/error-guidance.d.ts +2 -0
  5. package/dist/cli/error-guidance.js +52 -25
  6. package/dist/cli/main.js +40 -3
  7. package/dist/cli/register-mutation.js +4 -2
  8. package/dist/cli/register-operations.js +5 -5
  9. package/dist/cli-bundle/bundle-manifest.json +146 -178
  10. package/dist/cli-bundle/chunks/{chunk-F7FJYGK3.js → chunk-24GAV7XL.js} +2 -2
  11. package/dist/cli-bundle/chunks/chunk-AIM6VT2N.js +13 -0
  12. package/dist/cli-bundle/chunks/chunk-DSWDLTDR.js +197 -0
  13. package/dist/cli-bundle/chunks/{chunk-Q47C67TQ.js → chunk-J42EGKDK.js} +2 -2
  14. package/dist/cli-bundle/chunks/chunk-KIEGUBYQ.js +2 -0
  15. package/dist/cli-bundle/chunks/{chunk-3ZMOWAFM.js → chunk-KLKYLSDX.js} +2 -2
  16. package/dist/cli-bundle/chunks/{chunk-QGTUPEU5.js → chunk-LJHOAVGI.js} +59 -59
  17. package/dist/cli-bundle/chunks/chunk-MEM2ZS3O.js +5 -0
  18. package/dist/cli-bundle/chunks/chunk-QHPCJWEJ.js +35 -0
  19. package/dist/cli-bundle/chunks/{chunk-YLBAPY22.js → chunk-WLPDLNEZ.js} +2 -2
  20. package/dist/cli-bundle/chunks/{register-list-query-4HIZ7EA3.js → register-list-query-CT3LFDDN.js} +2 -2
  21. package/dist/cli-bundle/chunks/{register-mutation-W64FZ5HN.js → register-mutation-NWEVA5YS.js} +3 -3
  22. package/dist/cli-bundle/chunks/register-operations-AHIAG5KM.js +2 -0
  23. package/dist/cli-bundle/chunks/{register-setup-634MFRXU.js → register-setup-ZJZFVAKE.js} +2 -2
  24. package/dist/cli-bundle/focused-chunks/chunk-4X57RE4U.js +2 -0
  25. package/dist/cli-bundle/focused-chunks/chunk-6XKF3PGV.js +18 -0
  26. package/dist/cli-bundle/focused-chunks/chunk-7NJ4QYQ2.js +2 -0
  27. package/dist/cli-bundle/focused-chunks/{chunk-I75MANL7.js → chunk-EXZA4257.js} +2 -2
  28. package/dist/cli-bundle/focused-chunks/chunk-ITAUHSO6.js +50 -0
  29. package/dist/cli-bundle/focused-chunks/{chunk-OOYYKQWX.js → chunk-KLVUMNXJ.js} +2 -2
  30. package/dist/cli-bundle/focused-chunks/{chunk-2RI2FESN.js → chunk-KT5XMYSX.js} +2 -2
  31. package/dist/cli-bundle/focused-chunks/{chunk-E3AVJ655.js → chunk-KTKH4IMG.js} +2 -2
  32. package/dist/cli-bundle/focused-chunks/chunk-M67F5AIN.js +8 -0
  33. package/dist/cli-bundle/focused-chunks/{chunk-3DJSGWVB.js → chunk-NSPYTG6G.js} +2 -2
  34. package/dist/cli-bundle/focused-chunks/chunk-OKA6ELTL.js +2 -0
  35. package/dist/cli-bundle/focused-chunks/chunk-PUISBOPP.js +2 -0
  36. package/dist/cli-bundle/focused-chunks/chunk-QLNMCESQ.js +155 -0
  37. package/dist/cli-bundle/focused-chunks/{chunk-IIS2FRKL.js → chunk-SLKC6QLJ.js} +2 -2
  38. package/dist/cli-bundle/focused-chunks/chunk-U65UC4G3.js +2 -0
  39. package/dist/cli-bundle/focused-chunks/chunk-WTSER4WJ.js +16 -0
  40. package/dist/cli-bundle/focused-chunks/{chunk-2JP7W7GO.js → chunk-ZMFXQ7VF.js} +2 -2
  41. package/dist/cli-bundle/main.js +13 -13
  42. package/dist/cli-bundle/sdk-authoring.js +1 -1
  43. package/dist/cli-bundle/sdk-contracts.js +1 -1
  44. package/dist/cli-bundle/sdk-core.js +41 -41
  45. package/dist/cli-bundle/sdk-governance.js +1 -1
  46. package/dist/cli-bundle/sdk-graph.js +1 -1
  47. package/dist/cli-bundle/sdk-merge.js +110 -1
  48. package/dist/cli-bundle/sdk-query.js +1 -1
  49. package/dist/cli-bundle/sdk-runtime.js +1 -1
  50. package/dist/cli-bundle/sdk-testing.js +1 -1
  51. package/dist/cli-bundle/sdk.js +2 -2
  52. package/dist/core/diagnostics/remediation.js +7 -2
  53. package/dist/core/extensions/reserved-host-flags.js +3 -2
  54. package/dist/core/history/drift-scan.d.ts +6 -0
  55. package/dist/core/history/drift-scan.js +74 -50
  56. package/dist/core/history/replay.d.ts +14 -1
  57. package/dist/core/history/replay.js +45 -8
  58. package/dist/core/history/workspace-history.d.ts +59 -0
  59. package/dist/core/history/workspace-history.js +197 -10
  60. package/dist/core/output/output.d.ts +2 -0
  61. package/dist/core/output/output.js +13 -4
  62. package/dist/core/shared/command-types.d.ts +2 -0
  63. package/dist/core/shared/command-types.js +2 -2
  64. package/dist/core/shared/errors.d.ts +12 -0
  65. package/dist/core/shared/errors.js +2 -2
  66. package/dist/mcp/tool-definitions.js +9 -5
  67. package/dist/sdk/agent/refusal-reachability.d.ts +61 -0
  68. package/dist/sdk/agent/refusal-reachability.js +91 -3
  69. package/dist/sdk/cli-bootstrap.d.ts +2 -0
  70. package/dist/sdk/cli-bootstrap.js +7 -2
  71. package/dist/sdk/cli-contracts/completeness.js +3 -2
  72. package/dist/sdk/cli-contracts/flag-contracts.js +3 -2
  73. package/dist/sdk/cli-contracts/registration-helpers.js +3 -2
  74. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +11 -1
  75. package/dist/sdk/cli-contracts/runtime-contracts.js +176 -65
  76. package/dist/sdk/cli-contracts/tool-parameter-tables.js +15 -5
  77. package/dist/sdk/cli-contracts/tool-schema.js +10 -3
  78. package/dist/sdk/cli-program.js +4 -3
  79. package/dist/sdk/context-relevance.js +12 -4
  80. package/dist/sdk/core.d.ts +2 -2
  81. package/dist/sdk/core.js +3 -3
  82. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +26 -2
  83. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -26
  84. package/dist/sdk/governance/assurance-action.d.ts +7 -1
  85. package/dist/sdk/governance/assurance-action.js +7 -6
  86. package/dist/sdk/governance/assurance-mutation-error.d.ts +42 -1
  87. package/dist/sdk/governance/assurance-mutation-error.js +27 -3
  88. package/dist/sdk/governance/assurance-runtime.js +12 -11
  89. package/dist/sdk/governance/assurance.d.ts +9 -0
  90. package/dist/sdk/governance/assurance.js +82 -16
  91. package/dist/sdk/governance/extension-host-version.d.ts +25 -0
  92. package/dist/sdk/governance/extension-host-version.js +105 -0
  93. package/dist/sdk/governance/health.d.ts +32 -1
  94. package/dist/sdk/governance/health.js +132 -28
  95. package/dist/sdk/governance/provenance-health.d.ts +27 -0
  96. package/dist/sdk/governance/provenance-health.js +95 -3
  97. package/dist/sdk/governance/validate-history-drift.d.ts +7 -0
  98. package/dist/sdk/governance/validate-history-drift.js +68 -0
  99. package/dist/sdk/governance/validate.js +9 -52
  100. package/dist/sdk/governance.d.ts +6 -0
  101. package/dist/sdk/governance.js +8 -2
  102. package/dist/sdk/graph/assembly.d.ts +23 -0
  103. package/dist/sdk/graph/assembly.js +54 -2
  104. package/dist/sdk/graph/durable-cache.js +50 -20
  105. package/dist/sdk/graph/governance-contracts.d.ts +1 -1
  106. package/dist/sdk/graph/governance-contracts.js +4 -2
  107. package/dist/sdk/graph/governance.d.ts +21 -1
  108. package/dist/sdk/graph/governance.js +94 -32
  109. package/dist/sdk/graph/index.d.ts +2 -2
  110. package/dist/sdk/graph/index.js +4 -4
  111. package/dist/sdk/graph/mutation-advisory.js +15 -7
  112. package/dist/sdk/graph/remediation.js +12 -2
  113. package/dist/sdk/history-read.d.ts +8 -0
  114. package/dist/sdk/history-read.js +2 -2
  115. package/dist/sdk/history-repair.d.ts +13 -1
  116. package/dist/sdk/history-repair.js +62 -18
  117. package/dist/sdk/index.d.ts +1 -1
  118. package/dist/sdk/index.js +3 -3
  119. package/dist/sdk/linked-artifacts.js +16 -5
  120. package/dist/sdk/pagination.d.ts +15 -0
  121. package/dist/sdk/pagination.js +9 -5
  122. package/dist/sdk/query/context.d.ts +5 -1
  123. package/dist/sdk/query/context.js +14 -5
  124. package/dist/sdk/query/history.js +20 -3
  125. package/dist/sdk/read-output/continuation.d.ts +11 -0
  126. package/dist/sdk/read-output/continuation.js +132 -0
  127. package/dist/sdk/read-output-budget.d.ts +3 -1
  128. package/dist/sdk/read-output-budget.js +24 -13
  129. package/dist/sdk/read-output-contracts.d.ts +127 -7
  130. package/dist/sdk/read-output-contracts.js +381 -35
  131. package/dist/sdk/read-output-rows.d.ts +13 -0
  132. package/dist/sdk/read-output-rows.js +60 -2
  133. package/dist/sdk/runtime-input.js +4 -2
  134. package/dist/sdk/runtime-primitives.d.ts +1 -1
  135. package/dist/sdk/runtime-primitives.js +3 -3
  136. package/dist/sdk/runtime.js +5 -3
  137. package/docs/ASSURANCE.md +68 -2
  138. package/docs/COMMANDS.md +39 -4
  139. package/docs/READ_OUTPUT_CONTRACTS.md +85 -8
  140. package/docs/RELATIONSHIP_GRAPH.md +20 -5
  141. package/docs/RELEASING.md +42 -5
  142. package/docs/SDK.md +12 -5
  143. package/docs/SDK_CONTEXT_INTEGRITY.md +94 -1
  144. package/docs/TESTING.md +23 -1
  145. package/docs/performance/sdk-entrypoint-import-costs.md +20 -13
  146. package/marketplace.json +2 -2
  147. package/package.json +7 -7
  148. package/packages/pm-beads/extensions/beads/index.ts +1 -0
  149. package/packages/pm-beads/package.json +1 -1
  150. package/packages/pm-calendar/extensions/calendar/index.ts +1 -0
  151. package/packages/pm-calendar/package.json +1 -1
  152. package/packages/pm-command-kit/package.json +1 -1
  153. package/packages/pm-digital-twin/extensions/digital-twin/index.ts +7 -0
  154. package/packages/pm-digital-twin/package.json +1 -1
  155. package/packages/pm-governance-audit/extensions/governance-audit/index.ts +4 -0
  156. package/packages/pm-governance-audit/package.json +1 -1
  157. package/packages/pm-guide-shell/extensions/guide-shell/index.ts +5 -0
  158. package/packages/pm-guide-shell/package.json +1 -1
  159. package/packages/pm-kanban/package.json +1 -1
  160. package/packages/pm-lifecycle-hooks/package.json +1 -1
  161. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/index.ts +6 -0
  162. package/packages/pm-linked-test-adapters/package.json +1 -1
  163. package/packages/pm-search-advanced/extensions/search-advanced/index.ts +2 -0
  164. package/packages/pm-search-advanced/package.json +1 -1
  165. package/packages/pm-templates/extensions/templates/index.ts +4 -0
  166. package/packages/pm-templates/package.json +1 -1
  167. package/packages/pm-todos/extensions/todos/index.ts +2 -0
  168. package/packages/pm-todos/package.json +1 -1
  169. package/packages/pm-vcs/extensions/vcs/index.ts +7 -0
  170. package/packages/pm-vcs/package.json +1 -1
  171. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  172. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  173. package/scripts/bundle-cli.mjs +17 -4
  174. package/sdk/public-surface.json +1283 -157
  175. package/dist/cli-bundle/chunks/chunk-DEDU3DG7.js +0 -196
  176. package/dist/cli-bundle/chunks/chunk-DL5M5J3V.js +0 -13
  177. package/dist/cli-bundle/chunks/chunk-HIUZVCMN.js +0 -5
  178. package/dist/cli-bundle/chunks/chunk-IMGIN7R6.js +0 -2
  179. package/dist/cli-bundle/chunks/chunk-TF3TPKPR.js +0 -34
  180. package/dist/cli-bundle/chunks/register-operations-C44ET7R5.js +0 -2
  181. package/dist/cli-bundle/focused-chunks/chunk-27N23W6M.js +0 -31
  182. package/dist/cli-bundle/focused-chunks/chunk-3BNVU6LC.js +0 -8
  183. package/dist/cli-bundle/focused-chunks/chunk-6MLIRBLV.js +0 -5
  184. package/dist/cli-bundle/focused-chunks/chunk-6XYLENDV.js +0 -155
  185. package/dist/cli-bundle/focused-chunks/chunk-CP4K4WFS.js +0 -2
  186. package/dist/cli-bundle/focused-chunks/chunk-EBTNSFYE.js +0 -2
  187. package/dist/cli-bundle/focused-chunks/chunk-HC2OL2H2.js +0 -2
  188. package/dist/cli-bundle/focused-chunks/chunk-NFHFZH2Z.js +0 -2
  189. package/dist/cli-bundle/focused-chunks/chunk-OGC4XSBC.js +0 -17
  190. package/dist/cli-bundle/focused-chunks/chunk-PKPOZXLL.js +0 -2
  191. package/dist/cli-bundle/focused-chunks/chunk-QDZUABWL.js +0 -2
  192. package/dist/cli-bundle/focused-chunks/chunk-QQX5TDFT.js +0 -16
  193. package/dist/cli-bundle/focused-chunks/chunk-TEZIXMTH.js +0 -2
  194. package/dist/cli-bundle/focused-chunks/chunk-WEH6NSL6.js +0 -18
@@ -5,12 +5,16 @@
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]="0ab0c72c-cac0-5670-93d1-7a446f8a2301")}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]="f9774018-a5b7-505e-a8ea-cba08392afeb")}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";
12
- import { boundReadOutputRows, countReadOutputRows, mapReadOutputRows, readOutputRowPaths, } from "./read-output-rows.js";
11
+ import { compactReadOutputToBudget, estimateReadOutputTokens, updateReadOutputReceiptEstimate, } from "./read-output-budget.js";
12
+ import { resolvePmCommandOutputBudget } from "./cli-contracts/agent-output-contracts.js";
13
+ import { boundReadOutputRows, countReadOutputRows, mapReadOutputRows, readOutputRowCollections, readOutputRowPaths, } from "./read-output-rows.js";
14
+ import { applyReadOutputContinuation, decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, prioritizeAssuranceAssertions, readOutputCollectionFingerprint, } from "./read-output/continuation.js";
15
+ export { decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, } from "./read-output/continuation.js";
13
16
  import { applyReadOutputSessionReferences, attachReadOutputSessionReceipt, parseReadOutputSession, readOutputSessionRemainingTokens, } from "./read-output-session.js";
17
+ import { decodeQueryCursorEnvelope, encodeQueryCursor } from "./pagination.js";
14
18
  /** Stable output dimensions shared by every read surface. */
15
19
  export const PM_READ_OUTPUT_DIMENSIONS = [
16
20
  "include",
@@ -40,6 +44,8 @@ export const PM_READ_OUTPUT_SURFACES = [
40
44
  "stats",
41
45
  "aggregate",
42
46
  "package-manage",
47
+ "comments-audit",
48
+ "assurance",
43
49
  ];
44
50
  const READ_OUTPUT_PRECEDENCE = [
45
51
  "canonical",
@@ -58,6 +64,7 @@ export const PM_READ_OUTPUT_OPTION_FLAGS = Object.freeze(PM_READ_OUTPUT_DIMENSIO
58
64
  /** Canonical control that composes the four per-call dimensions across reads. */
59
65
  export const PM_READ_OUTPUT_COMPOSITION_OPTION_FLAGS = Object.freeze([
60
66
  "--output-session",
67
+ "--output-cursor",
61
68
  "--output-row-contract",
62
69
  ]);
63
70
  const LEGACY_FLAGS_BY_COMMAND = {
@@ -91,7 +98,7 @@ const LEGACY_FLAGS_BY_COMMAND = {
91
98
  encoding: ["--format"],
92
99
  },
93
100
  health: {
94
- include: ["--brief", "--check-only", "--full", "--summary", "--verbose"],
101
+ include: ["--brief", "--check-only", "--full", "--summary"],
95
102
  },
96
103
  deps: {
97
104
  include: ["--collapse", "--full", "--summary"],
@@ -113,7 +120,7 @@ const LEGACY_FLAGS_BY_COMMAND = {
113
120
  amount: ["--limit", "--unbounded"],
114
121
  encoding: ["--stream"],
115
122
  },
116
- validate: { include: ["--counts", "--full", "--verbose"] },
123
+ validate: { include: ["--counts", "--full"] },
117
124
  events: {
118
125
  include: ["--full"],
119
126
  amount: ["--limit"],
@@ -129,17 +136,26 @@ const LEGACY_FLAGS_BY_COMMAND = {
129
136
  stats: {},
130
137
  aggregate: {},
131
138
  "package-manage": {},
139
+ "comments-audit": {},
140
+ assurance: {},
132
141
  };
133
- const VALUE_BEARING_INCLUDE_ALIASES = new Set(["--fields", "--section"]);
142
+ const VALUE_BEARING_INCLUDE_ALIASES = new Set([
143
+ "--collapse",
144
+ "--fields",
145
+ "--section",
146
+ ]);
134
147
  const BEHAVIOR_PRESERVING_MIGRATION_HINTS = Object.freeze({
135
148
  "--after": "--after retains cursor-position semantics; use --output-limit <n> separately to bound returned rows.",
136
149
  "--check-only": "--check-only retains health side-effect semantics; --output-include does not suppress vector refresh.",
150
+ "--collapse": "--collapse retains dependency grouping semantics; --output-include does not replace it.",
137
151
  "--depth": "--depth retains traversal or detail-depth semantics; --output-limit does not replace it.",
138
152
  "--follow": "--follow retains event-tail semantics; --output-format does not enable following.",
139
153
  "--max-depth": "--max-depth retains graph traversal-depth semantics; --output-limit does not replace it.",
140
154
  "--max-paths": "--max-paths retains graph path-search semantics; use --output-limit separately to bound returned rows.",
155
+ "--no-truncate": "--no-truncate is a compatibility alias; prefer --output-limit unbounded.",
141
156
  "--offset": "--offset retains positional pagination semantics; use --output-limit separately to bound returned rows.",
142
157
  "--stream": "--stream retains command streaming semantics; --output-format selects only static result encoding.",
158
+ "--unbounded": "--unbounded is a compatibility alias; prefer --output-limit unbounded.",
143
159
  });
144
160
  function flagSelector(flag) {
145
161
  return flag.slice(2).replaceAll("-", "_");
@@ -170,6 +186,9 @@ function buildSurfaceContract(command) {
170
186
  inapplicable_reason: null,
171
187
  legacy_aliases: Object.freeze((legacy[dimension] ?? []).map((flag) => Object.freeze({
172
188
  flag,
189
+ semantics: BEHAVIOR_PRESERVING_MIGRATION_HINTS[flag] === undefined
190
+ ? "replacement"
191
+ : "behavior_preserving",
173
192
  migration_hint: migrationHint(flag, dimension),
174
193
  visibility: "hidden_alias",
175
194
  }))),
@@ -179,6 +198,7 @@ function buildSurfaceContract(command) {
179
198
  command,
180
199
  dimensions,
181
200
  precedence: READ_OUTPUT_PRECEDENCE,
201
+ budget_retention_policy: command === "assurance" ? "verdict_priority" : "ordered_prefix",
182
202
  });
183
203
  }
184
204
  /** Universal output contract for every built-in read surface. */
@@ -217,6 +237,8 @@ const CANONICAL_OPTION_KEYS = [
217
237
  "output_format",
218
238
  "outputSession",
219
239
  "output_session",
240
+ "outputCursor",
241
+ "output_cursor",
220
242
  "outputRowContract",
221
243
  "output_row_contract",
222
244
  ];
@@ -242,8 +264,8 @@ const READ_OUTPUT_VALUE_VALIDATORS = [
242
264
  },
243
265
  {
244
266
  keys: ["outputBudget", "output_budget"],
245
- valid: (value) => positiveInteger(value) !== undefined,
246
- message: "--output-budget must be a positive integer.",
267
+ valid: (value) => value === "unbounded" || positiveInteger(value) !== undefined,
268
+ message: "--output-budget must be a positive integer or unbounded.",
247
269
  },
248
270
  {
249
271
  keys: ["outputFormat", "output_format"],
@@ -258,6 +280,11 @@ const READ_OUTPUT_VALUE_VALIDATORS = [
258
280
  },
259
281
  message: "--output-session must be a valid session-state object.",
260
282
  },
283
+ {
284
+ keys: ["outputCursor", "output_cursor"],
285
+ valid: (value) => typeof value === "string" && value.trim().length > 0,
286
+ message: "--output-cursor requires a non-empty continuation cursor.",
287
+ },
261
288
  ];
262
289
  /** Reject malformed or mutation-scoped universal output controls before command execution. */
263
290
  export function validateReadOutputOptions(command, options) {
@@ -279,6 +306,68 @@ export function validateReadOutputOptions(command, options) {
279
306
  }
280
307
  }
281
308
  }
309
+ /**
310
+ * Map every canonical `--output-include` token that names a projection mode
311
+ * rather than a row field onto the command-local option that mode already owns.
312
+ *
313
+ * The include dimension folds two kinds of legacy alias into one canonical
314
+ * spelling: value-bearing selectors (`--fields`, `--section`) that name row
315
+ * fields, and mode flags (`--brief`, `--full`, `--summary`, ...) that select a
316
+ * whole declared projection. Only the first kind can be honoured by projecting
317
+ * an already-computed result, so mode tokens have to reach the command itself.
318
+ */
319
+ export function readOutputIncludeModeOptions(command) {
320
+ const surface = resolveReadOutputSurface(command);
321
+ if (!surface)
322
+ return new Map();
323
+ return new Map((LEGACY_FLAGS_BY_COMMAND[surface].include ?? [])
324
+ .filter((flag) => !VALUE_BEARING_INCLUDE_ALIASES.has(flag) &&
325
+ BEHAVIOR_PRESERVING_MIGRATION_HINTS[flag] === undefined)
326
+ .map((flag) => [flagSelector(flag), optionKey(flag)]));
327
+ }
328
+ /**
329
+ * Translate canonical projection-mode tokens into the command-local options
330
+ * they alias, so the spelling the migration hints recommend is behaviour
331
+ * identical to the legacy flag it replaces, and return the field selectors that
332
+ * remain for post-execution projection.
333
+ */
334
+ export function applyReadOutputIncludeModes(command, includeValue, commandOptions) {
335
+ const requested = stringList(includeValue) ?? [];
336
+ const modeOptions = readOutputIncludeModeOptions(command);
337
+ const selectors = [];
338
+ const modes = [];
339
+ for (const token of requested) {
340
+ const option = modeOptions.get(token);
341
+ if (option === undefined) {
342
+ selectors.push(token);
343
+ continue;
344
+ }
345
+ commandOptions[option] = true;
346
+ modes.push(token);
347
+ }
348
+ return { selectors, modes };
349
+ }
350
+ /**
351
+ * Resolve canonical include modes against one combined options bag, rewriting
352
+ * the include value in place to the selectors that remain.
353
+ *
354
+ * Used by dispatch paths that carry command options and universal output
355
+ * controls in a single record, so an action honours a mode token exactly as the
356
+ * CLI does.
357
+ */
358
+ export function normalizeReadOutputIncludeModeOptions(command, options) {
359
+ const include = options.outputInclude ?? options.output_include;
360
+ if (include === undefined)
361
+ return;
362
+ const { selectors, modes } = applyReadOutputIncludeModes(command, include, options);
363
+ if (modes.length === 0)
364
+ return;
365
+ const residual = selectors.length > 0 ? selectors.join(",") : undefined;
366
+ options.outputInclude = residual;
367
+ if (Object.hasOwn(options, "output_include")) {
368
+ options.output_include = residual;
369
+ }
370
+ }
282
371
  function optionKey(flag) {
283
372
  return flag
284
373
  .slice(2)
@@ -353,6 +442,9 @@ function resolveAmountValue(canonical, legacy) {
353
442
  : { source: "legacy", value: legacyLimit };
354
443
  }
355
444
  function resolveCostValue(canonical, legacy) {
445
+ if (canonical === "unbounded") {
446
+ return { source: "canonical", value: "unbounded" };
447
+ }
356
448
  const canonicalBudget = positiveInteger(canonical);
357
449
  if (canonicalBudget !== undefined) {
358
450
  return { source: "canonical", value: canonicalBudget };
@@ -404,12 +496,28 @@ export function resolveReadOutputDimensions(command, options) {
404
496
  const alias = contract.dimensions[dimension].legacy_aliases.find((entry) => entry.flag === resolved.flag);
405
497
  return [alias.migration_hint];
406
498
  });
499
+ const encoding = resolveEncodingValue(options.outputFormat ?? options.output_format, legacyByDimension.encoding);
500
+ const explicitCost = resolveCostValue(options.outputBudget ?? options.output_budget, legacyByDimension.cost);
501
+ const completeResultIntent = command.trim().toLowerCase().replaceAll(/\s+/gu, " ").split(" ")[0] ===
502
+ "list-all" || legacyByDimension.amount?.flag === "--no-truncate";
503
+ const budget = resolvePmCommandOutputBudget(command, {
504
+ generateFallback: true,
505
+ });
506
+ const resolvedOutputFormat = encoding?.value === "json" || options.resolvedOutputFormat === "json"
507
+ ? "json"
508
+ : "toon";
407
509
  return {
408
510
  command: normalizedCommand,
409
511
  include: resolveIncludeValue(options.outputInclude ?? options.output_include, legacyByDimension.include),
410
512
  amount: resolveAmountValue(options.outputLimit ?? options.output_limit, legacyByDimension.amount),
411
- cost: resolveCostValue(options.outputBudget ?? options.output_budget, legacyByDimension.cost),
412
- encoding: resolveEncodingValue(options.outputFormat ?? options.output_format, legacyByDimension.encoding),
513
+ cost: explicitCost ??
514
+ (completeResultIntent
515
+ ? { source: "intent", value: "unbounded" }
516
+ : {
517
+ source: "default",
518
+ value: budget.default_max_estimated_tokens_by_format[resolvedOutputFormat],
519
+ }),
520
+ encoding,
413
521
  legacy_aliases_used: legacyAliasesUsed,
414
522
  migration_hints: migrationHints,
415
523
  precedence: READ_OUTPUT_PRECEDENCE,
@@ -422,6 +530,8 @@ const ENVELOPE_KEYS = new Set([
422
530
  "applied_bound",
423
531
  "applied_limit",
424
532
  "completeness",
533
+ "continuation_kind",
534
+ "continuation_path",
425
535
  "continuation_contract",
426
536
  "count",
427
537
  "filters",
@@ -430,6 +540,7 @@ const ENVELOPE_KEYS = new Set([
430
540
  "now",
431
541
  "omission_receipt",
432
542
  "projection",
543
+ "budget_retention_policy",
433
544
  "row_contract",
434
545
  "sorting",
435
546
  "total",
@@ -525,6 +636,34 @@ function applyGetIncludeProjection(result, selectors) {
525
636
  };
526
637
  return projected;
527
638
  }
639
+ /** Count row objects that still carry at least one field. */
640
+ function countPopulatedRows(result) {
641
+ let populated = 0;
642
+ mapReadOutputRows({ ...result }, (entry) => {
643
+ if (isRecord(entry) && Object.keys(entry).length > 0)
644
+ populated += 1;
645
+ return entry;
646
+ });
647
+ return populated;
648
+ }
649
+ /**
650
+ * Refuse an include projection that strips every field from every row.
651
+ *
652
+ * Selectors that match no field are not a narrower answer, they are no answer:
653
+ * without this the surface returns the requested row count as empty objects and
654
+ * exits 0, so a mistyped or mode-shaped selector is indistinguishable from a
655
+ * workspace that genuinely holds nothing.
656
+ */
657
+ function rejectEmptyIncludeProjection(command, original, shaped, selectors) {
658
+ if (countPopulatedRows(original) === 0 || countPopulatedRows(shaped) > 0) {
659
+ return;
660
+ }
661
+ const modes = [...readOutputIncludeModeOptions(command).keys()];
662
+ const domain = modes.length > 0
663
+ ? ` Declared ${command} projection modes: ${modes.join(", ")}.`
664
+ : ` The ${command} surface declares no projection modes; name row fields instead.`;
665
+ throw new PmCliError(`Unknown --output-include selector(s) for ${command}: ${selectors.join(", ")}. No selector matched any returned row field.${domain}`, EXIT_CODE.USAGE);
666
+ }
528
667
  function applyIncludeProjection(command, result, selectors) {
529
668
  if (command === "get") {
530
669
  return applyGetIncludeProjection(result, selectors);
@@ -537,11 +676,10 @@ function applyIncludeProjection(command, result, selectors) {
537
676
  !rows.some((rowPath) => selector.startsWith(`${rowPath}.`)));
538
677
  if (rows.length > 0 && (!selectedRoot || qualifiedRowSelectors.length > 0)) {
539
678
  const projected = { ...result };
540
- return mapReadOutputRows(projected, (entry) => isRecord(entry)
541
- ? projectRecordFields(entry, qualifiedRowSelectors.length > 0
542
- ? qualifiedRowSelectors
543
- : selectors)
544
- : entry);
679
+ const rowSelectors = qualifiedRowSelectors.length > 0 ? qualifiedRowSelectors : selectors;
680
+ const shaped = mapReadOutputRows(projected, (entry) => isRecord(entry) ? projectRecordFields(entry, rowSelectors) : entry);
681
+ rejectEmptyIncludeProjection(command, result, shaped, rowSelectors);
682
+ return shaped;
545
683
  }
546
684
  return Object.fromEntries(Object.entries(result).filter(([key]) => selectors.some((selector) => selector.split(".")[0] === key) ||
547
685
  ENVELOPE_KEYS.has(key)));
@@ -565,7 +703,8 @@ function applyAmountBound(result, amount) {
565
703
  return bounded;
566
704
  }
567
705
  function requestedDimensions(resolved) {
568
- return PM_READ_OUTPUT_DIMENSIONS.filter((dimension) => resolved[dimension] !== undefined);
706
+ return PM_READ_OUTPUT_DIMENSIONS.filter((dimension) => resolved[dimension] !== undefined &&
707
+ resolved[dimension]?.source !== "default");
569
708
  }
570
709
  /** Stabilize the per-call and cross-call receipts in one complete envelope. */
571
710
  function attachReadOutputSessionContracts(result, state, receipt) {
@@ -596,11 +735,15 @@ export function stabilizeReadOutputReceiptEstimates(result, options) {
596
735
  return attachReadOutputSessionContracts(result, session, receipt);
597
736
  }
598
737
  /** Apply field, amount, and repeat projections to every declared row path. */
599
- function projectReadOutputRows(result, resolved, session) {
738
+ function projectReadOutputRows(result, resolved, session, cursor) {
600
739
  let projected = { ...result };
601
740
  if (resolved.include?.source === "canonical") {
602
741
  projected = applyIncludeProjection(resolved.command, projected, resolved.include.value);
603
742
  }
743
+ if (resolved.command === "assurance") {
744
+ projected = prioritizeAssuranceAssertions(projected);
745
+ }
746
+ projected = applyReadOutputContinuation(projected, resolved.command, cursor);
604
747
  if (resolved.amount?.source === "canonical") {
605
748
  projected = applyAmountBound(projected, resolved.amount.value);
606
749
  }
@@ -611,19 +754,34 @@ function projectReadOutputRows(result, resolved, session) {
611
754
  /** Resolve the smallest binding per-call or remaining cross-call ceiling. */
612
755
  function resolveBindingReadOutputBudget(resolved, session) {
613
756
  const budgets = [
614
- ...(resolved.cost?.source === "canonical" ? [resolved.cost.value] : []),
757
+ ...(resolved.cost !== undefined &&
758
+ resolved.cost.value !== "unbounded" &&
759
+ (resolved.cost.source === "canonical" || resolved.cost.source === "default")
760
+ ? [{ source: resolved.cost.source, tokens: resolved.cost.value }]
761
+ : []),
615
762
  ...(session === undefined
616
763
  ? []
617
- : [readOutputSessionRemainingTokens(session)]),
764
+ : [
765
+ {
766
+ source: "session",
767
+ tokens: readOutputSessionRemainingTokens(session),
768
+ },
769
+ ]),
618
770
  ];
619
- return budgets.length === 0 ? undefined : Math.min(...budgets);
771
+ return budgets.sort((left, right) => left.tokens - right.tokens)[0];
620
772
  }
621
773
  /** Build the smallest truthful omission envelope or reject an exhausted session. */
622
- function omitReadOutputForBudget(resolved, requested, session, budget) {
774
+ function omitReadOutputForBudget(resolved, requested, session, bindingBudget, omittedResultEstimatedTokens) {
623
775
  const minimalReceipt = {
624
776
  contract_version: 1,
625
777
  command: resolved.command,
626
778
  requested_dimensions: requested,
779
+ ...(bindingBudget.source === "default"
780
+ ? {
781
+ budget_source: bindingBudget.source,
782
+ budget_tokens: bindingBudget.tokens,
783
+ }
784
+ : {}),
627
785
  precedence: resolved.precedence,
628
786
  legacy_aliases_used: [],
629
787
  migration_hints: [],
@@ -632,12 +790,16 @@ function omitReadOutputForBudget(resolved, requested, session, budget) {
632
790
  strings_compacted: false,
633
791
  rows_compacted: false,
634
792
  result_omitted: true,
793
+ ...(session === undefined
794
+ ? { omitted_result_estimated_tokens: omittedResultEstimatedTokens }
795
+ : {}),
635
796
  };
636
797
  const omitted = {
637
798
  output_budget_exceeded: {
638
799
  omitted_result: true,
639
800
  reason: "requested_budget_infeasible",
640
- restore_with: "Increase --output-budget or narrow the read.",
801
+ restore_with: "Unbounded",
802
+ recovery: { outputBudget: "unbounded" },
641
803
  },
642
804
  read_output: minimalReceipt,
643
805
  };
@@ -647,27 +809,213 @@ function omitReadOutputForBudget(resolved, requested, session, budget) {
647
809
  if (session === undefined) {
648
810
  updateReadOutputReceiptEstimate(boundedOmission, minimalReceipt);
649
811
  }
650
- if (session !== undefined && minimalReceipt.estimated_tokens > budget) {
812
+ if (session !== undefined &&
813
+ minimalReceipt.estimated_tokens > bindingBudget.tokens) {
651
814
  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);
652
815
  }
653
816
  return boundedOmission;
654
817
  }
818
+ /** Decide whether shaping would add no value to an already-bounded result. */
819
+ function canReturnReadOutputUnchanged(resolved, requested, session, result) {
820
+ if (session !== undefined)
821
+ return false;
822
+ const canonicalRequestedCount = requested.filter((dimension) => resolved[dimension]?.source === "canonical").length;
823
+ if (resolved.cost?.value === "unbounded") {
824
+ return (canonicalRequestedCount === (resolved.cost.source === "canonical" ? 1 : 0));
825
+ }
826
+ if (resolved.cost?.source === "legacy" && canonicalRequestedCount === 0) {
827
+ return true;
828
+ }
829
+ return (canonicalRequestedCount === 0 &&
830
+ (resolved.cost === undefined ||
831
+ estimateReadOutputTokens(result) <= resolved.cost.value));
832
+ }
833
+ /**
834
+ * Disclose a budget-driven row drop in the envelope that carries it.
835
+ *
836
+ * `has_more` and `truncated` say that rows were withheld but not why, by what,
837
+ * or how to get them: the row-compaction path emits no continuation cursor, so
838
+ * without this an explicitly requested unbounded read is silently downgraded and
839
+ * the only working recovery is never named.
840
+ */
841
+ function attachReadOutputTruncationDisclosure(projected, resolved, receipt, bindingBudget, continuationCursorRebased, collectionsBeforeBudget) {
842
+ if (!receipt.rows_compacted)
843
+ return;
844
+ const overridden = resolved.amount?.value === "unbounded" ? ["amount"] : [];
845
+ const afterByPath = new Map(readOutputRowCollections(projected).map((collection) => [
846
+ collection.path,
847
+ Array.isArray(collection.value)
848
+ ? collection.value.length
849
+ : Object.keys(collection.value).length,
850
+ ]));
851
+ const continuations = [...collectionsBeforeBudget.entries()].flatMap(([path, before]) => {
852
+ // Budget compaction preserves every declared collection and shortens its
853
+ // contents, so each pre-budget path has a post-budget cardinality.
854
+ const retainedRows = afterByPath.get(path);
855
+ if (retainedRows >= before.rows)
856
+ return [];
857
+ const offset = before.baseOffset + retainedRows;
858
+ return [
859
+ {
860
+ path,
861
+ cursor: encodeReadOutputContinuationCursor({
862
+ command: resolved.command,
863
+ path,
864
+ offset,
865
+ total_rows: before.totalRows,
866
+ fingerprint: before.fingerprint,
867
+ }),
868
+ retained_rows: retainedRows,
869
+ remaining_rows: before.totalRows - offset,
870
+ total_rows: before.totalRows,
871
+ },
872
+ ];
873
+ });
874
+ const primary = continuations[0];
875
+ if (primary && typeof projected.next_cursor !== "string") {
876
+ projected.next_cursor = primary.cursor;
877
+ }
878
+ projected.continuation_kind = continuationCursorRebased
879
+ ? "producer_cursor"
880
+ : primary
881
+ ? "output_cursor"
882
+ : "none";
883
+ projected.output_budget_truncation = {
884
+ reason: "output_budget_reached",
885
+ budget_source: bindingBudget.source,
886
+ budget_tokens: bindingBudget.tokens,
887
+ overridden_dimensions: overridden,
888
+ compacted_row_paths: receipt.compacted_row_paths,
889
+ continuation_cursor_rebased: continuationCursorRebased,
890
+ continuation_available: continuations.length > 0,
891
+ recovery_budget_multiplier: 1,
892
+ continuations,
893
+ restore_with: primary
894
+ ? "Use recovery binding."
895
+ : "Increase --output-budget because no declared row collection can be continued.",
896
+ recovery: primary
897
+ ? {
898
+ cursor: primary.cursor,
899
+ cli: "--output-cursor",
900
+ sdk: "outputCursor",
901
+ mcp: "outputCursor",
902
+ }
903
+ : {
904
+ cli: "--output-budget 1200",
905
+ sdk: { outputBudget: 1200 },
906
+ mcp: { outputBudget: 1200 },
907
+ },
908
+ };
909
+ }
910
+ /** Rebase a producer cursor when budget compaction removes rows from its page. */
911
+ function rebaseBudgetCompactedCursor(projected, originalItemCount, cursorSource, cursorContinuesExistingPage) {
912
+ if (typeof cursorSource !== "string" || !Array.isArray(projected.items)) {
913
+ return false;
914
+ }
915
+ const retainedCount = projected.items.length;
916
+ if (retainedCount === 0 || retainedCount >= originalItemCount) {
917
+ return false;
918
+ }
919
+ let cursor;
920
+ try {
921
+ cursor = decodeQueryCursorEnvelope(cursorSource);
922
+ }
923
+ catch {
924
+ return false;
925
+ }
926
+ const sourceIndex = cursor.after_index;
927
+ if (sourceIndex === undefined)
928
+ return false;
929
+ const last = projected.items.at(-1);
930
+ if (Object.prototype.toString.call(last) !== "[object Object]") {
931
+ return false;
932
+ }
933
+ const lastId = Reflect.get(last, "id");
934
+ if (typeof lastId !== "string" || lastId.length === 0)
935
+ return false;
936
+ const afterIndex = cursorContinuesExistingPage
937
+ ? sourceIndex - (originalItemCount - retainedCount)
938
+ : sourceIndex + retainedCount;
939
+ if (afterIndex < 0)
940
+ return false;
941
+ projected.next_cursor = encodeQueryCursor(cursor.fingerprint, lastId, afterIndex, cursor.snapshot);
942
+ if (typeof projected.applied_limit === "number") {
943
+ projected.applied_limit = retainedCount;
944
+ }
945
+ return true;
946
+ }
947
+ function captureReadOutputContinuationState(projected, cursor, options) {
948
+ const collectionsBeforeBudget = new Map(readOutputRowCollections(projected).map((collection) => {
949
+ const rows = Array.isArray(collection.value)
950
+ ? collection.value.length
951
+ : Object.keys(collection.value).length;
952
+ const continued = cursor?.path === collection.path;
953
+ return [
954
+ collection.path,
955
+ {
956
+ rows,
957
+ totalRows: continued ? cursor.total_rows : rows,
958
+ baseOffset: continued ? cursor.offset : 0,
959
+ fingerprint: continued
960
+ ? cursor.fingerprint
961
+ : readOutputCollectionFingerprint(collection.path, collection.value),
962
+ },
963
+ ];
964
+ }));
965
+ const cursorContinuesExistingPage = typeof projected.next_cursor === "string";
966
+ return {
967
+ collectionsBeforeBudget,
968
+ originalItemCount: Array.isArray(projected.items)
969
+ ? projected.items.length
970
+ : 0,
971
+ cursorContinuesExistingPage,
972
+ cursorSource: cursorContinuesExistingPage
973
+ ? projected.next_cursor
974
+ : options.after,
975
+ };
976
+ }
977
+ function compactReadOutputProjection(projected, resolved, receipt, bindingBudget, session, continuationState) {
978
+ const assuranceMinimumRows = resolved.command === "assurance" && Array.isArray(projected.assertions)
979
+ ? projected.assertions.filter((row) => isRecord(row) && row.verdict !== "pass").length
980
+ : 0;
981
+ let compacted = compactReadOutputToBudget(projected, receipt, bindingBudget.tokens, assuranceMinimumRows > 0
982
+ ? new Map([["assertions", assuranceMinimumRows]])
983
+ : new Map());
984
+ const continuationCursorRebased = rebaseBudgetCompactedCursor(compacted, continuationState.originalItemCount, continuationState.cursorSource, continuationState.cursorContinuesExistingPage);
985
+ attachReadOutputTruncationDisclosure(compacted, resolved, receipt, bindingBudget, continuationCursorRebased, continuationState.collectionsBeforeBudget);
986
+ if (session !== undefined) {
987
+ compacted = attachReadOutputSessionContracts(compacted, session, receipt);
988
+ }
989
+ return compacted;
990
+ }
655
991
  /** Apply universal field, row, and token bounds and attach an exact receipt. */
656
992
  export function applyReadOutputDimensions(command, options, result) {
657
993
  const resolved = resolveReadOutputDimensions(command, options);
658
994
  if (!resolved)
659
995
  return result;
660
996
  const session = parseReadOutputSession(options.outputSession ?? options.output_session);
997
+ const rawCursor = options.outputCursor ?? options.output_cursor;
998
+ const cursor = typeof rawCursor === "string"
999
+ ? decodeReadOutputContinuationCursor(rawCursor)
1000
+ : undefined;
661
1001
  const requested = requestedDimensions(resolved);
662
- const canonicalRequested = requested.filter((dimension) => resolved[dimension]?.source === "canonical");
663
- if (canonicalRequested.length === 0 && session === undefined) {
1002
+ if (cursor === undefined &&
1003
+ canReturnReadOutputUnchanged(resolved, requested, session, result)) {
664
1004
  return result;
665
1005
  }
666
- let projected = projectReadOutputRows(result, resolved, session);
1006
+ const bindingBudget = resolveBindingReadOutputBudget(resolved, session);
1007
+ let projected = projectReadOutputRows(result, resolved, session, cursor);
1008
+ const continuationState = captureReadOutputContinuationState(projected, cursor, options);
667
1009
  const receipt = {
668
1010
  contract_version: 1,
669
1011
  command: resolved.command,
670
1012
  requested_dimensions: requested,
1013
+ ...(bindingBudget?.source === "default"
1014
+ ? {
1015
+ budget_source: bindingBudget.source,
1016
+ budget_tokens: bindingBudget.tokens,
1017
+ }
1018
+ : {}),
671
1019
  precedence: resolved.precedence,
672
1020
  legacy_aliases_used: resolved.legacy_aliases_used,
673
1021
  migration_hints: resolved.migration_hints,
@@ -683,15 +1031,13 @@ export function applyReadOutputDimensions(command, options, result) {
683
1031
  ? projected
684
1032
  : attachReadOutputSessionContracts(projected, session, receipt);
685
1033
  updateReadOutputReceiptEstimate(projected, receipt);
686
- const budget = resolveBindingReadOutputBudget(resolved, session);
687
- if (budget !== undefined && receipt.estimated_tokens > budget) {
688
- projected = compactReadOutputToBudget(projected, receipt, budget);
689
- if (session !== undefined) {
690
- projected = attachReadOutputSessionContracts(projected, session, receipt);
691
- }
1034
+ if (bindingBudget !== undefined &&
1035
+ receipt.estimated_tokens > bindingBudget.tokens) {
1036
+ projected = compactReadOutputProjection(projected, resolved, receipt, bindingBudget, session, continuationState);
692
1037
  }
693
- if (budget !== undefined && receipt.estimated_tokens > budget) {
694
- return omitReadOutputForBudget(resolved, requested, session, budget);
1038
+ if (bindingBudget !== undefined &&
1039
+ receipt.estimated_tokens > bindingBudget.tokens) {
1040
+ return omitReadOutputForBudget(resolved, requested, session, bindingBudget, receipt.estimated_tokens);
695
1041
  }
696
1042
  return projected;
697
1043
  }
@@ -710,4 +1056,4 @@ export function resolveReadOutputEncoding(command, options) {
710
1056
  : undefined;
711
1057
  }
712
1058
  //# sourceMappingURL=read-output-contracts.js.map
713
- //# debugId=0ab0c72c-cac0-5670-93d1-7a446f8a2301
1059
+ //# debugId=f9774018-a5b7-505e-a8ea-cba08392afeb
@@ -11,10 +11,23 @@ export interface PmReadOutputRowCollection {
11
11
  /** Array rows or a keyed row map stored at {@link path}. */
12
12
  value: unknown[] | Record<string, unknown>;
13
13
  }
14
+ /** Replace one declared row collection with a suffix beginning at an offset. */
15
+ export declare function sliceReadOutputRowCollection(result: Record<string, unknown>, rowPath: string, offset: number): Record<string, unknown>;
14
16
  /** Resolve declared row paths, falling back to top-level array properties. */
15
17
  export declare function readOutputRowPaths(result: Record<string, unknown>): string[];
16
18
  /** Resolve every declared row path that currently contains iterable rows. */
17
19
  export declare function readOutputRowCollections(result: Record<string, unknown>): PmReadOutputRowCollection[];
20
+ /**
21
+ * Discover every collection the token-budget degradation ladder may reduce.
22
+ *
23
+ * Ordinary field and amount projections stay bound to declared row paths (or
24
+ * top-level array fallbacks), because a nested tag list is not an independent
25
+ * result row. Budget degradation has a different obligation: it must exhaust
26
+ * nested content collections before omitting the whole useful result. This
27
+ * census therefore adds nested arrays while excluding receipt/envelope metadata
28
+ * whose mutation would make the disclosure itself incomplete.
29
+ */
30
+ export declare function readOutputBudgetCollections(result: Record<string, unknown>): PmReadOutputRowCollection[];
18
31
  /** Count array entries and object-map values across declared row collections. */
19
32
  export declare function countReadOutputRows(result: Record<string, unknown>): number;
20
33
  /**