@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.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +165 -113
- package/dist/cli/commander-usage.js +17 -4
- package/dist/cli/error-guidance.d.ts +2 -0
- package/dist/cli/error-guidance.js +52 -25
- package/dist/cli/main.js +40 -3
- package/dist/cli/register-mutation.js +4 -2
- package/dist/cli/register-operations.js +5 -5
- package/dist/cli-bundle/bundle-manifest.json +146 -178
- package/dist/cli-bundle/chunks/{chunk-F7FJYGK3.js → chunk-24GAV7XL.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-AIM6VT2N.js +13 -0
- package/dist/cli-bundle/chunks/chunk-DSWDLTDR.js +197 -0
- package/dist/cli-bundle/chunks/{chunk-Q47C67TQ.js → chunk-J42EGKDK.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-KIEGUBYQ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-3ZMOWAFM.js → chunk-KLKYLSDX.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-QGTUPEU5.js → chunk-LJHOAVGI.js} +59 -59
- package/dist/cli-bundle/chunks/chunk-MEM2ZS3O.js +5 -0
- package/dist/cli-bundle/chunks/chunk-QHPCJWEJ.js +35 -0
- package/dist/cli-bundle/chunks/{chunk-YLBAPY22.js → chunk-WLPDLNEZ.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-4HIZ7EA3.js → register-list-query-CT3LFDDN.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-W64FZ5HN.js → register-mutation-NWEVA5YS.js} +3 -3
- package/dist/cli-bundle/chunks/register-operations-AHIAG5KM.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-634MFRXU.js → register-setup-ZJZFVAKE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-4X57RE4U.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-6XKF3PGV.js +18 -0
- package/dist/cli-bundle/focused-chunks/chunk-7NJ4QYQ2.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-I75MANL7.js → chunk-EXZA4257.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ITAUHSO6.js +50 -0
- package/dist/cli-bundle/focused-chunks/{chunk-OOYYKQWX.js → chunk-KLVUMNXJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-2RI2FESN.js → chunk-KT5XMYSX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-E3AVJ655.js → chunk-KTKH4IMG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-M67F5AIN.js +8 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3DJSGWVB.js → chunk-NSPYTG6G.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-OKA6ELTL.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-PUISBOPP.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-QLNMCESQ.js +155 -0
- package/dist/cli-bundle/focused-chunks/{chunk-IIS2FRKL.js → chunk-SLKC6QLJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-U65UC4G3.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-WTSER4WJ.js +16 -0
- package/dist/cli-bundle/focused-chunks/{chunk-2JP7W7GO.js → chunk-ZMFXQ7VF.js} +2 -2
- package/dist/cli-bundle/main.js +13 -13
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +41 -41
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +110 -1
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +2 -2
- package/dist/core/diagnostics/remediation.js +7 -2
- package/dist/core/extensions/reserved-host-flags.js +3 -2
- package/dist/core/history/drift-scan.d.ts +6 -0
- package/dist/core/history/drift-scan.js +74 -50
- package/dist/core/history/replay.d.ts +14 -1
- package/dist/core/history/replay.js +45 -8
- package/dist/core/history/workspace-history.d.ts +59 -0
- package/dist/core/history/workspace-history.js +197 -10
- package/dist/core/output/output.d.ts +2 -0
- package/dist/core/output/output.js +13 -4
- package/dist/core/shared/command-types.d.ts +2 -0
- package/dist/core/shared/command-types.js +2 -2
- package/dist/core/shared/errors.d.ts +12 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/mcp/tool-definitions.js +9 -5
- package/dist/sdk/agent/refusal-reachability.d.ts +61 -0
- package/dist/sdk/agent/refusal-reachability.js +91 -3
- package/dist/sdk/cli-bootstrap.d.ts +2 -0
- package/dist/sdk/cli-bootstrap.js +7 -2
- package/dist/sdk/cli-contracts/completeness.js +3 -2
- package/dist/sdk/cli-contracts/flag-contracts.js +3 -2
- package/dist/sdk/cli-contracts/registration-helpers.js +3 -2
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +11 -1
- package/dist/sdk/cli-contracts/runtime-contracts.js +176 -65
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +15 -5
- package/dist/sdk/cli-contracts/tool-schema.js +10 -3
- package/dist/sdk/cli-program.js +4 -3
- package/dist/sdk/context-relevance.js +12 -4
- package/dist/sdk/core.d.ts +2 -2
- package/dist/sdk/core.js +3 -3
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +26 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -26
- package/dist/sdk/governance/assurance-action.d.ts +7 -1
- package/dist/sdk/governance/assurance-action.js +7 -6
- package/dist/sdk/governance/assurance-mutation-error.d.ts +42 -1
- package/dist/sdk/governance/assurance-mutation-error.js +27 -3
- package/dist/sdk/governance/assurance-runtime.js +12 -11
- package/dist/sdk/governance/assurance.d.ts +9 -0
- package/dist/sdk/governance/assurance.js +82 -16
- package/dist/sdk/governance/extension-host-version.d.ts +25 -0
- package/dist/sdk/governance/extension-host-version.js +105 -0
- package/dist/sdk/governance/health.d.ts +32 -1
- package/dist/sdk/governance/health.js +132 -28
- package/dist/sdk/governance/provenance-health.d.ts +27 -0
- package/dist/sdk/governance/provenance-health.js +95 -3
- package/dist/sdk/governance/validate-history-drift.d.ts +7 -0
- package/dist/sdk/governance/validate-history-drift.js +68 -0
- package/dist/sdk/governance/validate.js +9 -52
- package/dist/sdk/governance.d.ts +6 -0
- package/dist/sdk/governance.js +8 -2
- package/dist/sdk/graph/assembly.d.ts +23 -0
- package/dist/sdk/graph/assembly.js +54 -2
- package/dist/sdk/graph/durable-cache.js +50 -20
- package/dist/sdk/graph/governance-contracts.d.ts +1 -1
- package/dist/sdk/graph/governance-contracts.js +4 -2
- package/dist/sdk/graph/governance.d.ts +21 -1
- package/dist/sdk/graph/governance.js +94 -32
- package/dist/sdk/graph/index.d.ts +2 -2
- package/dist/sdk/graph/index.js +4 -4
- package/dist/sdk/graph/mutation-advisory.js +15 -7
- package/dist/sdk/graph/remediation.js +12 -2
- package/dist/sdk/history-read.d.ts +8 -0
- package/dist/sdk/history-read.js +2 -2
- package/dist/sdk/history-repair.d.ts +13 -1
- package/dist/sdk/history-repair.js +62 -18
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +3 -3
- package/dist/sdk/linked-artifacts.js +16 -5
- package/dist/sdk/pagination.d.ts +15 -0
- package/dist/sdk/pagination.js +9 -5
- package/dist/sdk/query/context.d.ts +5 -1
- package/dist/sdk/query/context.js +14 -5
- package/dist/sdk/query/history.js +20 -3
- package/dist/sdk/read-output/continuation.d.ts +11 -0
- package/dist/sdk/read-output/continuation.js +132 -0
- package/dist/sdk/read-output-budget.d.ts +3 -1
- package/dist/sdk/read-output-budget.js +24 -13
- package/dist/sdk/read-output-contracts.d.ts +127 -7
- package/dist/sdk/read-output-contracts.js +381 -35
- package/dist/sdk/read-output-rows.d.ts +13 -0
- package/dist/sdk/read-output-rows.js +60 -2
- package/dist/sdk/runtime-input.js +4 -2
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/runtime.js +5 -3
- package/docs/ASSURANCE.md +68 -2
- package/docs/COMMANDS.md +39 -4
- package/docs/READ_OUTPUT_CONTRACTS.md +85 -8
- package/docs/RELATIONSHIP_GRAPH.md +20 -5
- package/docs/RELEASING.md +42 -5
- package/docs/SDK.md +12 -5
- package/docs/SDK_CONTEXT_INTEGRITY.md +94 -1
- package/docs/TESTING.md +23 -1
- package/docs/performance/sdk-entrypoint-import-costs.md +20 -13
- package/marketplace.json +2 -2
- package/package.json +7 -7
- package/packages/pm-beads/extensions/beads/index.ts +1 -0
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/extensions/calendar/index.ts +1 -0
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/extensions/digital-twin/index.ts +7 -0
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/extensions/governance-audit/index.ts +4 -0
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/extensions/guide-shell/index.ts +5 -0
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/index.ts +6 -0
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/extensions/search-advanced/index.ts +2 -0
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/extensions/templates/index.ts +4 -0
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/extensions/todos/index.ts +2 -0
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/extensions/vcs/index.ts +7 -0
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/scripts/bundle-cli.mjs +17 -4
- package/sdk/public-surface.json +1283 -157
- package/dist/cli-bundle/chunks/chunk-DEDU3DG7.js +0 -196
- package/dist/cli-bundle/chunks/chunk-DL5M5J3V.js +0 -13
- package/dist/cli-bundle/chunks/chunk-HIUZVCMN.js +0 -5
- package/dist/cli-bundle/chunks/chunk-IMGIN7R6.js +0 -2
- package/dist/cli-bundle/chunks/chunk-TF3TPKPR.js +0 -34
- package/dist/cli-bundle/chunks/register-operations-C44ET7R5.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-27N23W6M.js +0 -31
- package/dist/cli-bundle/focused-chunks/chunk-3BNVU6LC.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-6MLIRBLV.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-6XYLENDV.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-CP4K4WFS.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-EBTNSFYE.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-HC2OL2H2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-NFHFZH2Z.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-OGC4XSBC.js +0 -17
- package/dist/cli-bundle/focused-chunks/chunk-PKPOZXLL.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QDZUABWL.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QQX5TDFT.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-TEZIXMTH.js +0 -2
- 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]="
|
|
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 {
|
|
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"
|
|
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"
|
|
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([
|
|
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:
|
|
412
|
-
|
|
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
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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
|
|
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
|
-
: [
|
|
764
|
+
: [
|
|
765
|
+
{
|
|
766
|
+
source: "session",
|
|
767
|
+
tokens: readOutputSessionRemainingTokens(session),
|
|
768
|
+
},
|
|
769
|
+
]),
|
|
618
770
|
];
|
|
619
|
-
return 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,
|
|
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: "
|
|
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 &&
|
|
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
|
-
|
|
663
|
-
|
|
1002
|
+
if (cursor === undefined &&
|
|
1003
|
+
canReturnReadOutputUnchanged(resolved, requested, session, result)) {
|
|
664
1004
|
return result;
|
|
665
1005
|
}
|
|
666
|
-
|
|
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
|
-
|
|
687
|
-
|
|
688
|
-
projected =
|
|
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 (
|
|
694
|
-
|
|
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=
|
|
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
|
/**
|