@unbrained/pm-cli 2026.8.24 → 2026.8.26
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 +46 -0
- package/dist/cli-bundle/bundle-manifest.json +149 -149
- package/dist/cli-bundle/chunks/chunk-E2GCFJSU.js +35 -0
- package/dist/cli-bundle/chunks/{chunk-TEQDR5KI.js → chunk-ES25LX3D.js} +62 -62
- package/dist/cli-bundle/chunks/{chunk-I5Q7QSZX.js → chunk-FRDWWB6R.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-X7WWQDYQ.js → chunk-ICQ3RVIY.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-YOLLRCLY.js → chunk-IV64RJVE.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-L22NP5MA.js → chunk-KBFP3E4E.js} +86 -86
- package/dist/cli-bundle/chunks/{chunk-AGUL3HUT.js → chunk-MVYLQ67M.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-DJNJBWAQ.js → chunk-S4U76VZF.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-IW72J5FW.js → chunk-UKBCRPA2.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-WRHJ3MB6.js +8 -0
- package/dist/cli-bundle/chunks/{chunk-ZAVCS2GH.js → chunk-ZNRLJ54C.js} +60 -60
- package/dist/cli-bundle/chunks/{register-list-query-37A4P6O4.js → register-list-query-EMCPMICY.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-TBJDHYIT.js → register-mutation-OJ67ABCB.js} +3 -3
- package/dist/cli-bundle/chunks/{register-operations-WRZNEBUM.js → register-operations-H2GLP7LT.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-H4PDLACD.js → register-setup-GLZAHLVI.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-IMWTYKII.js → chunk-4K2II4TV.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-4XNH2HM7.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-GJR6YEMR.js → chunk-57XY346D.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-4WP7LNE3.js → chunk-66VGB23P.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-72T6JGAE.js +50 -0
- package/dist/cli-bundle/focused-chunks/{chunk-BFA6KKCI.js → chunk-7I23XGWO.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-6Z24ZMU3.js → chunk-7YCDTCBC.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-O4ZXNJMT.js → chunk-A644DUFQ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-FXDLT6FL.js +16 -0
- package/dist/cli-bundle/focused-chunks/{chunk-RASVBJX5.js → chunk-IBHXMFE7.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-LMKG3DFE.js +5 -0
- package/dist/cli-bundle/focused-chunks/{chunk-6MUTDXMP.js → chunk-LV5N3LK5.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-CWCN5RLO.js → chunk-MMXUPDDJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-WZLSSGEU.js → chunk-OHIHZ7HS.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-P2E6LDAE.js +19 -0
- package/dist/cli-bundle/focused-chunks/{chunk-IZNRRCU3.js → chunk-TMJDFHVD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-QBP5FSBX.js → chunk-UYBA57GY.js} +4 -4
- package/dist/cli-bundle/focused-chunks/{chunk-MNPECIRL.js → chunk-YO3ZF3FI.js} +2 -2
- package/dist/cli-bundle/main.js +2 -2
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- package/dist/cli-bundle/sdk-core.js +41 -41
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +32 -33
- 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 +7 -6
- package/dist/core/diagnostics/remediation.js +17 -2
- package/dist/core/extensions/manifest-schema.d.ts +20 -0
- package/dist/core/extensions/manifest-schema.js +28 -10
- package/dist/mcp/http-server.d.ts +60 -0
- package/dist/mcp/http-server.js +451 -0
- package/dist/mcp/legacy-adapter.d.ts +50 -0
- package/dist/mcp/legacy-adapter.js +64 -0
- package/dist/mcp/server.d.ts +42 -9
- package/dist/mcp/server.js +457 -58
- package/dist/sdk/agent/refusal-closure-census.d.ts +6 -2
- package/dist/sdk/agent/refusal-closure-census.js +16 -8
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +10 -0
- package/dist/sdk/cli-contracts/runtime-contracts.js +20 -3
- package/dist/sdk/compose.d.ts +4 -1
- package/dist/sdk/compose.js +23 -36
- package/dist/sdk/extension/author-manifest.d.ts +22 -0
- package/dist/sdk/extension/author-manifest.js +93 -0
- package/dist/sdk/extension.js +6 -3
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +67 -28
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +30 -3
- package/dist/sdk/governance/health.js +103 -11
- package/dist/sdk/governance/validate.js +15 -9
- package/dist/sdk/history-repair.d.ts +24 -0
- package/dist/sdk/history-repair.js +145 -4
- package/dist/sdk/index.d.ts +6 -0
- package/dist/sdk/index.js +8 -2
- package/dist/sdk/mcp/authorization.d.ts +134 -0
- package/dist/sdk/mcp/authorization.js +405 -0
- package/dist/sdk/mcp/interactions.d.ts +118 -0
- package/dist/sdk/mcp/interactions.js +337 -0
- package/dist/sdk/mcp/protocol.d.ts +142 -0
- package/dist/sdk/mcp/protocol.js +174 -0
- package/dist/sdk/mcp/subscriptions.d.ts +65 -0
- package/dist/sdk/mcp/subscriptions.js +212 -0
- package/dist/sdk/mcp/tasks.d.ts +107 -0
- package/dist/sdk/mcp/tasks.js +431 -0
- package/dist/sdk/mcp/transport.d.ts +30 -0
- package/dist/sdk/mcp/transport.js +261 -0
- package/dist/sdk/merge/driver.js +25 -4
- package/dist/sdk/merge/receipt-file-boundary.d.ts +21 -0
- package/dist/sdk/merge/receipt-file-boundary.js +47 -0
- package/dist/sdk/merge/receipts.d.ts +40 -1
- package/dist/sdk/merge/receipts.js +343 -36
- package/dist/sdk/merge/reconcile.js +117 -47
- package/dist/sdk/read-output/continuation.d.ts +15 -2
- package/dist/sdk/read-output/continuation.js +86 -6
- package/dist/sdk/read-output-contracts.d.ts +4 -1
- package/dist/sdk/read-output-contracts.js +9 -6
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/test/execution.d.ts +6 -0
- package/dist/sdk/test/execution.js +32 -3
- package/docs/AGENT_PROVENANCE_ADR.md +6 -4
- package/docs/AGENT_RUNTIME_PRIMITIVES.md +6 -5
- package/docs/CLAUDE_CODE_PLUGIN.md +12 -5
- package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +8 -0
- package/docs/EXTENSIONS.md +3 -4
- package/docs/MCP_2026_07_28.md +138 -0
- package/docs/MCP_2026_07_28_CONFORMANCE.md +30 -0
- package/docs/MCP_REMOTE_TRANSPORT_SECURITY.md +180 -0
- package/docs/MERGE_SAFETY.md +34 -5
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +13 -1
- package/docs/README.md +4 -0
- package/docs/READ_OUTPUT_CONTRACTS.md +25 -2
- package/docs/RELEASING.md +3 -2
- package/docs/SDK.md +22 -1
- package/docs/SDK_AGENT_SESSION_CONTEXT.md +18 -13
- package/docs/SDK_MCP_INTERACTIONS.md +227 -0
- package/docs/TESTING.md +4 -0
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +13 -8
- package/marketplace.json +2 -2
- package/package.json +7 -5
- 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/scripts/finalize-build.mjs +1 -0
- package/sdk/public-surface.json +762 -15
- package/dist/cli-bundle/chunks/chunk-MKE6MD2K.js +0 -36
- package/dist/cli-bundle/chunks/chunk-NXBFO63A.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-FCTT4CZU.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-Q63PSLO4.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QV5UP27O.js +0 -51
- package/dist/cli-bundle/focused-chunks/chunk-RPRLENVA.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-TOFVXBWA.js +0 -19
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import type { PmReadOutputCursorEnvelope, PmReadOutputSurface } from "../read-output-contracts.js";
|
|
2
|
-
/**
|
|
3
|
-
export
|
|
2
|
+
/** Stable snapshot policy for a read surface whose probes refresh observation metadata. */
|
|
3
|
+
export interface PmReadOutputContinuationFingerprintPolicy {
|
|
4
|
+
/** Version included in fingerprints so policy changes invalidate older cursors. */
|
|
5
|
+
version: 3;
|
|
6
|
+
/** Declared continuation row paths governed by this policy. */
|
|
7
|
+
paths: readonly string[];
|
|
8
|
+
/** Exact direct detail fields excluded for each named dynamic row. */
|
|
9
|
+
ignored_detail_field_names_by_row: Readonly<Record<string, readonly string[]>>;
|
|
10
|
+
/** Promise that verdicts, stable configuration, and nonvolatile evidence remain bound. */
|
|
11
|
+
guarantee: "nonvolatile_snapshot_and_stable_configuration";
|
|
12
|
+
}
|
|
13
|
+
/** Command-specific exceptions to complete-row continuation fingerprinting. */
|
|
14
|
+
export declare const PM_READ_OUTPUT_CONTINUATION_FINGERPRINT_POLICIES: Readonly<Partial<Record<PmReadOutputSurface, PmReadOutputContinuationFingerprintPolicy>>>;
|
|
15
|
+
/** Fingerprint the policy-normalized row snapshot so stable evidence changes fail closed. */
|
|
16
|
+
export declare function readOutputCollectionFingerprint(path: string, value: unknown[] | Record<string, unknown>, command?: PmReadOutputSurface): string;
|
|
4
17
|
/** Encode one stable declared-row continuation for CLI, SDK, and MCP callers. */
|
|
5
18
|
export declare function encodeReadOutputContinuationCursor(cursor: Omit<PmReadOutputCursorEnvelope, "version">): string;
|
|
6
19
|
/** Decode and validate one universal declared-row continuation cursor. */
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* resolution and budget policy.
|
|
7
7
|
*/
|
|
8
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]="
|
|
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]="9e63b4b0-09a5-50bf-9f56-5f239c75ffe5")}catch(e){}}();
|
|
10
10
|
import { createHash } from "node:crypto";
|
|
11
11
|
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
12
12
|
import { PmCliError } from "../../core/shared/errors.js";
|
|
@@ -14,13 +14,93 @@ import { stableStringify } from "../../core/shared/serialization.js";
|
|
|
14
14
|
import { resolveReadOutputSurface } from "../read-output-contracts.js";
|
|
15
15
|
import { readOutputContinuationRowCollections, sliceReadOutputRowCollection, } from "../read-output-rows.js";
|
|
16
16
|
const MAX_READ_OUTPUT_CURSOR_LENGTH = 4096;
|
|
17
|
+
const HEALTH_TELEMETRY_VOLATILE_DETAIL_FIELDS = Object.freeze([
|
|
18
|
+
"queue_draining",
|
|
19
|
+
"queue_entries",
|
|
20
|
+
"queue_exists",
|
|
21
|
+
"queue_high_retry_entries",
|
|
22
|
+
"queue_invalid_rows",
|
|
23
|
+
"queue_max_attempts",
|
|
24
|
+
"queue_rows_total",
|
|
25
|
+
"queue_size_bytes",
|
|
26
|
+
"pending_otel_spans",
|
|
27
|
+
"last_attempted_flush_at",
|
|
28
|
+
"last_failed_flush_at",
|
|
29
|
+
"last_otel_attempt_at",
|
|
30
|
+
"last_otel_failure_at",
|
|
31
|
+
"last_otel_success_at",
|
|
32
|
+
"last_successful_flush_at",
|
|
33
|
+
]);
|
|
34
|
+
/** Command-specific exceptions to complete-row continuation fingerprinting. */
|
|
35
|
+
export const PM_READ_OUTPUT_CONTINUATION_FINGERPRINT_POLICIES = Object.freeze({
|
|
36
|
+
health: Object.freeze({
|
|
37
|
+
version: 3,
|
|
38
|
+
paths: Object.freeze(["checks"]),
|
|
39
|
+
ignored_detail_field_names_by_row: Object.freeze({
|
|
40
|
+
telemetry: HEALTH_TELEMETRY_VOLATILE_DETAIL_FIELDS,
|
|
41
|
+
}),
|
|
42
|
+
guarantee: "nonvolatile_snapshot_and_stable_configuration",
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
17
45
|
function isRecord(value) {
|
|
18
46
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
19
47
|
}
|
|
20
|
-
|
|
21
|
-
|
|
48
|
+
function normalizeReadOutputFingerprintValue(value) {
|
|
49
|
+
if (Array.isArray(value)) {
|
|
50
|
+
return value.map(normalizeReadOutputFingerprintValue);
|
|
51
|
+
}
|
|
52
|
+
if (!isRecord(value))
|
|
53
|
+
return value;
|
|
54
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
55
|
+
key,
|
|
56
|
+
normalizeReadOutputFingerprintValue(entry),
|
|
57
|
+
]));
|
|
58
|
+
}
|
|
59
|
+
function normalizeReadOutputFingerprintRow(value, policy) {
|
|
60
|
+
if (!isRecord(value))
|
|
61
|
+
return normalizeReadOutputFingerprintValue(value);
|
|
62
|
+
const rowName = typeof value.name === "string" ? value.name : undefined;
|
|
63
|
+
const ignoredDetailFields = rowName !== undefined &&
|
|
64
|
+
Object.hasOwn(policy.ignored_detail_field_names_by_row, rowName)
|
|
65
|
+
? policy.ignored_detail_field_names_by_row[rowName]
|
|
66
|
+
: undefined;
|
|
67
|
+
return Object.fromEntries(Object.entries(value)
|
|
68
|
+
.map(([key, entry]) => {
|
|
69
|
+
if (key !== "details" || !ignoredDetailFields || !isRecord(entry)) {
|
|
70
|
+
return [key, normalizeReadOutputFingerprintValue(entry)];
|
|
71
|
+
}
|
|
72
|
+
return [
|
|
73
|
+
key,
|
|
74
|
+
Object.fromEntries(Object.entries(entry)
|
|
75
|
+
.filter(([detailKey]) => !ignoredDetailFields.includes(detailKey))
|
|
76
|
+
.map(([detailKey, detailValue]) => [
|
|
77
|
+
detailKey,
|
|
78
|
+
normalizeReadOutputFingerprintValue(detailValue),
|
|
79
|
+
])),
|
|
80
|
+
];
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
function normalizeReadOutputFingerprintSnapshot(value, policy) {
|
|
84
|
+
return Array.isArray(value)
|
|
85
|
+
? value.map((row) => normalizeReadOutputFingerprintRow(row, policy))
|
|
86
|
+
: normalizeReadOutputFingerprintRow(value, policy);
|
|
87
|
+
}
|
|
88
|
+
/** Fingerprint the policy-normalized row snapshot so stable evidence changes fail closed. */
|
|
89
|
+
export function readOutputCollectionFingerprint(path, value, command) {
|
|
90
|
+
const policy = command
|
|
91
|
+
? PM_READ_OUTPUT_CONTINUATION_FINGERPRINT_POLICIES[command]
|
|
92
|
+
: undefined;
|
|
93
|
+
const policyApplies = policy?.paths.includes(path) === true;
|
|
22
94
|
return createHash("sha256")
|
|
23
|
-
.update(stableStringify({
|
|
95
|
+
.update(stableStringify({
|
|
96
|
+
path,
|
|
97
|
+
value: policyApplies
|
|
98
|
+
? normalizeReadOutputFingerprintSnapshot(value, policy)
|
|
99
|
+
: value,
|
|
100
|
+
...(policyApplies
|
|
101
|
+
? { fingerprint_policy_version: policy.version }
|
|
102
|
+
: {}),
|
|
103
|
+
}))
|
|
24
104
|
.digest("base64url")
|
|
25
105
|
.slice(0, 16);
|
|
26
106
|
}
|
|
@@ -105,11 +185,11 @@ export function applyReadOutputContinuation(result, command, cursor) {
|
|
|
105
185
|
if (!collection ||
|
|
106
186
|
totalRows !== cursor.total_rows ||
|
|
107
187
|
cursor.offset > totalRows ||
|
|
108
|
-
readOutputCollectionFingerprint(cursor.path, collection.value) !==
|
|
188
|
+
readOutputCollectionFingerprint(cursor.path, collection.value, command) !==
|
|
109
189
|
cursor.fingerprint) {
|
|
110
190
|
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" });
|
|
111
191
|
}
|
|
112
192
|
return sliceReadOutputRowCollection(result, cursor.path, cursor.offset);
|
|
113
193
|
}
|
|
114
194
|
//# sourceMappingURL=continuation.js.map
|
|
115
|
-
//# debugId=
|
|
195
|
+
//# debugId=9e63b4b0-09a5-50bf-9f56-5f239c75ffe5
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { resolveReadOutputRecoveryBudget } from "./read-output-budget.js";
|
|
2
2
|
export type { PmReadOutputRecoveryBudget, PmReadOutputRecoveryBudgetInput, } from "./read-output-budget.js";
|
|
3
|
-
export { decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, } from "./read-output/continuation.js";
|
|
3
|
+
export { decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, PM_READ_OUTPUT_CONTINUATION_FINGERPRINT_POLICIES, readOutputCollectionFingerprint, } from "./read-output/continuation.js";
|
|
4
|
+
export type { PmReadOutputContinuationFingerprintPolicy } from "./read-output/continuation.js";
|
|
4
5
|
import { type PmReadOutputSessionReceipt, type PmReadOutputSessionState } from "./read-output-session.js";
|
|
5
6
|
/** Stable output dimensions shared by every read surface. */
|
|
6
7
|
export declare const PM_READ_OUTPUT_DIMENSIONS: readonly ["include", "amount", "cost", "encoding"];
|
|
@@ -61,6 +62,8 @@ export interface PmReadOutputSurfaceContract {
|
|
|
61
62
|
precedence: readonly ["canonical", "legacy", "intent", "default"];
|
|
62
63
|
/** Stable policy used before budget compaction selects retained rows. */
|
|
63
64
|
budget_retention_policy: "ordered_prefix" | "verdict_priority";
|
|
65
|
+
/** Exact command-local whole-result modes accepted by `outputInclude`. */
|
|
66
|
+
projection_modes?: readonly string[];
|
|
64
67
|
}
|
|
65
68
|
/** Source that selected an effective output dimension. */
|
|
66
69
|
export type PmReadOutputDimensionSource = "canonical" | "legacy" | "intent" | "default";
|
|
@@ -5,7 +5,7 @@
|
|
|
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]="d084da05-c967-58f1-afe4-069f09838e6f")}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, resolveReadOutputRecoveryBudget, updateReadOutputReceiptEstimate, } from "./read-output-budget.js";
|
|
@@ -13,7 +13,7 @@ export { resolveReadOutputRecoveryBudget } from "./read-output-budget.js";
|
|
|
13
13
|
import { resolvePmCommandOutputBudget } from "./cli-contracts/agent-output-contracts.js";
|
|
14
14
|
import { boundReadOutputRows, countReadOutputRows, mapReadOutputRows, readOutputBudgetCollections, readOutputContinuationRowCollections, readOutputRowPaths, } from "./read-output-rows.js";
|
|
15
15
|
import { applyReadOutputContinuation, decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, prioritizeAssuranceAssertions, readOutputCollectionFingerprint, } from "./read-output/continuation.js";
|
|
16
|
-
export { decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, } from "./read-output/continuation.js";
|
|
16
|
+
export { decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, PM_READ_OUTPUT_CONTINUATION_FINGERPRINT_POLICIES, readOutputCollectionFingerprint, } from "./read-output/continuation.js";
|
|
17
17
|
import { applyReadOutputSessionReferences, attachReadOutputSessionReceipt, parseReadOutputSession, readOutputSessionRemainingTokens, } from "./read-output-session.js";
|
|
18
18
|
import { decodeQueryCursorEnvelope, encodeQueryCursor } from "./pagination.js";
|
|
19
19
|
/** Stable output dimensions shared by every read surface. */
|
|
@@ -205,6 +205,9 @@ function buildSurfaceContract(command) {
|
|
|
205
205
|
dimensions,
|
|
206
206
|
precedence: READ_OUTPUT_PRECEDENCE,
|
|
207
207
|
budget_retention_policy: command === "assurance" ? "verdict_priority" : "ordered_prefix",
|
|
208
|
+
projection_modes: Object.freeze([
|
|
209
|
+
...readOutputIncludeModeOptions(command).keys(),
|
|
210
|
+
]),
|
|
208
211
|
});
|
|
209
212
|
}
|
|
210
213
|
/** Universal output contract for every built-in read surface. */
|
|
@@ -1092,7 +1095,7 @@ function rebaseBudgetCompactedCursor(projected, originalItemCount, cursorSource,
|
|
|
1092
1095
|
}
|
|
1093
1096
|
return true;
|
|
1094
1097
|
}
|
|
1095
|
-
function captureReadOutputContinuationState(projected, cursor, options) {
|
|
1098
|
+
function captureReadOutputContinuationState(projected, command, cursor, options) {
|
|
1096
1099
|
const collectionsBeforeBudget = new Map(readOutputContinuationRowCollections(projected).map((collection) => {
|
|
1097
1100
|
const rows = Array.isArray(collection.value)
|
|
1098
1101
|
? collection.value.length
|
|
@@ -1106,7 +1109,7 @@ function captureReadOutputContinuationState(projected, cursor, options) {
|
|
|
1106
1109
|
baseOffset: continued ? cursor.offset : 0,
|
|
1107
1110
|
fingerprint: continued
|
|
1108
1111
|
? cursor.fingerprint
|
|
1109
|
-
: readOutputCollectionFingerprint(collection.path, collection.value),
|
|
1112
|
+
: readOutputCollectionFingerprint(collection.path, collection.value, command),
|
|
1110
1113
|
},
|
|
1111
1114
|
];
|
|
1112
1115
|
}));
|
|
@@ -1154,7 +1157,7 @@ export function applyReadOutputDimensions(command, options, result) {
|
|
|
1154
1157
|
const continuationReadyResult = attachValidateDiagnosticRowContract(resolved.command, result);
|
|
1155
1158
|
const bindingBudget = resolveBindingReadOutputBudget(resolved, session);
|
|
1156
1159
|
let projected = projectReadOutputRows(continuationReadyResult, resolved, session, cursor);
|
|
1157
|
-
const continuationState = captureReadOutputContinuationState(projected, cursor, options);
|
|
1160
|
+
const continuationState = captureReadOutputContinuationState(projected, resolved.command, cursor, options);
|
|
1158
1161
|
const receipt = {
|
|
1159
1162
|
contract_version: 1,
|
|
1160
1163
|
command: resolved.command,
|
|
@@ -1207,4 +1210,4 @@ export function resolveReadOutputEncoding(command, options) {
|
|
|
1207
1210
|
: undefined;
|
|
1208
1211
|
}
|
|
1209
1212
|
//# sourceMappingURL=read-output-contracts.js.map
|
|
1210
|
-
//# debugId=
|
|
1213
|
+
//# debugId=d084da05-c967-58f1-afe4-069f09838e6f
|
|
@@ -13,7 +13,7 @@ export { type ActiveExtensionHookContext, type ExtensionCommandRegistry, type Ex
|
|
|
13
13
|
export { applyRegisteredItemFieldDefaultsAndValidation, collectRegisteredItemFieldNames, parseRegisteredItemFieldAssignments, } from "../core/extensions/item-fields.js";
|
|
14
14
|
export { resolveExtensionRoots } from "../core/extensions/loader.js";
|
|
15
15
|
export { resolveRegisteredSearchProvider, resolveRegisteredVectorStoreAdapter, } from "../core/extensions/runtime-registrations.js";
|
|
16
|
-
export { pathExists, readFileIfExists, removeFileIfExists, writeFileAtomic, } from "../core/fs/fs-utils.js";
|
|
16
|
+
export { isFileMissingError, pathExists, readFileIfExists, removeFileIfExists, writeFileAtomic, } from "../core/fs/fs-utils.js";
|
|
17
17
|
export { normalizeBulkIdsValue, parseBulkIdsText, resolveCliBulkIdsInput, type BulkIdsFileReader, type BulkIdsInputReaders, type BulkIdsStdinReader, type BulkIdsValue, } from "../core/io/bulk-ids-input.js";
|
|
18
18
|
export { type HistoryDiffValueEntry, computeHistoryDiff, patchPathToChangedField, } from "../core/history/history-diff.js";
|
|
19
19
|
export { enforceHistoryStreamPolicyForItem, enforceHistoryStreamPolicyForItems, } from "../core/history/history-stream-policy.js";
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* prefer the typed operations exported by the main SDK barrel.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
!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]="
|
|
10
|
+
!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]="4be36c51-a9fc-507d-8f13-d764b5668ab9")}catch(e){}}();
|
|
11
11
|
export { createCheckpointId, loadMutationCheckpoint, restoreCheckpointItems, writeMutationCheckpoint, } from "../core/checkpoint/mutation-checkpoint.js";
|
|
12
12
|
export { flattenFlagListValue, resolveFlagValueKind, } from "../core/extensions/flag-value-types.js";
|
|
13
13
|
export { createUnknownSubcommandError, } from "./agent/subcommand-recovery.js";
|
|
@@ -15,7 +15,7 @@ export { activateExtensions, clearActiveExtensionHooks, consumeAfterCommandAffec
|
|
|
15
15
|
export { applyRegisteredItemFieldDefaultsAndValidation, collectRegisteredItemFieldNames, parseRegisteredItemFieldAssignments, } from "../core/extensions/item-fields.js";
|
|
16
16
|
export { resolveExtensionRoots } from "../core/extensions/loader.js";
|
|
17
17
|
export { resolveRegisteredSearchProvider, resolveRegisteredVectorStoreAdapter, } from "../core/extensions/runtime-registrations.js";
|
|
18
|
-
export { pathExists, readFileIfExists, removeFileIfExists, writeFileAtomic, } from "../core/fs/fs-utils.js";
|
|
18
|
+
export { isFileMissingError, pathExists, readFileIfExists, removeFileIfExists, writeFileAtomic, } from "../core/fs/fs-utils.js";
|
|
19
19
|
export { normalizeBulkIdsValue, parseBulkIdsText, resolveCliBulkIdsInput, } from "../core/io/bulk-ids-input.js";
|
|
20
20
|
export { computeHistoryDiff, patchPathToChangedField, } from "../core/history/history-diff.js";
|
|
21
21
|
export { enforceHistoryStreamPolicyForItem, enforceHistoryStreamPolicyForItems, } from "../core/history/history-stream-policy.js";
|
|
@@ -82,4 +82,4 @@ export { maybeRunFirstUseTelemetryPrompt } from "../core/telemetry/consent.js";
|
|
|
82
82
|
export { deriveTelemetryCommandResolution, } from "../core/telemetry/observability.js";
|
|
83
83
|
export { emitTelemetryErrorEvent, finishTelemetryCommand, startTelemetryCommand, } from "../core/telemetry/runtime.js";
|
|
84
84
|
//# sourceMappingURL=runtime-primitives.js.map
|
|
85
|
-
//# debugId=
|
|
85
|
+
//# debugId=4be36c51-a9fc-507d-8f13-d764b5668ab9
|
|
@@ -220,6 +220,11 @@ declare function copyIntoSandboxIfPresent(sourcePath: string, targetPath: string
|
|
|
220
220
|
}) => Promise<unknown>): Promise<void>;
|
|
221
221
|
declare function seedLinkedTestSandbox(sandboxPmPath: string, sandboxGlobalPath: string, sourceRoots: LinkedTestSandboxSourceRoots): Promise<void>;
|
|
222
222
|
declare function seedLinkedTestTrackerData(sourceRoot: string, sandboxRoot: string): Promise<void>;
|
|
223
|
+
/**
|
|
224
|
+
* Create an audited settings snapshot only for source trackers that predate
|
|
225
|
+
* workspace history, while preserving any existing source history verbatim.
|
|
226
|
+
*/
|
|
227
|
+
declare function seedMissingLinkedTestSettingsHistory(sourceRoot: string, sandboxRoot: string): Promise<void>;
|
|
223
228
|
declare function countLinkedTestItemFiles(pmRoot: string): Promise<number>;
|
|
224
229
|
/** Implements resolve linked test failure exit code for the public runtime surface of this module. */
|
|
225
230
|
export declare function resolveLinkedTestFailureExitCode(execution: Pick<LinkedTestExecutionResult, "exitCode" | "timedOut" | "maxBufferExceeded">): number;
|
|
@@ -321,6 +326,7 @@ export declare const _testOnlyTestCommand: {
|
|
|
321
326
|
resolveTestRunOptions: typeof resolveTestRunOptions;
|
|
322
327
|
resolveTrackedRunId: typeof resolveTrackedRunId;
|
|
323
328
|
runLinkedTestCommand: typeof runLinkedTestCommand;
|
|
329
|
+
seedMissingLinkedTestSettingsHistory: typeof seedMissingLinkedTestSettingsHistory;
|
|
324
330
|
seedLinkedTestSandbox: typeof seedLinkedTestSandbox;
|
|
325
331
|
seedLinkedTestTrackerData: typeof seedLinkedTestTrackerData;
|
|
326
332
|
segmentInvokesRecursiveTestAll: typeof segmentInvokesRecursiveTestAll;
|
|
@@ -4,14 +4,15 @@
|
|
|
4
4
|
* Implements the pm test command surface and its agent-facing runtime behavior.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!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]="
|
|
7
|
+
!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]="99ce92bb-ed45-5327-b148-b5bb26a0bf05")}catch(e){}}();
|
|
8
8
|
import { assertInitializedTracker } from "../environment/tracker-preflight.js";
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
10
|
import { cp, mkdir, mkdtemp, open, readdir, rm, symlink, } from "node:fs/promises";
|
|
11
11
|
import { tmpdir } from "node:os";
|
|
12
12
|
import path from "node:path";
|
|
13
13
|
import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
|
|
14
|
-
import { isFileMissingError, pathExists } from "../../core/fs/fs-utils.js";
|
|
14
|
+
import { isFileMissingError, pathExists, readFileIfExists, } from "../../core/fs/fs-utils.js";
|
|
15
|
+
import { getWorkspaceHistoryPath, writeWorkspaceJsonWithHistory, } from "../../core/history/workspace-history.js";
|
|
15
16
|
import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
|
|
16
17
|
import { createStdinTokenResolver, parseCsvKv, parseOptionalNumber, } from "../../core/item/parse.js";
|
|
17
18
|
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
@@ -1043,6 +1044,31 @@ async function seedLinkedTestTrackerData(sourceRoot, sandboxRoot) {
|
|
|
1043
1044
|
}
|
|
1044
1045
|
}
|
|
1045
1046
|
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Create an audited settings snapshot only for source trackers that predate
|
|
1049
|
+
* workspace history, while preserving any existing source history verbatim.
|
|
1050
|
+
*/
|
|
1051
|
+
async function seedMissingLinkedTestSettingsHistory(sourceRoot, sandboxRoot) {
|
|
1052
|
+
const sourceSettingsRaw = await readFileIfExists(getSettingsPath(sourceRoot));
|
|
1053
|
+
if (sourceSettingsRaw === null ||
|
|
1054
|
+
(await pathExists(getWorkspaceHistoryPath(sourceRoot)))) {
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
const sandboxSettings = await readSettings(sandboxRoot);
|
|
1058
|
+
await rm(getWorkspaceHistoryPath(sandboxRoot), { force: true });
|
|
1059
|
+
await rm(getSettingsPath(sandboxRoot), { force: true });
|
|
1060
|
+
await writeWorkspaceJsonWithHistory({
|
|
1061
|
+
pmRoot: sandboxRoot,
|
|
1062
|
+
filePath: getSettingsPath(sandboxRoot),
|
|
1063
|
+
raw: sourceSettingsRaw,
|
|
1064
|
+
op: "settings:write",
|
|
1065
|
+
author: resolveAuthor(undefined, sandboxSettings.author_default),
|
|
1066
|
+
lockTtlSeconds: sandboxSettings.locks.ttl_seconds,
|
|
1067
|
+
lockWaitMs: sandboxSettings.locks.wait_ms,
|
|
1068
|
+
recordCreation: true,
|
|
1069
|
+
message: "Seed linked-test tracker settings history",
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1046
1072
|
async function countLinkedTestItemFiles(pmRoot) {
|
|
1047
1073
|
if (!(await pathExists(pmRoot))) {
|
|
1048
1074
|
return 0;
|
|
@@ -1339,6 +1365,8 @@ async function seedLinkedTestSandboxesFromSource(layout, sourceRoots, includeTra
|
|
|
1339
1365
|
await seedLinkedTestSandbox(layout.trackerProjectPmPath, layout.trackerGlobalPmPath, sourceRoots);
|
|
1340
1366
|
await seedLinkedTestTrackerData(sourceRoots.projectPmRoot, layout.trackerProjectPmPath);
|
|
1341
1367
|
await seedLinkedTestTrackerData(sourceRoots.globalPmRoot, layout.trackerGlobalPmPath);
|
|
1368
|
+
await seedMissingLinkedTestSettingsHistory(sourceRoots.projectPmRoot, layout.trackerProjectPmPath);
|
|
1369
|
+
await seedMissingLinkedTestSettingsHistory(sourceRoots.globalPmRoot, layout.trackerGlobalPmPath);
|
|
1342
1370
|
}
|
|
1343
1371
|
function linkedTestsRequireTrackerData(tests, runLevelPmContextMode, options) {
|
|
1344
1372
|
return tests.some((linkedTest) => {
|
|
@@ -2124,6 +2152,7 @@ export const _testOnlyTestCommand = {
|
|
|
2124
2152
|
resolveTestRunOptions,
|
|
2125
2153
|
resolveTrackedRunId,
|
|
2126
2154
|
runLinkedTestCommand,
|
|
2155
|
+
seedMissingLinkedTestSettingsHistory,
|
|
2127
2156
|
seedLinkedTestSandbox,
|
|
2128
2157
|
seedLinkedTestTrackerData,
|
|
2129
2158
|
segmentInvokesRecursiveTestAll,
|
|
@@ -2131,4 +2160,4 @@ export const _testOnlyTestCommand = {
|
|
|
2131
2160
|
summarizeRunResultStatuses,
|
|
2132
2161
|
};
|
|
2133
2162
|
//# sourceMappingURL=execution.js.map
|
|
2134
|
-
//# debugId=
|
|
2163
|
+
//# debugId=99ce92bb-ed45-5327-b148-b5bb26a0bf05
|
|
@@ -80,11 +80,13 @@ All new history fields are optional. Readers must accept:
|
|
|
80
80
|
- explicit `model: null`, `effort: null`, or `role: null` observations meaning
|
|
81
81
|
the dimension was declared but unavailable for a detected harness.
|
|
82
82
|
|
|
83
|
-
MCP clients may supply a bounded
|
|
83
|
+
Modern MCP clients may supply a bounded
|
|
84
|
+
`io.modelcontextprotocol/clientInfo.provenance` map in each request's `_meta`.
|
|
84
85
|
The server retains only valid dimension names and trimmed values, then resolves
|
|
85
|
-
that map inside the invocation-scoped identity context for
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
that map inside the invocation-scoped identity context for that request. The
|
|
87
|
+
bounded `2025-06-18` adapter accepts the same map during legacy `initialize`.
|
|
88
|
+
A missing MCP signal is recorded as explicit `null`; it is never confused with
|
|
89
|
+
a legacy entry that predates the dimension.
|
|
88
90
|
|
|
89
91
|
Unknown provenance dimensions are preserved as data and do not change author
|
|
90
92
|
resolution. Removing a dimension from a descriptor never rewrites existing
|
|
@@ -156,11 +156,12 @@ author literals at read time; every row reports `harness_source` and
|
|
|
156
156
|
`vocabulary_version`, and unresolved literals remain visible in the bounded
|
|
157
157
|
summary. No history entry is rewritten.
|
|
158
158
|
|
|
159
|
-
MCP
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
159
|
+
MCP 2026-07-28 reads `io.modelcontextprotocol/clientInfo` independently from
|
|
160
|
+
every request's `_meta` and scopes only that request to the client signal. The
|
|
161
|
+
bounded legacy adapter still reads `clientInfo` during `2025-06-18`
|
|
162
|
+
`initialize`. Optional host-provided `model`, `session`, `provenance`, and
|
|
163
|
+
`episode` fields are supported, but version is not misclassified as a model or
|
|
164
|
+
session. Provenance keys must use the bounded
|
|
164
165
|
lowercase dimension vocabulary; blank, malformed, and oversized data is
|
|
165
166
|
discarded before mutation context is created. See
|
|
166
167
|
[Agent Provenance ADR Amendment](AGENT_PROVENANCE_ADR.md) for precedence,
|
|
@@ -73,9 +73,10 @@ Add to the project's `.mcp.json`:
|
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
The repo root `.mcp.json` uses this approach and activates automatically when
|
|
76
|
-
Claude Code opens this repository.
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
Claude Code opens this repository. Under MCP `2026-07-28`, every request carries
|
|
77
|
+
the protocol version, client capabilities, and client identity in `_meta`, so
|
|
78
|
+
pm's bounded identity detector does not depend on session state and normal
|
|
79
|
+
agent mutations do not need a hard-wired `PM_AUTHOR`.
|
|
79
80
|
|
|
80
81
|
## MCP Server Launcher
|
|
81
82
|
|
|
@@ -115,7 +116,10 @@ node scripts/smoke-claude-plugin.mjs
|
|
|
115
116
|
pnpm smoke:claude-plugin
|
|
116
117
|
```
|
|
117
118
|
|
|
118
|
-
Verifies: plugin file structure, manifest name consistency, MCP
|
|
119
|
+
Verifies: plugin file structure, manifest name consistency, stateless MCP
|
|
120
|
+
discovery for `2026-07-28`, 31 tools present, full workflow (init → create →
|
|
121
|
+
claim → update → link files/docs/tests → get → context → search → validate →
|
|
122
|
+
health), and session-start hook.
|
|
119
123
|
|
|
120
124
|
### MCP server smoke test
|
|
121
125
|
|
|
@@ -182,7 +186,10 @@ After installing the plugin:
|
|
|
182
186
|
|
|
183
187
|
The authoritative plugin version is `plugins/pm-claude/.claude-plugin/plugin.json`; this row stays on the `1.x` major line so it does not drift with each plugin release.
|
|
184
188
|
|
|
185
|
-
The MCP server uses JSON-RPC 2.0 over stdio with protocol version
|
|
189
|
+
The MCP server uses JSON-RPC 2.0 over stdio with canonical protocol version
|
|
190
|
+
`2026-07-28`. A bounded legacy path remains for unversioned older hosts, with
|
|
191
|
+
`2025-06-18` initialize available to enrich client identity; current hosts
|
|
192
|
+
discover the server and send metadata on every request.
|
|
186
193
|
|
|
187
194
|
## Extension Policy Diagnostics
|
|
188
195
|
|
|
@@ -103,6 +103,14 @@ refusal; schema, items, history, settings, and package state must not change.
|
|
|
103
103
|
Ephemeral runtime lock/cache directories are excluded from that semantic
|
|
104
104
|
snapshot.
|
|
105
105
|
|
|
106
|
+
The complete error-code census currently retains executable evidence for 18
|
|
107
|
+
catalog rows across 17 canonical groups. Two of those rows are author-manifest
|
|
108
|
+
schema findings reached through a real `pm health --full --strict-exit --json`
|
|
109
|
+
process: an unknown top-level key and omitted canonical pm version bounds. The
|
|
110
|
+
remaining rows stay explicit `uncovered` obligations in
|
|
111
|
+
[the generated census](generated/REFUSAL_CLOSURE_CENSUS.md); the ratchet does not
|
|
112
|
+
turn partial catalog closure into an approval claim.
|
|
113
|
+
|
|
106
114
|
Run the focused proof with:
|
|
107
115
|
|
|
108
116
|
```bash
|
package/docs/EXTENSIONS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Packages and Extensions
|
|
2
2
|
|
|
3
|
-
Extension flags declared with `list: true` accumulate repeated long/short alias occurrences and comma-separated values into one array. Dynamic commands preserve flag-like variadic content after `--`, and package handlers can use the public `suppressHostOutput()` protocol when they already emitted streaming, binary, or pre-rendered output. Declarative blueprints are also checked for reserved item-field collisions during SDK lint/preflight and harness activation, so a package cannot pass author-time validation and then fail only when users create or update items. Local archive installation, command ownership,
|
|
3
|
+
Extension flags declared with `list: true` accumulate repeated long/short alias occurrences and comma-separated values into one array. Dynamic commands preserve flag-like variadic content after `--`, and package handlers can use the public `suppressHostOutput()` protocol when they already emitted streaming, binary, or pre-rendered output. Declarative blueprints are also checked for reserved item-field collisions during SDK lint/preflight and harness activation, so a package cannot pass author-time validation and then fail only when users create or update items. Local archive installation, command ownership, MCP custom-field diagnostics, and author-manifest schema diagnostics are tracked by [pm-lw6acw](../.agents/pm/issues/pm-lw6acw.toon), [pm-6z0wzf](../.agents/pm/issues/pm-6z0wzf.toon), [pm-yfdav2](../.agents/pm/issues/pm-yfdav2.toon), and [pm-gh1091](../.agents/pm/issues/pm-gh1091.toon). Transactional mutation guards, host-bound command test SDKs, and installed custom-type lifecycle parity are tracked by [pm-hx23u5](../.agents/pm/issues/pm-hx23u5.toon), [pm-wx2lr5](../.agents/pm/issues/pm-wx2lr5.toon), and [pm-scga6k](../.agents/pm/issues/pm-scga6k.toon). Durable migration application, explicit source resolution, and composable preflight ownership are covered in [Extension Lifecycle Contracts](EXTENSION_LIFECYCLE.md).
|
|
4
4
|
|
|
5
5
|
Packages add optional `pm` workflows without changing the core CLI. A package can ship one or more runtime extensions plus metadata such as docs and examples. Prefer the package-first commands in new docs and automation:
|
|
6
6
|
|
|
@@ -191,10 +191,9 @@ useful for agents without inflating context or leaking private item content.
|
|
|
191
191
|
|
|
192
192
|
Runnable manifest examples are the source of truth: [starter extension manifest](examples/starter-extension/manifest.json) and [policy-restricted manifest](examples/policy-restricted-extension/manifest.json).
|
|
193
193
|
|
|
194
|
-
Use [extension-manifest.schema.json](schemas/extension-manifest.schema.json) as the `$schema` value for inline editor validation. The loader ignores `$schema` and tolerates future manifest fields, but the schema documents the fields pm reads.
|
|
195
|
-
|
|
196
|
-
Rules:
|
|
194
|
+
Use [extension-manifest.schema.json](schemas/extension-manifest.schema.json) as the `$schema` value for inline editor validation. The loader ignores `$schema` and tolerates future manifest fields, but the schema documents the fields pm reads. Rules:
|
|
197
195
|
|
|
196
|
+
- `manifest.json` is the runtime declaration; package catalog metadata belongs in `package.json#pm`, and a top-level `compatibility` object is ignored. Use the public `inspectExtensionManifestSchema` / `lintExtensionManifestSchema` helpers for schema-only checks. In author workspaces, `pm health --full`, `pm package doctor`, and `pm extension --doctor` expose the same read-only `author_manifest` findings without activating the extension.
|
|
198
197
|
- `entry` must resolve inside the extension directory.
|
|
199
198
|
- `manifest_version` is an optional integer identifying the manifest schema generation. Runtime contracts currently support manifest versions `1` and `2`, and first-party runnable examples use `2`. First-party packages declare it; the manifest governance test requires it on every first-party package.
|
|
200
199
|
- `pm_min_version` is an inclusive minimum pm CLI version. If the running CLI is older, discovery emits `extension_pm_min_version_unmet:<layer>:<name>:required=<version>:current=<version>` and skips the extension before import.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# MCP 2026-07-28 Protocol and Compatibility Decision
|
|
2
|
+
|
|
3
|
+
Tracker references: [pm-sqvshj](../.agents/pm/decisions/pm-sqvshj.toon),
|
|
4
|
+
[pm-vae5ec](../.agents/pm/features/pm-vae5ec.toon), and
|
|
5
|
+
[pm-55yf1t](../.agents/pm/tasks/pm-55yf1t.toon). MRTR, durable tasks,
|
|
6
|
+
and the cache/schema surface are tracked by
|
|
7
|
+
[pm-rz9gep](../.agents/pm/features/pm-rz9gep.toon),
|
|
8
|
+
[pm-rzs24j](../.agents/pm/features/pm-rzs24j.toon), and
|
|
9
|
+
[pm-hv1x1x](../.agents/pm/features/pm-hv1x1x.toon). Subscriptions,
|
|
10
|
+
Streamable HTTP, remote authorization, and the deprecation ratchet are tracked
|
|
11
|
+
by [pm-v7e337](../.agents/pm/features/pm-v7e337.toon),
|
|
12
|
+
[pm-3zh9s4](../.agents/pm/features/pm-3zh9s4.toon), and
|
|
13
|
+
[pm-vzcisw](../.agents/pm/chores/pm-vzcisw.toon).
|
|
14
|
+
|
|
15
|
+
Status: accepted. MCP `2026-07-28` is pm's canonical protocol revision.
|
|
16
|
+
|
|
17
|
+
## Decision
|
|
18
|
+
|
|
19
|
+
The public pm SDK owns protocol versions, request metadata validation,
|
|
20
|
+
capability checks, discovery, result envelopes, error codes, HTTP header
|
|
21
|
+
parity, subscriptions, authorization boundaries, trace isolation, and legacy
|
|
22
|
+
result interpretation. `pm-mcp` is a JSON-RPC/stdio adapter over those
|
|
23
|
+
contracts; `pm-mcp-http` binds the same dispatcher to sessionless Streamable
|
|
24
|
+
HTTP POST.
|
|
25
|
+
|
|
26
|
+
Modern requests are stateless. Every request carries:
|
|
27
|
+
|
|
28
|
+
- `io.modelcontextprotocol/protocolVersion` = `2026-07-28`;
|
|
29
|
+
- `io.modelcontextprotocol/clientCapabilities` as an object, including `{}`;
|
|
30
|
+
- optional `io.modelcontextprotocol/clientInfo` with `name` and `version`.
|
|
31
|
+
|
|
32
|
+
Every modern result carries an explicit `resultType` (`complete`,
|
|
33
|
+
`input_required`, or `task`) and `io.modelcontextprotocol/serverInfo` in
|
|
34
|
+
result `_meta`. The mandatory
|
|
35
|
+
`server/discover` method returns the supported modern revisions, deterministic
|
|
36
|
+
capabilities, public cache policy, server identity, and bounded instructions.
|
|
37
|
+
No modern request reads identity, capabilities, or version from a previous
|
|
38
|
+
request.
|
|
39
|
+
|
|
40
|
+
## Legacy boundary
|
|
41
|
+
|
|
42
|
+
The sole supported legacy revision is `2025-06-18`, accepted through the
|
|
43
|
+
existing stdio adapter. Unversioned requests stay on this legacy path because
|
|
44
|
+
they cannot claim the current revision; `initialize` enriches their client
|
|
45
|
+
identity but is not required for compatibility with older pm hosts. The
|
|
46
|
+
adapter has no session id, does not affect modern requests, and is excluded
|
|
47
|
+
from `server/discover`'s `supportedVersions` because it cannot be selected
|
|
48
|
+
through modern per-request metadata.
|
|
49
|
+
|
|
50
|
+
The adapter is scheduled for removal only after published-client telemetry and
|
|
51
|
+
release probes show no required legacy consumers for two consecutive release
|
|
52
|
+
windows. Removal is a reviewed compatibility change, never a history rewrite.
|
|
53
|
+
|
|
54
|
+
## Transport behavior
|
|
55
|
+
|
|
56
|
+
- Stdio modern clients call `server/discover` with current request metadata,
|
|
57
|
+
then send the same version and capability keys on every request.
|
|
58
|
+
- Stdio legacy clients retain their existing response shapes and may use
|
|
59
|
+
`initialize` with `2025-06-18` to supply client identity.
|
|
60
|
+
- Streamable HTTP requires `MCP-Protocol-Version` and `Mcp-Method` on every
|
|
61
|
+
request. `Mcp-Name` is required only for `prompts/get`, `resources/read`, and
|
|
62
|
+
`tools/call`; other methods omit it. Schema-declared `x-mcp-header` values are
|
|
63
|
+
encoded, decoded, and compared with tool arguments before dispatch.
|
|
64
|
+
Header/version mismatch uses code `-32020` and HTTP 400.
|
|
65
|
+
- `subscriptions/listen` is a request-scoped stdio or SSE stream. The first
|
|
66
|
+
message acknowledges the supported filter; later messages carry its request
|
|
67
|
+
id as `io.modelcontextprotocol/subscriptionId`. Disconnect deletes the
|
|
68
|
+
subscription and a caller retries lost work with a new request id.
|
|
69
|
+
- The remote adapter defaults to loopback, enforces exact browser origins,
|
|
70
|
+
bounds bodies, maps parse/invalid requests to HTTP 400, and can require an
|
|
71
|
+
issuer-, audience-, and scope-bound bearer token.
|
|
72
|
+
- Unsupported modern versions return `-32022` plus the exact supported modern
|
|
73
|
+
list. Missing required capabilities return `-32021` with a structured
|
|
74
|
+
capability map. Malformed metadata uses JSON-RPC Invalid Params `-32602`.
|
|
75
|
+
|
|
76
|
+
## Removed, migrated, and deprecated behavior
|
|
77
|
+
|
|
78
|
+
| Prior behavior | Disposition |
|
|
79
|
+
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
80
|
+
| `initialize` and `notifications/initialized` | Legacy stdio adapter only; absent from modern behavior. |
|
|
81
|
+
| `Mcp-Session-Id` and protocol sessions | Removed; explicit application handles are ordinary arguments. |
|
|
82
|
+
| `ping` | Legacy adapter only; modern calls return Method Not Found. |
|
|
83
|
+
| `resources/subscribe` and `resources/unsubscribe` | Replaced by the implemented `subscriptions/listen` filter. |
|
|
84
|
+
| SSE event ids and `Last-Event-ID` replay | Removed; callers retry with a new request id. |
|
|
85
|
+
| Reverse `roots/list`, sampling, and elicitation requests | Migrate to MRTR `input_required` under `pm-rz9gep`. |
|
|
86
|
+
| Core tasks | Migrate to `io.modelcontextprotocol/tasks` under `pm-rzs24j`. |
|
|
87
|
+
| `logging/setLevel` | Removed; optional request-local log metadata is never shared, and remote operations use host OpenTelemetry. |
|
|
88
|
+
| Roots, Sampling, Logging, HTTP+SSE, and non-none `includeContext` | Retain only in bounded legacy compatibility while `pm-vzcisw` drives deprecation removal. |
|
|
89
|
+
| Dynamic Client Registration | Legacy authorization fallback; Client ID Metadata Documents are canonical under `pm-3zh9s4`. |
|
|
90
|
+
|
|
91
|
+
## Rollout, rollback, and proof
|
|
92
|
+
|
|
93
|
+
Local and hosted gates must prove SDK primitives, direct server calls, real
|
|
94
|
+
stdio, packed artifacts, npx, bunx, and published artifacts agree on discovery
|
|
95
|
+
and the canonical revision. Negative controls cover unsupported versions,
|
|
96
|
+
missing/malformed metadata, missing capabilities, header mismatch, removed
|
|
97
|
+
methods, and omitted modern `resultType`.
|
|
98
|
+
|
|
99
|
+
Rollback preserves the SDK contract and re-enables only the reviewed legacy
|
|
100
|
+
adapter. It must never reintroduce session ids or make modern behavior depend
|
|
101
|
+
on initialization. Release evidence records exact source, package, tag, and
|
|
102
|
+
consumer revisions separately.
|
|
103
|
+
|
|
104
|
+
## MRTR, tasks, and cache behavior
|
|
105
|
+
|
|
106
|
+
An SDK handler that cannot finish without host input throws
|
|
107
|
+
`PmMcpInputRequiredError`. The modern adapter validates the requested
|
|
108
|
+
`elicitation/create`, `roots/list`, or `sampling/createMessage` capability and
|
|
109
|
+
returns `resultType: "input_required"`. Continuation state can be bounded,
|
|
110
|
+
HMAC-sealed, expiry-bound, method-bound, parameter-bound, principal-bound, and
|
|
111
|
+
protected from in-process replay with the public interaction helpers. Retry
|
|
112
|
+
payloads arrive as request-local `inputResponses`; they never depend on a
|
|
113
|
+
protocol session.
|
|
114
|
+
|
|
115
|
+
Clients negotiate `io.modelcontextprotocol/tasks` in request capabilities.
|
|
116
|
+
Eligible long-running `tools/call` operations can then return a durable task
|
|
117
|
+
handle. `tasks/get`, `tasks/update`, and `tasks/cancel` are principal-scoped,
|
|
118
|
+
persist records atomically under the ignored tracker runtime area, enforce
|
|
119
|
+
immutable terminal states, expire abandoned work deterministically, and turn
|
|
120
|
+
a disappeared worker into an actionable terminal failure. Task state remains
|
|
121
|
+
retrieved through the task methods. Change subscriptions do not become
|
|
122
|
+
task-progress channels, and pm's current handlers do not emit request progress
|
|
123
|
+
or deprecated log-message notifications.
|
|
124
|
+
|
|
125
|
+
Modern tool, resource, resource-template, and prompt list/read results carry
|
|
126
|
+
explicit `ttlMs` and `cacheScope`. Tool schemas are validated as bounded JSON
|
|
127
|
+
Schema 2020-12 documents before advertisement. Tool and resource data stay
|
|
128
|
+
private; public metadata lists may be cached for their advertised lifetime.
|
|
129
|
+
|
|
130
|
+
## Public SDK
|
|
131
|
+
|
|
132
|
+
Use `PM_MCP_PROTOCOL_VERSION`, `resolveMcpRequestContext()`,
|
|
133
|
+
`buildMcpDiscoverResult()`, `buildMcpCompleteResult()`,
|
|
134
|
+
`PmMcpSubscriptionRegistry`, `buildMcpHttpRequestHeaders()`,
|
|
135
|
+
`validateMcpHttpRequestHeaders()`, `buildMcpProtectedResourceMetadata()`, and
|
|
136
|
+
the issuer/trace authorization helpers from `@unbrained/pm-cli/sdk`. See
|
|
137
|
+
[MCP interaction and task SDK](SDK_MCP_INTERACTIONS.md) and
|
|
138
|
+
[remote transport, authorization, and migration](MCP_REMOTE_TRANSPORT_SECURITY.md).
|