@unbrained/pm-cli 2026.8.14 → 2026.8.16
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 +51 -11
- package/dist/cli/commander-usage.js +17 -4
- package/dist/cli/error-guidance.d.ts +7 -0
- package/dist/cli/error-guidance.js +65 -25
- package/dist/cli/main.js +3 -2
- package/dist/cli/register-history-author.js +16 -11
- package/dist/cli/register-mutation.js +4 -2
- package/dist/cli/register-operations.js +5 -5
- package/dist/cli-bundle/bundle-manifest.json +148 -148
- package/dist/cli-bundle/chunks/chunk-47OQEOQB.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-XAVMOK6B.js → chunk-73UGEBRS.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-HCIYWD6M.js +35 -0
- package/dist/cli-bundle/chunks/{chunk-FIW4P64F.js → chunk-I2LUWWR5.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-SBRKH6OR.js → chunk-IC5W2T34.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-TMJ7URWS.js → chunk-PANOOBIS.js} +9 -9
- package/dist/cli-bundle/chunks/{chunk-BFALV3YP.js → chunk-RIS565OA.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-TXMEUUUY.js → chunk-TK6N7HGM.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-TOFG2URD.js +197 -0
- package/dist/cli-bundle/chunks/{chunk-G5JUB66K.js → chunk-URW4QRMI.js} +65 -59
- package/dist/cli-bundle/chunks/{register-list-query-T3EHHNNV.js → register-list-query-EYCXHZAG.js} +2 -2
- package/dist/cli-bundle/chunks/register-mutation-7YVIG54J.js +20 -0
- package/dist/cli-bundle/chunks/register-operations-KGDNRMCL.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-3YXZ444E.js → register-setup-NVXBOD5I.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-PPFGQDSI.js → chunk-4JPEBFFC.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-5NMFSX26.js +155 -0
- package/dist/cli-bundle/focused-chunks/{chunk-YOOI3UZX.js → chunk-6ROKKT4X.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-725JSCMP.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-XDNAW5OI.js → chunk-C7JUBRFP.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-4DQ2YERC.js → chunk-CODV5LUT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-DQ6SMTBF.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-HAACPSUW.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-WCVE2NIG.js → chunk-J4UFYHOD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-JX5Z344Q.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-L4RDYBIQ.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KSEDUWVZ.js → chunk-NJ5RLEFD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-K7RWWOAG.js → chunk-QYZERYR5.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-SSNDYZTM.js +8 -0
- package/dist/cli-bundle/focused-chunks/chunk-T46KLOIB.js +50 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KFSZ3BP6.js → chunk-TZATVC4G.js} +6 -6
- package/dist/cli-bundle/focused-chunks/chunk-WY3WRPVN.js +2 -0
- 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 +32 -35
- 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 +32 -31
- 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/replay.d.ts +14 -1
- package/dist/core/history/replay.js +45 -8
- package/dist/core/history/workspace-history.js +32 -10
- package/dist/core/output/output.d.ts +2 -0
- package/dist/core/output/output.js +7 -3
- 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 +14 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/store/item-store.js +28 -2
- package/dist/mcp/tool-definitions.js +9 -5
- package/dist/sdk/agent/refusal-reachability.d.ts +69 -0
- package/dist/sdk/agent/refusal-reachability.js +159 -3
- package/dist/sdk/author-attribution.d.ts +56 -11
- package/dist/sdk/author-attribution.js +174 -50
- 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 +6 -2
- package/dist/sdk/cli-contracts/registration-helpers.js +3 -2
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +5 -0
- package/dist/sdk/cli-contracts/runtime-contracts.js +23 -7
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +22 -5
- package/dist/sdk/cli-contracts/tool-schema.js +20 -5
- package/dist/sdk/cli-program.js +3 -2
- package/dist/sdk/completion.js +11 -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 +50 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +74 -14
- 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 +80 -14
- package/dist/sdk/governance/coverage-assurance.d.ts +24 -0
- package/dist/sdk/governance/coverage-assurance.js +61 -0
- package/dist/sdk/governance/extension-host-version.d.ts +25 -0
- package/dist/sdk/governance/extension-host-version.js +116 -0
- package/dist/sdk/governance/health.d.ts +32 -1
- package/dist/sdk/governance/health.js +119 -27
- package/dist/sdk/governance/provenance-health.d.ts +27 -0
- package/dist/sdk/governance/provenance-health.js +95 -3
- package/dist/sdk/governance/validate.js +7 -8
- package/dist/sdk/governance.d.ts +6 -0
- package/dist/sdk/governance.js +8 -2
- package/dist/sdk/history-repair.d.ts +13 -1
- package/dist/sdk/history-repair.js +62 -18
- package/dist/sdk/index.d.ts +2 -1
- package/dist/sdk/index.js +4 -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/read-output/continuation.d.ts +11 -0
- package/dist/sdk/read-output/continuation.js +132 -0
- package/dist/sdk/read-output-budget.d.ts +1 -1
- package/dist/sdk/read-output-budget.js +14 -10
- package/dist/sdk/read-output-contracts.d.ts +66 -2
- package/dist/sdk/read-output-contracts.js +185 -19
- package/dist/sdk/read-output-rows.d.ts +2 -0
- package/dist/sdk/read-output-rows.js +15 -2
- package/dist/sdk/runtime-input.js +4 -2
- package/dist/sdk/runtime.d.ts +2 -5
- package/dist/sdk/runtime.js +3 -2
- package/docs/ASSURANCE.md +59 -2
- package/docs/COMMANDS.md +8 -2
- package/docs/READ_OUTPUT_CONTRACTS.md +55 -8
- package/docs/RELEASING.md +54 -11
- package/docs/SDK_CONTEXT_INTEGRITY.md +94 -4
- package/docs/SDK_CONTEXT_TRUTH_CONTRACTS.md +13 -5
- package/marketplace.json +2 -2
- package/package.json +3 -3
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- 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/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- 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/sdk/public-surface.json +1241 -180
- package/dist/cli-bundle/chunks/chunk-BBOFSVAK.js +0 -197
- package/dist/cli-bundle/chunks/chunk-YAMTJL6Y.js +0 -34
- package/dist/cli-bundle/chunks/chunk-YSVSMJ2B.js +0 -2
- package/dist/cli-bundle/chunks/register-mutation-E27WCLSZ.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-4R6I7CPY.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-F43TT2QQ.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-KYUQGTSB.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-LZ4MV3RH.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-PGXJQLCT.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-Q4YY3XNF.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QK753U3U.js +0 -46
- package/dist/cli-bundle/focused-chunks/chunk-QUMB2J27.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-SM7MTG27.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-ZM6TZVHC.js +0 -2
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/read-output/continuation
|
|
3
|
+
*
|
|
4
|
+
* Encodes, validates, and applies stable continuations for declared read-output
|
|
5
|
+
* row collections while keeping cursor mechanics separate from dimension
|
|
6
|
+
* resolution and budget policy.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
!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]="8e523bbc-5745-514e-a1d8-a6ad6ece001a")}catch(e){}}();
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
12
|
+
import { PmCliError } from "../../core/shared/errors.js";
|
|
13
|
+
import { resolveReadOutputSurface } from "../read-output-contracts.js";
|
|
14
|
+
import { readOutputRowCollections, sliceReadOutputRowCollection, } from "../read-output-rows.js";
|
|
15
|
+
const MAX_READ_OUTPUT_CURSOR_LENGTH = 4096;
|
|
16
|
+
function isRecord(value) {
|
|
17
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
18
|
+
}
|
|
19
|
+
/** Fingerprint stable row identities without including volatile observation fields. */
|
|
20
|
+
export function readOutputCollectionFingerprint(path, value) {
|
|
21
|
+
const identities = Array.isArray(value)
|
|
22
|
+
? value.map((row, index) => {
|
|
23
|
+
if (!isRecord(row))
|
|
24
|
+
return `index:${String(index)}`;
|
|
25
|
+
for (const key of [
|
|
26
|
+
"id",
|
|
27
|
+
"assertion_id",
|
|
28
|
+
"measurement_id",
|
|
29
|
+
"event_id",
|
|
30
|
+
]) {
|
|
31
|
+
const candidate = row[key];
|
|
32
|
+
if (typeof candidate === "string" && candidate.length > 0) {
|
|
33
|
+
return `${key}:${candidate}`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return `index:${String(index)}`;
|
|
37
|
+
})
|
|
38
|
+
: Object.keys(value);
|
|
39
|
+
return createHash("sha256")
|
|
40
|
+
.update(JSON.stringify({ path, identities }))
|
|
41
|
+
.digest("base64url")
|
|
42
|
+
.slice(0, 16);
|
|
43
|
+
}
|
|
44
|
+
/** Encode one stable declared-row continuation for CLI, SDK, and MCP callers. */
|
|
45
|
+
export function encodeReadOutputContinuationCursor(cursor) {
|
|
46
|
+
return Buffer.from(JSON.stringify({
|
|
47
|
+
v: 1,
|
|
48
|
+
c: cursor.command,
|
|
49
|
+
p: cursor.path,
|
|
50
|
+
o: cursor.offset,
|
|
51
|
+
n: cursor.total_rows,
|
|
52
|
+
f: cursor.fingerprint,
|
|
53
|
+
}), "utf8").toString("base64url");
|
|
54
|
+
}
|
|
55
|
+
/** Decode and validate one universal declared-row continuation cursor. */
|
|
56
|
+
export function decodeReadOutputContinuationCursor(raw) {
|
|
57
|
+
if (raw.length > MAX_READ_OUTPUT_CURSOR_LENGTH) {
|
|
58
|
+
throw new PmCliError("The read-output continuation cursor is malformed or unsupported.", EXIT_CODE.USAGE, { code: "read_output_cursor_invalid" });
|
|
59
|
+
}
|
|
60
|
+
let candidate;
|
|
61
|
+
try {
|
|
62
|
+
candidate = JSON.parse(Buffer.from(raw, "base64url").toString("utf8"));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
candidate = null;
|
|
66
|
+
}
|
|
67
|
+
if (!isRecord(candidate) ||
|
|
68
|
+
candidate.v !== 1 ||
|
|
69
|
+
resolveReadOutputSurface(String(candidate.c ?? "")) !== candidate.c ||
|
|
70
|
+
typeof candidate.p !== "string" ||
|
|
71
|
+
candidate.p.length === 0 ||
|
|
72
|
+
!Number.isSafeInteger(candidate.o) ||
|
|
73
|
+
candidate.o < 0 ||
|
|
74
|
+
!Number.isSafeInteger(candidate.n) ||
|
|
75
|
+
candidate.n < 1 ||
|
|
76
|
+
typeof candidate.f !== "string" ||
|
|
77
|
+
candidate.f.length === 0) {
|
|
78
|
+
throw new PmCliError("The read-output continuation cursor is malformed or unsupported.", EXIT_CODE.USAGE, { code: "read_output_cursor_invalid" });
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
version: 1,
|
|
82
|
+
command: candidate.c,
|
|
83
|
+
path: candidate.p,
|
|
84
|
+
offset: candidate.o,
|
|
85
|
+
total_rows: candidate.n,
|
|
86
|
+
fingerprint: candidate.f,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** Place every non-passing assurance assertion before passing evidence. */
|
|
90
|
+
export function prioritizeAssuranceAssertions(result) {
|
|
91
|
+
if (!Array.isArray(result.assertions))
|
|
92
|
+
return result;
|
|
93
|
+
const priority = (row) => {
|
|
94
|
+
if (!isRecord(row) || row.verdict === "pass")
|
|
95
|
+
return 4;
|
|
96
|
+
if (row.verdict === "retired")
|
|
97
|
+
return 3;
|
|
98
|
+
return row.enforcement === "block" ? 0 : row.enforcement === "warn" ? 1 : 2;
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
...result,
|
|
102
|
+
assertions: result.assertions
|
|
103
|
+
.map((row, index) => ({ row, index }))
|
|
104
|
+
.sort((left, right) => priority(left.row) - priority(right.row) || left.index - right.index)
|
|
105
|
+
.map(({ row }) => row),
|
|
106
|
+
budget_retention_policy: "verdict_priority",
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** Validate and apply a continuation suffix to its declared row collection. */
|
|
110
|
+
export function applyReadOutputContinuation(result, command, cursor) {
|
|
111
|
+
if (!cursor)
|
|
112
|
+
return result;
|
|
113
|
+
if (cursor.command !== command) {
|
|
114
|
+
throw new PmCliError(`The read-output cursor belongs to ${cursor.command}, not ${command}.`, EXIT_CODE.USAGE, { code: "read_output_cursor_command_mismatch" });
|
|
115
|
+
}
|
|
116
|
+
const collection = readOutputRowCollections(result).find((entry) => entry.path === cursor.path);
|
|
117
|
+
const totalRows = collection
|
|
118
|
+
? Array.isArray(collection.value)
|
|
119
|
+
? collection.value.length
|
|
120
|
+
: Object.keys(collection.value).length
|
|
121
|
+
: 0;
|
|
122
|
+
if (!collection ||
|
|
123
|
+
totalRows !== cursor.total_rows ||
|
|
124
|
+
cursor.offset > totalRows ||
|
|
125
|
+
readOutputCollectionFingerprint(cursor.path, collection.value) !==
|
|
126
|
+
cursor.fingerprint) {
|
|
127
|
+
throw new PmCliError("The read-output continuation no longer matches the declared row collection; restart the bounded read.", EXIT_CODE.USAGE, { code: "read_output_cursor_stale" });
|
|
128
|
+
}
|
|
129
|
+
return sliceReadOutputRowCollection(result, cursor.path, cursor.offset);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=continuation.js.map
|
|
132
|
+
//# debugId=8e523bbc-5745-514e-a1d8-a6ad6ece001a
|
|
@@ -10,4 +10,4 @@ export declare function estimateReadOutputTokens(result: unknown): number;
|
|
|
10
10
|
/** Update a receipt to the fixed-point estimate of the result containing it. */
|
|
11
11
|
export declare function updateReadOutputReceiptEstimate(result: Record<string, unknown>, receipt: PmReadOutputReceipt): void;
|
|
12
12
|
/** Compact strings and rows in place, then return the final exact estimate. */
|
|
13
|
-
export declare function compactReadOutputToBudget(result: Record<string, unknown>, receipt: PmReadOutputReceipt, budget: number): Record<string, unknown>;
|
|
13
|
+
export declare function compactReadOutputToBudget(result: Record<string, unknown>, receipt: PmReadOutputReceipt, budget: number, minimumRowsByPath?: ReadonlyMap<string, number>): Record<string, unknown>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="737ac274-c165-5d1a-8b8e-cb5d57a81c46")}catch(e){}}();
|
|
3
3
|
import { countReadOutputRows, readOutputBudgetCollections, } from "./read-output-rows.js";
|
|
4
4
|
const MAX_ESTIMATE_ITERATIONS = 8;
|
|
5
5
|
const MAX_COMPACTION_ITERATIONS = 64;
|
|
@@ -42,15 +42,18 @@ export function updateReadOutputReceiptEstimate(result, receipt) {
|
|
|
42
42
|
receipt.estimated_tokens = estimate;
|
|
43
43
|
}
|
|
44
44
|
/** Reduce the largest row collection until the budget fits or no rows can move. */
|
|
45
|
-
function compactRowsToBudget(result, receipt, budget) {
|
|
45
|
+
function compactRowsToBudget(result, receipt, budget, minimumRowsByPath) {
|
|
46
46
|
for (let iteration = 0; iteration < MAX_COMPACTION_ITERATIONS; iteration += 1) {
|
|
47
47
|
updateReadOutputReceiptEstimate(result, receipt);
|
|
48
48
|
if (receipt.estimated_tokens <= budget)
|
|
49
49
|
return;
|
|
50
50
|
const candidate = readOutputBudgetCollections(result)
|
|
51
|
-
.filter((collection) =>
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
.filter((collection) => {
|
|
52
|
+
const length = Array.isArray(collection.value)
|
|
53
|
+
? collection.value.length
|
|
54
|
+
: Object.keys(collection.value).length;
|
|
55
|
+
return (length > Math.max(1, minimumRowsByPath.get(collection.path) ?? 0));
|
|
56
|
+
})
|
|
54
57
|
.map((collection) => ({
|
|
55
58
|
collection,
|
|
56
59
|
length: Array.isArray(collection.value)
|
|
@@ -61,12 +64,13 @@ function compactRowsToBudget(result, receipt, budget) {
|
|
|
61
64
|
left.collection.path.localeCompare(right.collection.path))[0]?.collection;
|
|
62
65
|
if (!candidate)
|
|
63
66
|
return;
|
|
67
|
+
const minimumRows = Math.max(1, minimumRowsByPath.get(candidate.path) ?? 0);
|
|
64
68
|
if (Array.isArray(candidate.value)) {
|
|
65
|
-
candidate.value.splice(-Math.max(1, Math.ceil(candidate.value.length / 2)));
|
|
69
|
+
candidate.value.splice(-Math.min(candidate.value.length - minimumRows, Math.max(1, Math.ceil(candidate.value.length / 2))));
|
|
66
70
|
}
|
|
67
71
|
else {
|
|
68
72
|
const keys = Object.keys(candidate.value);
|
|
69
|
-
for (const key of keys.slice(-Math.max(1, Math.ceil(keys.length / 2)))) {
|
|
73
|
+
for (const key of keys.slice(-Math.min(keys.length - minimumRows, Math.max(1, Math.ceil(keys.length / 2))))) {
|
|
70
74
|
delete candidate.value[key];
|
|
71
75
|
}
|
|
72
76
|
}
|
|
@@ -82,14 +86,14 @@ function compactRowsToBudget(result, receipt, budget) {
|
|
|
82
86
|
}
|
|
83
87
|
}
|
|
84
88
|
/** Compact strings and rows in place, then return the final exact estimate. */
|
|
85
|
-
export function compactReadOutputToBudget(result, receipt, budget) {
|
|
89
|
+
export function compactReadOutputToBudget(result, receipt, budget, minimumRowsByPath = new Map()) {
|
|
86
90
|
const stringCompactionState = { compacted: false };
|
|
87
91
|
const compacted = compactStrings(result, stringCompactionState);
|
|
88
92
|
receipt.strings_compacted = stringCompactionState.compacted;
|
|
89
93
|
compacted.read_output = receipt;
|
|
90
|
-
compactRowsToBudget(compacted, receipt, budget);
|
|
94
|
+
compactRowsToBudget(compacted, receipt, budget, minimumRowsByPath);
|
|
91
95
|
updateReadOutputReceiptEstimate(compacted, receipt);
|
|
92
96
|
return compacted;
|
|
93
97
|
}
|
|
94
98
|
//# sourceMappingURL=read-output-budget.js.map
|
|
95
|
-
//# debugId=
|
|
99
|
+
//# debugId=737ac274-c165-5d1a-8b8e-cb5d57a81c46
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, } from "./read-output/continuation.js";
|
|
1
2
|
import { type PmReadOutputSessionReceipt, type PmReadOutputSessionState } from "./read-output-session.js";
|
|
2
3
|
/** Stable output dimensions shared by every read surface. */
|
|
3
4
|
export declare const PM_READ_OUTPUT_DIMENSIONS: readonly ["include", "amount", "cost", "encoding"];
|
|
@@ -19,6 +20,8 @@ export interface PmReadOutputOptions {
|
|
|
19
20
|
outputFormat?: "json" | "toon";
|
|
20
21
|
/** Caller-carried cross-call budget and served-fact state. */
|
|
21
22
|
outputSession?: string | PmReadOutputSessionState;
|
|
23
|
+
/** Opaque continuation returned after a budget-compacted declared row path. */
|
|
24
|
+
outputCursor?: string;
|
|
22
25
|
/** Include row selector and encoding discovery metadata. */
|
|
23
26
|
outputRowContract?: boolean;
|
|
24
27
|
}
|
|
@@ -54,6 +57,8 @@ export interface PmReadOutputSurfaceContract {
|
|
|
54
57
|
dimensions: Record<PmReadOutputDimension, PmReadOutputDimensionContract>;
|
|
55
58
|
/** Deterministic precedence from strongest caller declaration to fallback. */
|
|
56
59
|
precedence: readonly ["canonical", "legacy", "intent", "default"];
|
|
60
|
+
/** Stable policy used before budget compaction selects retained rows. */
|
|
61
|
+
budget_retention_policy: "ordered_prefix" | "verdict_priority";
|
|
57
62
|
}
|
|
58
63
|
/** Source that selected an effective output dimension. */
|
|
59
64
|
export type PmReadOutputDimensionSource = "canonical" | "legacy" | "intent" | "default";
|
|
@@ -128,8 +133,63 @@ export interface PmReadOutputTruncationDisclosure {
|
|
|
128
133
|
overridden_dimensions: PmReadOutputDimension[];
|
|
129
134
|
/** Declared or nested collection paths reduced by budget degradation. */
|
|
130
135
|
compacted_row_paths: string[];
|
|
136
|
+
/** Whether next_cursor was moved back to the last row that survived compaction. */
|
|
137
|
+
continuation_cursor_rebased: boolean;
|
|
138
|
+
/** Whether at least one declared row collection can be resumed within the budget. */
|
|
139
|
+
continuation_available: boolean;
|
|
140
|
+
/** Maximum next-page useful-result budget relative to the current budget. */
|
|
141
|
+
recovery_budget_multiplier: 1;
|
|
142
|
+
/** Bounded continuation instructions for every compacted declared row path. */
|
|
143
|
+
continuations: PmReadOutputContinuation[];
|
|
131
144
|
/** Executable recovery instruction for retrieving the complete result. */
|
|
132
145
|
restore_with: string;
|
|
146
|
+
/** Transport-specific machine recovery options. */
|
|
147
|
+
recovery: {
|
|
148
|
+
/** Opaque value supplied through each declared transport binding. */
|
|
149
|
+
cursor: string;
|
|
150
|
+
/** CLI option accepting cursor. */
|
|
151
|
+
cli: "--output-cursor";
|
|
152
|
+
/** SDK option field accepting cursor. */
|
|
153
|
+
sdk: "outputCursor";
|
|
154
|
+
/** MCP input field accepting cursor. */
|
|
155
|
+
mcp: "outputCursor";
|
|
156
|
+
} | {
|
|
157
|
+
cli: string;
|
|
158
|
+
sdk: {
|
|
159
|
+
outputBudget: number;
|
|
160
|
+
};
|
|
161
|
+
mcp: {
|
|
162
|
+
outputBudget: number;
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/** One resumable declared-row collection withheld by budget compaction. */
|
|
167
|
+
export interface PmReadOutputContinuation {
|
|
168
|
+
/** Dot-delimited declared row path being resumed. */
|
|
169
|
+
path: string;
|
|
170
|
+
/** Opaque cursor accepted by CLI, SDK, and MCP outputCursor inputs. */
|
|
171
|
+
cursor: string;
|
|
172
|
+
/** Rows retained from this path in the current response. */
|
|
173
|
+
retained_rows: number;
|
|
174
|
+
/** Rows remaining after the current response. */
|
|
175
|
+
remaining_rows: number;
|
|
176
|
+
/** Total rows in the stable collection snapshot. */
|
|
177
|
+
total_rows: number;
|
|
178
|
+
}
|
|
179
|
+
/** Versioned, command-bound cursor payload for one stable declared row collection. */
|
|
180
|
+
export interface PmReadOutputCursorEnvelope {
|
|
181
|
+
/** Serialized cursor format version. */
|
|
182
|
+
version: 1;
|
|
183
|
+
/** Canonical read surface that produced the cursor. */
|
|
184
|
+
command: PmReadOutputSurface;
|
|
185
|
+
/** Dot-delimited declared row path being continued. */
|
|
186
|
+
path: string;
|
|
187
|
+
/** Zero-based index of the first withheld row. */
|
|
188
|
+
offset: number;
|
|
189
|
+
/** Stable pre-projection denominator for the row collection. */
|
|
190
|
+
total_rows: number;
|
|
191
|
+
/** Stable identity fingerprint used to refuse stale continuation. */
|
|
192
|
+
fingerprint: string;
|
|
133
193
|
}
|
|
134
194
|
/** Result returned when the requested cost ceiling cannot fit useful content. */
|
|
135
195
|
export interface PmReadOutputBudgetExceeded {
|
|
@@ -141,6 +201,10 @@ export interface PmReadOutputBudgetExceeded {
|
|
|
141
201
|
reason: "requested_budget_infeasible";
|
|
142
202
|
/** Human- and agent-readable recovery instruction. */
|
|
143
203
|
restore_with: string;
|
|
204
|
+
/** Transport-specific machine recovery options. */
|
|
205
|
+
recovery: {
|
|
206
|
+
outputBudget: "unbounded";
|
|
207
|
+
};
|
|
144
208
|
};
|
|
145
209
|
/** Exact receipt for the bounded omission envelope. */
|
|
146
210
|
read_output: PmReadOutputReceipt;
|
|
@@ -154,11 +218,11 @@ export type PmReadOutputResult<Result> = (Result & {
|
|
|
154
218
|
read_session?: PmReadOutputSessionReceipt;
|
|
155
219
|
});
|
|
156
220
|
/** Select the omission-aware result type when an option shape can request a budget. */
|
|
157
|
-
export type PmReadOutputResultFor<Result, Options> = "outputBudget" extends keyof Options ? PmReadOutputResult<Result> : "outputSession" extends keyof Options ? PmReadOutputResult<Result> : Result;
|
|
221
|
+
export type PmReadOutputResultFor<Result, Options> = "outputBudget" extends keyof Options ? PmReadOutputResult<Result> : "outputSession" extends keyof Options ? PmReadOutputResult<Result> : "outputCursor" extends keyof Options ? PmReadOutputResult<Result> : Result;
|
|
158
222
|
/** Canonical CLI flags that opt a read invocation into universal output shaping. */
|
|
159
223
|
export declare const PM_READ_OUTPUT_OPTION_FLAGS: readonly string[];
|
|
160
224
|
/** Canonical control that composes the four per-call dimensions across reads. */
|
|
161
|
-
export declare const PM_READ_OUTPUT_COMPOSITION_OPTION_FLAGS: readonly ["--output-session", "--output-row-contract"];
|
|
225
|
+
export declare const PM_READ_OUTPUT_COMPOSITION_OPTION_FLAGS: readonly ["--output-session", "--output-cursor", "--output-row-contract"];
|
|
162
226
|
/** Universal output contract for every built-in read surface. */
|
|
163
227
|
export declare const PM_READ_OUTPUT_SURFACE_CONTRACTS: readonly PmReadOutputSurfaceContract[];
|
|
164
228
|
/** Resolve a command or list/context alias to its canonical read-output surface. */
|
|
@@ -5,13 +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]="e9621264-0180-53cf-862f-b59640b971da")}catch(e){}}();
|
|
9
9
|
import { EXIT_CODE } from "../core/shared/constants.js";
|
|
10
10
|
import { PmCliError } from "../core/shared/errors.js";
|
|
11
11
|
import { compactReadOutputToBudget, estimateReadOutputTokens, updateReadOutputReceiptEstimate, } from "./read-output-budget.js";
|
|
12
12
|
import { resolvePmCommandOutputBudget } from "./cli-contracts/agent-output-contracts.js";
|
|
13
|
-
import { boundReadOutputRows, countReadOutputRows, mapReadOutputRows, readOutputRowPaths, } from "./read-output-rows.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";
|
|
14
16
|
import { applyReadOutputSessionReferences, attachReadOutputSessionReceipt, parseReadOutputSession, readOutputSessionRemainingTokens, } from "./read-output-session.js";
|
|
17
|
+
import { decodeQueryCursorEnvelope, encodeQueryCursor } from "./pagination.js";
|
|
15
18
|
/** Stable output dimensions shared by every read surface. */
|
|
16
19
|
export const PM_READ_OUTPUT_DIMENSIONS = [
|
|
17
20
|
"include",
|
|
@@ -61,6 +64,7 @@ export const PM_READ_OUTPUT_OPTION_FLAGS = Object.freeze(PM_READ_OUTPUT_DIMENSIO
|
|
|
61
64
|
/** Canonical control that composes the four per-call dimensions across reads. */
|
|
62
65
|
export const PM_READ_OUTPUT_COMPOSITION_OPTION_FLAGS = Object.freeze([
|
|
63
66
|
"--output-session",
|
|
67
|
+
"--output-cursor",
|
|
64
68
|
"--output-row-contract",
|
|
65
69
|
]);
|
|
66
70
|
const LEGACY_FLAGS_BY_COMMAND = {
|
|
@@ -194,6 +198,7 @@ function buildSurfaceContract(command) {
|
|
|
194
198
|
command,
|
|
195
199
|
dimensions,
|
|
196
200
|
precedence: READ_OUTPUT_PRECEDENCE,
|
|
201
|
+
budget_retention_policy: command === "assurance" ? "verdict_priority" : "ordered_prefix",
|
|
197
202
|
});
|
|
198
203
|
}
|
|
199
204
|
/** Universal output contract for every built-in read surface. */
|
|
@@ -232,6 +237,8 @@ const CANONICAL_OPTION_KEYS = [
|
|
|
232
237
|
"output_format",
|
|
233
238
|
"outputSession",
|
|
234
239
|
"output_session",
|
|
240
|
+
"outputCursor",
|
|
241
|
+
"output_cursor",
|
|
235
242
|
"outputRowContract",
|
|
236
243
|
"output_row_contract",
|
|
237
244
|
];
|
|
@@ -273,6 +280,11 @@ const READ_OUTPUT_VALUE_VALIDATORS = [
|
|
|
273
280
|
},
|
|
274
281
|
message: "--output-session must be a valid session-state object.",
|
|
275
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
|
+
},
|
|
276
288
|
];
|
|
277
289
|
/** Reject malformed or mutation-scoped universal output controls before command execution. */
|
|
278
290
|
export function validateReadOutputOptions(command, options) {
|
|
@@ -486,6 +498,10 @@ export function resolveReadOutputDimensions(command, options) {
|
|
|
486
498
|
});
|
|
487
499
|
const encoding = resolveEncodingValue(options.outputFormat ?? options.output_format, legacyByDimension.encoding);
|
|
488
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" ||
|
|
503
|
+
legacyByDimension.amount?.flag === "--no-truncate" ||
|
|
504
|
+
legacyByDimension.include?.flag === "--full";
|
|
489
505
|
const budget = resolvePmCommandOutputBudget(command, {
|
|
490
506
|
generateFallback: true,
|
|
491
507
|
});
|
|
@@ -496,10 +512,13 @@ export function resolveReadOutputDimensions(command, options) {
|
|
|
496
512
|
command: normalizedCommand,
|
|
497
513
|
include: resolveIncludeValue(options.outputInclude ?? options.output_include, legacyByDimension.include),
|
|
498
514
|
amount: resolveAmountValue(options.outputLimit ?? options.output_limit, legacyByDimension.amount),
|
|
499
|
-
cost: explicitCost ??
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
515
|
+
cost: explicitCost ??
|
|
516
|
+
(completeResultIntent
|
|
517
|
+
? { source: "intent", value: "unbounded" }
|
|
518
|
+
: {
|
|
519
|
+
source: "default",
|
|
520
|
+
value: budget.default_max_estimated_tokens_by_format[resolvedOutputFormat],
|
|
521
|
+
}),
|
|
503
522
|
encoding,
|
|
504
523
|
legacy_aliases_used: legacyAliasesUsed,
|
|
505
524
|
migration_hints: migrationHints,
|
|
@@ -513,6 +532,8 @@ const ENVELOPE_KEYS = new Set([
|
|
|
513
532
|
"applied_bound",
|
|
514
533
|
"applied_limit",
|
|
515
534
|
"completeness",
|
|
535
|
+
"continuation_kind",
|
|
536
|
+
"continuation_path",
|
|
516
537
|
"continuation_contract",
|
|
517
538
|
"count",
|
|
518
539
|
"filters",
|
|
@@ -521,6 +542,7 @@ const ENVELOPE_KEYS = new Set([
|
|
|
521
542
|
"now",
|
|
522
543
|
"omission_receipt",
|
|
523
544
|
"projection",
|
|
545
|
+
"budget_retention_policy",
|
|
524
546
|
"row_contract",
|
|
525
547
|
"sorting",
|
|
526
548
|
"total",
|
|
@@ -715,11 +737,15 @@ export function stabilizeReadOutputReceiptEstimates(result, options) {
|
|
|
715
737
|
return attachReadOutputSessionContracts(result, session, receipt);
|
|
716
738
|
}
|
|
717
739
|
/** Apply field, amount, and repeat projections to every declared row path. */
|
|
718
|
-
function projectReadOutputRows(result, resolved, session) {
|
|
740
|
+
function projectReadOutputRows(result, resolved, session, cursor) {
|
|
719
741
|
let projected = { ...result };
|
|
720
742
|
if (resolved.include?.source === "canonical") {
|
|
721
743
|
projected = applyIncludeProjection(resolved.command, projected, resolved.include.value);
|
|
722
744
|
}
|
|
745
|
+
if (resolved.command === "assurance") {
|
|
746
|
+
projected = prioritizeAssuranceAssertions(projected);
|
|
747
|
+
}
|
|
748
|
+
projected = applyReadOutputContinuation(projected, resolved.command, cursor);
|
|
723
749
|
if (resolved.amount?.source === "canonical") {
|
|
724
750
|
projected = applyAmountBound(projected, resolved.amount.value);
|
|
725
751
|
}
|
|
@@ -774,7 +800,8 @@ function omitReadOutputForBudget(resolved, requested, session, bindingBudget, om
|
|
|
774
800
|
output_budget_exceeded: {
|
|
775
801
|
omitted_result: true,
|
|
776
802
|
reason: "requested_budget_infeasible",
|
|
777
|
-
restore_with: "
|
|
803
|
+
restore_with: "Unbounded",
|
|
804
|
+
recovery: { outputBudget: "unbounded" },
|
|
778
805
|
},
|
|
779
806
|
read_output: minimalReceipt,
|
|
780
807
|
};
|
|
@@ -796,7 +823,7 @@ function canReturnReadOutputUnchanged(resolved, requested, session, result) {
|
|
|
796
823
|
return false;
|
|
797
824
|
const canonicalRequestedCount = requested.filter((dimension) => resolved[dimension]?.source === "canonical").length;
|
|
798
825
|
if (resolved.cost?.value === "unbounded") {
|
|
799
|
-
return canonicalRequestedCount === 1;
|
|
826
|
+
return (canonicalRequestedCount === (resolved.cost.source === "canonical" ? 1 : 0));
|
|
800
827
|
}
|
|
801
828
|
if (resolved.cost?.source === "legacy" && canonicalRequestedCount === 0) {
|
|
802
829
|
return true;
|
|
@@ -813,31 +840,174 @@ function canReturnReadOutputUnchanged(resolved, requested, session, result) {
|
|
|
813
840
|
* without this an explicitly requested unbounded read is silently downgraded and
|
|
814
841
|
* the only working recovery is never named.
|
|
815
842
|
*/
|
|
816
|
-
function attachReadOutputTruncationDisclosure(projected, resolved, receipt, bindingBudget) {
|
|
843
|
+
function attachReadOutputTruncationDisclosure(projected, resolved, receipt, bindingBudget, continuationCursorRebased, collectionsBeforeBudget) {
|
|
817
844
|
if (!receipt.rows_compacted)
|
|
818
845
|
return;
|
|
819
846
|
const overridden = resolved.amount?.value === "unbounded" ? ["amount"] : [];
|
|
847
|
+
const afterByPath = new Map(readOutputRowCollections(projected).map((collection) => [
|
|
848
|
+
collection.path,
|
|
849
|
+
Array.isArray(collection.value)
|
|
850
|
+
? collection.value.length
|
|
851
|
+
: Object.keys(collection.value).length,
|
|
852
|
+
]));
|
|
853
|
+
const continuations = [...collectionsBeforeBudget.entries()].flatMap(([path, before]) => {
|
|
854
|
+
// Budget compaction preserves every declared collection and shortens its
|
|
855
|
+
// contents, so each pre-budget path has a post-budget cardinality.
|
|
856
|
+
const retainedRows = afterByPath.get(path);
|
|
857
|
+
if (retainedRows >= before.rows)
|
|
858
|
+
return [];
|
|
859
|
+
const offset = before.baseOffset + retainedRows;
|
|
860
|
+
return [
|
|
861
|
+
{
|
|
862
|
+
path,
|
|
863
|
+
cursor: encodeReadOutputContinuationCursor({
|
|
864
|
+
command: resolved.command,
|
|
865
|
+
path,
|
|
866
|
+
offset,
|
|
867
|
+
total_rows: before.totalRows,
|
|
868
|
+
fingerprint: before.fingerprint,
|
|
869
|
+
}),
|
|
870
|
+
retained_rows: retainedRows,
|
|
871
|
+
remaining_rows: before.totalRows - offset,
|
|
872
|
+
total_rows: before.totalRows,
|
|
873
|
+
},
|
|
874
|
+
];
|
|
875
|
+
});
|
|
876
|
+
const primary = continuations[0];
|
|
877
|
+
if (primary && typeof projected.next_cursor !== "string") {
|
|
878
|
+
projected.next_cursor = primary.cursor;
|
|
879
|
+
}
|
|
880
|
+
projected.continuation_kind = continuationCursorRebased
|
|
881
|
+
? "producer_cursor"
|
|
882
|
+
: primary
|
|
883
|
+
? "output_cursor"
|
|
884
|
+
: "none";
|
|
820
885
|
projected.output_budget_truncation = {
|
|
821
886
|
reason: "output_budget_reached",
|
|
822
887
|
budget_source: bindingBudget.source,
|
|
823
888
|
budget_tokens: bindingBudget.tokens,
|
|
824
889
|
overridden_dimensions: overridden,
|
|
825
890
|
compacted_row_paths: receipt.compacted_row_paths,
|
|
826
|
-
|
|
891
|
+
continuation_cursor_rebased: continuationCursorRebased,
|
|
892
|
+
continuation_available: continuations.length > 0,
|
|
893
|
+
recovery_budget_multiplier: 1,
|
|
894
|
+
continuations,
|
|
895
|
+
restore_with: primary
|
|
896
|
+
? "Use recovery binding."
|
|
897
|
+
: "Increase --output-budget because no declared row collection can be continued.",
|
|
898
|
+
recovery: primary
|
|
899
|
+
? {
|
|
900
|
+
cursor: primary.cursor,
|
|
901
|
+
cli: "--output-cursor",
|
|
902
|
+
sdk: "outputCursor",
|
|
903
|
+
mcp: "outputCursor",
|
|
904
|
+
}
|
|
905
|
+
: {
|
|
906
|
+
cli: "--output-budget 1200",
|
|
907
|
+
sdk: { outputBudget: 1200 },
|
|
908
|
+
mcp: { outputBudget: 1200 },
|
|
909
|
+
},
|
|
827
910
|
};
|
|
828
911
|
}
|
|
912
|
+
/** Rebase a producer cursor when budget compaction removes rows from its page. */
|
|
913
|
+
function rebaseBudgetCompactedCursor(projected, originalItemCount, cursorSource, cursorContinuesExistingPage) {
|
|
914
|
+
if (typeof cursorSource !== "string" || !Array.isArray(projected.items)) {
|
|
915
|
+
return false;
|
|
916
|
+
}
|
|
917
|
+
const retainedCount = projected.items.length;
|
|
918
|
+
if (retainedCount === 0 || retainedCount >= originalItemCount) {
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
let cursor;
|
|
922
|
+
try {
|
|
923
|
+
cursor = decodeQueryCursorEnvelope(cursorSource);
|
|
924
|
+
}
|
|
925
|
+
catch {
|
|
926
|
+
return false;
|
|
927
|
+
}
|
|
928
|
+
const sourceIndex = cursor.after_index;
|
|
929
|
+
if (sourceIndex === undefined)
|
|
930
|
+
return false;
|
|
931
|
+
const last = projected.items.at(-1);
|
|
932
|
+
if (Object.prototype.toString.call(last) !== "[object Object]") {
|
|
933
|
+
return false;
|
|
934
|
+
}
|
|
935
|
+
const lastId = Reflect.get(last, "id");
|
|
936
|
+
if (typeof lastId !== "string" || lastId.length === 0)
|
|
937
|
+
return false;
|
|
938
|
+
const afterIndex = cursorContinuesExistingPage
|
|
939
|
+
? sourceIndex - (originalItemCount - retainedCount)
|
|
940
|
+
: sourceIndex + retainedCount;
|
|
941
|
+
if (afterIndex < 0)
|
|
942
|
+
return false;
|
|
943
|
+
projected.next_cursor = encodeQueryCursor(cursor.fingerprint, lastId, afterIndex, cursor.snapshot);
|
|
944
|
+
if (typeof projected.applied_limit === "number") {
|
|
945
|
+
projected.applied_limit = retainedCount;
|
|
946
|
+
}
|
|
947
|
+
return true;
|
|
948
|
+
}
|
|
949
|
+
function captureReadOutputContinuationState(projected, cursor, options) {
|
|
950
|
+
const collectionsBeforeBudget = new Map(readOutputRowCollections(projected).map((collection) => {
|
|
951
|
+
const rows = Array.isArray(collection.value)
|
|
952
|
+
? collection.value.length
|
|
953
|
+
: Object.keys(collection.value).length;
|
|
954
|
+
const continued = cursor?.path === collection.path;
|
|
955
|
+
return [
|
|
956
|
+
collection.path,
|
|
957
|
+
{
|
|
958
|
+
rows,
|
|
959
|
+
totalRows: continued ? cursor.total_rows : rows,
|
|
960
|
+
baseOffset: continued ? cursor.offset : 0,
|
|
961
|
+
fingerprint: continued
|
|
962
|
+
? cursor.fingerprint
|
|
963
|
+
: readOutputCollectionFingerprint(collection.path, collection.value),
|
|
964
|
+
},
|
|
965
|
+
];
|
|
966
|
+
}));
|
|
967
|
+
const cursorContinuesExistingPage = typeof projected.next_cursor === "string";
|
|
968
|
+
return {
|
|
969
|
+
collectionsBeforeBudget,
|
|
970
|
+
originalItemCount: Array.isArray(projected.items)
|
|
971
|
+
? projected.items.length
|
|
972
|
+
: 0,
|
|
973
|
+
cursorContinuesExistingPage,
|
|
974
|
+
cursorSource: cursorContinuesExistingPage
|
|
975
|
+
? projected.next_cursor
|
|
976
|
+
: options.after,
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
function compactReadOutputProjection(projected, resolved, receipt, bindingBudget, session, continuationState) {
|
|
980
|
+
const assuranceMinimumRows = resolved.command === "assurance" && Array.isArray(projected.assertions)
|
|
981
|
+
? projected.assertions.filter((row) => isRecord(row) && row.verdict !== "pass").length
|
|
982
|
+
: 0;
|
|
983
|
+
let compacted = compactReadOutputToBudget(projected, receipt, bindingBudget.tokens, assuranceMinimumRows > 0
|
|
984
|
+
? new Map([["assertions", assuranceMinimumRows]])
|
|
985
|
+
: new Map());
|
|
986
|
+
const continuationCursorRebased = rebaseBudgetCompactedCursor(compacted, continuationState.originalItemCount, continuationState.cursorSource, continuationState.cursorContinuesExistingPage);
|
|
987
|
+
attachReadOutputTruncationDisclosure(compacted, resolved, receipt, bindingBudget, continuationCursorRebased, continuationState.collectionsBeforeBudget);
|
|
988
|
+
if (session !== undefined) {
|
|
989
|
+
compacted = attachReadOutputSessionContracts(compacted, session, receipt);
|
|
990
|
+
}
|
|
991
|
+
return compacted;
|
|
992
|
+
}
|
|
829
993
|
/** Apply universal field, row, and token bounds and attach an exact receipt. */
|
|
830
994
|
export function applyReadOutputDimensions(command, options, result) {
|
|
831
995
|
const resolved = resolveReadOutputDimensions(command, options);
|
|
832
996
|
if (!resolved)
|
|
833
997
|
return result;
|
|
834
998
|
const session = parseReadOutputSession(options.outputSession ?? options.output_session);
|
|
999
|
+
const rawCursor = options.outputCursor ?? options.output_cursor;
|
|
1000
|
+
const cursor = typeof rawCursor === "string"
|
|
1001
|
+
? decodeReadOutputContinuationCursor(rawCursor)
|
|
1002
|
+
: undefined;
|
|
835
1003
|
const requested = requestedDimensions(resolved);
|
|
836
|
-
if (
|
|
1004
|
+
if (cursor === undefined &&
|
|
1005
|
+
canReturnReadOutputUnchanged(resolved, requested, session, result)) {
|
|
837
1006
|
return result;
|
|
838
1007
|
}
|
|
839
1008
|
const bindingBudget = resolveBindingReadOutputBudget(resolved, session);
|
|
840
|
-
let projected = projectReadOutputRows(result, resolved, session);
|
|
1009
|
+
let projected = projectReadOutputRows(result, resolved, session, cursor);
|
|
1010
|
+
const continuationState = captureReadOutputContinuationState(projected, cursor, options);
|
|
841
1011
|
const receipt = {
|
|
842
1012
|
contract_version: 1,
|
|
843
1013
|
command: resolved.command,
|
|
@@ -865,11 +1035,7 @@ export function applyReadOutputDimensions(command, options, result) {
|
|
|
865
1035
|
updateReadOutputReceiptEstimate(projected, receipt);
|
|
866
1036
|
if (bindingBudget !== undefined &&
|
|
867
1037
|
receipt.estimated_tokens > bindingBudget.tokens) {
|
|
868
|
-
projected =
|
|
869
|
-
attachReadOutputTruncationDisclosure(projected, resolved, receipt, bindingBudget);
|
|
870
|
-
if (session !== undefined) {
|
|
871
|
-
projected = attachReadOutputSessionContracts(projected, session, receipt);
|
|
872
|
-
}
|
|
1038
|
+
projected = compactReadOutputProjection(projected, resolved, receipt, bindingBudget, session, continuationState);
|
|
873
1039
|
}
|
|
874
1040
|
if (bindingBudget !== undefined &&
|
|
875
1041
|
receipt.estimated_tokens > bindingBudget.tokens) {
|
|
@@ -892,4 +1058,4 @@ export function resolveReadOutputEncoding(command, options) {
|
|
|
892
1058
|
: undefined;
|
|
893
1059
|
}
|
|
894
1060
|
//# sourceMappingURL=read-output-contracts.js.map
|
|
895
|
-
//# debugId=
|
|
1061
|
+
//# debugId=e9621264-0180-53cf-862f-b59640b971da
|
|
@@ -11,6 +11,8 @@ 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. */
|