@unbrained/pm-cli 2026.8.14 → 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 +25 -2
- 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 +3 -2
- package/dist/cli/register-mutation.js +4 -2
- package/dist/cli/register-operations.js +5 -5
- package/dist/cli-bundle/bundle-manifest.json +150 -150
- package/dist/cli-bundle/chunks/{chunk-TXMEUUUY.js → chunk-24GAV7XL.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-TMJ7URWS.js → chunk-AIM6VT2N.js} +9 -9
- package/dist/cli-bundle/chunks/chunk-DSWDLTDR.js +197 -0
- package/dist/cli-bundle/chunks/{chunk-FIW4P64F.js → chunk-J42EGKDK.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-KIEGUBYQ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-SBRKH6OR.js → chunk-KLKYLSDX.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-G5JUB66K.js → chunk-LJHOAVGI.js} +59 -59
- package/dist/cli-bundle/chunks/{chunk-BFALV3YP.js → chunk-MEM2ZS3O.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-QHPCJWEJ.js +35 -0
- package/dist/cli-bundle/chunks/{chunk-XAVMOK6B.js → chunk-WLPDLNEZ.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-T3EHHNNV.js → register-list-query-CT3LFDDN.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-E27WCLSZ.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-3YXZ444E.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-XDNAW5OI.js → chunk-6XKF3PGV.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-7NJ4QYQ2.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-WCVE2NIG.js → chunk-EXZA4257.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ITAUHSO6.js +50 -0
- package/dist/cli-bundle/focused-chunks/{chunk-4DQ2YERC.js → chunk-KLVUMNXJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-K7RWWOAG.js → chunk-KT5XMYSX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-PPFGQDSI.js → chunk-KTKH4IMG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-M67F5AIN.js +8 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KSEDUWVZ.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-LZ4MV3RH.js → chunk-SLKC6QLJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-U65UC4G3.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KFSZ3BP6.js → chunk-WTSER4WJ.js} +6 -6
- package/dist/cli-bundle/focused-chunks/{chunk-YOOI3UZX.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 +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/output/output.d.ts +2 -0
- package/dist/core/output/output.js +3 -2
- 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 +5 -0
- package/dist/sdk/cli-contracts/runtime-contracts.js +23 -7
- 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 +3 -2
- 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 +80 -14
- 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 +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/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 +183 -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/docs/ASSURANCE.md +59 -2
- package/docs/COMMANDS.md +8 -2
- package/docs/READ_OUTPUT_CONTRACTS.md +49 -8
- package/docs/RELEASING.md +42 -5
- package/docs/SDK_CONTEXT_INTEGRITY.md +64 -2
- 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 +1133 -187
- 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-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-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
|
@@ -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]="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
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,8 @@ 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" || legacyByDimension.amount?.flag === "--no-truncate";
|
|
489
503
|
const budget = resolvePmCommandOutputBudget(command, {
|
|
490
504
|
generateFallback: true,
|
|
491
505
|
});
|
|
@@ -496,10 +510,13 @@ export function resolveReadOutputDimensions(command, options) {
|
|
|
496
510
|
command: normalizedCommand,
|
|
497
511
|
include: resolveIncludeValue(options.outputInclude ?? options.output_include, legacyByDimension.include),
|
|
498
512
|
amount: resolveAmountValue(options.outputLimit ?? options.output_limit, legacyByDimension.amount),
|
|
499
|
-
cost: explicitCost ??
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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
|
+
}),
|
|
503
520
|
encoding,
|
|
504
521
|
legacy_aliases_used: legacyAliasesUsed,
|
|
505
522
|
migration_hints: migrationHints,
|
|
@@ -513,6 +530,8 @@ const ENVELOPE_KEYS = new Set([
|
|
|
513
530
|
"applied_bound",
|
|
514
531
|
"applied_limit",
|
|
515
532
|
"completeness",
|
|
533
|
+
"continuation_kind",
|
|
534
|
+
"continuation_path",
|
|
516
535
|
"continuation_contract",
|
|
517
536
|
"count",
|
|
518
537
|
"filters",
|
|
@@ -521,6 +540,7 @@ const ENVELOPE_KEYS = new Set([
|
|
|
521
540
|
"now",
|
|
522
541
|
"omission_receipt",
|
|
523
542
|
"projection",
|
|
543
|
+
"budget_retention_policy",
|
|
524
544
|
"row_contract",
|
|
525
545
|
"sorting",
|
|
526
546
|
"total",
|
|
@@ -715,11 +735,15 @@ export function stabilizeReadOutputReceiptEstimates(result, options) {
|
|
|
715
735
|
return attachReadOutputSessionContracts(result, session, receipt);
|
|
716
736
|
}
|
|
717
737
|
/** Apply field, amount, and repeat projections to every declared row path. */
|
|
718
|
-
function projectReadOutputRows(result, resolved, session) {
|
|
738
|
+
function projectReadOutputRows(result, resolved, session, cursor) {
|
|
719
739
|
let projected = { ...result };
|
|
720
740
|
if (resolved.include?.source === "canonical") {
|
|
721
741
|
projected = applyIncludeProjection(resolved.command, projected, resolved.include.value);
|
|
722
742
|
}
|
|
743
|
+
if (resolved.command === "assurance") {
|
|
744
|
+
projected = prioritizeAssuranceAssertions(projected);
|
|
745
|
+
}
|
|
746
|
+
projected = applyReadOutputContinuation(projected, resolved.command, cursor);
|
|
723
747
|
if (resolved.amount?.source === "canonical") {
|
|
724
748
|
projected = applyAmountBound(projected, resolved.amount.value);
|
|
725
749
|
}
|
|
@@ -774,7 +798,8 @@ function omitReadOutputForBudget(resolved, requested, session, bindingBudget, om
|
|
|
774
798
|
output_budget_exceeded: {
|
|
775
799
|
omitted_result: true,
|
|
776
800
|
reason: "requested_budget_infeasible",
|
|
777
|
-
restore_with: "
|
|
801
|
+
restore_with: "Unbounded",
|
|
802
|
+
recovery: { outputBudget: "unbounded" },
|
|
778
803
|
},
|
|
779
804
|
read_output: minimalReceipt,
|
|
780
805
|
};
|
|
@@ -796,7 +821,7 @@ function canReturnReadOutputUnchanged(resolved, requested, session, result) {
|
|
|
796
821
|
return false;
|
|
797
822
|
const canonicalRequestedCount = requested.filter((dimension) => resolved[dimension]?.source === "canonical").length;
|
|
798
823
|
if (resolved.cost?.value === "unbounded") {
|
|
799
|
-
return canonicalRequestedCount === 1;
|
|
824
|
+
return (canonicalRequestedCount === (resolved.cost.source === "canonical" ? 1 : 0));
|
|
800
825
|
}
|
|
801
826
|
if (resolved.cost?.source === "legacy" && canonicalRequestedCount === 0) {
|
|
802
827
|
return true;
|
|
@@ -813,31 +838,174 @@ function canReturnReadOutputUnchanged(resolved, requested, session, result) {
|
|
|
813
838
|
* without this an explicitly requested unbounded read is silently downgraded and
|
|
814
839
|
* the only working recovery is never named.
|
|
815
840
|
*/
|
|
816
|
-
function attachReadOutputTruncationDisclosure(projected, resolved, receipt, bindingBudget) {
|
|
841
|
+
function attachReadOutputTruncationDisclosure(projected, resolved, receipt, bindingBudget, continuationCursorRebased, collectionsBeforeBudget) {
|
|
817
842
|
if (!receipt.rows_compacted)
|
|
818
843
|
return;
|
|
819
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";
|
|
820
883
|
projected.output_budget_truncation = {
|
|
821
884
|
reason: "output_budget_reached",
|
|
822
885
|
budget_source: bindingBudget.source,
|
|
823
886
|
budget_tokens: bindingBudget.tokens,
|
|
824
887
|
overridden_dimensions: overridden,
|
|
825
888
|
compacted_row_paths: receipt.compacted_row_paths,
|
|
826
|
-
|
|
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
|
+
},
|
|
827
908
|
};
|
|
828
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
|
+
}
|
|
829
991
|
/** Apply universal field, row, and token bounds and attach an exact receipt. */
|
|
830
992
|
export function applyReadOutputDimensions(command, options, result) {
|
|
831
993
|
const resolved = resolveReadOutputDimensions(command, options);
|
|
832
994
|
if (!resolved)
|
|
833
995
|
return result;
|
|
834
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;
|
|
835
1001
|
const requested = requestedDimensions(resolved);
|
|
836
|
-
if (
|
|
1002
|
+
if (cursor === undefined &&
|
|
1003
|
+
canReturnReadOutputUnchanged(resolved, requested, session, result)) {
|
|
837
1004
|
return result;
|
|
838
1005
|
}
|
|
839
1006
|
const bindingBudget = resolveBindingReadOutputBudget(resolved, session);
|
|
840
|
-
let projected = projectReadOutputRows(result, resolved, session);
|
|
1007
|
+
let projected = projectReadOutputRows(result, resolved, session, cursor);
|
|
1008
|
+
const continuationState = captureReadOutputContinuationState(projected, cursor, options);
|
|
841
1009
|
const receipt = {
|
|
842
1010
|
contract_version: 1,
|
|
843
1011
|
command: resolved.command,
|
|
@@ -865,11 +1033,7 @@ export function applyReadOutputDimensions(command, options, result) {
|
|
|
865
1033
|
updateReadOutputReceiptEstimate(projected, receipt);
|
|
866
1034
|
if (bindingBudget !== undefined &&
|
|
867
1035
|
receipt.estimated_tokens > bindingBudget.tokens) {
|
|
868
|
-
projected =
|
|
869
|
-
attachReadOutputTruncationDisclosure(projected, resolved, receipt, bindingBudget);
|
|
870
|
-
if (session !== undefined) {
|
|
871
|
-
projected = attachReadOutputSessionContracts(projected, session, receipt);
|
|
872
|
-
}
|
|
1036
|
+
projected = compactReadOutputProjection(projected, resolved, receipt, bindingBudget, session, continuationState);
|
|
873
1037
|
}
|
|
874
1038
|
if (bindingBudget !== undefined &&
|
|
875
1039
|
receipt.estimated_tokens > bindingBudget.tokens) {
|
|
@@ -892,4 +1056,4 @@ export function resolveReadOutputEncoding(command, options) {
|
|
|
892
1056
|
: undefined;
|
|
893
1057
|
}
|
|
894
1058
|
//# sourceMappingURL=read-output-contracts.js.map
|
|
895
|
-
//# debugId=
|
|
1059
|
+
//# debugId=f9774018-a5b7-505e-a8ea-cba08392afeb
|
|
@@ -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. */
|
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
* envelopes, including dot-delimited nested paths used by graph projections.
|
|
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]="0c69ff43-7bbc-5128-9533-bbf15365126b")}catch(e){}}();
|
|
9
9
|
const BUDGET_METADATA_ROOT_KEYS = new Set([
|
|
10
10
|
"applied_bound",
|
|
11
11
|
"completeness",
|
|
12
|
+
"budget_retention_policy",
|
|
12
13
|
"continuation_contract",
|
|
14
|
+
"continuation_kind",
|
|
15
|
+
"continuation_path",
|
|
13
16
|
"filters",
|
|
14
17
|
"omission_receipt",
|
|
15
18
|
"output_budget_truncation",
|
|
@@ -48,6 +51,16 @@ function replaceValueAtPath(result, rowPath, replacement) {
|
|
|
48
51
|
target[segments.at(-1)] = replacement;
|
|
49
52
|
return root;
|
|
50
53
|
}
|
|
54
|
+
/** Replace one declared row collection with a suffix beginning at an offset. */
|
|
55
|
+
export function sliceReadOutputRowCollection(result, rowPath, offset) {
|
|
56
|
+
const collection = readOutputRowCollections(result).find((entry) => entry.path === rowPath);
|
|
57
|
+
if (!collection)
|
|
58
|
+
return result;
|
|
59
|
+
const replacement = Array.isArray(collection.value)
|
|
60
|
+
? collection.value.slice(offset)
|
|
61
|
+
: Object.fromEntries(Object.entries(collection.value).slice(offset));
|
|
62
|
+
return replaceValueAtPath(result, rowPath, replacement);
|
|
63
|
+
}
|
|
51
64
|
/** Resolve declared row paths, falling back to top-level array properties. */
|
|
52
65
|
export function readOutputRowPaths(result) {
|
|
53
66
|
const contract = result.row_contract;
|
|
@@ -142,4 +155,4 @@ export function boundReadOutputRows(result, amount) {
|
|
|
142
155
|
return { result: projected, truncated };
|
|
143
156
|
}
|
|
144
157
|
//# sourceMappingURL=read-output-rows.js.map
|
|
145
|
-
//# debugId=
|
|
158
|
+
//# debugId=0c69ff43-7bbc-5128-9533-bbf15365126b
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* primitives are shared by native action dispatchers and MCP-specific adapters.
|
|
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]="0e153ece-4fc0-5134-97f0-c2315aff0031")}catch(e){}}();
|
|
9
9
|
import { EXIT_CODE } from "../core/shared/constants.js";
|
|
10
10
|
import { PmCliError } from "../core/shared/errors.js";
|
|
11
11
|
import { asRecordClone } from "../core/shared/primitives.js";
|
|
@@ -83,6 +83,7 @@ export function actionGlobalOptions(args) {
|
|
|
83
83
|
outputLimit: readRuntimeScalarString(args, "outputLimit"),
|
|
84
84
|
outputBudget: readRuntimeScalarString(args, "outputBudget"),
|
|
85
85
|
outputSession: readRuntimeString(args, "outputSession"),
|
|
86
|
+
outputCursor: readRuntimeString(args, "outputCursor"),
|
|
86
87
|
outputFormat: outputFormat === "json" || outputFormat === "toon"
|
|
87
88
|
? outputFormat
|
|
88
89
|
: undefined,
|
|
@@ -167,6 +168,7 @@ const UNIVERSAL_READ_OUTPUT_OPTION_KEYS = [
|
|
|
167
168
|
"outputBudget",
|
|
168
169
|
"outputFormat",
|
|
169
170
|
"outputSession",
|
|
171
|
+
"outputCursor",
|
|
170
172
|
];
|
|
171
173
|
/** Reconcile MCP array/scalar option spellings with CLI flag expectations. */
|
|
172
174
|
export function normalizeMcpOptionsArrays(options, action) {
|
|
@@ -501,4 +503,4 @@ export function updateManyOptionsFromFlat(options) {
|
|
|
501
503
|
};
|
|
502
504
|
}
|
|
503
505
|
//# sourceMappingURL=runtime-input.js.map
|
|
504
|
-
//# debugId=
|
|
506
|
+
//# debugId=0e153ece-4fc0-5134-97f0-c2315aff0031
|
package/docs/ASSURANCE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Project Assurance Primitives
|
|
2
2
|
|
|
3
|
-
Tracker: [pm-2lex4r](../.agents/pm/features/pm-2lex4r.toon), [pm-lyfu7b](../.agents/pm/features/pm-lyfu7b.toon), [pm-wn6wot](../.agents/pm/features/pm-wn6wot.toon), [pm-91xeam](../.agents/pm/features/pm-91xeam.toon), [pm-uhv1m5](../.agents/pm/features/pm-uhv1m5.toon), [pm-m7bb7r](../.agents/pm/features/pm-m7bb7r.toon), [pm-py7qv2](../.agents/pm/issues/pm-py7qv2.toon), [pm-33mjrw](../.agents/pm/issues/pm-33mjrw.toon), [pm-q6n8sj](../.agents/pm/issues/pm-q6n8sj.toon), [pm-h06944](../.agents/pm/issues/pm-h06944.toon), [pm-dwj33e](../.agents/pm/decisions/pm-dwj33e.toon)
|
|
3
|
+
Tracker: [pm-2lex4r](../.agents/pm/features/pm-2lex4r.toon), [pm-lyfu7b](../.agents/pm/features/pm-lyfu7b.toon), [pm-wn6wot](../.agents/pm/features/pm-wn6wot.toon), [pm-91xeam](../.agents/pm/features/pm-91xeam.toon), [pm-uhv1m5](../.agents/pm/features/pm-uhv1m5.toon), [pm-m7bb7r](../.agents/pm/features/pm-m7bb7r.toon), [pm-py7qv2](../.agents/pm/issues/pm-py7qv2.toon), [pm-33mjrw](../.agents/pm/issues/pm-33mjrw.toon), [pm-q6n8sj](../.agents/pm/issues/pm-q6n8sj.toon), [pm-h06944](../.agents/pm/issues/pm-h06944.toon), [pm-88mo8m](../.agents/pm/issues/pm-88mo8m.toon), [pm-atnfh4](../.agents/pm/issues/pm-atnfh4.toon), [pm-xmmafu](../.agents/pm/issues/pm-xmmafu.toon), [pm-4ok4ex](../.agents/pm/tasks/pm-4ok4ex.toon), [pm-dwj33e](../.agents/pm/decisions/pm-dwj33e.toon)
|
|
4
4
|
|
|
5
5
|
## Agent Quick Context
|
|
6
6
|
|
|
@@ -43,6 +43,14 @@ Measurements support these built-in sources:
|
|
|
43
43
|
| `derived` | Combine numeric measurements with deterministic arithmetic and cycle detection. |
|
|
44
44
|
| `provider` | Delegate a measurement to an explicitly supplied host/package resolver. |
|
|
45
45
|
|
|
46
|
+
`ASSURANCE_MEASUREMENT_SOURCE_KINDS` and `ASSURANCE_GATE_TRIGGERS` are the
|
|
47
|
+
public SDK constants for these closed vocabularies. Runtime validation rejects
|
|
48
|
+
missing arrays and unknown discriminants with `AssuranceMutationRefusalError`;
|
|
49
|
+
it never persists an unrecognized source or leaks an incidental JavaScript
|
|
50
|
+
property-access error. Hosts that generate forms or package schemas can obtain
|
|
51
|
+
the same values from `pm contracts --command assurance --json` under
|
|
52
|
+
`assurance_contracts`.
|
|
53
|
+
|
|
46
54
|
Each measurement may declare `max_cost`. Evaluation fails closed when the total abstract compute units exceed that ceiling. Every result reports units, scanned items, scanned history rows, provider calls, duration, population size, and contributors.
|
|
47
55
|
|
|
48
56
|
One workspace context memoizes identical graph operations and the shared
|
|
@@ -263,15 +271,64 @@ await pm.assurance({
|
|
|
263
271
|
});
|
|
264
272
|
```
|
|
265
273
|
|
|
266
|
-
For direct host composition, use `evaluateMeasurement`, `evaluateAssuranceGate`, `createAssuranceWorkspaceContext`, the preset/derivation helpers, and the audited declaration/verdict helpers exported from `@unbrained/pm-cli/sdk
|
|
274
|
+
For direct host composition, use `evaluateMeasurement`, `evaluateAssuranceGate`, `createAssuranceWorkspaceContext`, the preset/derivation helpers, and the audited declaration/verdict helpers exported from `@unbrained/pm-cli/sdk` and its focused `@unbrained/pm-cli/sdk/governance` entrypoint. Active extension registrations are discovered automatically. Embedding hosts may additionally pass stable resolver ids and matching `provider_capabilities` to `createAssuranceWorkspaceContext`; an absent resolver or capability fails loudly. The core evaluator bounds concurrent assertions and expression operands, and workspace history loading uses bounded concurrency; item-only callers can explicitly skip history and Git identity resolution.
|
|
275
|
+
|
|
276
|
+
Hosts that want the normal action transport and its audited registry lookup can
|
|
277
|
+
pass the same adapters as the third `runAssuranceAction` argument. The request
|
|
278
|
+
and project path remain transport data; resolver capabilities remain explicit
|
|
279
|
+
runtime authority:
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
await runAssuranceAction(
|
|
283
|
+
{
|
|
284
|
+
action: "run",
|
|
285
|
+
id: "repository-static-quality",
|
|
286
|
+
trigger: "ci",
|
|
287
|
+
dry_run: true,
|
|
288
|
+
},
|
|
289
|
+
{ path: ".agents/pm" },
|
|
290
|
+
{
|
|
291
|
+
workspace: {
|
|
292
|
+
include_history: false,
|
|
293
|
+
providers: {
|
|
294
|
+
"repository-quality": resolveRepositoryQualityMeasurement,
|
|
295
|
+
},
|
|
296
|
+
provider_capabilities: {
|
|
297
|
+
"repository-quality": { cost_class: "high", network: false },
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
);
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
This is the migration boundary for repository automation: scripts may remain
|
|
305
|
+
focused process adapters, while assertion composition, provider policy,
|
|
306
|
+
negative controls, lifecycle triggers, and verdicts move into ordinary
|
|
307
|
+
assurance declarations. `scripts/release/gate-registry.json` records every
|
|
308
|
+
gate script as migrated, provider-backed, or retained and fails unless the
|
|
309
|
+
migrated/provider-backed population is the majority.
|
|
310
|
+
|
|
311
|
+
`AssuranceMutationRefusalError` and `AssuranceEvaluationRefusalError` are
|
|
312
|
+
exported from both `@unbrained/pm-cli/sdk` and
|
|
313
|
+
`@unbrained/pm-cli/sdk/governance`, so hosts can classify expected declaration
|
|
314
|
+
or evaluation refusals without parsing messages. Source-resolution refusals
|
|
315
|
+
also carry the gate, assertion, measurement, source kind, field, and optional
|
|
316
|
+
health/validate check, so a zero value remains distinct from an absent or
|
|
317
|
+
mistyped field.
|
|
267
318
|
|
|
268
319
|
Generic SDK and MCP dispatch use `action: "assurance"` with `subcommand` set to `list`, `show`, `put`, `remove`, `run`, `verdicts`, `presets`, `apply`, `derive`, or `promote`. Discover the current machine contract instead of copying parameter lists:
|
|
269
320
|
|
|
270
321
|
```bash
|
|
271
322
|
pm contracts --action assurance --schema-only --json
|
|
272
323
|
pm contracts --command assurance --flags-only --json
|
|
324
|
+
pm contracts --command assurance --json
|
|
273
325
|
```
|
|
274
326
|
|
|
327
|
+
Command-scoped contract output omits unrelated extension, governance,
|
|
328
|
+
relationship, and Commander-alias catalogs unless `--full` is requested. This
|
|
329
|
+
keeps the selected action schema and its assurance vocabularies complete under
|
|
330
|
+
the default output budget instead of truncating the very enum a caller needs.
|
|
331
|
+
|
|
275
332
|
## Verdict Contract
|
|
276
333
|
|
|
277
334
|
A gate emits one object containing:
|
package/docs/COMMANDS.md
CHANGED
|
@@ -4,6 +4,8 @@ This is a task-oriented command guide. For exact flags, use runtime help because
|
|
|
4
4
|
|
|
5
5
|
Tracked implementation updates: [pm-52eh](../.agents/pm/features/pm-52eh.toon), [pm-mcxr](../.agents/pm/issues/pm-mcxr.toon), [pm-qd3woa](../.agents/pm/issues/pm-qd3woa.toon), [pm-ypuc39](../.agents/pm/issues/pm-ypuc39.toon), [pm-tz2ikr](../.agents/pm/issues/pm-tz2ikr.toon), the schema-migration recovery contract [pm-s79kel](../.agents/pm/issues/pm-s79kel.toon), the lossless mutation contracts [pm-x3dq0l](../.agents/pm/issues/pm-x3dq0l.toon), [pm-lppm6y](../.agents/pm/issues/pm-lppm6y.toon), and [pm-embm6t](../.agents/pm/issues/pm-embm6t.toon), and the SDK-first agent grammar tranche [pm-p316vn](../.agents/pm/issues/pm-p316vn.toon), [pm-st7wgu](../.agents/pm/issues/pm-st7wgu.toon), [pm-mkinft](../.agents/pm/issues/pm-mkinft.toon), [pm-ulqu](../.agents/pm/issues/pm-ulqu.toon), [pm-qmjx](../.agents/pm/issues/pm-qmjx.toon), [pm-4bzq](../.agents/pm/features/pm-4bzq.toon), [pm-x2vx](../.agents/pm/issues/pm-x2vx.toon), and [pm-g543](../.agents/pm/issues/pm-g543.toon).
|
|
6
6
|
|
|
7
|
+
Workspace-integrity contracts are tracked by [pm-22rzjp](../.agents/pm/issues/pm-22rzjp.toon), [pm-76fkpp](../.agents/pm/issues/pm-76fkpp.toon), [pm-igdvfq](../.agents/pm/issues/pm-igdvfq.toon), [pm-643e0k](../.agents/pm/issues/pm-643e0k.toon), and [pm-larv4r](../.agents/pm/issues/pm-larv4r.toon).
|
|
8
|
+
|
|
7
9
|
```bash
|
|
8
10
|
pm <command> --help
|
|
9
11
|
pm <command> --help --json
|
|
@@ -965,6 +967,8 @@ pm history-repair <id> --dry-run
|
|
|
965
967
|
pm history-repair <id> --message "re-anchor legacy drift"
|
|
966
968
|
pm history-repair --all --dry-run
|
|
967
969
|
pm history-repair --all --message "bulk re-anchor drifted streams"
|
|
970
|
+
pm history-repair --all --normalize-provenance --dry-run
|
|
971
|
+
pm history-repair --all --normalize-provenance --message "normalize invalid legacy provenance"
|
|
968
972
|
pm activity # item digest for the last 24 hours
|
|
969
973
|
pm activity --raw --id <id> --limit 50
|
|
970
974
|
pm activity --full --id <id> --limit 50
|
|
@@ -1020,8 +1024,10 @@ For governance dashboards, `--metadata-coverage` adds a `metadata_coverage` bloc
|
|
|
1020
1024
|
`history-redact` rewrites matching history payloads deterministically, recomputes hash chains, and appends an auditable `history_redact` marker entry when changes are applied. Its result reports only `literal_count`, `regex_count`, `total_count`, and whether the default replacement was selected; literal values, regex source text, and replacement text are never echoed in CLI, SDK, MCP, recovery, profile, or telemetry output. Treat regex text as sensitive input because it can contain the exact material being removed.
|
|
1021
1025
|
`history-compact` rewrites long streams into a synthetic checkpoint baseline plus a retained tail (`--before` accepts a 1-based version or ISO timestamp), re-anchors hashes, verifies integrity, and appends an auditable `history_compact` marker when applied.
|
|
1022
1026
|
`history-compact` bulk mode (mutually exclusive with a positional `<id>`) compacts many streams in one audited pass. Select with `--ids <a,b,c>` (an explicit list — used on its own, not combined with the scan selectors below), or a scan: `--all-over <N>` (every stream with more than N entries) and/or a lifecycle filter `--closed` (terminal items only) or `--all-streams` (every stream). `--closed` and `--all-streams` are mutually exclusive. `--min-entries <N>` (default 3) skips already-compact streams; when `history.compact_policy` is enabled and `--all-over` is omitted, the policy's `max_entries` becomes the default threshold. `--before` is single-id only and is rejected in bulk mode. Each selected stream runs the same single-item compaction; one failing stream never aborts the rest — the result reports `totals` (`streams_considered`/`selected`/`items_compacted`/`items_skipped`/`items_errored`) plus one row per stream (`compacted`/`skipped` with a `skip_reason`/`errored`), and the command exits non-zero only if any stream errored.
|
|
1023
|
-
`history-repair` re-anchors a drifted history chain when `pm health`/`pm validate --check-history-drift` report stale hashes: it replays the stream, recomputes every before/after hash, repairs legacy patch ops that no longer strictly apply, reconciles the latest hash with the on-disk item, and appends an auditable `history_repair` marker. It never modifies item content and is a safe no-op on a clean stream.
|
|
1024
|
-
`history-repair --all` (mutually exclusive with `<id>`) runs the same drift scan `pm health` uses and applies the audited single-stream repair (ownership check, lock, post-repair no-drift verification, `--message` audit marker, per-stream `--force`) to every drifted stream in one pass. One failing stream never aborts the rest: the result lists one compact row per
|
|
1027
|
+
`history-repair` re-anchors a drifted history chain when `pm health`/`pm validate --check-history-drift` report stale hashes: it replays the stream, recomputes every before/after hash using the stream's detected hash epoch, repairs legacy patch ops that no longer strictly apply, reconciles the latest hash with the on-disk item, and appends an auditable `history_repair` marker. It never modifies item content and is a safe no-op on a clean stream. The result reports the before/after hash versions and whether the epoch was preserved or selected for an ambiguous broken stream, preventing old/new runtimes from alternately rewriting an otherwise consistent legacy chain.
|
|
1028
|
+
`history-repair --all` (mutually exclusive with `<id>`) runs the same drift scan `pm health` uses and applies the audited single-stream repair (ownership check, lock, post-repair no-drift verification, `--message` audit marker, per-stream `--force`) to every drifted stream in one pass. One failing stream never aborts the rest: the result lists one compact row per targeted stream (`repaired` / `skipped_clean` / `failed`) plus `totals`, and the command exits non-zero only if any stream failed. Add `--normalize-provenance` to include streams containing invalid boolean or single-digit provenance observations. The normalizer removes only those invalid observations and writes aggregate harness/dimension/kind counts in the audit receipt; it never echoes or retains the removed value.
|
|
1029
|
+
|
|
1030
|
+
Every `pm health` projection exposes `findings` and `failed_because`. A finding binds one warning token to its owning check, stable code, `advisory|gate_failing` severity, and either an executable remediation or `no_safe_automatic_remediation`. Extension health also publishes `host_version_census`, which enumerates the host and every pm-cli copy resolved by loaded extensions across npm/pnpm layouts. A version mismatch makes the extension check non-clean; matching workspace-linked or deduplicated copies remain healthy.
|
|
1025
1031
|
|
|
1026
1032
|
`pm health --verbose-author-events --json` includes the complete actionable unknown-author coordinate list and an explicit `samples_truncated` marker. After evidence review, `pm history-author-acknowledge --all-actionable --attributed-author <principal> --reviewer <reviewer> --reason <evidence>` records one append-only disposition for the current complete set. `--all-actionable` and repeatable `--event <item-id:line>` are mutually exclusive; reviewer, attributed author, and reason remain mandatory.
|
|
1027
1033
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# Universal Read Output Contracts
|
|
2
2
|
|
|
3
|
-
Tracker references: [pm-hb7ug8](../.agents/pm/features/pm-hb7ug8.toon), [pm-cxr0jb](../.agents/pm/features/pm-cxr0jb.toon), [pm-hid9g1](../.agents/pm/features/pm-hid9g1.toon), [pm-h8tpeh](../.agents/pm/features/pm-h8tpeh.toon), [pm-sb0tns](../.agents/pm/issues/pm-sb0tns.toon), [pm-gjjurs](../.agents/pm/issues/pm-gjjurs.toon), [pm-eugaqy](../.agents/pm/issues/pm-eugaqy.toon), [pm-jt8aa2](../.agents/pm/issues/pm-jt8aa2.toon),
|
|
3
|
+
Tracker references: [pm-hb7ug8](../.agents/pm/features/pm-hb7ug8.toon), [pm-cxr0jb](../.agents/pm/features/pm-cxr0jb.toon), [pm-hid9g1](../.agents/pm/features/pm-hid9g1.toon), [pm-h8tpeh](../.agents/pm/features/pm-h8tpeh.toon), [pm-5t33or](../.agents/pm/features/pm-5t33or.toon), [pm-sb0tns](../.agents/pm/issues/pm-sb0tns.toon), [pm-gjjurs](../.agents/pm/issues/pm-gjjurs.toon), [pm-eugaqy](../.agents/pm/issues/pm-eugaqy.toon), [pm-jt8aa2](../.agents/pm/issues/pm-jt8aa2.toon), [pm-kyjdne](../.agents/pm/issues/pm-kyjdne.toon), [pm-8nev0o](../.agents/pm/issues/pm-8nev0o.toon), [pm-e5gl05](../.agents/pm/issues/pm-e5gl05.toon), and [pm-cha95z](../.agents/pm/tasks/pm-cha95z.toon).
|
|
4
4
|
|
|
5
5
|
## Agent Quick Context
|
|
6
6
|
|
|
7
7
|
Every built-in read surface uses four output dimensions: what to include, how much to return, how much the result may cost, and how to encode it. The same canonical controls work through the CLI, SDK, MCP, generated schemas, runtime contracts, and shell completions.
|
|
8
8
|
|
|
9
|
-
| Dimension | CLI
|
|
10
|
-
| --------- |
|
|
11
|
-
| Include | `--output-include <csv>`
|
|
12
|
-
| Amount | `--output-limit <n\|unbounded>`
|
|
13
|
-
| Cost | `--output-budget <
|
|
14
|
-
| Encoding | `--output-format <toon\|json>`
|
|
9
|
+
| Dimension | CLI | SDK and MCP | Meaning |
|
|
10
|
+
| --------- | -------------------------------- | --------------- | ---------------------------------------------------------------------- |
|
|
11
|
+
| Include | `--output-include <csv>` | `outputInclude` | Retain named fields or sections, or select a declared projection mode. |
|
|
12
|
+
| Amount | `--output-limit <n\|unbounded>` | `outputLimit` | Bound shared row collections. |
|
|
13
|
+
| Cost | `--output-budget <n\|unbounded>` | `outputBudget` | Fail closed when even the compact result cannot fit. |
|
|
14
|
+
| Encoding | `--output-format <toon\|json>` | `outputFormat` | Select the CLI renderer and record the requested encoding. |
|
|
15
15
|
|
|
16
16
|
The contract covers `list`, `context`, `search`, `get`, `next`, `health`, `deps`, `graph`, `history`, `activity`, `validate`, `events`, `contracts`, `comments`, `notes`, `files`, `docs`, `stats`, and `aggregate`, including list aliases and `ctx`.
|
|
17
17
|
|
|
@@ -117,6 +117,12 @@ tracker content.
|
|
|
117
117
|
|
|
118
118
|
Resolution is deterministic: canonical controls win over command-local compatibility options, which win over intent defaults, which win over command defaults. Existing options such as `--fields`, `--limit`, `--token-budget`, `--format`, `--brief`, and `--full` remain accepted. Contract output marks them as hidden compatibility aliases and supplies a migration hint; traversal, cursor, side-effect, and streaming controls instead receive an explicit behavior-preservation hint because a static output control cannot replace their semantics. Callers that omit the four shaping dimensions retain the established data projection; the one intentional envelope correction is that repeated `row_contract` metadata is now opt-in.
|
|
119
119
|
|
|
120
|
+
Completeness spellings preserve their established promise. `pm list-all` and
|
|
121
|
+
list-family `--no-truncate` imply an unbounded cost dimension when the caller
|
|
122
|
+
does not supply `--output-budget`; they cannot silently return a budget-trimmed
|
|
123
|
+
subset while claiming to return every matched row. An explicit canonical
|
|
124
|
+
budget still has precedence and may request a bounded result deliberately.
|
|
125
|
+
|
|
120
126
|
```bash
|
|
121
127
|
pm list-open --output-include id,title,status --output-limit 10
|
|
122
128
|
pm context --for orient --output-budget 900 --output-format toon
|
|
@@ -127,7 +133,41 @@ pm contracts --full --json
|
|
|
127
133
|
|
|
128
134
|
Every projected result carries a `read_output` receipt with the requested dimensions, precedence, observed compatibility aliases, deterministic estimated token count, string/row compaction signals, and budget outcome. Budget degradation discovers nested arrays as well as declared result rows, so validation diagnostics and other governance payloads compact their inner findings before the useful result is omitted. `compacted_row_paths` names every reduced collection without redefining those nested arrays as ordinary pagination rows.
|
|
129
135
|
|
|
130
|
-
When rows are dropped to satisfy a ceiling, the result also carries `output_budget_truncation`, naming the binding budget and its source, any explicitly requested dimension the budget overrode, every compacted collection path, and
|
|
136
|
+
When rows are dropped to satisfy a ceiling, the result also carries `output_budget_truncation`, naming the binding budget and its source, any explicitly requested dimension the budget overrode, every compacted collection path, and executable CLI/SDK/MCP recovery options — a default ceiling can override an explicit `--output-limit unbounded`, and that override is reported rather than silent. If a producer supplied an opaque item-page cursor, compaction rebases it to the last row actually returned and reports `continuation_cursor_rebased: true`; following the cursor therefore cannot skip rows removed from the middle of a producer page. If no useful content can fit, `PmReadOutputBudgetExceeded` provides a discriminated omission result, a compact `{ outputBudget: "unbounded" }` recovery object, and `omitted_result_estimated_tokens`, the last useful-result estimate before omission; use `isReadOutputBudgetExceeded` before accessing result-specific fields. Universal controls are rejected on mutation commands and on the mutation mode of hybrid commands such as `comments`, `notes`, `files`, and `docs`.
|
|
137
|
+
|
|
138
|
+
Cursor recovery carries the opaque value once in `recovery.cursor` and declares
|
|
139
|
+
the accepting `cli`, `sdk`, and `mcp` binding beside it. This avoids
|
|
140
|
+
serializing the same cursor once per transport while retaining an executable,
|
|
141
|
+
machine-readable binding for each surface.
|
|
142
|
+
|
|
143
|
+
Budget-compacted declared row paths are independently resumable. The
|
|
144
|
+
disclosure's `continuations` entries name the row path, retained/remaining/total
|
|
145
|
+
counts, and an opaque cursor. `continuation_kind` distinguishes a rebased
|
|
146
|
+
producer cursor, a universal output cursor, and a terminal page;
|
|
147
|
+
`next_cursor` mirrors the first universal entry for ordinary one-path
|
|
148
|
+
consumers. Replay the same query and budget
|
|
149
|
+
with `--output-cursor <cursor>` / `outputCursor`. The cursor validates the
|
|
150
|
+
command, declared row path, total, and stable row identities before slicing, so
|
|
151
|
+
a mismatched or stale replay fails closed instead of skipping evidence. A
|
|
152
|
+
bounded recovery therefore does not require replacing a 600-token request with
|
|
153
|
+
an unbounded multi-megabyte response;
|
|
154
|
+
`recovery_budget_multiplier: 1` declares that each next page retains the same
|
|
155
|
+
useful-result ceiling.
|
|
156
|
+
|
|
157
|
+
Assurance declares `budget_retention_policy: verdict_priority`: failing block,
|
|
158
|
+
warn, and observe rows precede retired and passing rows while preserving order
|
|
159
|
+
within each class. `assertions_total` remains the pre-projection denominator,
|
|
160
|
+
and the `assertions` row path uses the same continuation primitive. A blocking
|
|
161
|
+
verdict consequently keeps its causal evidence on the first bounded page even
|
|
162
|
+
when the failing assertion was declared last.
|
|
163
|
+
|
|
164
|
+
Diagnostic gates retain bounded, actionable predicates. Every metadata field
|
|
165
|
+
required by the active validation profile emits a numeric count, including
|
|
166
|
+
zero, so assurance expressions can distinguish a clean check from a missing
|
|
167
|
+
key. Health retains at most 100 warning rows and reports `warning_count`,
|
|
168
|
+
`warning_limit`, and `warnings_truncated`; `--strict-exit` defaults to summary
|
|
169
|
+
projection unless `--full` is explicit, keeping the failing check identities
|
|
170
|
+
and warning codes inside the ordinary budget.
|
|
131
171
|
|
|
132
172
|
## SDK and Package Usage
|
|
133
173
|
|
|
@@ -150,6 +190,7 @@ const result = await pm.list({
|
|
|
150
190
|
spent_tokens: 0,
|
|
151
191
|
seen_item_ids: [],
|
|
152
192
|
},
|
|
193
|
+
// Supply outputCursor from output_budget_truncation to fetch the next row page.
|
|
153
194
|
});
|
|
154
195
|
```
|
|
155
196
|
|