@stigmer/runner 3.12.3 → 3.12.5
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/dist/.build-fingerprint +1 -1
- package/dist/activities/call-http.js +12 -0
- package/dist/activities/call-http.js.map +1 -1
- package/dist/activities/call-llm.d.ts +18 -0
- package/dist/activities/call-llm.js +56 -2
- package/dist/activities/call-llm.js.map +1 -1
- package/dist/activities/execute-cursor/agent-session-cache.d.ts +72 -0
- package/dist/activities/execute-cursor/agent-session-cache.js +186 -0
- package/dist/activities/execute-cursor/agent-session-cache.js.map +1 -0
- package/dist/activities/execute-cursor/cursor-mcp-config.d.ts +45 -0
- package/dist/activities/execute-cursor/cursor-mcp-config.js +76 -0
- package/dist/activities/execute-cursor/cursor-mcp-config.js.map +1 -0
- package/dist/activities/execute-cursor/index.d.ts +10 -1
- package/dist/activities/execute-cursor/index.js +108 -57
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +13 -2
- package/dist/activities/execute-cursor/prompt-builder.js +11 -0
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/service-tier.d.ts +5 -15
- package/dist/activities/execute-cursor/service-tier.js +5 -21
- package/dist/activities/execute-cursor/service-tier.js.map +1 -1
- package/dist/activities/execute-cursor/session-lifecycle.d.ts +1 -1
- package/dist/activities/execute-cursor/skill-resolver.d.ts +2 -21
- package/dist/activities/execute-cursor/skill-resolver.js +5 -108
- package/dist/activities/execute-cursor/skill-resolver.js.map +1 -1
- package/dist/activities/execute-deep-agent/approval-file-change.d.ts +9 -0
- package/dist/activities/execute-deep-agent/approval-file-change.js +2 -1
- package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
- package/dist/activities/execute-deep-agent/cas-capture-backend.d.ts +18 -1
- package/dist/activities/execute-deep-agent/cas-capture-backend.js +20 -3
- package/dist/activities/execute-deep-agent/cas-capture-backend.js.map +1 -1
- package/dist/activities/execute-deep-agent/index.js +57 -5
- package/dist/activities/execute-deep-agent/index.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +9 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js +10 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.js +31 -16
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/activities/execute-deep-agent/shell-env.d.ts +8 -5
- package/dist/activities/execute-deep-agent/shell-env.js +10 -7
- package/dist/activities/execute-deep-agent/shell-env.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.js +17 -11
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +3 -3
- package/dist/config.js +10 -5
- package/dist/config.js.map +1 -1
- package/dist/encryption/config.js +7 -2
- package/dist/encryption/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/main.js +12 -6
- package/dist/main.js.map +1 -1
- package/dist/middleware/path-normalization.d.ts +49 -49
- package/dist/middleware/path-normalization.js +73 -84
- package/dist/middleware/path-normalization.js.map +1 -1
- package/dist/middleware/types.d.ts +3 -3
- package/dist/payload-codecs.js +2 -1
- package/dist/payload-codecs.js.map +1 -1
- package/dist/runner-manager.d.ts +1 -1
- package/dist/runner-manager.js +42 -22
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.js +30 -6
- package/dist/runner.js.map +1 -1
- package/dist/shared/args-preview.d.ts +8 -0
- package/dist/shared/args-preview.js +14 -3
- package/dist/shared/args-preview.js.map +1 -1
- package/dist/shared/artifact-storage.d.ts +11 -1
- package/dist/shared/artifact-storage.js +10 -1
- package/dist/shared/artifact-storage.js.map +1 -1
- package/dist/shared/declared-preferences.d.ts +47 -0
- package/dist/shared/declared-preferences.js +64 -0
- package/dist/shared/declared-preferences.js.map +1 -0
- package/dist/shared/fingerprint-secret.d.ts +3 -2
- package/dist/shared/fingerprint-secret.js +5 -3
- package/dist/shared/fingerprint-secret.js.map +1 -1
- package/dist/shared/llm-backend.js +8 -1
- package/dist/shared/llm-backend.js.map +1 -1
- package/dist/shared/mcp-enabled-tools.d.ts +2 -3
- package/dist/shared/mcp-enabled-tools.js +2 -3
- package/dist/shared/mcp-enabled-tools.js.map +1 -1
- package/dist/shared/mcp-resolver.d.ts +20 -15
- package/dist/shared/mcp-resolver.js +11 -12
- package/dist/shared/mcp-resolver.js.map +1 -1
- package/dist/shared/model-client.d.ts +15 -0
- package/dist/shared/model-client.js +57 -13
- package/dist/shared/model-client.js.map +1 -1
- package/dist/shared/placeholder-resolver.d.ts +9 -2
- package/dist/shared/placeholder-resolver.js +9 -2
- package/dist/shared/placeholder-resolver.js.map +1 -1
- package/dist/shared/plan-mode-permissions.d.ts +26 -46
- package/dist/shared/plan-mode-permissions.js +27 -55
- package/dist/shared/plan-mode-permissions.js.map +1 -1
- package/dist/shared/registry-endpoint.d.ts +5 -0
- package/dist/shared/registry-endpoint.js +7 -1
- package/dist/shared/registry-endpoint.js.map +1 -1
- package/dist/shared/runner-credential-keys.d.ts +26 -1
- package/dist/shared/runner-credential-keys.js +34 -1
- package/dist/shared/runner-credential-keys.js.map +1 -1
- package/dist/shared/runner-credential-store.d.ts +77 -0
- package/dist/shared/runner-credential-store.js +111 -0
- package/dist/shared/runner-credential-store.js.map +1 -0
- package/dist/shared/service-tier.d.ts +55 -0
- package/dist/shared/service-tier.js +67 -0
- package/dist/shared/service-tier.js.map +1 -0
- package/dist/shared/skill-mount.d.ts +89 -0
- package/dist/shared/skill-mount.js +142 -0
- package/dist/shared/skill-mount.js.map +1 -0
- package/dist/shared/skill-writer.d.ts +28 -26
- package/dist/shared/skill-writer.js +79 -102
- package/dist/shared/skill-writer.js.map +1 -1
- package/dist/shared/worker-shutdown.d.ts +67 -0
- package/dist/shared/worker-shutdown.js +79 -0
- package/dist/shared/worker-shutdown.js.map +1 -0
- package/dist/shared/workspace/types.d.ts +3 -2
- package/dist/shared/zip-extract.d.ts +10 -3
- package/dist/shared/zip-extract.js +10 -3
- package/dist/shared/zip-extract.js.map +1 -1
- package/dist/workflow-engine/loader.js +38 -1
- package/dist/workflow-engine/loader.js.map +1 -1
- package/dist/workflow-engine/tasks/call-function.d.ts +14 -0
- package/dist/workflow-engine/tasks/call-function.js +49 -5
- package/dist/workflow-engine/tasks/call-function.js.map +1 -1
- package/dist/workflow-engine/tasks/human-input.js +23 -2
- package/dist/workflow-engine/tasks/human-input.js.map +1 -1
- package/dist/workflow-engine/types.d.ts +6 -0
- package/dist/workflow-engine/types.js.map +1 -1
- package/dist/workflows/engine-core.js +36 -8
- package/dist/workflows/engine-core.js.map +1 -1
- package/package.json +15 -11
- package/src/activities/__tests__/call-http.test.ts +36 -0
- package/src/activities/__tests__/call-llm.test.ts +77 -0
- package/src/activities/call-http.ts +17 -0
- package/src/activities/call-llm.ts +78 -2
- package/src/activities/execute-cursor/__tests__/agent-session-cache.test.ts +220 -0
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +50 -0
- package/src/activities/execute-cursor/__tests__/cursor-mcp-config.test.ts +111 -0
- package/src/activities/execute-cursor/__tests__/service-tier.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/skill-resolver.test.ts +3 -94
- package/src/activities/execute-cursor/agent-session-cache.ts +229 -0
- package/src/activities/execute-cursor/cursor-mcp-config.ts +107 -0
- package/src/activities/execute-cursor/index.ts +129 -55
- package/src/activities/execute-cursor/prompt-builder.ts +29 -2
- package/src/activities/execute-cursor/service-tier.ts +5 -29
- package/src/activities/execute-cursor/session-lifecycle.ts +1 -1
- package/src/activities/execute-cursor/skill-resolver.ts +10 -137
- package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +15 -0
- package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +75 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/index.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +42 -29
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +52 -0
- package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +11 -8
- package/src/activities/execute-deep-agent/approval-file-change.ts +11 -1
- package/src/activities/execute-deep-agent/cas-capture-backend.ts +20 -3
- package/src/activities/execute-deep-agent/index.ts +57 -5
- package/src/activities/execute-deep-agent/prompt-builder.ts +22 -0
- package/src/activities/execute-deep-agent/setup.ts +36 -19
- package/src/activities/execute-deep-agent/shell-env.ts +10 -7
- package/src/activities/execute-deep-agent/subagent-transformer.ts +19 -12
- package/src/activities/execute-deep-agent/subagent-wiring.ts +3 -3
- package/src/config.ts +10 -5
- package/src/encryption/config.ts +8 -2
- package/src/index.ts +1 -1
- package/src/main.ts +16 -6
- package/src/middleware/__tests__/path-normalization.test.ts +32 -32
- package/src/middleware/path-normalization.ts +78 -90
- package/src/middleware/types.ts +3 -3
- package/src/payload-codecs.ts +2 -1
- package/src/runner-manager.ts +55 -22
- package/src/runner.ts +39 -6
- package/src/shared/__tests__/artifact-storage.test.ts +28 -0
- package/src/shared/__tests__/bedrock-seam.test.ts +5 -5
- package/src/shared/__tests__/declared-preferences.test.ts +109 -0
- package/src/shared/__tests__/foundry-seam.test.ts +5 -5
- package/src/shared/__tests__/model-client.test.ts +99 -0
- package/src/shared/__tests__/plan-mode-permissions.test.ts +15 -44
- package/src/shared/__tests__/runner-credential-store.test.ts +155 -0
- package/src/shared/__tests__/skill-mount.test.ts +238 -0
- package/src/shared/__tests__/skill-writer.test.ts +151 -128
- package/src/shared/__tests__/vertex-adapter.test.ts +30 -3
- package/src/shared/__tests__/vertex-seam.test.ts +5 -5
- package/src/shared/__tests__/worker-shutdown.test.ts +101 -0
- package/src/shared/__tests__/zip-extract.test.ts +46 -11
- package/src/shared/args-preview.ts +17 -3
- package/src/shared/artifact-storage.ts +20 -1
- package/src/shared/declared-preferences.ts +84 -0
- package/src/shared/fingerprint-secret.ts +5 -3
- package/src/shared/llm-backend.ts +7 -1
- package/src/shared/mcp-enabled-tools.ts +2 -3
- package/src/shared/mcp-resolver.ts +20 -20
- package/src/shared/model-client.ts +76 -13
- package/src/shared/placeholder-resolver.ts +9 -2
- package/src/shared/plan-mode-permissions.ts +27 -58
- package/src/shared/registry-endpoint.ts +9 -1
- package/src/shared/runner-credential-keys.ts +36 -1
- package/src/shared/runner-credential-store.ts +115 -0
- package/src/shared/service-tier.ts +78 -0
- package/src/shared/skill-mount.ts +179 -0
- package/src/shared/skill-writer.ts +96 -130
- package/src/shared/worker-shutdown.ts +99 -0
- package/src/shared/workspace/types.ts +3 -2
- package/src/shared/zip-extract.ts +14 -7
- package/src/workflow-engine/__tests__/golden-execution.test.ts +20 -1
- package/src/workflow-engine/__tests__/loader.test.ts +51 -0
- package/src/workflow-engine/__tests__/tasks/call-function.test.ts +105 -0
- package/src/workflow-engine/__tests__/tasks/human-input.test.ts +117 -0
- package/src/workflow-engine/loader.ts +46 -1
- package/src/workflow-engine/tasks/call-function.ts +74 -13
- package/src/workflow-engine/tasks/human-input.ts +33 -5
- package/src/workflow-engine/types.ts +6 -0
- package/src/workflows/engine-core.ts +39 -8
- package/dist/activities/execute-cursor/connect-backfill.d.ts +0 -19
- package/dist/activities/execute-cursor/connect-backfill.js +0 -27
- package/dist/activities/execute-cursor/connect-backfill.js.map +0 -1
- package/dist/activities/execute-cursor/mcp-resolver.d.ts +0 -120
- package/dist/activities/execute-cursor/mcp-resolver.js +0 -194
- package/dist/activities/execute-cursor/mcp-resolver.js.map +0 -1
- package/dist/activities/execute-cursor/placeholder-resolver.d.ts +0 -34
- package/dist/activities/execute-cursor/placeholder-resolver.js +0 -82
- package/dist/activities/execute-cursor/placeholder-resolver.js.map +0 -1
- package/src/activities/execute-cursor/__tests__/mcp-resolver.test.ts +0 -125
- package/src/activities/execute-cursor/connect-backfill.ts +0 -52
- package/src/activities/execute-cursor/mcp-resolver.ts +0 -324
- package/src/activities/execute-cursor/placeholder-resolver.ts +0 -109
|
@@ -78,10 +78,33 @@ import { stampFlowedFileEditRows, stampFlowedSubAgentFileEditRows } from "./stam
|
|
|
78
78
|
import { deriveTurnCommandProvenance } from "./command-provenance.js";
|
|
79
79
|
import { describeExecutionError } from "../../shared/model-error.js";
|
|
80
80
|
import { inferProvider, type LlmProvider } from "../../shared/llm-proxy.js";
|
|
81
|
+
import { getShutdownSignalForQueue } from "../../shared/worker-shutdown.js";
|
|
81
82
|
|
|
82
83
|
/** The harness id stamped on the deep-agent's file-review ledger events. */
|
|
83
84
|
const DEEP_AGENT_HARNESS_ID = "deep-agent";
|
|
84
85
|
|
|
86
|
+
/**
|
|
87
|
+
* The worker-shutdown terminal status (#776). A shutdown is not a pause: the
|
|
88
|
+
* execution will not resume on this worker, so persisting PAUSED would strand
|
|
89
|
+
* the user with a lie. The copy is byte-identical to the Cursor harness's
|
|
90
|
+
* worker-shutdown branch so every downstream status.error consumer (the Go and
|
|
91
|
+
* Java workflow fallbacks, the cloud channel decision table) keys on ONE shape.
|
|
92
|
+
*/
|
|
93
|
+
function buildWorkerShutdownStatus(): AgentExecutionStatus {
|
|
94
|
+
return create(AgentExecutionStatusSchema, {
|
|
95
|
+
phase: ExecutionPhase.EXECUTION_FAILED,
|
|
96
|
+
error: "Execution interrupted: runner worker was shut down. Retry or resume.",
|
|
97
|
+
completedAt: utcTimestamp(),
|
|
98
|
+
messages: [
|
|
99
|
+
create(AgentMessageSchema, {
|
|
100
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
101
|
+
content: "Execution interrupted: the runner worker was shut down while the agent was still running. You can retry or resume.",
|
|
102
|
+
timestamp: utcTimestamp(),
|
|
103
|
+
}),
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
85
108
|
/**
|
|
86
109
|
* Best-effort provider inference for error-message wording. inferProvider
|
|
87
110
|
* throws on unrecognized names; an error path must never throw over a label.
|
|
@@ -115,6 +138,11 @@ export function createDeepAgentActivities(config: Config) {
|
|
|
115
138
|
): Promise<unknown> => {
|
|
116
139
|
const { executionId, threadId, turnSeq } = normalizeActivityInput(arg0, arg1);
|
|
117
140
|
activityStarted();
|
|
141
|
+
// Worker-shutdown classification channel (#776): the pause paths below
|
|
142
|
+
// consult this signal to distinguish "my worker is draining" (SIGTERM,
|
|
143
|
+
// desktop quit) from "the orchestrator cancelled me" (a real user
|
|
144
|
+
// pause). See shared/worker-shutdown.ts for the ownership contract.
|
|
145
|
+
const shutdownSignal = getShutdownSignalForQueue(Context.current().info.taskQueue);
|
|
118
146
|
let setup: SetupResult | null = null;
|
|
119
147
|
// Exclusive turn lock on the workspace working tree — held across the
|
|
120
148
|
// entire tree-mutating window (decision reconcile, agent writes,
|
|
@@ -567,6 +595,13 @@ export function createDeepAgentActivities(config: Config) {
|
|
|
567
595
|
|
|
568
596
|
if (result.terminalStatus) {
|
|
569
597
|
if (initialStatus.phase === ExecutionPhase.EXECUTION_PAUSED) {
|
|
598
|
+
// The stream loop marks PAUSED for ANY platform cancellation; a
|
|
599
|
+
// worker shutdown is not a pause and must not persist as one (#776).
|
|
600
|
+
if (shutdownSignal?.aborted) {
|
|
601
|
+
console.log(`[ExecuteDeepAgent] Cancelled (worker shutdown) for execution ${executionId}: events=${result.eventsProcessed}`);
|
|
602
|
+
await persistStatus(client, executionId, buildWorkerShutdownStatus(), { offload: statusOffload }).catch(() => {});
|
|
603
|
+
throw new CancelledFailure("Activity cancelled (worker shutdown, not user pause)");
|
|
604
|
+
}
|
|
570
605
|
await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
|
|
571
606
|
console.log(`[ExecuteDeepAgent] Paused for execution ${executionId}: events=${result.eventsProcessed}`);
|
|
572
607
|
throw new CancelledFailure("Activity paused by orchestrator");
|
|
@@ -617,15 +652,20 @@ export function createDeepAgentActivities(config: Config) {
|
|
|
617
652
|
policyEngineVersion: intr.policySource ? POLICY_ENGINE_VERSION : "",
|
|
618
653
|
});
|
|
619
654
|
|
|
620
|
-
// Capture a sanitized args preview
|
|
621
|
-
//
|
|
622
|
-
//
|
|
623
|
-
//
|
|
624
|
-
|
|
655
|
+
// Capture a sanitized args preview AND the redacted args object
|
|
656
|
+
// while the graph is paused, so the approval UI renders the
|
|
657
|
+
// proposed change before the tool runs — and the row header can
|
|
658
|
+
// extract its filename-first path from `args` like every other
|
|
659
|
+
// row (issue #754: a placeholder without args rendered a
|
|
660
|
+
// pathless "Write" header). Args are correlated from the
|
|
661
|
+
// AI-message tool call in graph state (the single source of
|
|
662
|
+
// truth).
|
|
663
|
+
const { argsPreview, args } = captureApprovalArtifacts({
|
|
625
664
|
toolCallId: intr.toolCallId,
|
|
626
665
|
messages: aiMessages,
|
|
627
666
|
});
|
|
628
667
|
if (argsPreview) toolCall.argsPreview = argsPreview;
|
|
668
|
+
if (args) toolCall.args = args as typeof toolCall.args;
|
|
629
669
|
|
|
630
670
|
aiMsg.toolCalls.push(toolCall);
|
|
631
671
|
}
|
|
@@ -749,6 +789,13 @@ export function createDeepAgentActivities(config: Config) {
|
|
|
749
789
|
|
|
750
790
|
} catch (err: unknown) {
|
|
751
791
|
if (err instanceof CancelledFailure) {
|
|
792
|
+
// Worker shutdown is infrastructure failure, not pause — the caught
|
|
793
|
+
// CancelledFailure is itself the interruption evidence (#776).
|
|
794
|
+
if (shutdownSignal?.aborted) {
|
|
795
|
+
console.log(`[ExecuteDeepAgent] Cancelled (worker shutdown) for execution ${executionId}`);
|
|
796
|
+
await persistStatus(client, executionId, buildWorkerShutdownStatus()).catch(() => {});
|
|
797
|
+
throw err;
|
|
798
|
+
}
|
|
752
799
|
console.log(`[ExecuteDeepAgent] Cancelled (pause) for execution ${executionId}`);
|
|
753
800
|
const pausedStatus = create(AgentExecutionStatusSchema, {
|
|
754
801
|
phase: ExecutionPhase.EXECUTION_PAUSED,
|
|
@@ -758,6 +805,11 @@ export function createDeepAgentActivities(config: Config) {
|
|
|
758
805
|
}
|
|
759
806
|
|
|
760
807
|
if (Context.current().cancellationSignal.aborted) {
|
|
808
|
+
if (shutdownSignal?.aborted) {
|
|
809
|
+
console.log(`[ExecuteDeepAgent] Error during worker-shutdown cancellation for ${executionId}: ${err}`);
|
|
810
|
+
await persistStatus(client, executionId, buildWorkerShutdownStatus()).catch(() => {});
|
|
811
|
+
throw new CancelledFailure("Activity cancelled (worker shutdown, not user pause)");
|
|
812
|
+
}
|
|
761
813
|
console.log(`[ExecuteDeepAgent] Error during cancellation for ${executionId}, treating as pause: ${err}`);
|
|
762
814
|
const pausedStatus = create(AgentExecutionStatusSchema, {
|
|
763
815
|
phase: ExecutionPhase.EXECUTION_PAUSED,
|
|
@@ -17,6 +17,10 @@ import {
|
|
|
17
17
|
type SenderIdentity,
|
|
18
18
|
} from "../../shared/sender-identity.js";
|
|
19
19
|
import { formatSessionContextText } from "../../shared/session-context.js";
|
|
20
|
+
import {
|
|
21
|
+
formatDeclaredPreferencesText,
|
|
22
|
+
type DeclaredPreferencesContent,
|
|
23
|
+
} from "../../shared/declared-preferences.js";
|
|
20
24
|
import {
|
|
21
25
|
visionDisclosureLines,
|
|
22
26
|
type NotViewableEntry,
|
|
@@ -166,6 +170,14 @@ export interface PromptBuilderInput {
|
|
|
166
170
|
* context is standing session state, like skills.
|
|
167
171
|
*/
|
|
168
172
|
sessionContext?: string;
|
|
173
|
+
/**
|
|
174
|
+
* Platform-declared standing preferences (stigmer/stigmer#293): the org's
|
|
175
|
+
* and user's standing context, server-snapshotted onto the execution
|
|
176
|
+
* spec's `declared_preferences` at create. Injected on EVERY turn like
|
|
177
|
+
* the bridge — the native system prompt is rebuilt per invocation, so an
|
|
178
|
+
* edited preference reaches the very next turn.
|
|
179
|
+
*/
|
|
180
|
+
declaredPreferences?: DeclaredPreferencesContent;
|
|
169
181
|
}
|
|
170
182
|
|
|
171
183
|
// The prompt renders the injector's own result type — a local structural twin
|
|
@@ -229,6 +241,16 @@ export function buildEnhancedSystemPrompt(input: PromptBuilderInput): string {
|
|
|
229
241
|
formatSenderIdentityText(input.senderIdentity);
|
|
230
242
|
}
|
|
231
243
|
|
|
244
|
+
// Platform-declared standing facts precede embedder-supplied context
|
|
245
|
+
// (DD-002 D3): both are standing background, but the declared preferences
|
|
246
|
+
// are platform-authored while session context is the embedder's overlay —
|
|
247
|
+
// the more specific overlay reads later and naturally refines.
|
|
248
|
+
if (input.declaredPreferences) {
|
|
249
|
+
prompt +=
|
|
250
|
+
"\n\n## Declared preferences\n\n" +
|
|
251
|
+
formatDeclaredPreferencesText(input.declaredPreferences);
|
|
252
|
+
}
|
|
253
|
+
|
|
232
254
|
// Standing facts about the user (session context) come before the
|
|
233
255
|
// carried conversation (bridge): the bridge may refer back to them.
|
|
234
256
|
if (input.sessionContext) {
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
resolveCallerIdentity,
|
|
33
33
|
} from "../../shared/caller-identity.js";
|
|
34
34
|
import { readSessionContext } from "../../shared/session-context.js";
|
|
35
|
+
import { readDeclaredPreferences } from "../../shared/declared-preferences.js";
|
|
35
36
|
import { connectMcpServers, type McpConnectionResult } from "../../shared/mcp-manager.js";
|
|
36
37
|
import { mergeMcpServerUsages, resolveMcpServers } from "../../shared/mcp-resolver.js";
|
|
37
38
|
import { resolveMcpTransportPosture } from "../../shared/mcp-transport-guard.js";
|
|
@@ -72,6 +73,7 @@ import { getRunnerHitlMasterSecret } from "../../shared/fingerprint-secret.js";
|
|
|
72
73
|
import { getModelPricing, ensureLoaded as ensurePricingLoaded } from "../../shared/model-pricing.js";
|
|
73
74
|
import { getDefaultModel, getModelVisionCapability } from "../../shared/model-registry.js";
|
|
74
75
|
import { buildChatModel } from "../../shared/model-client.js";
|
|
76
|
+
import { resolveEffectiveServiceTier } from "../../shared/service-tier.js";
|
|
75
77
|
import {
|
|
76
78
|
loadArtifactStorageConfig,
|
|
77
79
|
resolveUsableArtifactStorage,
|
|
@@ -87,12 +89,9 @@ import type { ToolApprovalCategory } from "../../shared/tool-kind.js";
|
|
|
87
89
|
import {
|
|
88
90
|
mergeSkillRefs,
|
|
89
91
|
fetchSkillsByRefs,
|
|
90
|
-
|
|
91
|
-
computeSkillPaths,
|
|
92
|
-
checkSkillIntegrity,
|
|
92
|
+
mountSkills,
|
|
93
93
|
generatePromptSection,
|
|
94
94
|
generateAlsoAvailableSection,
|
|
95
|
-
fetchSkillArtifacts,
|
|
96
95
|
} from "../../shared/skill-writer.js";
|
|
97
96
|
import { filterSkills, SKILL_COUNT_THRESHOLD } from "../../shared/skill-relevance.js";
|
|
98
97
|
import { injectAttachments } from "./attachment-injector.js";
|
|
@@ -477,8 +476,11 @@ export async function performSetup(deps: SetupDependencies): Promise<SetupResult
|
|
|
477
476
|
const skills = await fetchSkillsByRefs(client, skillRefs);
|
|
478
477
|
|
|
479
478
|
if (skills.length > 0) {
|
|
480
|
-
|
|
481
|
-
|
|
479
|
+
// platformDir is an invariant of this path: provisionWorkspace below
|
|
480
|
+
// threads ensurePlatformDir into every backend it constructs.
|
|
481
|
+
const { paths: skillPaths } = await mountSkills(
|
|
482
|
+
client, skills, workspaceBackend.platformDir!,
|
|
483
|
+
);
|
|
482
484
|
|
|
483
485
|
const userMessage = execution.spec!.message || "";
|
|
484
486
|
const skillNames = skills.map(s => s.spec?.name || s.metadata?.slug || "unknown");
|
|
@@ -572,6 +574,9 @@ export async function performSetup(deps: SetupDependencies): Promise<SetupResult
|
|
|
572
574
|
contextBridge: readContextBridge(session.spec!.metadata),
|
|
573
575
|
senderIdentity: readSenderIdentity(session.spec!.metadata),
|
|
574
576
|
sessionContext: readSessionContext(session.spec!.metadata),
|
|
577
|
+
declaredPreferences: readDeclaredPreferences(
|
|
578
|
+
execution.spec!.declaredPreferences,
|
|
579
|
+
),
|
|
575
580
|
});
|
|
576
581
|
|
|
577
582
|
// Step 9: Construct the LLM model. Resolution to the provider API id
|
|
@@ -580,11 +585,22 @@ export async function performSetup(deps: SetupDependencies): Promise<SetupResult
|
|
|
580
585
|
// The operator's STIGMER_LLM_REQUEST_TIMEOUT_MS bound is applied inside
|
|
581
586
|
// buildChatModel (#468) — the sub-agent modelFactory below silently
|
|
582
587
|
// dropped it when each caller parsed the env itself.
|
|
588
|
+
//
|
|
589
|
+
// The service tier resolves ONCE here (UNSPECIFIED → explicit
|
|
590
|
+
// STANDARD, shared/service-tier.ts) and rides every model this
|
|
591
|
+
// execution constructs — the primary below AND the sub-agent factory —
|
|
592
|
+
// so the provider account's default can never pick the price of any
|
|
593
|
+
// turn (#361, the native half of #357's contract). Sub-agents inherit
|
|
594
|
+
// it because the tier is an attribute of the EXECUTION's bill, and
|
|
595
|
+
// sub-agent calls land on the same ledger.
|
|
596
|
+
const serviceTier = resolveEffectiveServiceTier(
|
|
597
|
+
execution.spec!.executionConfig?.serviceTier);
|
|
583
598
|
const { model } = await buildChatModel({
|
|
584
599
|
modelName,
|
|
585
600
|
proxyEndpoint: config.proxyEndpoint ?? undefined,
|
|
586
601
|
stigmerToken: config.stigmerToken ?? undefined,
|
|
587
602
|
headerScope: { executionId },
|
|
603
|
+
serviceTier,
|
|
588
604
|
});
|
|
589
605
|
timing.mark("build_model");
|
|
590
606
|
|
|
@@ -594,16 +610,13 @@ export async function performSetup(deps: SetupDependencies): Promise<SetupResult
|
|
|
594
610
|
const execConfig = execution.spec!.executionConfig;
|
|
595
611
|
const isPlanMode = execConfig?.interactionMode === InteractionMode.PLAN;
|
|
596
612
|
const shellEnv = isPlanMode ? undefined : buildShellEnv(envResult.mergedEnvVars);
|
|
597
|
-
// Plan mode's filesystem permission rules, hoisted once: the parent graph
|
|
598
|
-
// every sub-agent graph
|
|
599
|
-
//
|
|
600
|
-
//
|
|
601
|
-
//
|
|
602
|
-
//
|
|
603
|
-
|
|
604
|
-
const planModePermissions = isPlanMode
|
|
605
|
-
? buildPlanModePermissions(workspaceBackend.rootDir)
|
|
606
|
-
: undefined;
|
|
613
|
+
// Plan mode's filesystem permission rules, hoisted once: the parent graph
|
|
614
|
+
// and every sub-agent graph carry this single value. The rules are the
|
|
615
|
+
// write-deny half of plan mode only — the read boundary is structural
|
|
616
|
+
// (virtual-rooted backends, issue #754), and the path-normalization shim
|
|
617
|
+
// is no longer tied to the rules: every native graph installs it (see
|
|
618
|
+
// buildMiddlewareStack below) so the whole harness speaks one dialect.
|
|
619
|
+
const planModePermissions = isPlanMode ? buildPlanModePermissions() : undefined;
|
|
607
620
|
|
|
608
621
|
const toolServerMap = new Map<string, string>();
|
|
609
622
|
if (mcpConnection) {
|
|
@@ -717,9 +730,10 @@ export async function performSetup(deps: SetupDependencies): Promise<SetupResult
|
|
|
717
730
|
} : null,
|
|
718
731
|
otelSpans: { toolServerMap },
|
|
719
732
|
approvalGate: approvalGateConfig,
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
733
|
+
// Every graph, every mode (issue #754): the dialect-repair seam that
|
|
734
|
+
// keeps model-supplied paths canonical for the virtual-rooted backend
|
|
735
|
+
// and every downstream consumer (gate, capture, spans).
|
|
736
|
+
pathNormalization: { rootDir: workspaceBackend.rootDir },
|
|
723
737
|
});
|
|
724
738
|
timing.mark("build_middleware");
|
|
725
739
|
|
|
@@ -776,6 +790,9 @@ export async function performSetup(deps: SetupDependencies): Promise<SetupResult
|
|
|
776
790
|
proxyEndpoint: config.proxyEndpoint ?? undefined,
|
|
777
791
|
stigmerToken: config.stigmerToken ?? undefined,
|
|
778
792
|
headerScope: { executionId },
|
|
793
|
+
// The execution's tier, inherited: sub-agent calls bill to the
|
|
794
|
+
// same execution (#361 — see the Step 9 resolution comment).
|
|
795
|
+
serviceTier,
|
|
779
796
|
})).model,
|
|
780
797
|
// Presence of shellEnv is the shell-capability switch for sub-agent
|
|
781
798
|
// backends too (undefined in plan mode; see buildShellEnv above).
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shell environment for the native harness `execute` tool.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Since #508's boot capture, runner secrets never LIVE in `process.env`, so
|
|
5
|
+
* the denylist below is defense-in-depth: it keeps this surface safe even if
|
|
6
|
+
* something re-plants a secret in the environment after boot (a test, an
|
|
7
|
+
* embedder, a future regression). Still built per execution — the snapshot
|
|
8
|
+
* must reflect the env as it is now, not at process start.
|
|
7
9
|
*/
|
|
8
10
|
|
|
9
|
-
import {
|
|
11
|
+
import { RUNNER_SECRET_ENV_KEYS } from "../../shared/runner-credential-keys.js";
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Runner-internal keys that must never reach agent shell commands: every
|
|
13
|
-
* credential the runner holds for its own outbound calls (issue #385)
|
|
14
|
-
*
|
|
15
|
+
* credential the runner holds for its own outbound calls (issue #385) plus
|
|
16
|
+
* the runner's encryption keys (issue #508). The names — and the rules for
|
|
17
|
+
* adding one — live in runner-credential-keys.ts.
|
|
15
18
|
*/
|
|
16
|
-
export const SHELL_ENV_DENYLIST: readonly string[] =
|
|
19
|
+
export const SHELL_ENV_DENYLIST: readonly string[] = RUNNER_SECRET_ENV_KEYS;
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* Build the environment map passed to deepagents' LocalShellBackend.
|
|
@@ -42,8 +42,7 @@ import { SubAgentGate } from "../../shared/subagent-gate.js";
|
|
|
42
42
|
import { isModelRegistered } from "../../shared/model-registry.js";
|
|
43
43
|
import {
|
|
44
44
|
fetchSkillsByRefs,
|
|
45
|
-
|
|
46
|
-
writeSkills,
|
|
45
|
+
mountSkills,
|
|
47
46
|
generatePromptSection,
|
|
48
47
|
} from "../../shared/skill-writer.js";
|
|
49
48
|
|
|
@@ -493,6 +492,10 @@ export function resolveSubagentSkillPrompt(
|
|
|
493
492
|
* (approval-gated by the sub-agent's own middleware). Absent (plan mode),
|
|
494
493
|
* the backend is filesystem-only — read-only by construction, matching the
|
|
495
494
|
* parent.
|
|
495
|
+
*
|
|
496
|
+
* Every variant is virtual-rooted (`virtualMode: true`) like the parent's —
|
|
497
|
+
* see the cas-capture-backend.ts header (issue #754): workspace confinement
|
|
498
|
+
* is structural on every graph, sub-agents included.
|
|
496
499
|
*/
|
|
497
500
|
async function buildSubagentBackend(opts: {
|
|
498
501
|
readonly workspaceRootDir: string;
|
|
@@ -508,11 +511,12 @@ async function buildSubagentBackend(opts: {
|
|
|
508
511
|
}
|
|
509
512
|
|
|
510
513
|
if (opts.shellEnv === undefined) {
|
|
511
|
-
return new FilesystemBackend({ rootDir: opts.workspaceRootDir });
|
|
514
|
+
return new FilesystemBackend({ rootDir: opts.workspaceRootDir, virtualMode: true });
|
|
512
515
|
}
|
|
513
516
|
|
|
514
517
|
const shellBackend = new LocalShellBackend({
|
|
515
518
|
rootDir: opts.workspaceRootDir,
|
|
519
|
+
virtualMode: true,
|
|
516
520
|
env: opts.shellEnv,
|
|
517
521
|
});
|
|
518
522
|
await shellBackend.initialize();
|
|
@@ -554,17 +558,14 @@ export async function compileSubagents(
|
|
|
554
558
|
// Structural coupling (DD-19): a sub-agent gate flows gitignored writes into
|
|
555
559
|
// CAS iff a CAS observer backs that sub-agent's filesystem backend. Deriving
|
|
556
560
|
// both from the same `casObserver` makes "unobserved unreviewable bytes"
|
|
557
|
-
// impossible by construction.
|
|
558
|
-
// (issue #
|
|
559
|
-
//
|
|
560
|
-
// prompt-compliant relative paths from dying in rule validation.
|
|
561
|
+
// impossible by construction. Path normalization is unconditional
|
|
562
|
+
// (issue #754): every graph speaks the virtual dialect, so every graph
|
|
563
|
+
// carries the repair seam — matching the parent's composition.
|
|
561
564
|
const middleware = buildSubAgentMiddleware({
|
|
562
565
|
costCap: opts.costCap,
|
|
563
566
|
approvalGate: opts.approvalGate,
|
|
564
567
|
captureIgnored: !!opts.casObserver,
|
|
565
|
-
|
|
566
|
-
? { pathNormalization: { rootDir: opts.workspaceRootDir } }
|
|
567
|
-
: {}),
|
|
568
|
+
pathNormalization: { rootDir: opts.workspaceRootDir },
|
|
568
569
|
});
|
|
569
570
|
|
|
570
571
|
const modelName = spec.model ?? opts.parentModelName;
|
|
@@ -679,8 +680,14 @@ export async function transformAndCompileSubagents(
|
|
|
679
680
|
const skills = await fetchSkillsByRefs(skillClient, refs);
|
|
680
681
|
|
|
681
682
|
if (skills.length > 0) {
|
|
682
|
-
|
|
683
|
-
|
|
683
|
+
// Runs after the parent's setup step 7b mounted its skills, so any
|
|
684
|
+
// skill shared by parent and sub-agent is a cache hit here — the
|
|
685
|
+
// hash-keyed marker turns the old double download into a no-op.
|
|
686
|
+
// platformDir is an invariant: provisionWorkspace threads
|
|
687
|
+
// ensurePlatformDir into every backend it constructs.
|
|
688
|
+
const { paths: skillPaths } = await mountSkills(
|
|
689
|
+
skillClient, skills, workspaceBackend.platformDir!,
|
|
690
|
+
);
|
|
684
691
|
|
|
685
692
|
for (const skill of skills) {
|
|
686
693
|
const slug = (skill as { metadata?: { slug?: string } }).metadata?.slug;
|
|
@@ -75,9 +75,9 @@ export interface SubAgentMiddlewareOptions {
|
|
|
75
75
|
*/
|
|
76
76
|
readonly captureIgnored?: boolean;
|
|
77
77
|
/**
|
|
78
|
-
*
|
|
79
|
-
* sub-agent
|
|
80
|
-
*
|
|
78
|
+
* Virtual-dialect path normalization (issues #429/#754). Present on every
|
|
79
|
+
* sub-agent graph — the backends are virtual-rooted, so every graph
|
|
80
|
+
* carries the repair seam, matching the parent composition.
|
|
81
81
|
*/
|
|
82
82
|
readonly pathNormalization?: PathNormalizationConfig;
|
|
83
83
|
}
|
package/src/config.ts
CHANGED
|
@@ -53,6 +53,7 @@ export const DEFAULT_CURSOR_AGENT_RESOLVE_TIMEOUT_MS = 120_000;
|
|
|
53
53
|
// three construction sites — mirrors DEFAULT_CURSOR_STREAM_STALL_TIMEOUT_MS).
|
|
54
54
|
export { DEFAULT_WORKSPACE_LOCK_TIMEOUT_MS } from "./shared/workspace/workspace-lock.js";
|
|
55
55
|
import { DEFAULT_WORKSPACE_LOCK_TIMEOUT_MS } from "./shared/workspace/workspace-lock.js";
|
|
56
|
+
import { getRunnerSecret } from "./shared/runner-credential-store.js";
|
|
56
57
|
|
|
57
58
|
export interface Config {
|
|
58
59
|
readonly taskQueue: string;
|
|
@@ -158,9 +159,13 @@ export function loadConfig(): Config {
|
|
|
158
159
|
: requireEnv("STIGMER_BACKEND_ENDPOINT"),
|
|
159
160
|
);
|
|
160
161
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
// Secrets resolve through the credential store, not process.env — the
|
|
163
|
+
// boot capture has already moved them out of the environment (#508).
|
|
164
|
+
const stigmerTokenValue = getRunnerSecret("STIGMER_TOKEN");
|
|
165
|
+
if ((mode === "cloud" || proxyActive) && !stigmerTokenValue) {
|
|
166
|
+
throw new Error("Required environment variable STIGMER_TOKEN is not set");
|
|
167
|
+
}
|
|
168
|
+
const stigmerToken = stigmerTokenValue ?? null;
|
|
164
169
|
|
|
165
170
|
const mcpBridgeEndpoint = process.env.STIGMER_MCP_BRIDGE_ENDPOINT ?? null;
|
|
166
171
|
|
|
@@ -170,8 +175,8 @@ export function loadConfig(): Config {
|
|
|
170
175
|
// the SDK's authorization header (Cursor access token) passes through to
|
|
171
176
|
// api2.cursor.sh unchanged.
|
|
172
177
|
const cursorApiKey = proxyActive
|
|
173
|
-
? (
|
|
174
|
-
: (
|
|
178
|
+
? (getRunnerSecret("CURSOR_API_KEY") ?? stigmerToken ?? "proxy-managed")
|
|
179
|
+
: (getRunnerSecret("CURSOR_API_KEY") ?? "");
|
|
175
180
|
|
|
176
181
|
const workspaceRootDir = resolveWorkspaceRootDir();
|
|
177
182
|
|
package/src/encryption/config.ts
CHANGED
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
* on the next runner boot — there is no live re-key.
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
+
import { getRunnerSecret } from "../shared/runner-credential-store.js";
|
|
29
|
+
|
|
28
30
|
export interface EncryptionKey {
|
|
29
31
|
readonly keyId: string;
|
|
30
32
|
/** 32-byte AES-256 key. */
|
|
@@ -75,14 +77,18 @@ const AES_256_KEY_BYTES = 32;
|
|
|
75
77
|
export function loadPayloadEncryptionConfig(
|
|
76
78
|
bootstrap?: BootstrapKeyMaterial,
|
|
77
79
|
): PayloadEncryptionConfig | undefined {
|
|
78
|
-
|
|
80
|
+
// Key VALUES resolve through the credential store (the #508 boot capture
|
|
81
|
+
// moves them out of process.env — agent shells must not read them); the
|
|
82
|
+
// *_KEY_ID companions are rotation bookkeeping, not secrets, and stay
|
|
83
|
+
// plain env reads.
|
|
84
|
+
const rawKey = getRunnerSecret(KEY_ENV);
|
|
79
85
|
if (rawKey) {
|
|
80
86
|
const primary: EncryptionKey = {
|
|
81
87
|
keyId: requireKeyId(KEY_ID_ENV),
|
|
82
88
|
key: parseKey(rawKey, KEY_ENV),
|
|
83
89
|
};
|
|
84
90
|
|
|
85
|
-
const rawSecondary =
|
|
91
|
+
const rawSecondary = getRunnerSecret(SECONDARY_KEY_ENV);
|
|
86
92
|
const secondary: EncryptionKey | undefined = rawSecondary
|
|
87
93
|
? {
|
|
88
94
|
keyId: requireKeyId(SECONDARY_KEY_ID_ENV),
|
package/src/index.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* import { createStigmerRunner } from '@stigmer/runner';
|
|
15
15
|
*
|
|
16
16
|
* const runner = await createStigmerRunner({
|
|
17
|
-
* taskQueue: '
|
|
17
|
+
* taskQueue: 'stigmer_runner',
|
|
18
18
|
* temporalAddress: 'localhost:7233',
|
|
19
19
|
* stigmerEndpoint: 'http://localhost:7234',
|
|
20
20
|
* });
|
package/src/main.ts
CHANGED
|
@@ -32,6 +32,10 @@ import { createInterface } from "node:readline";
|
|
|
32
32
|
import { preflightNodeRuntime } from "./preflight.js";
|
|
33
33
|
import { markBoot, emitRunnerBootTiming } from "./shared/cold-start-timing.js";
|
|
34
34
|
import { loadConfig } from "./config.js";
|
|
35
|
+
import {
|
|
36
|
+
captureRunnerSecrets,
|
|
37
|
+
getRunnerSecret,
|
|
38
|
+
} from "./shared/runner-credential-store.js";
|
|
35
39
|
import { initTracing, initMetrics } from "./otel.js";
|
|
36
40
|
import { createStigmerRunner } from "./runner.js";
|
|
37
41
|
import { createStigmerRunnerManager } from "./runner-manager.js";
|
|
@@ -214,11 +218,12 @@ async function runPoolMode(
|
|
|
214
218
|
});
|
|
215
219
|
|
|
216
220
|
// Sandbox credential self-renewal (see sandbox-token-renewal.ts). Watches
|
|
217
|
-
// the
|
|
218
|
-
// manager's internal ref: a blank member's pool_sandbox token
|
|
219
|
-
// loop, the claim's updateToken swaps in a renewable session
|
|
220
|
-
// from then on renewal applies fresh tokens back through the
|
|
221
|
-
// updateToken (which also cascades to the proxy-credential
|
|
221
|
+
// the credential store because manager.updateToken keeps it in lockstep
|
|
222
|
+
// with the manager's internal ref: a blank member's pool_sandbox token
|
|
223
|
+
// parks the loop, the claim's updateToken swaps in a renewable session
|
|
224
|
+
// token, and from then on renewal applies fresh tokens back through the
|
|
225
|
+
// same updateToken (which also cascades to the proxy-credential
|
|
226
|
+
// coordinator).
|
|
222
227
|
const { startSandboxTokenRenewal } = await import("./sandbox-token-renewal.js");
|
|
223
228
|
const { StigmerClient } = await import("./client/stigmer-client.js");
|
|
224
229
|
const renewalClient = new StigmerClient({
|
|
@@ -226,7 +231,7 @@ async function runPoolMode(
|
|
|
226
231
|
token: null,
|
|
227
232
|
});
|
|
228
233
|
const tokenRenewal = startSandboxTokenRenewal({
|
|
229
|
-
getToken: () =>
|
|
234
|
+
getToken: () => getRunnerSecret("STIGMER_TOKEN") ?? null,
|
|
230
235
|
renew: (currentToken) =>
|
|
231
236
|
renewalClient.getRunnerScopedToken({ renewal: true }, currentToken),
|
|
232
237
|
applyToken: (token) => manager.updateToken(token),
|
|
@@ -449,6 +454,11 @@ async function main(): Promise<void> {
|
|
|
449
454
|
|
|
450
455
|
checkBuildFreshness();
|
|
451
456
|
|
|
457
|
+
// Take custody of runner secrets before the config load reads them (#508).
|
|
458
|
+
// The factories capture too (they are the library boot doors); doing it
|
|
459
|
+
// here as well keeps main.ts's own late readers store-only from the start.
|
|
460
|
+
captureRunnerSecrets();
|
|
461
|
+
|
|
452
462
|
const config = loadConfig();
|
|
453
463
|
markBoot("config_loaded");
|
|
454
464
|
|