@unbrained/pm-cli 2026.8.22 → 2026.8.24
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 +42 -1
- package/dist/cli/description-stdin.js +5 -4
- package/dist/cli/error-guidance.d.ts +13 -0
- package/dist/cli/error-guidance.js +62 -6
- package/dist/cli/extension-command-help.d.ts +5 -0
- package/dist/cli/extension-command-help.js +6 -2
- package/dist/cli/help-content.d.ts +5 -0
- package/dist/cli/help-content.js +56 -3
- package/dist/cli/help-json-payload.d.ts +5 -2
- package/dist/cli/help-json-payload.js +57 -17
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.js +39 -5
- package/dist/cli/register-annotations.js +5 -5
- package/dist/cli/register-mutation.js +77 -31
- package/dist/cli/register-operations.d.ts +73 -0
- package/dist/cli/register-operations.js +39 -14
- package/dist/cli/register-setup.js +3 -3
- package/dist/cli/schema-registration-helpers.d.ts +8 -1
- package/dist/cli/schema-registration-helpers.js +14 -5
- package/dist/cli-bundle/bundle-manifest.json +155 -155
- package/dist/cli-bundle/chunks/chunk-AGUL3HUT.js +3 -0
- package/dist/cli-bundle/chunks/{chunk-WG4STC36.js → chunk-DJNJBWAQ.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-MYYI3ZOA.js → chunk-I5Q7QSZX.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-IW72J5FW.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-BWX4SK46.js → chunk-L22NP5MA.js} +66 -66
- package/dist/cli-bundle/chunks/chunk-MKE6MD2K.js +36 -0
- package/dist/cli-bundle/chunks/{chunk-MZTZQTMS.js → chunk-NXBFO63A.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-TEQDR5KI.js +202 -0
- package/dist/cli-bundle/chunks/chunk-X7WWQDYQ.js +2 -0
- package/dist/cli-bundle/chunks/chunk-YOLLRCLY.js +13 -0
- package/dist/cli-bundle/chunks/{chunk-U6GQ4VMV.js → chunk-ZAVCS2GH.js} +4 -4
- package/dist/cli-bundle/chunks/{register-list-query-HZKBQNWW.js → register-list-query-37A4P6O4.js} +2 -2
- package/dist/cli-bundle/chunks/register-mutation-TBJDHYIT.js +20 -0
- package/dist/cli-bundle/chunks/register-operations-WRZNEBUM.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-QK4OTOXN.js → register-setup-H4PDLACD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-GMYPD4FX.js → chunk-4WP7LNE3.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-6MUTDXMP.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-6Z24ZMU3.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-2ARQGDDW.js → chunk-BFA6KKCI.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-CWCN5RLO.js +26 -0
- package/dist/cli-bundle/focused-chunks/chunk-FCTT4CZU.js +5 -0
- package/dist/cli-bundle/focused-chunks/chunk-GJR6YEMR.js +156 -0
- package/dist/cli-bundle/focused-chunks/{chunk-2POVTNLY.js → chunk-IMWTYKII.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-D6RBZEJJ.js → chunk-IZNRRCU3.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-PMGJUFNQ.js → chunk-MNPECIRL.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-A2BC5PQL.js → chunk-O4ZXNJMT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-Q63PSLO4.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-QBP5FSBX.js +4 -0
- package/dist/cli-bundle/focused-chunks/{chunk-R6SR45XU.js → chunk-QV5UP27O.js} +48 -47
- package/dist/cli-bundle/focused-chunks/chunk-RASVBJX5.js +8 -0
- package/dist/cli-bundle/focused-chunks/{chunk-E2EWYPY6.js → chunk-RPRLENVA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-TOFVXBWA.js +19 -0
- package/dist/cli-bundle/focused-chunks/{chunk-6S2MO3Q3.js → chunk-WZLSSGEU.js} +2 -2
- package/dist/cli-bundle/main.js +18 -17
- 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 +33 -32
- 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 +6 -5
- package/dist/core/config/nested-settings.js +8 -2
- package/dist/core/config/positional-value.d.ts +1 -1
- package/dist/core/config/positional-value.js +5 -2
- package/dist/core/extensions/command-metadata-contract.d.ts +10 -0
- package/dist/core/extensions/command-metadata-contract.js +23 -0
- package/dist/core/extensions/command-visibility-tier.js +12 -2
- package/dist/core/extensions/extension-types.d.ts +6 -0
- package/dist/core/extensions/extension-types.js +2 -2
- package/dist/core/extensions/loader.js +4 -3
- package/dist/core/history/history.js +3 -3
- package/dist/core/io/body-file.js +7 -2
- package/dist/core/io/bulk-ids-input.d.ts +24 -0
- package/dist/core/io/bulk-ids-input.js +113 -0
- package/dist/core/item/item-format.js +66 -12
- package/dist/core/item/parse.d.ts +22 -2
- package/dist/core/item/parse.js +97 -4
- package/dist/core/reproducibility/context.d.ts +4 -0
- package/dist/core/reproducibility/context.js +14 -8
- package/dist/core/shared/author.d.ts +55 -1
- package/dist/core/shared/author.js +333 -16
- package/dist/core/shared/constants.js +3 -2
- package/dist/core/store/settings-validator.d.ts +1 -0
- package/dist/core/store/settings-validator.js +6 -3
- package/dist/core/store/settings.js +5 -2
- package/dist/mcp/server.d.ts +4 -3
- package/dist/mcp/server.js +44 -16
- package/dist/sdk/agent/identity-config.d.ts +63 -0
- package/dist/sdk/agent/identity-config.js +107 -0
- package/dist/sdk/agent/refusal-closure-census.d.ts +66 -0
- package/dist/sdk/agent/refusal-closure-census.js +144 -0
- package/dist/sdk/agent/refusal-corpus-contracts.d.ts +76 -0
- package/dist/sdk/agent/refusal-corpus-contracts.js +194 -0
- package/dist/sdk/agent-capability-contracts.d.ts +34 -1
- package/dist/sdk/agent-capability-contracts.js +104 -6
- package/dist/sdk/annotations.d.ts +2 -0
- package/dist/sdk/annotations.js +25 -7
- package/dist/sdk/cli-contracts/agent-output-contracts.js +6 -4
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +4 -0
- package/dist/sdk/cli-contracts/enum-contracts.js +9 -2
- package/dist/sdk/cli-contracts/flag-contracts.js +9 -2
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +4 -4
- package/dist/sdk/cli-contracts/registration-helpers.js +5 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +58 -2
- package/dist/sdk/cli-contracts/tool-schema.d.ts +1 -1
- package/dist/sdk/cli-contracts/tool-schema.js +14 -3
- package/dist/sdk/cli-contracts/typed-action-inputs.d.ts +4 -1
- package/dist/sdk/cli-contracts/typed-action-inputs.js +2 -2
- package/dist/sdk/cli-contracts.d.ts +3 -3
- package/dist/sdk/cli-contracts.js +4 -4
- package/dist/sdk/comments.js +15 -7
- package/dist/sdk/config.d.ts +6 -1
- package/dist/sdk/config.js +119 -14
- package/dist/sdk/context-intent-contracts.js +4 -2
- package/dist/sdk/core-governance.d.ts +1 -1
- package/dist/sdk/core-governance.js +3 -3
- package/dist/sdk/extension/scaffold.js +11 -5
- package/dist/sdk/flag-invocation-contracts.d.ts +2 -0
- package/dist/sdk/flag-invocation-contracts.js +30 -3
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +83 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +87 -2
- package/dist/sdk/governance/assurance-action.js +30 -10
- package/dist/sdk/governance/validate.d.ts +2 -2
- package/dist/sdk/governance/validate.js +39 -14
- package/dist/sdk/guide-topics.d.ts +0 -5
- package/dist/sdk/guide-topics.js +28 -2
- package/dist/sdk/history-compact.d.ts +2 -1
- package/dist/sdk/history-compact.js +24 -5
- package/dist/sdk/history-mcp.js +11 -10
- package/dist/sdk/index.d.ts +8 -2
- package/dist/sdk/index.js +9 -3
- package/dist/sdk/item-transaction.js +19 -12
- package/dist/sdk/lifecycle/append.js +4 -4
- package/dist/sdk/lifecycle/close-many.js +16 -7
- package/dist/sdk/lifecycle/create.js +33 -22
- package/dist/sdk/lifecycle/plan.js +24 -6
- package/dist/sdk/lifecycle/update-many.js +15 -8
- package/dist/sdk/lifecycle/update.d.ts +2 -0
- package/dist/sdk/lifecycle/update.js +37 -25
- package/dist/sdk/merge/three-way.js +105 -26
- package/dist/sdk/read-output-budget.d.ts +21 -0
- package/dist/sdk/read-output-budget.js +39 -2
- package/dist/sdk/read-output-contracts.d.ts +5 -3
- package/dist/sdk/read-output-contracts.js +20 -12
- package/dist/sdk/reproducibility/process.d.ts +19 -0
- package/dist/sdk/reproducibility/process.js +88 -0
- package/dist/sdk/runtime-extended-actions.js +5 -3
- package/dist/sdk/runtime-input.d.ts +4 -0
- package/dist/sdk/runtime-input.js +98 -23
- package/dist/sdk/runtime-primitives.d.ts +3 -2
- package/dist/sdk/runtime-primitives.js +5 -4
- package/dist/sdk/runtime.js +11 -23
- package/dist/sdk/scheduling-shortcuts.js +5 -3
- package/dist/sdk/structured-mutations.js +10 -3
- package/dist/sdk/test/batch.d.ts +6 -0
- package/dist/sdk/test/batch.js +15 -3
- package/dist/sdk/test/entry.d.ts +1 -1
- package/dist/sdk/test/entry.js +3 -2
- package/dist/sdk/test/execution.d.ts +28 -3
- package/dist/sdk/test/execution.js +193 -34
- package/dist/sdk/test/parsers.d.ts +6 -0
- package/dist/sdk/test/parsers.js +21 -2
- package/dist/sdk/test/trust.d.ts +33 -0
- package/dist/sdk/test/trust.js +207 -0
- package/dist/sdk/workspace-contracts.d.ts +3 -0
- package/dist/sdk/workspace-contracts.js +3 -2
- package/dist/types.d.ts +23 -0
- package/dist/types.js +2 -2
- package/docs/AGENT_PROVENANCE_ADR.md +41 -5
- package/docs/CONFIGURATION.md +4 -0
- package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +19 -2
- package/docs/MERGE_SAFETY.md +15 -1
- package/docs/README.md +2 -0
- package/docs/READ_OUTPUT_CONTRACTS.md +11 -1
- package/docs/RELEASING.md +40 -21
- package/docs/REPRODUCIBLE_WORKSPACES.md +42 -8
- package/docs/SCRIPTING.md +62 -3
- package/docs/SDK.md +17 -0
- package/docs/SDK_AGENT_SESSION_CONTEXT.md +6 -4
- package/docs/SDK_EVIDENCE_TRACEABILITY.md +1 -1
- package/docs/TESTING.md +75 -8
- package/docs/agent-task-token-baseline.json +2 -2
- package/docs/generated/AGENT_CAPABILITY_ROUTING.md +17 -0
- package/docs/generated/AGENT_COMMAND_SURFACE.md +1 -1
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +2 -2
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +355 -0
- package/marketplace.json +2 -2
- package/package.json +2 -2
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/README.md +9 -11
- package/packages/pm-command-kit/extensions/command-kit/index.ts +3 -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/extensions/guide-shell/index.ts +10 -0
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/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/generate-agent-capability-surfaces.mjs +27 -1
- package/sdk/public-surface.json +642 -28
- package/dist/cli-bundle/chunks/chunk-EMWDM5FI.js +0 -13
- package/dist/cli-bundle/chunks/chunk-HYG6LRL4.js +0 -200
- package/dist/cli-bundle/chunks/chunk-QI2CT3IX.js +0 -2
- package/dist/cli-bundle/chunks/chunk-SMWXHMVB.js +0 -35
- package/dist/cli-bundle/chunks/chunk-VMMIL3SI.js +0 -2
- package/dist/cli-bundle/chunks/chunk-YBPJAOQQ.js +0 -3
- package/dist/cli-bundle/chunks/register-mutation-HTKEEGRD.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-6EMRWJJY.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-2AZT5WXZ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-3LKU6PTJ.js +0 -4
- package/dist/cli-bundle/focused-chunks/chunk-5SHSBMX2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-C4S4A4JJ.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-L5LDSRO2.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-MB37AYN6.js +0 -26
- package/dist/cli-bundle/focused-chunks/chunk-MCOR37QK.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-PH2OXXVZ.js +0 -18
- package/dist/cli-bundle/focused-chunks/chunk-WZE4LIPW.js +0 -8
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { GlobalOptions } from "../../core/shared/command-types.js";
|
|
2
2
|
import { resolveAuthor } from "../../core/shared/author.js";
|
|
3
3
|
import { runInit } from "../init.js";
|
|
4
|
-
import { type LinkedTestPmContextMode } from "./parsers.js";
|
|
4
|
+
import { type LinkedTestPmContextMode, type LinkedTestWorkspaceContextMode } from "./parsers.js";
|
|
5
5
|
import { type LinkedTestRunSelection } from "../../core/test/run-selectors.js";
|
|
6
6
|
import type { LinkedTest, LinkScope, TestRunMeasurement } from "../../types/index.js";
|
|
7
7
|
import { type TestRunMeasurementDiff } from "./measurements.js";
|
|
8
|
+
import { type LinkedTestTrustDecision } from "./trust.js";
|
|
8
9
|
type ResolvedLinkedTestPmContextMode = Exclude<LinkedTestPmContextMode, "auto">;
|
|
9
10
|
interface LinkedTestExecutionResult {
|
|
10
11
|
stdout: string;
|
|
@@ -61,6 +62,14 @@ export interface TestCommandOptions {
|
|
|
61
62
|
pmContext?: string;
|
|
62
63
|
/** Value that configures or reports override linked pm context for this contract. */
|
|
63
64
|
overrideLinkedPmContext?: boolean;
|
|
65
|
+
/** Source-workspace visibility and working-directory mode. */
|
|
66
|
+
workspaceContext?: string;
|
|
67
|
+
/** Force the run-level workspace mode over per-test metadata. */
|
|
68
|
+
overrideLinkedWorkspaceContext?: boolean;
|
|
69
|
+
/** Explicitly permit an untrusted linked command when project policy also permits it. */
|
|
70
|
+
allowUntrustedLinkedTests?: boolean;
|
|
71
|
+
/** Record clone-local acknowledgement for the item's current linked tests. */
|
|
72
|
+
acknowledgeLinkedTests?: boolean;
|
|
64
73
|
/** Value that configures or reports fail on context mismatch for this contract. */
|
|
65
74
|
failOnContextMismatch?: boolean;
|
|
66
75
|
/** Value that configures or reports fail on skipped for this contract. */
|
|
@@ -87,7 +96,7 @@ export interface TestCommandOptions {
|
|
|
87
96
|
metricDiff?: string;
|
|
88
97
|
}
|
|
89
98
|
/** Restricts linked test failure category values accepted by command, SDK, and storage contracts. */
|
|
90
|
-
export type LinkedTestFailureCategory = "infra_collision" | "assertion_failure" | "empty_run" | "timeout" | "max_buffer" | "spawn_error" | "signal";
|
|
99
|
+
export type LinkedTestFailureCategory = "infra_collision" | "trust_refusal" | "assertion_failure" | "empty_run" | "timeout" | "max_buffer" | "spawn_error" | "signal";
|
|
91
100
|
/** Documents the test run result payload exchanged by command, SDK, and package integrations. */
|
|
92
101
|
export interface TestRunResult {
|
|
93
102
|
/** Value that configures or reports command for this contract. */
|
|
@@ -118,6 +127,11 @@ export interface TestRunResult {
|
|
|
118
127
|
mismatch_detected: boolean;
|
|
119
128
|
project_extensions_seeded: boolean;
|
|
120
129
|
global_extensions_seeded: boolean;
|
|
130
|
+
requested_workspace_context_mode: LinkedTestWorkspaceContextMode;
|
|
131
|
+
workspace_context_mode: LinkedTestWorkspaceContextMode;
|
|
132
|
+
working_directory: string;
|
|
133
|
+
source_workspace_root: string;
|
|
134
|
+
trust: LinkedTestTrustDecision;
|
|
121
135
|
};
|
|
122
136
|
/** Value that configures or reports stdout for this contract. */
|
|
123
137
|
stdout?: string;
|
|
@@ -195,7 +209,7 @@ declare function segmentInvokesRecursiveTestAll(segment: string): boolean;
|
|
|
195
209
|
declare function parseLinkedTestTimeoutSeconds(timeoutSecondsRaw: string | undefined, timeoutAliasRaw: string | undefined): number | undefined;
|
|
196
210
|
declare function parseAddJsonEntries(raw: string[] | undefined): LinkedTest[];
|
|
197
211
|
declare function endLinkedTestProgress(context: LinkedTestProgressContext, executionResult: Pick<LinkedTestExecutionResult, "timedOut" | "maxBufferExceeded" | "outputTruncated" | "exitCode" | "signal">, startedAt: number, mode: LinkedTestProgressMode): void;
|
|
198
|
-
declare function runLinkedTestCommand(command: string, timeoutMs: number, env: NodeJS.ProcessEnv, progressContext: LinkedTestProgressContext, progressMode: LinkedTestProgressMode): Promise<LinkedTestExecutionResult>;
|
|
212
|
+
declare function runLinkedTestCommand(command: string, timeoutMs: number, env: NodeJS.ProcessEnv, progressContext: LinkedTestProgressContext, progressMode: LinkedTestProgressMode, cwd?: string): Promise<LinkedTestExecutionResult>;
|
|
199
213
|
declare function formatLinkedTestExecutionError(result: LinkedTestExecutionResult, timeoutMs: number): string;
|
|
200
214
|
/** Implements classify linked test failure for the public runtime surface of this module. */
|
|
201
215
|
export declare function classifyLinkedTestFailure(result: Pick<LinkedTestExecutionResult, "stdout" | "stderr" | "spawnError" | "signal" | "timedOut" | "maxBufferExceeded">): LinkedTestFailureCategory;
|
|
@@ -228,6 +242,11 @@ interface RunLinkedTestsOptions {
|
|
|
228
242
|
requireAssertionsForPm?: boolean;
|
|
229
243
|
checkContext?: boolean;
|
|
230
244
|
autoPmContext?: boolean;
|
|
245
|
+
workspaceContext?: string;
|
|
246
|
+
overrideLinkedWorkspaceContext?: boolean;
|
|
247
|
+
pmRoot?: string;
|
|
248
|
+
allowUntrustedLinkedTests?: boolean;
|
|
249
|
+
untrustedLinkedTestsPolicyEnabled?: boolean;
|
|
231
250
|
}
|
|
232
251
|
interface LinkedTestSandboxLayout {
|
|
233
252
|
root: string;
|
|
@@ -235,6 +254,8 @@ interface LinkedTestSandboxLayout {
|
|
|
235
254
|
schemaGlobalPmPath: string;
|
|
236
255
|
trackerProjectPmPath: string;
|
|
237
256
|
trackerGlobalPmPath: string;
|
|
257
|
+
workspaceSnapshotRoot: string;
|
|
258
|
+
workspaceIsolatedRoot: string;
|
|
238
259
|
}
|
|
239
260
|
interface LinkedTestSandboxCounts {
|
|
240
261
|
sourceProjectItemCount: number;
|
|
@@ -255,6 +276,10 @@ declare function buildLinkedTestExecutionContext(params: {
|
|
|
255
276
|
requestedPmContextMode: LinkedTestPmContextMode;
|
|
256
277
|
effectivePmContextMode: ResolvedLinkedTestPmContextMode;
|
|
257
278
|
autoPmContextApplied: boolean;
|
|
279
|
+
requestedWorkspaceContextMode: LinkedTestWorkspaceContextMode;
|
|
280
|
+
workspaceContextMode: LinkedTestWorkspaceContextMode;
|
|
281
|
+
sourceWorkspaceRoot: string;
|
|
282
|
+
trust: LinkedTestTrustDecision;
|
|
258
283
|
}): NonNullable<TestRunResult["execution_context"]>;
|
|
259
284
|
/** Implements run linked tests for the public runtime surface of this module. */
|
|
260
285
|
export declare function runLinkedTests(tests: LinkedTest[], defaultTimeoutSeconds: number | undefined, options?: RunLinkedTestsOptions): Promise<TestRunResult[]>;
|
|
@@ -4,10 +4,10 @@
|
|
|
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]="7659721c-21f5-55da-8cce-31b290de5bfb")}catch(e){}}();
|
|
8
8
|
import { assertInitializedTracker } from "../environment/tracker-preflight.js";
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
|
-
import { cp, mkdir, mkdtemp, open, readdir, rm } from "node:fs/promises";
|
|
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";
|
|
@@ -25,12 +25,13 @@ import { readSettings } from "../../core/store/settings.js";
|
|
|
25
25
|
import { appendTrackedTestRunSummary, buildTrackedTestRunHistory, } from "../../core/test/item-test-run-tracking.js";
|
|
26
26
|
import { runInit } from "../init.js";
|
|
27
27
|
import { looksLikeStructuredLinkedTestEntry, normalizeStructuredLinkedTestEntry, } from "./entry.js";
|
|
28
|
-
import { LINKED_TEST_PM_CONTEXT_MODE_VALUES as PM_CONTEXT_MODE_VALUES, LINKED_TEST_PROTECTED_ENV_KEYS, parseLinkedTestAssertionEqualsMap, parseLinkedTestAssertionGteMap, parseLinkedTestBoolean as parseLinkedTestBooleanValue, parseLinkedTestContextMode as parseLinkedTestContextModeValue, parseLinkedTestEnvClear as parseLinkedTestEnvClearValue, parseLinkedTestEnvSet as parseLinkedTestEnvSetValue, parseLinkedTestJsonEntries, parseLinkedTestMinLines, parseLinkedTestRegexList, parseLinkedTestStringList, } from "./parsers.js";
|
|
28
|
+
import { LINKED_TEST_PM_CONTEXT_MODE_VALUES as PM_CONTEXT_MODE_VALUES, LINKED_TEST_PROTECTED_ENV_KEYS, parseLinkedTestAssertionEqualsMap, parseLinkedTestAssertionGteMap, parseLinkedTestBoolean as parseLinkedTestBooleanValue, parseLinkedTestContextMode as parseLinkedTestContextModeValue, parseLinkedTestEnvClear as parseLinkedTestEnvClearValue, parseLinkedTestEnvSet as parseLinkedTestEnvSetValue, parseLinkedTestJsonEntries, parseLinkedTestMinLines, parseLinkedTestRegexList, parseLinkedTestStringList, parseLinkedTestWorkspaceContextMode, } from "./parsers.js";
|
|
29
29
|
import { parseOnlyIndexValue, resolveLinkedTestRunSelection, } from "../../core/test/run-selectors.js";
|
|
30
30
|
import { SCOPE_VALUES } from "../../types/index.js";
|
|
31
31
|
import { diffTestRunMeasurements, parseTestRunMeasurements, queryTestRunMeasurementsBelow, } from "./measurements.js";
|
|
32
32
|
import { withHostEnvironmentBoundary } from "../environment/host-environment-errors.js";
|
|
33
33
|
import { SOURCE_CONTEXT_ACCESS_ENV } from "../environment/source-context.js";
|
|
34
|
+
import { acknowledgeLinkedTests, attachLinkedTestMutationProvenance, resolveLinkedTestSourceRef, resolveLinkedTestSourceWorkspaceRoot, resolveLinkedTestTrust, } from "./trust.js";
|
|
34
35
|
const TEST_OUTPUT_MAX_BUFFER_BYTES = 20 * 1024 * 1024;
|
|
35
36
|
const DEFAULT_LINKED_TEST_TIMEOUT_FORCE_KILL_DELAY_MS = 3000;
|
|
36
37
|
const DEFAULT_LINKED_TEST_HEARTBEAT_INTERVAL_MS = 10000;
|
|
@@ -170,6 +171,15 @@ function parsePmContextMode(raw) {
|
|
|
170
171
|
}
|
|
171
172
|
throw new PmCliError(`Invalid --pm-context value "${raw}". Expected one of: ${PM_CONTEXT_MODE_VALUES.join(", ")}`, EXIT_CODE.USAGE);
|
|
172
173
|
}
|
|
174
|
+
function parseWorkspaceContextMode(raw) {
|
|
175
|
+
return parseLinkedTestWorkspaceContextMode(raw ?? "source", "--workspace-context");
|
|
176
|
+
}
|
|
177
|
+
function resolveLinkedTestWorkspaceContextMode(linkedTest, runLevelMode, overrideLinkedMode) {
|
|
178
|
+
if (overrideLinkedMode) {
|
|
179
|
+
return runLevelMode;
|
|
180
|
+
}
|
|
181
|
+
return (parseLinkedTestWorkspaceContextMode(linkedTest.workspace_context_mode, "linked test") ?? runLevelMode);
|
|
182
|
+
}
|
|
173
183
|
function resolveLinkedTestRequestedContextMode(linkedTest, runLevelMode, overrideLinkedPmContext) {
|
|
174
184
|
if (overrideLinkedPmContext) {
|
|
175
185
|
return runLevelMode;
|
|
@@ -460,6 +470,7 @@ function parseAddEntry(entry) {
|
|
|
460
470
|
scope: ensureScope(kv.scope),
|
|
461
471
|
timeout_seconds: parseLinkedTestTimeoutSeconds(trimLinkedTestEntryField(kv.timeout_seconds), trimLinkedTestEntryField(kv.timeout)),
|
|
462
472
|
pm_context_mode: parseLinkedTestContextModeValue(trimLinkedTestEntryField(kv.pm_context_mode), "--add"),
|
|
473
|
+
workspace_context_mode: parseLinkedTestWorkspaceContextMode(trimLinkedTestEntryField(kv.workspace_context_mode), "--add"),
|
|
463
474
|
env_set: parseLinkedTestEnvSetValue(trimLinkedTestEntryField(kv.env_set), "--add"),
|
|
464
475
|
env_clear: parseLinkedTestEnvClearValue(trimLinkedTestEntryField(kv.env_clear), "--add"),
|
|
465
476
|
shared_host_safe: parseLinkedTestBooleanValue(trimLinkedTestEntryField(kv.shared_host_safe), "--add", "shared_host_safe"),
|
|
@@ -760,9 +771,9 @@ function waitForLinkedTestChildClose(child) {
|
|
|
760
771
|
});
|
|
761
772
|
});
|
|
762
773
|
}
|
|
763
|
-
function createLinkedTestChild(command, env, stdoutFd, stderrFd) {
|
|
774
|
+
function createLinkedTestChild(command, env, stdoutFd, stderrFd, cwd) {
|
|
764
775
|
return spawn(command, {
|
|
765
|
-
cwd
|
|
776
|
+
cwd,
|
|
766
777
|
env,
|
|
767
778
|
shell: true,
|
|
768
779
|
windowsHide: true,
|
|
@@ -791,7 +802,7 @@ async function readLinkedTestCapture(capturePath) {
|
|
|
791
802
|
await handle.close();
|
|
792
803
|
}
|
|
793
804
|
}
|
|
794
|
-
async function runLinkedTestCommand(command, timeoutMs, env, progressContext, progressMode) {
|
|
805
|
+
async function runLinkedTestCommand(command, timeoutMs, env, progressContext, progressMode, cwd = process.cwd()) {
|
|
795
806
|
const startedAt = Date.now();
|
|
796
807
|
const captureRoot = await mkdtemp(path.join(tmpdir(), "pm-linked-test-output-"));
|
|
797
808
|
try {
|
|
@@ -803,7 +814,7 @@ async function runLinkedTestCommand(command, timeoutMs, env, progressContext, pr
|
|
|
803
814
|
]);
|
|
804
815
|
let child;
|
|
805
816
|
try {
|
|
806
|
-
child = createLinkedTestChild(command, env, stdoutHandle.fd, stderrHandle.fd);
|
|
817
|
+
child = createLinkedTestChild(command, env, stdoutHandle.fd, stderrHandle.fd, cwd);
|
|
807
818
|
}
|
|
808
819
|
finally {
|
|
809
820
|
await Promise.all([stdoutHandle.close(), stderrHandle.close()]);
|
|
@@ -902,6 +913,7 @@ export function classifyLinkedTestFailure(result) {
|
|
|
902
913
|
function createEmptyFailureCategoryCounts() {
|
|
903
914
|
return {
|
|
904
915
|
infra_collision: 0,
|
|
916
|
+
trust_refusal: 0,
|
|
905
917
|
assertion_failure: 0,
|
|
906
918
|
empty_run: 0,
|
|
907
919
|
timeout: 0,
|
|
@@ -1264,8 +1276,48 @@ function createLinkedTestSandboxLayout(sandboxRoot) {
|
|
|
1264
1276
|
schemaGlobalPmPath: path.join(sandboxRoot, "schema", "global"),
|
|
1265
1277
|
trackerProjectPmPath: path.join(sandboxRoot, "tracker", "project", ".agents", "pm"),
|
|
1266
1278
|
trackerGlobalPmPath: path.join(sandboxRoot, "tracker", "global"),
|
|
1279
|
+
workspaceSnapshotRoot: path.join(sandboxRoot, "workspace", "project"),
|
|
1280
|
+
workspaceIsolatedRoot: path.join(sandboxRoot, "workspace", "isolated"),
|
|
1267
1281
|
};
|
|
1268
1282
|
}
|
|
1283
|
+
function linkedTestsRequireWorkspaceSnapshot(tests, runLevelMode, overrideLinkedMode) {
|
|
1284
|
+
return tests.some((linkedTest) => resolveLinkedTestWorkspaceContextMode(linkedTest, runLevelMode, overrideLinkedMode) === "snapshot");
|
|
1285
|
+
}
|
|
1286
|
+
async function seedLinkedTestWorkspaceSnapshot(layout, sourceWorkspaceRoot) {
|
|
1287
|
+
const excludedSegments = new Set([
|
|
1288
|
+
".agents",
|
|
1289
|
+
".git",
|
|
1290
|
+
".nyc_output",
|
|
1291
|
+
".turbo",
|
|
1292
|
+
"coverage",
|
|
1293
|
+
"node_modules",
|
|
1294
|
+
]);
|
|
1295
|
+
await mkdir(path.dirname(layout.workspaceSnapshotRoot), { recursive: true });
|
|
1296
|
+
await cp(sourceWorkspaceRoot, layout.workspaceSnapshotRoot, {
|
|
1297
|
+
recursive: true,
|
|
1298
|
+
force: true,
|
|
1299
|
+
filter(source) {
|
|
1300
|
+
const relative = path.relative(sourceWorkspaceRoot, source);
|
|
1301
|
+
if (!relative) {
|
|
1302
|
+
return true;
|
|
1303
|
+
}
|
|
1304
|
+
return !relative
|
|
1305
|
+
.split(path.sep)
|
|
1306
|
+
.some((segment) => excludedSegments.has(segment));
|
|
1307
|
+
},
|
|
1308
|
+
});
|
|
1309
|
+
const sourceNodeModules = path.join(sourceWorkspaceRoot, "node_modules");
|
|
1310
|
+
if (await pathExists(sourceNodeModules)) {
|
|
1311
|
+
await symlink(sourceNodeModules, path.join(layout.workspaceSnapshotRoot, "node_modules"), process.platform === "win32" ? "junction" : "dir");
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
async function bindSnapshotTracker(snapshotRoot, sandboxPmPath) {
|
|
1315
|
+
const agentsRoot = path.join(snapshotRoot, ".agents");
|
|
1316
|
+
const target = path.join(agentsRoot, "pm");
|
|
1317
|
+
await mkdir(agentsRoot, { recursive: true });
|
|
1318
|
+
await rm(target, { recursive: true, force: true });
|
|
1319
|
+
await symlink(sandboxPmPath, target, process.platform === "win32" ? "junction" : "dir");
|
|
1320
|
+
}
|
|
1269
1321
|
async function initializeLinkedTestSandboxes(layout, initialize = runInit, includeTrackerData = true) {
|
|
1270
1322
|
const initOptions = { defaults: true, agentGuidance: "skip" };
|
|
1271
1323
|
await initialize(undefined, { path: layout.schemaProjectPmPath }, initOptions);
|
|
@@ -1326,6 +1378,12 @@ function buildLinkedTestExecutionContext(params) {
|
|
|
1326
1378
|
const selectedSandboxGlobalItemCount = trackerMode
|
|
1327
1379
|
? params.counts.trackerGlobalItemCount
|
|
1328
1380
|
: params.counts.schemaGlobalItemCount;
|
|
1381
|
+
const workingDirectory = params.workspaceContextMode === "snapshot"
|
|
1382
|
+
? params.layout.workspaceSnapshotRoot
|
|
1383
|
+
: params.workspaceContextMode === "isolated"
|
|
1384
|
+
? params.layout.workspaceIsolatedRoot
|
|
1385
|
+
: params.sourceWorkspaceRoot;
|
|
1386
|
+
const exposedSourceWorkspaceRoot = params.workspaceContextMode === "isolated" ? "" : workingDirectory;
|
|
1329
1387
|
return {
|
|
1330
1388
|
requested_pm_context_mode: params.requestedPmContextMode,
|
|
1331
1389
|
pm_context_mode: params.effectivePmContextMode,
|
|
@@ -1346,9 +1404,14 @@ function buildLinkedTestExecutionContext(params) {
|
|
|
1346
1404
|
params.counts.sourceGlobalItemCount !== selectedSandboxGlobalItemCount),
|
|
1347
1405
|
project_extensions_seeded: Boolean(params.sourceRoots),
|
|
1348
1406
|
global_extensions_seeded: Boolean(params.sourceRoots),
|
|
1407
|
+
requested_workspace_context_mode: params.requestedWorkspaceContextMode,
|
|
1408
|
+
workspace_context_mode: params.workspaceContextMode,
|
|
1409
|
+
working_directory: workingDirectory,
|
|
1410
|
+
source_workspace_root: exposedSourceWorkspaceRoot,
|
|
1411
|
+
trust: params.trust,
|
|
1349
1412
|
};
|
|
1350
1413
|
}
|
|
1351
|
-
function resolveLinkedTestCommandContext(params) {
|
|
1414
|
+
async function resolveLinkedTestCommandContext(params) {
|
|
1352
1415
|
const linkedOverridePmContextMode = typeof params.linkedTest.pm_context_mode === "string" &&
|
|
1353
1416
|
params.linkedTest.pm_context_mode.trim().length > 0
|
|
1354
1417
|
? parsePmContextMode(params.linkedTest.pm_context_mode)
|
|
@@ -1366,6 +1429,15 @@ function resolveLinkedTestCommandContext(params) {
|
|
|
1366
1429
|
? "auto"
|
|
1367
1430
|
: resolveLinkedTestRequestedContextMode(params.linkedTest, params.runLevelPmContextMode, params.options?.overrideLinkedPmContext === true);
|
|
1368
1431
|
const effectivePmContextMode = resolveLinkedTestEffectiveContextMode(requestedPmContextMode, isPmTrackerReadCommand);
|
|
1432
|
+
const selectedSandboxProjectPmPath = effectivePmContextMode === "tracker"
|
|
1433
|
+
? params.layout.trackerProjectPmPath
|
|
1434
|
+
: params.layout.schemaProjectPmPath;
|
|
1435
|
+
if (params.workspaceContextMode === "snapshot") {
|
|
1436
|
+
await bindSnapshotTracker(params.layout.workspaceSnapshotRoot, selectedSandboxProjectPmPath);
|
|
1437
|
+
}
|
|
1438
|
+
const trust = params.options?.pmRoot
|
|
1439
|
+
? await resolveLinkedTestTrust(params.options.pmRoot, params.linkedTest, params.currentSourceRef)
|
|
1440
|
+
: await resolveLinkedTestTrust(params.layout.root, params.linkedTest, params.currentSourceRef);
|
|
1369
1441
|
return {
|
|
1370
1442
|
linkedOverridePmContextMode,
|
|
1371
1443
|
executionContext: buildLinkedTestExecutionContext({
|
|
@@ -1377,6 +1449,10 @@ function resolveLinkedTestCommandContext(params) {
|
|
|
1377
1449
|
requestedPmContextMode,
|
|
1378
1450
|
effectivePmContextMode,
|
|
1379
1451
|
autoPmContextApplied,
|
|
1452
|
+
requestedWorkspaceContextMode: params.requestedWorkspaceContextMode,
|
|
1453
|
+
workspaceContextMode: params.workspaceContextMode,
|
|
1454
|
+
sourceWorkspaceRoot: params.sourceWorkspaceRoot,
|
|
1455
|
+
trust,
|
|
1380
1456
|
}),
|
|
1381
1457
|
};
|
|
1382
1458
|
}
|
|
@@ -1401,14 +1477,47 @@ function buildLinkedTestAssertionFailureResult(linkedTest, executionContext, err
|
|
|
1401
1477
|
error,
|
|
1402
1478
|
};
|
|
1403
1479
|
}
|
|
1404
|
-
function
|
|
1480
|
+
function buildLinkedTestTrustRefusalResult(linkedTest, executionContext, error) {
|
|
1481
|
+
return {
|
|
1482
|
+
command: linkedTest.command,
|
|
1483
|
+
path: linkedTest.path,
|
|
1484
|
+
status: "failed",
|
|
1485
|
+
exit_code: 1,
|
|
1486
|
+
failure_category: "trust_refusal",
|
|
1487
|
+
execution_context: executionContext,
|
|
1488
|
+
error,
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
/** Build the fail-closed result for a command this clone has not trusted. */
|
|
1492
|
+
function resolveLinkedTestTrustPreflightResult(params) {
|
|
1493
|
+
if (params.executionContext.trust.trusted)
|
|
1494
|
+
return null;
|
|
1495
|
+
const overrideRequested = params.options?.allowUntrustedLinkedTests === true;
|
|
1496
|
+
const policyEnabled = params.options?.untrustedLinkedTestsPolicyEnabled === true;
|
|
1497
|
+
if (overrideRequested && policyEnabled)
|
|
1498
|
+
return null;
|
|
1499
|
+
const recovery = policyEnabled
|
|
1500
|
+
? "Retry with --allow-untrusted-linked-tests for this invocation, or acknowledge the current commands with --acknowledge-linked-tests."
|
|
1501
|
+
: "Set testing.allow_untrusted_linked_tests=true, then retry with --allow-untrusted-linked-tests; alternatively acknowledge the current commands with --acknowledge-linked-tests.";
|
|
1502
|
+
return buildLinkedTestTrustRefusalResult(params.linkedTest, params.executionContext, `Linked test command is not trusted by this clone (source_ref=${params.executionContext.trust.source_ref ?? "unknown"}, current_ref=${params.executionContext.trust.current_source_ref ?? "unknown"}). ${recovery}`);
|
|
1503
|
+
}
|
|
1504
|
+
/** Resolve missing-command and runtime-safety skips before policy checks. */
|
|
1505
|
+
function resolveLinkedTestSafetyPreflightResult(params) {
|
|
1405
1506
|
if (!params.linkedTest.command) {
|
|
1406
1507
|
return buildLinkedTestSkippedResult(params.linkedTest, params.executionContext, "No command configured for this linked test.");
|
|
1407
1508
|
}
|
|
1408
1509
|
const runtimeSafetySkipReason = getRuntimeSafetySkipReason(params.linkedTest.command);
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1510
|
+
return runtimeSafetySkipReason
|
|
1511
|
+
? buildLinkedTestSkippedResult(params.linkedTest, params.executionContext, runtimeSafetySkipReason)
|
|
1512
|
+
: null;
|
|
1513
|
+
}
|
|
1514
|
+
function resolveLinkedTestPreflightResult(params) {
|
|
1515
|
+
const safetyFailure = resolveLinkedTestSafetyPreflightResult(params);
|
|
1516
|
+
if (safetyFailure)
|
|
1517
|
+
return safetyFailure;
|
|
1518
|
+
const trustFailure = resolveLinkedTestTrustPreflightResult(params);
|
|
1519
|
+
if (trustFailure)
|
|
1520
|
+
return trustFailure;
|
|
1412
1521
|
const failOnMismatchByDefault = params.executionContext.pm_context_mode === "schema" &&
|
|
1413
1522
|
params.executionContext.is_pm_tracker_read_command &&
|
|
1414
1523
|
params.executionContext.mismatch_detected;
|
|
@@ -1451,11 +1560,20 @@ function buildLinkedTestExecutionEnv(params) {
|
|
|
1451
1560
|
executionEnv.FORCE_COLOR = "0";
|
|
1452
1561
|
executionEnv.PM_PATH = params.executionContext.sandbox_project_pm_path;
|
|
1453
1562
|
executionEnv.PM_GLOBAL_PATH = params.executionContext.sandbox_global_pm_path;
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1563
|
+
if (params.executionContext.workspace_context_mode === "isolated") {
|
|
1564
|
+
delete executionEnv.PM_SOURCE_WORKSPACE_ROOT;
|
|
1565
|
+
delete executionEnv.PM_SOURCE_PM_PATH;
|
|
1566
|
+
delete executionEnv[SOURCE_CONTEXT_ACCESS_ENV];
|
|
1567
|
+
}
|
|
1568
|
+
else {
|
|
1569
|
+
executionEnv.PM_SOURCE_WORKSPACE_ROOT =
|
|
1570
|
+
params.executionContext.source_workspace_root;
|
|
1571
|
+
executionEnv.PM_SOURCE_PM_PATH =
|
|
1572
|
+
params.executionContext.workspace_context_mode === "snapshot"
|
|
1573
|
+
? params.executionContext.sandbox_project_pm_path
|
|
1574
|
+
: params.executionContext.source_project_pm_path;
|
|
1575
|
+
executionEnv[SOURCE_CONTEXT_ACCESS_ENV] = "read_only";
|
|
1576
|
+
}
|
|
1459
1577
|
return executionEnv;
|
|
1460
1578
|
}
|
|
1461
1579
|
function buildLinkedTestPassedResult(linkedTest, executionContext, execution) {
|
|
@@ -1518,7 +1636,7 @@ async function runSingleLinkedTest(params) {
|
|
|
1518
1636
|
total: params.total,
|
|
1519
1637
|
timeoutMs,
|
|
1520
1638
|
command,
|
|
1521
|
-
}, params.progressMode);
|
|
1639
|
+
}, params.progressMode, params.executionContext.working_directory);
|
|
1522
1640
|
const passed = execution.exitCode === 0 &&
|
|
1523
1641
|
!execution.timedOut &&
|
|
1524
1642
|
!execution.maxBufferExceeded;
|
|
@@ -1532,23 +1650,36 @@ export async function runLinkedTests(tests, defaultTimeoutSeconds, options) {
|
|
|
1532
1650
|
const sandboxRoot = await mkdtemp(path.join(tmpdir(), "pm-linked-test-"));
|
|
1533
1651
|
const layout = createLinkedTestSandboxLayout(sandboxRoot);
|
|
1534
1652
|
const runLevelPmContextMode = parsePmContextMode(options?.pmContext);
|
|
1653
|
+
const runLevelWorkspaceContextMode = parseWorkspaceContextMode(options?.workspaceContext);
|
|
1535
1654
|
const progressMode = options?.progress === true ? "always" : "auto";
|
|
1536
1655
|
const runtimeDirectives = resolveRuntimeDirectives(options?.envSet, options?.envClear, options?.sharedHostSafe);
|
|
1537
1656
|
const sourceRoots = options?.sourceRoots;
|
|
1657
|
+
const sourceWorkspaceRoot = resolveLinkedTestSourceWorkspaceRoot();
|
|
1538
1658
|
const includeTrackerData = linkedTestsRequireTrackerData(tests, runLevelPmContextMode, options);
|
|
1659
|
+
const includeWorkspaceSnapshot = linkedTestsRequireWorkspaceSnapshot(tests, runLevelWorkspaceContextMode, options?.overrideLinkedWorkspaceContext === true);
|
|
1660
|
+
const currentSourceRef = await resolveLinkedTestSourceRef(sourceWorkspaceRoot);
|
|
1539
1661
|
try {
|
|
1540
1662
|
await initializeLinkedTestSandboxes(layout, runInit, includeTrackerData);
|
|
1663
|
+
await mkdir(layout.workspaceIsolatedRoot, { recursive: true });
|
|
1541
1664
|
await seedLinkedTestSandboxesFromSource(layout, sourceRoots, includeTrackerData);
|
|
1665
|
+
if (includeWorkspaceSnapshot) {
|
|
1666
|
+
await seedLinkedTestWorkspaceSnapshot(layout, sourceWorkspaceRoot);
|
|
1667
|
+
}
|
|
1542
1668
|
const counts = await countLinkedTestSandboxItems(layout, sourceRoots);
|
|
1543
1669
|
for (let index = 0; index < tests.length; index += 1) {
|
|
1544
1670
|
const linkedTest = tests[index];
|
|
1545
|
-
const
|
|
1671
|
+
const workspaceContextMode = resolveLinkedTestWorkspaceContextMode(linkedTest, runLevelWorkspaceContextMode, options?.overrideLinkedWorkspaceContext === true);
|
|
1672
|
+
const commandContext = await resolveLinkedTestCommandContext({
|
|
1546
1673
|
linkedTest,
|
|
1547
1674
|
layout,
|
|
1548
1675
|
counts,
|
|
1549
1676
|
sourceRoots,
|
|
1550
1677
|
runLevelPmContextMode,
|
|
1551
1678
|
options,
|
|
1679
|
+
requestedWorkspaceContextMode: runLevelWorkspaceContextMode,
|
|
1680
|
+
workspaceContextMode,
|
|
1681
|
+
currentSourceRef,
|
|
1682
|
+
sourceWorkspaceRoot,
|
|
1552
1683
|
});
|
|
1553
1684
|
const preflightResult = resolveLinkedTestPreflightResult({
|
|
1554
1685
|
linkedTest,
|
|
@@ -1602,7 +1733,8 @@ function linkedTestsHaveSameIdentity(left, right) {
|
|
|
1602
1733
|
return (left.command === right.command &&
|
|
1603
1734
|
left.path === right.path &&
|
|
1604
1735
|
left.scope === right.scope &&
|
|
1605
|
-
left.pm_context_mode === right.pm_context_mode
|
|
1736
|
+
left.pm_context_mode === right.pm_context_mode &&
|
|
1737
|
+
left.workspace_context_mode === right.workspace_context_mode);
|
|
1606
1738
|
}
|
|
1607
1739
|
function appendMissingLinkedTests(current, additions) {
|
|
1608
1740
|
const next = [...current];
|
|
@@ -1635,21 +1767,29 @@ function applyLinkedTestMutations(previous, adds, removes, removeIndexes) {
|
|
|
1635
1767
|
return removeLinkedTestsBySelector(appendMissingLinkedTests(previous, adds), removes, removeIndexes);
|
|
1636
1768
|
}
|
|
1637
1769
|
function hasTestRuntimeDirectiveFlags(options) {
|
|
1638
|
-
return
|
|
1639
|
-
(options.
|
|
1640
|
-
options.
|
|
1641
|
-
options.
|
|
1642
|
-
options.
|
|
1643
|
-
options.
|
|
1644
|
-
options.
|
|
1645
|
-
options.
|
|
1646
|
-
options.
|
|
1647
|
-
options.
|
|
1648
|
-
options.
|
|
1770
|
+
return [
|
|
1771
|
+
(options.envSet?.length ?? 0) > 0,
|
|
1772
|
+
(options.envClear?.length ?? 0) > 0,
|
|
1773
|
+
options.sharedHostSafe === true,
|
|
1774
|
+
options.pmContext !== undefined,
|
|
1775
|
+
options.overrideLinkedPmContext === true,
|
|
1776
|
+
options.failOnContextMismatch === true,
|
|
1777
|
+
options.failOnSkipped === true,
|
|
1778
|
+
options.failOnEmptyTestRun === true,
|
|
1779
|
+
options.requireAssertionsForPm === true,
|
|
1780
|
+
options.checkContext === true,
|
|
1781
|
+
options.autoPmContext === true,
|
|
1782
|
+
options.workspaceContext !== undefined,
|
|
1783
|
+
options.overrideLinkedWorkspaceContext === true,
|
|
1784
|
+
options.allowUntrustedLinkedTests === true,
|
|
1785
|
+
].some(Boolean);
|
|
1649
1786
|
}
|
|
1650
1787
|
function assertTestRunFlagUsage(options) {
|
|
1651
1788
|
if (hasTestRuntimeDirectiveFlags(options) && options.run !== true) {
|
|
1652
|
-
throw new PmCliError("--env-set, --env-clear, --shared-host-safe, --pm-context, --override-linked-pm-context, --fail-on-context-mismatch, --fail-on-skipped, --fail-on-empty-test-run, --require-assertions-for-pm, --check-context, and --auto-pm-context require --run", EXIT_CODE.USAGE);
|
|
1789
|
+
throw new PmCliError("--env-set, --env-clear, --shared-host-safe, --pm-context, --override-linked-pm-context, --workspace-context, --override-linked-workspace-context, --allow-untrusted-linked-tests, --fail-on-context-mismatch, --fail-on-skipped, --fail-on-empty-test-run, --require-assertions-for-pm, --check-context, and --auto-pm-context require --run", EXIT_CODE.USAGE);
|
|
1790
|
+
}
|
|
1791
|
+
if (options.acknowledgeLinkedTests === true && options.run === true) {
|
|
1792
|
+
throw new PmCliError("--acknowledge-linked-tests records trust without executing commands; run it separately before --run", EXIT_CODE.USAGE);
|
|
1653
1793
|
}
|
|
1654
1794
|
const hasSelectorFlags = options.match !== undefined ||
|
|
1655
1795
|
options.onlyIndex !== undefined ||
|
|
@@ -1749,6 +1889,11 @@ async function executeSelectedLinkedTests(params) {
|
|
|
1749
1889
|
requireAssertionsForPm: options.requireAssertionsForPm,
|
|
1750
1890
|
checkContext: options.checkContext,
|
|
1751
1891
|
autoPmContext: options.autoPmContext,
|
|
1892
|
+
workspaceContext: options.workspaceContext,
|
|
1893
|
+
overrideLinkedWorkspaceContext: options.overrideLinkedWorkspaceContext,
|
|
1894
|
+
pmRoot,
|
|
1895
|
+
allowUntrustedLinkedTests: options.allowUntrustedLinkedTests,
|
|
1896
|
+
untrustedLinkedTestsPolicyEnabled: params.untrustedLinkedTestsPolicyEnabled,
|
|
1752
1897
|
sourceRoots: {
|
|
1753
1898
|
projectPmRoot: pmRoot,
|
|
1754
1899
|
globalPmRoot: resolveGlobalPmRoot(process.cwd()),
|
|
@@ -1798,6 +1943,8 @@ function buildTrackedTestRunSummary(params) {
|
|
|
1798
1943
|
command: result.command.trim(),
|
|
1799
1944
|
requested_pm_context_mode: result.execution_context?.requested_pm_context_mode,
|
|
1800
1945
|
pm_context_mode: result.execution_context?.pm_context_mode,
|
|
1946
|
+
workspace_context_mode: result.execution_context?.workspace_context_mode,
|
|
1947
|
+
trust_reason: result.execution_context?.trust.reason,
|
|
1801
1948
|
})),
|
|
1802
1949
|
};
|
|
1803
1950
|
}
|
|
@@ -1854,6 +2001,12 @@ function buildTestMeasurementProjection(options, runs, recordedRun) {
|
|
|
1854
2001
|
: diffTestRunMeasurements(runs, options.metricDiff),
|
|
1855
2002
|
};
|
|
1856
2003
|
}
|
|
2004
|
+
/** Acknowledge current linked commands only when the dedicated mode is active. */
|
|
2005
|
+
async function maybeAcknowledgeLinkedTests(options, pmRoot, tests) {
|
|
2006
|
+
if (options.acknowledgeLinkedTests !== true)
|
|
2007
|
+
return undefined;
|
|
2008
|
+
return acknowledgeLinkedTests(pmRoot, tests, nowIso());
|
|
2009
|
+
}
|
|
1857
2010
|
/** Implements run test for the public runtime surface of this module. */
|
|
1858
2011
|
export async function runTest(id, options, global) {
|
|
1859
2012
|
const stdinResolver = createStdinTokenResolver();
|
|
@@ -1869,10 +2022,11 @@ export async function runTest(id, options, global) {
|
|
|
1869
2022
|
const resolvedAdds = await stdinResolver.resolveList(options.add, "--add");
|
|
1870
2023
|
const resolvedAddJsons = await stdinResolver.resolveList(options.addJson, "--add-json");
|
|
1871
2024
|
const resolvedRemoves = await stdinResolver.resolveList(options.remove, "--remove");
|
|
1872
|
-
const
|
|
2025
|
+
const parsedAdds = [
|
|
1873
2026
|
...parseAddEntries(resolvedAdds),
|
|
1874
2027
|
...parseAddJsonEntries(resolvedAddJsons),
|
|
1875
2028
|
];
|
|
2029
|
+
const adds = (await attachLinkedTestMutationProvenance(parsedAdds, resolveAuthor(options.author, settings.author_default), nowIso())) ?? [];
|
|
1876
2030
|
const removes = parseRemoveEntries(resolvedRemoves);
|
|
1877
2031
|
const removeIndexes = parseRemoveIndexes(options.removeIndex);
|
|
1878
2032
|
const item = await resolveLinkedTestItem({
|
|
@@ -1886,17 +2040,22 @@ export async function runTest(id, options, global) {
|
|
|
1886
2040
|
removeIndexes,
|
|
1887
2041
|
});
|
|
1888
2042
|
const runOptions = resolveTestRunOptions(options, item.tests);
|
|
2043
|
+
const trustAcknowledgement = await maybeAcknowledgeLinkedTests(options, pmRoot, item.tests);
|
|
1889
2044
|
const runStartedAt = options.run === true ? nowIso() : undefined;
|
|
1890
2045
|
const runResults = await executeSelectedLinkedTests({
|
|
1891
2046
|
options,
|
|
1892
2047
|
runOptions,
|
|
1893
2048
|
pmRoot,
|
|
2049
|
+
untrustedLinkedTestsPolicyEnabled: settings.testing.allow_untrusted_linked_tests,
|
|
1894
2050
|
});
|
|
1895
2051
|
const failureCategories = countFailureCategories(runResults);
|
|
1896
2052
|
const failOnSkippedTriggered = options.run === true &&
|
|
1897
2053
|
options.failOnSkipped === true &&
|
|
1898
2054
|
runResults.some((entry) => entry.status === "skipped");
|
|
1899
2055
|
const warnings = buildTestWarnings(options, runOptions.runSelection, runResults);
|
|
2056
|
+
if (trustAcknowledgement) {
|
|
2057
|
+
warnings.push(`linked_test_trust_acknowledged:${trustAcknowledgement.acknowledged}`);
|
|
2058
|
+
}
|
|
1900
2059
|
const recordedRun = await recordTestRunSummary({
|
|
1901
2060
|
options,
|
|
1902
2061
|
pmRoot,
|
|
@@ -1972,4 +2131,4 @@ export const _testOnlyTestCommand = {
|
|
|
1972
2131
|
summarizeRunResultStatuses,
|
|
1973
2132
|
};
|
|
1974
2133
|
//# sourceMappingURL=execution.js.map
|
|
1975
|
-
//# debugId=
|
|
2134
|
+
//# debugId=7659721c-21f5-55da-8cce-31b290de5bfb
|
|
@@ -20,6 +20,10 @@ export declare const LINKED_TEST_ENV_NAME_PATTERN: RegExp;
|
|
|
20
20
|
export declare const LINKED_TEST_PM_CONTEXT_MODE_VALUES: readonly ["schema", "tracker", "auto"];
|
|
21
21
|
/** Restricts linked test pm context mode values accepted by command, SDK, and storage contracts. */
|
|
22
22
|
export type LinkedTestPmContextMode = (typeof LINKED_TEST_PM_CONTEXT_MODE_VALUES)[number];
|
|
23
|
+
/** Supported values accepted by the linked test workspace context contract. */
|
|
24
|
+
export declare const LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES: readonly ["source", "isolated", "snapshot"];
|
|
25
|
+
/** Restricts source-workspace modes accepted by command and storage contracts. */
|
|
26
|
+
export type LinkedTestWorkspaceContextMode = (typeof LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES)[number];
|
|
23
27
|
/** Implements parse linked test env set for the public runtime surface of this module. */
|
|
24
28
|
export declare function parseLinkedTestEnvSet(raw: string | undefined, optionName: string): Record<string, string> | undefined;
|
|
25
29
|
/** Implements parse linked test env clear for the public runtime surface of this module. */
|
|
@@ -28,6 +32,8 @@ export declare function parseLinkedTestEnvClear(raw: string | undefined, optionN
|
|
|
28
32
|
export declare function parseLinkedTestBoolean(raw: string | undefined, optionName: string, fieldLabel: string): boolean | undefined;
|
|
29
33
|
/** Implements parse linked test context mode for the public runtime surface of this module. */
|
|
30
34
|
export declare function parseLinkedTestContextMode(raw: string | undefined, optionName: string): LinkedTest["pm_context_mode"] | undefined;
|
|
35
|
+
/** Parse one linked-test source-workspace context mode. */
|
|
36
|
+
export declare function parseLinkedTestWorkspaceContextMode(raw: string | undefined, optionName: string): LinkedTest["workspace_context_mode"] | undefined;
|
|
31
37
|
/** Implements parse linked test string list for the public runtime surface of this module. */
|
|
32
38
|
export declare function parseLinkedTestStringList(raw: string | undefined): string[] | undefined;
|
|
33
39
|
/** Implements parse linked test regex list for the public runtime surface of this module. */
|
package/dist/sdk/test/parsers.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Implements the pm linked test parsers 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]="64adcc3c-3646-5990-9442-4c4374a2dc7d")}catch(e){}}();
|
|
8
8
|
import { parseOptionalNumber } from "../../core/item/parse.js";
|
|
9
9
|
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
10
10
|
import { PmCliError } from "../../core/shared/errors.js";
|
|
@@ -43,6 +43,12 @@ export const LINKED_TEST_PM_CONTEXT_MODE_VALUES = [
|
|
|
43
43
|
"tracker",
|
|
44
44
|
"auto",
|
|
45
45
|
];
|
|
46
|
+
/** Supported values accepted by the linked test workspace context contract. */
|
|
47
|
+
export const LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES = [
|
|
48
|
+
"source",
|
|
49
|
+
"isolated",
|
|
50
|
+
"snapshot",
|
|
51
|
+
];
|
|
46
52
|
/** Implements parse linked test env set for the public runtime surface of this module. */
|
|
47
53
|
export function parseLinkedTestEnvSet(raw, optionName) {
|
|
48
54
|
if (!raw) {
|
|
@@ -119,6 +125,17 @@ export function parseLinkedTestContextMode(raw, optionName) {
|
|
|
119
125
|
}
|
|
120
126
|
throw new PmCliError(`${optionName} pm_context_mode must be one of: ${LINKED_TEST_PM_CONTEXT_MODE_VALUES.join(", ")}`, EXIT_CODE.USAGE);
|
|
121
127
|
}
|
|
128
|
+
/** Parse one linked-test source-workspace context mode. */
|
|
129
|
+
export function parseLinkedTestWorkspaceContextMode(raw, optionName) {
|
|
130
|
+
if (!raw) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
const value = raw.trim().toLowerCase();
|
|
134
|
+
if (LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES.includes(value)) {
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
throw new PmCliError(`${optionName} workspace_context_mode must be one of: ${LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES.join(", ")}`, EXIT_CODE.USAGE);
|
|
138
|
+
}
|
|
122
139
|
/** Implements parse linked test string list for the public runtime surface of this module. */
|
|
123
140
|
export function parseLinkedTestStringList(raw) {
|
|
124
141
|
if (!raw) {
|
|
@@ -476,6 +493,7 @@ function parseLinkedTestJsonEntry(rawEntry, label, optionName) {
|
|
|
476
493
|
!LINKED_TEST_PM_CONTEXT_MODE_VALUES.includes(pmContextModeValue)) {
|
|
477
494
|
throw fail(`field "pm_context_mode" must be one of: ${LINKED_TEST_PM_CONTEXT_MODE_VALUES.join(", ")}`);
|
|
478
495
|
}
|
|
496
|
+
const workspaceContextModeValue = parseLinkedTestWorkspaceContextMode(readJsonEntryString(entry, "workspace_context_mode", fail), `${optionName} ${label}`);
|
|
479
497
|
const noteValue = readJsonEntryString(entry, "note", fail);
|
|
480
498
|
return {
|
|
481
499
|
command,
|
|
@@ -483,6 +501,7 @@ function parseLinkedTestJsonEntry(rawEntry, label, optionName) {
|
|
|
483
501
|
scope: readJsonEntryScope(entry, fail),
|
|
484
502
|
timeout_seconds: readJsonEntryTimeoutSeconds(entry, fail),
|
|
485
503
|
pm_context_mode: pmContextModeValue,
|
|
504
|
+
workspace_context_mode: workspaceContextModeValue,
|
|
486
505
|
env_set: readJsonEntryEnvSet(entry, fail),
|
|
487
506
|
env_clear: readJsonEntryEnvClear(entry, fail),
|
|
488
507
|
shared_host_safe: readJsonEntryBoolean(entry, "shared_host_safe", fail),
|
|
@@ -524,4 +543,4 @@ export const _testOnlyLinkedTestParsers = {
|
|
|
524
543
|
parseLinkedTestJsonEntry,
|
|
525
544
|
};
|
|
526
545
|
//# sourceMappingURL=parsers.js.map
|
|
527
|
-
//# debugId=
|
|
546
|
+
//# debugId=64adcc3c-3646-5990-9442-4c4374a2dc7d
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { LinkedTest } from "../../types/index.js";
|
|
2
|
+
/** Classification of one linked-test command against the current clone. */
|
|
3
|
+
export interface LinkedTestTrustDecision {
|
|
4
|
+
/** Stable hash binding the decision to command, context, and provenance. */
|
|
5
|
+
fingerprint: string;
|
|
6
|
+
/** Whether execution may proceed without an untrusted-command override. */
|
|
7
|
+
trusted: boolean;
|
|
8
|
+
/** Machine-readable reason for the decision. */
|
|
9
|
+
reason: "legacy" | "local_mutation" | "local_source_ref" | "acknowledged" | "invalid_provenance" | "foreign_source_ref";
|
|
10
|
+
/** Source ref recorded when the command entered tracker data. */
|
|
11
|
+
source_ref?: string;
|
|
12
|
+
/** Current source ref used for the local decision. */
|
|
13
|
+
current_source_ref?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Resolve the current Git branch without invoking a shell. */
|
|
16
|
+
export declare function resolveLinkedTestSourceRef(cwd?: string): Promise<string | undefined>;
|
|
17
|
+
/** Resolve the source checkout shared by linked-test provenance and execution. */
|
|
18
|
+
export declare function resolveLinkedTestSourceWorkspaceRoot(cwd?: string): string;
|
|
19
|
+
/** Attach immutable author/time/ref provenance to newly stored commands. */
|
|
20
|
+
export declare function attachLinkedTestProvenance(tests: LinkedTest[] | undefined, author: string, createdAt: string, sourceRef: string | undefined): LinkedTest[] | undefined;
|
|
21
|
+
/** Attach provenance while avoiding Git inspection for an empty mutation. */
|
|
22
|
+
export declare function attachLinkedTestMutationProvenance(tests: LinkedTest[] | undefined, author: string, createdAt: string): Promise<LinkedTest[] | undefined>;
|
|
23
|
+
/** Produce the clone-local trust identity for one linked-test entry. */
|
|
24
|
+
export declare function linkedTestTrustFingerprint(test: LinkedTest): string;
|
|
25
|
+
/** Resolve whether one stored command is trusted by this clone. */
|
|
26
|
+
export declare function resolveLinkedTestTrust(pmRoot: string, test: LinkedTest, currentSourceRef?: string): Promise<LinkedTestTrustDecision>;
|
|
27
|
+
/** Resolve a collection with one ledger read for validation and batch runs. */
|
|
28
|
+
export declare function resolveLinkedTestTrustBatch(pmRoot: string, tests: LinkedTest[], currentSourceRef?: string): Promise<LinkedTestTrustDecision[]>;
|
|
29
|
+
/** Persist explicit clone-local acknowledgement for selected linked tests. */
|
|
30
|
+
export declare function acknowledgeLinkedTests(pmRoot: string, tests: LinkedTest[], acknowledgedAt: string): Promise<{
|
|
31
|
+
acknowledged: number;
|
|
32
|
+
fingerprints: string[];
|
|
33
|
+
}>;
|