@stigmer/runner 3.40.1 → 3.41.0
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/README.md +3 -1
- package/dist/.build-fingerprint +1 -1
- package/dist/__test-utils__/execution-record-fixture.d.ts +2 -1
- package/dist/__test-utils__/execution-record-fixture.js.map +1 -1
- package/dist/activities/call-agent.js +1 -1
- package/dist/activities/discover-mcp-server.d.ts +7 -1
- package/dist/activities/discover-mcp-server.js +13 -29
- package/dist/activities/discover-mcp-server.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/fold.d.ts +4 -2
- package/dist/activities/execute-cursor/__test-utils__/fold.js +3 -4
- package/dist/activities/execute-cursor/__test-utils__/fold.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +1 -0
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
- package/dist/activities/execute-cursor/approval-policy.d.ts +1 -29
- package/dist/activities/execute-cursor/approval-policy.js +11 -35
- package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
- package/dist/activities/execute-cursor/boundary-rows.js +4 -4
- package/dist/activities/execute-cursor/boundary-rows.js.map +1 -1
- package/dist/activities/execute-cursor/translator.d.ts +12 -17
- package/dist/activities/execute-cursor/translator.js +13 -30
- package/dist/activities/execute-cursor/translator.js.map +1 -1
- package/dist/activities/execute-cursor/turn-stream.js +4 -2
- package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +11 -1
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +22 -3
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -1
- package/dist/activities/execute-deep-agent/inline-publisher.d.ts +33 -2
- package/dist/activities/execute-deep-agent/inline-publisher.js +33 -7
- package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -1
- package/dist/activities/execute-deep-agent/platform-route.d.ts +48 -13
- package/dist/activities/execute-deep-agent/platform-route.js +87 -19
- package/dist/activities/execute-deep-agent/platform-route.js.map +1 -1
- package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +20 -3
- package/dist/activities/execute-deep-agent/streaming-side-effects.js +26 -4
- package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
- package/dist/activities/execute-deep-agent/translator.d.ts +5 -4
- package/dist/activities/execute-deep-agent/translator.js +5 -4
- package/dist/activities/execute-deep-agent/translator.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn-settle.js +6 -6
- package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn-setup.js +7 -7
- package/dist/activities/execute-deep-agent/turn-setup.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn-stream.d.ts +10 -6
- package/dist/activities/execute-deep-agent/turn-stream.js +6 -16
- package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn.d.ts +4 -1
- package/dist/activities/execute-deep-agent/turn.js +15 -6
- package/dist/activities/execute-deep-agent/turn.js.map +1 -1
- package/dist/activities/workflow-event-activities.js +2 -0
- package/dist/activities/workflow-event-activities.js.map +1 -1
- package/dist/config.d.ts +9 -0
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/exit-backstop.d.ts +64 -0
- package/dist/exit-backstop.js +79 -0
- package/dist/exit-backstop.js.map +1 -0
- package/dist/harness/terminal-table.d.ts +12 -5
- package/dist/harness/terminal-table.js +13 -13
- package/dist/harness/terminal-table.js.map +1 -1
- package/dist/harness/transcript/builder.d.ts +21 -0
- package/dist/harness/transcript/builder.js +53 -31
- package/dist/harness/transcript/builder.js.map +1 -1
- package/dist/harness/transcript/events.d.ts +22 -26
- package/dist/harness/transcript/events.js +6 -5
- package/dist/harness/transcript/events.js.map +1 -1
- package/dist/harness/turn-context.d.ts +3 -1
- package/dist/harness/turn-context.js +5 -3
- package/dist/harness/turn-context.js.map +1 -1
- package/dist/main.js +10 -4
- package/dist/main.js.map +1 -1
- package/dist/middleware/cost-advisory.d.ts +6 -3
- package/dist/middleware/cost-advisory.js +6 -3
- package/dist/middleware/cost-advisory.js.map +1 -1
- package/dist/middleware/execution-budget.d.ts +22 -7
- package/dist/middleware/execution-budget.js +57 -35
- package/dist/middleware/execution-budget.js.map +1 -1
- package/dist/middleware/index.d.ts +10 -7
- package/dist/middleware/index.js +10 -7
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/types.d.ts +6 -1
- package/dist/runner-manager.js +3 -2
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.d.ts +25 -0
- package/dist/runner.js +41 -14
- package/dist/runner.js.map +1 -1
- package/dist/shared/approval-policy.d.ts +23 -13
- package/dist/shared/approval-policy.js +47 -14
- package/dist/shared/approval-policy.js.map +1 -1
- package/dist/shared/caller-identity.d.ts +4 -5
- package/dist/shared/caller-identity.js +4 -5
- package/dist/shared/caller-identity.js.map +1 -1
- package/dist/shared/channel-attachment.js +3 -2
- package/dist/shared/channel-attachment.js.map +1 -1
- package/dist/shared/connect-backfill.d.ts +2 -1
- package/dist/shared/connect-backfill.js +2 -2
- package/dist/shared/connect-backfill.js.map +1 -1
- package/dist/shared/mcp-resolver.d.ts +10 -1
- package/dist/shared/mcp-resolver.js +11 -2
- package/dist/shared/mcp-resolver.js.map +1 -1
- package/dist/shared/memory-attachment.js +3 -2
- package/dist/shared/memory-attachment.js.map +1 -1
- package/dist/shared/model-error.d.ts +25 -3
- package/dist/shared/model-error.js +78 -10
- package/dist/shared/model-error.js.map +1 -1
- package/dist/shared/platform-server-address.d.ts +71 -0
- package/dist/shared/platform-server-address.js +103 -0
- package/dist/shared/platform-server-address.js.map +1 -0
- package/dist/shared/synthesized-attachment.d.ts +0 -5
- package/dist/shared/synthesized-attachment.js +0 -12
- package/dist/shared/synthesized-attachment.js.map +1 -1
- package/dist/shared/tool-rounds.d.ts +51 -23
- package/dist/shared/tool-rounds.js +67 -24
- package/dist/shared/tool-rounds.js.map +1 -1
- package/dist/shared/workspace/platform-dir.d.ts +15 -0
- package/dist/shared/workspace/platform-dir.js +18 -1
- package/dist/shared/workspace/platform-dir.js.map +1 -1
- package/dist/shared/workspace/stigmer-link.d.ts +21 -14
- package/dist/shared/workspace/stigmer-link.js +91 -29
- package/dist/shared/workspace/stigmer-link.js.map +1 -1
- package/dist/tools/url-guard.d.ts +5 -1
- package/dist/tools/url-guard.js +9 -2
- package/dist/tools/url-guard.js.map +1 -1
- package/dist/worker.d.ts +11 -2
- package/dist/worker.js +1 -1
- package/dist/worker.js.map +1 -1
- package/dist/workflow-engine/tasks/human-input.d.ts +16 -0
- package/dist/workflow-engine/tasks/human-input.js +79 -37
- package/dist/workflow-engine/tasks/human-input.js.map +1 -1
- package/dist/workflow-engine/types.d.ts +14 -4
- package/dist/workflow-engine/types.js.map +1 -1
- package/dist/workflows/call-agent-orchestrator.d.ts +13 -0
- package/dist/workflows/call-agent-orchestrator.js.map +1 -1
- package/dist/workflows/engine-core.d.ts +25 -0
- package/dist/workflows/engine-core.js.map +1 -1
- package/dist/workflows/execute-from-execution.d.ts +3 -0
- package/dist/workflows/execute-from-execution.js.map +1 -1
- package/dist/workflows/human-input-orchestrator.d.ts +9 -12
- package/dist/workflows/human-input-orchestrator.js +12 -44
- package/dist/workflows/human-input-orchestrator.js.map +1 -1
- package/package.json +5 -5
- package/src/__test-utils__/config-fixture.ts +1 -0
- package/src/__test-utils__/execution-record-fixture.ts +2 -1
- package/src/__test-utils__/harness-contract/runtime-contract.ts +5 -3
- package/src/__test-utils__/test-gate.ts +8 -0
- package/src/__tests__/exit-backstop.test.ts +91 -0
- package/src/__tests__/golden-e2e.test.ts +80 -62
- package/src/__tests__/history-encryption-e2e.test.ts +51 -27
- package/src/__tests__/runner.test.ts +60 -2
- package/src/activities/__tests__/classify-tool-approvals.test.ts +1 -0
- package/src/activities/__tests__/discover-mcp-server.hang.test.ts +5 -1
- package/src/activities/__tests__/discover-mcp-server.test.ts +90 -49
- package/src/activities/__tests__/workflow-event-activities.test.ts +28 -7
- package/src/activities/call-agent.ts +1 -1
- package/src/activities/discover-mcp-server.ts +27 -37
- package/src/activities/execute-cursor/__test-utils__/fold.ts +6 -4
- package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +1 -0
- package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +4 -29
- package/src/activities/execute-cursor/__tests__/hermetic/bypassed-tool-call.test.ts +120 -0
- package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +5 -5
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/file-review-capture.status.json +0 -2
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/resolution-error.status.json +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.error-delta.status.json +0 -3
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.output-first.status.json +0 -2
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.status.json +0 -2
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/stall.status.json +0 -2
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +0 -3
- package/src/activities/execute-cursor/__tests__/hermetic/shell-output-delta.test.ts +9 -7
- package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +6 -1
- package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +8 -11
- package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +1 -3
- package/src/activities/execute-cursor/__tests__/translator.test.ts +68 -15
- package/src/activities/execute-cursor/approval-policy.ts +11 -36
- package/src/activities/execute-cursor/boundary-rows.ts +3 -3
- package/src/activities/execute-cursor/translator.ts +15 -32
- package/src/activities/execute-cursor/turn-stream.ts +4 -1
- package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +33 -2
- package/src/activities/execute-deep-agent/__tests__/adapter.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +4 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +1 -1
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +1 -1
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +1 -1
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +8 -73
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/resolution-error.status.json +1 -1
- package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +17 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +86 -26
- package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +9 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/thrown-turn-drains-publishes.test.ts +159 -0
- package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +84 -0
- package/src/activities/execute-deep-agent/__tests__/platform-route.test.ts +47 -10
- package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +34 -0
- package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +13 -5
- package/src/activities/execute-deep-agent/inline-publisher.ts +47 -7
- package/src/activities/execute-deep-agent/platform-route.ts +109 -20
- package/src/activities/execute-deep-agent/streaming-side-effects.ts +27 -4
- package/src/activities/execute-deep-agent/translator.ts +5 -4
- package/src/activities/execute-deep-agent/turn-settle.ts +6 -6
- package/src/activities/execute-deep-agent/turn-setup.ts +7 -7
- package/src/activities/execute-deep-agent/turn-stream.ts +15 -22
- package/src/activities/execute-deep-agent/turn.ts +16 -7
- package/src/activities/workflow-event-activities.ts +2 -0
- package/src/config.ts +11 -0
- package/src/exit-backstop.ts +97 -0
- package/src/harness/README.md +5 -5
- package/src/harness/terminal-table.ts +13 -13
- package/src/harness/transcript/__tests__/builder.test.ts +93 -21
- package/src/harness/transcript/builder.ts +53 -30
- package/src/harness/transcript/events.ts +22 -27
- package/src/harness/turn-context.ts +5 -3
- package/src/main.ts +9 -5
- package/src/middleware/__tests__/execution-budget.test.ts +181 -103
- package/src/middleware/cost-advisory.ts +6 -3
- package/src/middleware/execution-budget.ts +60 -34
- package/src/middleware/index.ts +10 -7
- package/src/middleware/types.ts +6 -1
- package/src/runner-manager.ts +3 -2
- package/src/runner.ts +57 -15
- package/src/shared/__tests__/approval-policy.test.ts +41 -0
- package/src/shared/__tests__/artifact-storage.test.ts +1 -0
- package/src/shared/__tests__/connect-backfill.test.ts +15 -11
- package/src/shared/__tests__/mcp-resolver.test.ts +72 -10
- package/src/shared/__tests__/model-error.test.ts +71 -3
- package/src/shared/__tests__/platform-server-address.test.ts +122 -0
- package/src/shared/__tests__/tool-rounds.test.ts +64 -14
- package/src/shared/approval-policy.ts +57 -14
- package/src/shared/caller-identity.ts +4 -5
- package/src/shared/channel-attachment.ts +2 -2
- package/src/shared/connect-backfill.ts +5 -1
- package/src/shared/mcp-resolver.ts +11 -1
- package/src/shared/memory-attachment.ts +2 -2
- package/src/shared/model-error.ts +87 -9
- package/src/shared/platform-server-address.ts +123 -0
- package/src/shared/synthesized-attachment.ts +0 -12
- package/src/shared/tool-rounds.ts +70 -24
- package/src/shared/workspace/__tests__/stigmer-link.test.ts +107 -10
- package/src/shared/workspace/platform-dir.ts +19 -1
- package/src/shared/workspace/stigmer-link.ts +99 -29
- package/src/tools/__tests__/url-guard.test.ts +19 -1
- package/src/tools/url-guard.ts +9 -1
- package/src/worker.ts +12 -2
- package/src/workflow-engine/__tests__/golden-execution.test.ts +2 -1
- package/src/workflow-engine/__tests__/loader.test.ts +1 -1
- package/src/workflow-engine/__tests__/tasks/human-input.test.ts +133 -57
- package/src/workflow-engine/tasks/human-input.ts +92 -42
- package/src/workflow-engine/types.ts +16 -4
- package/src/workflows/call-agent-orchestrator.ts +7 -0
- package/src/workflows/engine-core.ts +18 -0
- package/src/workflows/execute-from-execution.ts +2 -1
- package/src/workflows/human-input-orchestrator.ts +15 -56
|
@@ -4,6 +4,10 @@ import type {
|
|
|
4
4
|
DiscoveredToolResult,
|
|
5
5
|
DiscoverMcpServerOutput,
|
|
6
6
|
} from "../discover-mcp-server.js";
|
|
7
|
+
import { testConfig } from "../../__test-utils__/config-fixture.js";
|
|
8
|
+
|
|
9
|
+
/** The runner endpoints discovery fills STIGMER_SERVER_ADDRESS from. */
|
|
10
|
+
const PLATFORM_ENDPOINTS = testConfig();
|
|
7
11
|
|
|
8
12
|
vi.mock("../../idle-watchdog.js", () => ({
|
|
9
13
|
activityStarted: vi.fn(),
|
|
@@ -221,47 +225,83 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
221
225
|
});
|
|
222
226
|
|
|
223
227
|
// ─────────────────────────────────────────────────────────────────────────
|
|
224
|
-
//
|
|
228
|
+
// STIGMER_SERVER_ADDRESS — the platform fill (shared/platform-server-address.ts)
|
|
225
229
|
// ─────────────────────────────────────────────────────────────────────────
|
|
226
230
|
|
|
227
|
-
describe("
|
|
228
|
-
|
|
231
|
+
describe("the platform STIGMER_SERVER_ADDRESS fill", () => {
|
|
232
|
+
async function connectionConfigFor(
|
|
233
|
+
spec: any,
|
|
234
|
+
executionContext: any,
|
|
235
|
+
platformEndpoints = PLATFORM_ENDPOINTS,
|
|
236
|
+
): Promise<any> {
|
|
237
|
+
const { discoverMcpServer } = await import("../discover-mcp-server.js");
|
|
238
|
+
const { MultiServerMCPClient } = await import("@langchain/mcp-adapters");
|
|
239
|
+
const mockClient = makeMockStigmerClient({
|
|
240
|
+
mcpServer: makeMcpServer({ metadata: { slug: "stigmer" }, spec }),
|
|
241
|
+
executionContext,
|
|
242
|
+
});
|
|
243
|
+
mockInitializeConnections.mockResolvedValue({});
|
|
244
|
+
mockGetClient.mockResolvedValue(makeMockMcpClient({ tools: [] }));
|
|
245
|
+
await discoverMcpServer(
|
|
246
|
+
{ mcpServerId: "mcp-stigmer", executionContextId: "ctx-addr" },
|
|
247
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints },
|
|
248
|
+
);
|
|
249
|
+
return (vi.mocked(MultiServerMCPClient).mock.calls[0][0] as any).stigmer;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
it("fills a stdio server's required address from the backend endpoint instead of failing closed", async () => {
|
|
253
|
+
const spec = makeStdioSpec("stigmer", ["mcp-server"]);
|
|
254
|
+
spec.env = { STIGMER_SERVER_ADDRESS: { description: "gRPC host:port" } };
|
|
229
255
|
|
|
230
|
-
|
|
231
|
-
process.env = savedEnv;
|
|
232
|
-
});
|
|
256
|
+
const config = await connectionConfigFor(spec, { spec: { data: {} } });
|
|
233
257
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const env = { SOME_KEY: "value" };
|
|
237
|
-
const result = injectPlatformEnv(new Set(["SOME_KEY"]), env);
|
|
238
|
-
expect(result).toBe(env);
|
|
258
|
+
// testConfig's backend endpoint is http://127.0.0.1:1.
|
|
259
|
+
expect(config.env.STIGMER_SERVER_ADDRESS).toBe("127.0.0.1:1");
|
|
239
260
|
});
|
|
240
261
|
|
|
241
|
-
it("
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
262
|
+
it("keeps an address the execution context delivered", async () => {
|
|
263
|
+
const spec = makeStdioSpec("stigmer", ["mcp-server"]);
|
|
264
|
+
spec.env = { STIGMER_SERVER_ADDRESS: { description: "gRPC host:port" } };
|
|
265
|
+
|
|
266
|
+
const config = await connectionConfigFor(
|
|
267
|
+
spec,
|
|
268
|
+
{ spec: { data: { STIGMER_SERVER_ADDRESS: { value: "other.example:7234" } } } },
|
|
269
|
+
testConfig({ mcpPublicEndpoint: "https://api.example.com" }),
|
|
247
270
|
);
|
|
248
|
-
|
|
271
|
+
|
|
272
|
+
expect(config.env.STIGMER_SERVER_ADDRESS).toBe("other.example:7234");
|
|
249
273
|
});
|
|
250
274
|
|
|
251
|
-
it("
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
|
|
275
|
+
it("templates an http server's header from the operator's public endpoint", async () => {
|
|
276
|
+
const spec = makeHttpSpec("https://mcp.example.com");
|
|
277
|
+
spec.serverType.value.headers = { "X-Stigmer-Server": "${STIGMER_SERVER_ADDRESS}" };
|
|
278
|
+
spec.env = { STIGMER_SERVER_ADDRESS: {} };
|
|
279
|
+
|
|
280
|
+
const config = await connectionConfigFor(
|
|
281
|
+
spec,
|
|
282
|
+
{ spec: { data: {} } },
|
|
283
|
+
testConfig({ mcpPublicEndpoint: "https://api.example.com" }),
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
expect(config.headers["X-Stigmer-Server"]).toBe("api.example.com:443");
|
|
258
287
|
});
|
|
259
288
|
|
|
260
|
-
it("
|
|
261
|
-
const {
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
289
|
+
it("never hands an http server the backend endpoint: without a public one its required address is a credential the connect flow owes", async () => {
|
|
290
|
+
const { discoverMcpServer, CredentialResolutionError } = await import("../discover-mcp-server.js");
|
|
291
|
+
const spec = makeHttpSpec("https://mcp.example.com");
|
|
292
|
+
spec.env = { STIGMER_SERVER_ADDRESS: {} };
|
|
293
|
+
const mockClient = makeMockStigmerClient({
|
|
294
|
+
mcpServer: makeMcpServer({ metadata: { slug: "stigmer" }, spec }),
|
|
295
|
+
executionContext: { spec: { data: {} } },
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const promise = discoverMcpServer(
|
|
299
|
+
{ mcpServerId: "mcp-stigmer", executionContextId: "ctx-addr" },
|
|
300
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
await expect(promise).rejects.toThrow(CredentialResolutionError);
|
|
304
|
+
await expect(promise).rejects.toThrow(/STIGMER_SERVER_ADDRESS/);
|
|
265
305
|
});
|
|
266
306
|
});
|
|
267
307
|
|
|
@@ -291,7 +331,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
291
331
|
|
|
292
332
|
const result = await discoverMcpServer(
|
|
293
333
|
{ mcpServerId: "mcp-123" },
|
|
294
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed" },
|
|
334
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
295
335
|
);
|
|
296
336
|
|
|
297
337
|
expect(result.tools).toHaveLength(2);
|
|
@@ -320,7 +360,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
320
360
|
await expect(
|
|
321
361
|
discoverMcpServer(
|
|
322
362
|
{ mcpServerId: "mcp-123" },
|
|
323
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden" },
|
|
363
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
324
364
|
),
|
|
325
365
|
).rejects.toThrow(McpTransportError);
|
|
326
366
|
expect(mockInitializeConnections).not.toHaveBeenCalled();
|
|
@@ -348,7 +388,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
348
388
|
|
|
349
389
|
const result = await discoverMcpServer(
|
|
350
390
|
{ mcpServerId: "mcp-456" },
|
|
351
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed" },
|
|
391
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
352
392
|
);
|
|
353
393
|
|
|
354
394
|
expect(result.tools).toHaveLength(1);
|
|
@@ -369,7 +409,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
369
409
|
});
|
|
370
410
|
|
|
371
411
|
await expect(
|
|
372
|
-
discoverMcpServer({ mcpServerId: "mcp-bad" }, { stigmerClient: mockClient as any, transportPosture: "stdio-allowed" }),
|
|
412
|
+
discoverMcpServer({ mcpServerId: "mcp-bad" }, { stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS }),
|
|
373
413
|
).rejects.toThrow("not found or has no spec");
|
|
374
414
|
});
|
|
375
415
|
|
|
@@ -384,7 +424,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
384
424
|
});
|
|
385
425
|
|
|
386
426
|
await expect(
|
|
387
|
-
discoverMcpServer({ mcpServerId: "mcp-noconfig" }, { stigmerClient: mockClient as any, transportPosture: "stdio-allowed" }),
|
|
427
|
+
discoverMcpServer({ mcpServerId: "mcp-noconfig" }, { stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS }),
|
|
388
428
|
).rejects.toThrow("no valid server type configured");
|
|
389
429
|
});
|
|
390
430
|
|
|
@@ -412,7 +452,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
412
452
|
|
|
413
453
|
const result = await discoverMcpServer(
|
|
414
454
|
{ mcpServerId: "mcp-env", executionContextId: "ctx-abc" },
|
|
415
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed" },
|
|
455
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
416
456
|
);
|
|
417
457
|
|
|
418
458
|
expect(result.tools).toEqual([]);
|
|
@@ -448,7 +488,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
448
488
|
executionContextId: "ctx-abc",
|
|
449
489
|
executionContextToken: "scoped-ec-token",
|
|
450
490
|
},
|
|
451
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed" },
|
|
491
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
452
492
|
);
|
|
453
493
|
|
|
454
494
|
expect(mockClient.getExecutionContextByExecutionId).toHaveBeenCalledWith(
|
|
@@ -494,7 +534,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
494
534
|
|
|
495
535
|
const result = await discoverMcpServer(
|
|
496
536
|
{ mcpServerId: "mcp-isc", executionContextId: "ctx-isc" },
|
|
497
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden" },
|
|
537
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
498
538
|
);
|
|
499
539
|
|
|
500
540
|
expect(result.tools).toHaveLength(1);
|
|
@@ -522,7 +562,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
522
562
|
|
|
523
563
|
await discoverMcpServer(
|
|
524
564
|
{ mcpServerId: "mcp-no-env" },
|
|
525
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed" },
|
|
565
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
526
566
|
);
|
|
527
567
|
|
|
528
568
|
expect(mockClient.getExecutionContextByExecutionId).not.toHaveBeenCalled();
|
|
@@ -548,7 +588,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
548
588
|
|
|
549
589
|
const result = await discoverMcpServer(
|
|
550
590
|
{ mcpServerId: "mcp-no-res" },
|
|
551
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed" },
|
|
591
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
552
592
|
);
|
|
553
593
|
|
|
554
594
|
expect(result.tools).toHaveLength(1);
|
|
@@ -582,7 +622,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
582
622
|
|
|
583
623
|
const result = await discoverMcpServer(
|
|
584
624
|
{ mcpServerId: "mcp-existing" },
|
|
585
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed" },
|
|
625
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
586
626
|
);
|
|
587
627
|
|
|
588
628
|
expect(result.previousToolsFingerprint).not.toBe("");
|
|
@@ -617,7 +657,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
617
657
|
|
|
618
658
|
const result = await discoverMcpServer(
|
|
619
659
|
{ mcpServerId: "mcp-fp" },
|
|
620
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed" },
|
|
660
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
621
661
|
);
|
|
622
662
|
|
|
623
663
|
const expected = toolsFingerprint(result.tools);
|
|
@@ -640,7 +680,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
640
680
|
|
|
641
681
|
const result = await discoverMcpServer(
|
|
642
682
|
{ mcpServerId: "mcp-empty" },
|
|
643
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed" },
|
|
683
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
644
684
|
);
|
|
645
685
|
|
|
646
686
|
expect(result.newToolsFingerprint).toBe("");
|
|
@@ -665,7 +705,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
665
705
|
await expect(
|
|
666
706
|
discoverMcpServer(
|
|
667
707
|
{ mcpServerId: "mcp-monday", executionContextId: "ctx-1" },
|
|
668
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden" },
|
|
708
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
669
709
|
),
|
|
670
710
|
).rejects.toThrow(CredentialResolutionError);
|
|
671
711
|
expect(mockInitializeConnections).not.toHaveBeenCalled();
|
|
@@ -689,7 +729,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
689
729
|
|
|
690
730
|
const result = await discoverMcpServer(
|
|
691
731
|
{ mcpServerId: "mcp-lenient", executionContextId: "ctx-2" },
|
|
692
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden" },
|
|
732
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
693
733
|
);
|
|
694
734
|
expect(result.tools).toEqual([]);
|
|
695
735
|
});
|
|
@@ -714,7 +754,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
714
754
|
|
|
715
755
|
const result = await discoverMcpServer(
|
|
716
756
|
{ mcpServerId: "mcp-optional", executionContextId: "ctx-3" },
|
|
717
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden" },
|
|
757
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
718
758
|
);
|
|
719
759
|
expect(result.tools).toEqual([]);
|
|
720
760
|
});
|
|
@@ -731,7 +771,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
731
771
|
|
|
732
772
|
const promise = discoverMcpServer(
|
|
733
773
|
{ mcpServerId: "mcp-monday", executionContextId: "ctx-4" },
|
|
734
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden" },
|
|
774
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
735
775
|
);
|
|
736
776
|
await expect(promise).rejects.toThrow(CredentialResolutionError);
|
|
737
777
|
await expect(promise).rejects.toThrow(/delivered no credentials/);
|
|
@@ -755,7 +795,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
755
795
|
|
|
756
796
|
const promise = discoverMcpServer(
|
|
757
797
|
{ mcpServerId: "mcp-monday", executionContextId: "ctx-5" },
|
|
758
|
-
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden" },
|
|
798
|
+
{ stigmerClient: mockClient as any, transportPosture: "stdio-forbidden", platformEndpoints: PLATFORM_ENDPOINTS },
|
|
759
799
|
);
|
|
760
800
|
await expect(promise).rejects.toThrow(CredentialResolutionError);
|
|
761
801
|
await expect(promise).rejects.toThrow(/MONDAY_ACCESS_TOKEN.*delivered redacted|delivered redacted.*MONDAY_ACCESS_TOKEN/s);
|
|
@@ -775,7 +815,7 @@ describe("DiscoverMcpServer activity", () => {
|
|
|
775
815
|
mockInitializeConnections.mockRejectedValue(new Error("Connection refused"));
|
|
776
816
|
|
|
777
817
|
await expect(
|
|
778
|
-
discoverMcpServer({ mcpServerId: "mcp-fail" }, { stigmerClient: mockClient as any, transportPosture: "stdio-allowed" }),
|
|
818
|
+
discoverMcpServer({ mcpServerId: "mcp-fail" }, { stigmerClient: mockClient as any, transportPosture: "stdio-allowed", platformEndpoints: PLATFORM_ENDPOINTS }),
|
|
779
819
|
).rejects.toThrow("Connection refused");
|
|
780
820
|
|
|
781
821
|
expect(mockClose).toHaveBeenCalled();
|
|
@@ -903,6 +943,7 @@ function makeConfig() {
|
|
|
903
943
|
temporalConnection: {},
|
|
904
944
|
stigmerBackendEndpoint: "http://localhost:7234",
|
|
905
945
|
mcpBridgeEndpoint: null,
|
|
946
|
+
mcpPublicEndpoint: null,
|
|
906
947
|
stigmerTokenRef: { current: "test-token" },
|
|
907
948
|
cursorApiKey: "",
|
|
908
949
|
workspaceRootDir: "/tmp/test",
|
|
@@ -4,6 +4,7 @@ import { StigmerClient } from "../../client/stigmer-client.js";
|
|
|
4
4
|
import { WorkflowEventType } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/event_pb";
|
|
5
5
|
import { WorkflowTaskKind } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/enum_pb";
|
|
6
6
|
import { WorkflowTaskStatus } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/enum_pb";
|
|
7
|
+
import { ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
7
8
|
import type { WorkflowEventDescriptor } from "../../workflow-engine/types.js";
|
|
8
9
|
|
|
9
10
|
const mockGetEventLogHighWaterMark = vi.fn<(executionId: string) => Promise<bigint>>();
|
|
@@ -648,7 +649,7 @@ describe("toProtoEvent", () => {
|
|
|
648
649
|
expect(actor!.avatar).toBe("https://example.com/ada.png");
|
|
649
650
|
});
|
|
650
651
|
|
|
651
|
-
it("
|
|
652
|
+
it("maps the chosen outcome and a human decision's autoResolved=false", () => {
|
|
652
653
|
const evt = toProtoEvent({
|
|
653
654
|
type: "approval_resolved",
|
|
654
655
|
taskName: "gate",
|
|
@@ -657,16 +658,36 @@ describe("toProtoEvent", () => {
|
|
|
657
658
|
resolvedBy: "bob",
|
|
658
659
|
comment: "",
|
|
659
660
|
waitDurationMs: 1000,
|
|
661
|
+
autoResolved: false,
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
if (evt.payload.case !== "approvalResolved") throw new Error("unexpected");
|
|
665
|
+
const p = evt.payload.value;
|
|
666
|
+
expect(p.outcome).toBe("needs_revision");
|
|
667
|
+
expect(p.autoResolved).toBe(false);
|
|
668
|
+
// A human_input gate's outcome is a declared string, never mapped onto
|
|
669
|
+
// the agent ApprovalAction enum: action stays unset.
|
|
670
|
+
expect(p.action).toBe(ApprovalAction.UNSPECIFIED);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
it("maps a timeout auto-resolution: the policy's outcome, autoResolved, no reviewer", () => {
|
|
674
|
+
const evt = toProtoEvent({
|
|
675
|
+
type: "approval_resolved",
|
|
676
|
+
taskName: "gate",
|
|
677
|
+
occurredAt: NOW,
|
|
678
|
+
outcome: "escalate",
|
|
679
|
+
resolvedBy: "",
|
|
680
|
+
comment: "",
|
|
681
|
+
waitDurationMs: 5000,
|
|
660
682
|
autoResolved: true,
|
|
661
683
|
});
|
|
662
684
|
|
|
663
685
|
if (evt.payload.case !== "approvalResolved") throw new Error("unexpected");
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
expect(
|
|
669
|
-
expect(evt.payload.value.waitDurationMs).toBe(BigInt(1000));
|
|
686
|
+
const p = evt.payload.value;
|
|
687
|
+
expect(p.outcome).toBe("escalate");
|
|
688
|
+
expect(p.autoResolved).toBe(true);
|
|
689
|
+
expect(p.resolvedBy).toBe("");
|
|
690
|
+
expect(p.resolvedByActor).toBeUndefined();
|
|
670
691
|
});
|
|
671
692
|
});
|
|
672
693
|
|
|
@@ -228,7 +228,7 @@ export async function callAgentAction(
|
|
|
228
228
|
// the author may set is forwarded to a field the runner enforces.
|
|
229
229
|
// model_name replaces the agent's default outright; max_cost_usd feeds
|
|
230
230
|
// the turn runtime's cost guard (shared/cost-guard.ts, both harnesses);
|
|
231
|
-
// max_tool_rounds feeds
|
|
231
|
+
// max_tool_rounds feeds resolveToolRoundLimit (native
|
|
232
232
|
// harness only); service_tier and thinking_mode feed the cursor
|
|
233
233
|
// harness's explicit variant selection (issues #357/#772). Zero/unset
|
|
234
234
|
// means "no override" and is omitted.
|
|
@@ -31,6 +31,12 @@ import {
|
|
|
31
31
|
} from "../shared/mcp-transport-guard.js";
|
|
32
32
|
import { detectOAuthChallenge } from "../shared/mcp-oauth-detect.js";
|
|
33
33
|
import { injectAnonymousCallerIdentityForDiscovery } from "../shared/caller-identity.js";
|
|
34
|
+
import {
|
|
35
|
+
fillPlatformServerAddress,
|
|
36
|
+
platformServerAddress,
|
|
37
|
+
SERVER_ADDRESS_ENV_KEY,
|
|
38
|
+
type PlatformEndpoints,
|
|
39
|
+
} from "../shared/platform-server-address.js";
|
|
34
40
|
import { startHeartbeat } from "../shared/heartbeat.js";
|
|
35
41
|
import { withTimeout } from "../shared/with-timeout.js";
|
|
36
42
|
import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
@@ -70,10 +76,6 @@ const STDIO_INIT_TIMEOUT_MS = 270_000;
|
|
|
70
76
|
*/
|
|
71
77
|
const REDACTED_MARKER = "***REDACTED***";
|
|
72
78
|
|
|
73
|
-
const PLATFORM_INJECTABLE_MAP: Record<string, string> = {
|
|
74
|
-
STIGMER_SERVER_ADDRESS: "STIGMER_MCP_PUBLIC_ENDPOINT",
|
|
75
|
-
};
|
|
76
|
-
|
|
77
79
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
78
80
|
// Types
|
|
79
81
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -237,36 +239,6 @@ function structToPlainObject(struct: unknown): Record<string, unknown> | null {
|
|
|
237
239
|
}
|
|
238
240
|
}
|
|
239
241
|
|
|
240
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
241
|
-
// Platform Env Injection
|
|
242
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
243
|
-
|
|
244
|
-
export function injectPlatformEnv(
|
|
245
|
-
declaredEnvKeys: Set<string>,
|
|
246
|
-
envVars: Record<string, string>,
|
|
247
|
-
): Record<string, string> {
|
|
248
|
-
if (declaredEnvKeys.size === 0) return envVars;
|
|
249
|
-
|
|
250
|
-
let result: Record<string, string> | undefined;
|
|
251
|
-
|
|
252
|
-
for (const [targetKey, sourceKey] of Object.entries(PLATFORM_INJECTABLE_MAP)) {
|
|
253
|
-
if (!declaredEnvKeys.has(targetKey)) continue;
|
|
254
|
-
const value = process.env[sourceKey];
|
|
255
|
-
if (!value) continue;
|
|
256
|
-
|
|
257
|
-
if (!result) result = { ...envVars };
|
|
258
|
-
if (targetKey in result && result[targetKey] !== value) {
|
|
259
|
-
console.info(
|
|
260
|
-
`Platform env var '${targetKey}' overrides value from ExecutionContext ` +
|
|
261
|
-
`(platform infra vars are authoritative)`,
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
result[targetKey] = value;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return result ?? envVars;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
242
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
271
243
|
// Core Discovery Logic (no Temporal coupling)
|
|
272
244
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -281,6 +253,12 @@ export interface DiscoverDeps {
|
|
|
281
253
|
* tool enumeration.
|
|
282
254
|
*/
|
|
283
255
|
transportPosture: McpTransportPosture;
|
|
256
|
+
/**
|
|
257
|
+
* The runner's endpoints a missing STIGMER_SERVER_ADDRESS is filled from
|
|
258
|
+
* (the runner Config satisfies it) — the same fill execution applies, so
|
|
259
|
+
* discovery dials what the run will dial.
|
|
260
|
+
*/
|
|
261
|
+
platformEndpoints: PlatformEndpoints;
|
|
284
262
|
}
|
|
285
263
|
|
|
286
264
|
export async function discoverMcpServer(
|
|
@@ -305,16 +283,25 @@ export async function discoverMcpServer(
|
|
|
305
283
|
const previousState = extractPreviousState(mcpServer);
|
|
306
284
|
|
|
307
285
|
const declaredEnv = mcpServer.spec.env ?? {};
|
|
286
|
+
// A key the platform fills for this transport is not a credential the
|
|
287
|
+
// connect flow must deliver, so it never makes an empty EC a failure.
|
|
288
|
+
const platformFillsAddress =
|
|
289
|
+
platformServerAddress(mcpServer.spec.serverType.case, deps.platformEndpoints) !== null;
|
|
290
|
+
const credentialDeclarations = platformFillsAddress
|
|
291
|
+
? Object.fromEntries(
|
|
292
|
+
Object.entries(declaredEnv).filter(([key]) => key !== SERVER_ADDRESS_ENV_KEY),
|
|
293
|
+
)
|
|
294
|
+
: declaredEnv;
|
|
308
295
|
const envVars = await resolveEnvVarsForDiscovery(
|
|
309
296
|
stigmerClient,
|
|
310
297
|
executionContextId ?? null,
|
|
311
298
|
executionContextToken ?? null,
|
|
312
299
|
slug,
|
|
313
|
-
|
|
300
|
+
credentialDeclarations,
|
|
314
301
|
);
|
|
315
302
|
|
|
316
303
|
const declaredEnvKeys = new Set(Object.keys(declaredEnv));
|
|
317
|
-
const platformEnv =
|
|
304
|
+
const platformEnv = fillPlatformServerAddress(mcpServer, envVars, deps.platformEndpoints);
|
|
318
305
|
|
|
319
306
|
// Discovery runs with no session, so every declared caller-identity key
|
|
320
307
|
// resolves to the anonymous sentinel — without it, a server templating
|
|
@@ -385,7 +372,9 @@ export async function discoverMcpServer(
|
|
|
385
372
|
* sentinel can only produce a misleading 401.
|
|
386
373
|
* - No non-optional declarations → the old lenient path (warn and continue):
|
|
387
374
|
* servers declaring nothing (or only optional/injected keys like the
|
|
388
|
-
* caller-identity family) legitimately discover without an EC.
|
|
375
|
+
* caller-identity family) legitimately discover without an EC. A
|
|
376
|
+
* STIGMER_SERVER_ADDRESS the platform fills for the server's transport is
|
|
377
|
+
* left out of the count by the caller (platform-server-address.ts).
|
|
389
378
|
*/
|
|
390
379
|
async function resolveEnvVarsForDiscovery(
|
|
391
380
|
client: StigmerClient,
|
|
@@ -635,6 +624,7 @@ export function createDiscoverMcpServerActivities(config: Config) {
|
|
|
635
624
|
return await discoverMcpServer(input, {
|
|
636
625
|
stigmerClient,
|
|
637
626
|
transportPosture: resolveMcpTransportPosture(config.mode),
|
|
627
|
+
platformEndpoints: config,
|
|
638
628
|
});
|
|
639
629
|
} finally {
|
|
640
630
|
hb.stop();
|
|
@@ -21,7 +21,7 @@ import { create } from "@bufbuild/protobuf";
|
|
|
21
21
|
import type { InteractionUpdate, SDKMessage } from "@cursor/sdk";
|
|
22
22
|
import { AgentExecutionStatusSchema, type AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
23
23
|
import type { AgentMessage, ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
24
|
-
import { TranscriptBuilder } from "../../../harness/transcript/builder.js";
|
|
24
|
+
import { TranscriptBuilder, type TranscriptObserver } from "../../../harness/transcript/builder.js";
|
|
25
25
|
import { CursorTranslator, type CursorTranslatorOptions } from "../translator.js";
|
|
26
26
|
|
|
27
27
|
export interface CursorFoldOptions {
|
|
@@ -35,6 +35,8 @@ export interface CursorFoldOptions {
|
|
|
35
35
|
readonly messages?: AgentMessage[];
|
|
36
36
|
readonly policies?: CursorTranslatorOptions["policies"];
|
|
37
37
|
readonly leases?: CursorTranslatorOptions["leases"];
|
|
38
|
+
/** The builder's observer, as the runtime passes its turn timeline; a test that moves a fake clock between folds passes one. */
|
|
39
|
+
readonly observer?: TranscriptObserver;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export class CursorFold {
|
|
@@ -50,12 +52,12 @@ export class CursorFold {
|
|
|
50
52
|
leases: options.leases ?? { global: false, categories: new Set() },
|
|
51
53
|
seeded: this.status.messages,
|
|
52
54
|
});
|
|
53
|
-
this.builder = new TranscriptBuilder("exec-fold", this.status);
|
|
55
|
+
this.builder = new TranscriptBuilder("exec-fold", this.status, options.observer);
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
/** One stream event, translated and folded, then the deltas queued so far — the loop's order. */
|
|
58
|
+
/** One stream event, translated and folded as one observation, then the deltas queued so far — the loop's order. */
|
|
57
59
|
event(event: SDKMessage): this {
|
|
58
|
-
|
|
60
|
+
this.builder.applyObservation(this.translator.translate(event));
|
|
59
61
|
this.drain();
|
|
60
62
|
return this;
|
|
61
63
|
}
|
|
@@ -148,6 +148,7 @@ export function hermeticCursorConfig(env: HermeticEnvironment): Config {
|
|
|
148
148
|
temporalConnection: {},
|
|
149
149
|
stigmerBackendEndpoint: "http://localhost:7234",
|
|
150
150
|
mcpBridgeEndpoint: null,
|
|
151
|
+
mcpPublicEndpoint: null,
|
|
151
152
|
stigmerTokenRef: { current: null },
|
|
152
153
|
cursorApiKey: FIXTURE.cursorApiKey,
|
|
153
154
|
workspaceRootDir: env.workspaceRootDir,
|
|
@@ -23,8 +23,6 @@ import { ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecutio
|
|
|
23
23
|
|
|
24
24
|
import {
|
|
25
25
|
approvalCategory,
|
|
26
|
-
builtInRequiresApproval,
|
|
27
|
-
getBuiltInApprovalMessage,
|
|
28
26
|
getBuiltInGatedList,
|
|
29
27
|
getBuiltInGatedCategories,
|
|
30
28
|
extractArgKey,
|
|
@@ -81,22 +79,10 @@ describe("approvalCategory (cross-taxonomy drift-guard)", () => {
|
|
|
81
79
|
});
|
|
82
80
|
});
|
|
83
81
|
|
|
84
|
-
describe("
|
|
85
|
-
it("
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("allows read-only built-in tools", () => {
|
|
92
|
-
for (const t of ["Read", "read", "Grep", "grep", "Glob", "glob", "ls", "think", "task"]) {
|
|
93
|
-
expect(builtInRequiresApproval(t)).toBe(false);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("fails open for unknown tools (parity with native, avoids denying auto-approved MCP)", () => {
|
|
98
|
-
expect(builtInRequiresApproval("SomeFutureTool")).toBe(false);
|
|
99
|
-
expect(builtInRequiresApproval("search_services")).toBe(false);
|
|
82
|
+
describe("the hook's gated set", () => {
|
|
83
|
+
it("fails open for unknown tools: no category, so the hook allows them (parity with native, avoids denying auto-approved MCP)", () => {
|
|
84
|
+
expect(approvalCategory("SomeFutureTool")).toBeUndefined();
|
|
85
|
+
expect(approvalCategory("search_services")).toBeUndefined();
|
|
100
86
|
});
|
|
101
87
|
|
|
102
88
|
it("exposes the gated set in the HOOK taxonomy (what the hook matches)", () => {
|
|
@@ -114,17 +100,6 @@ describe("builtInRequiresApproval", () => {
|
|
|
114
100
|
});
|
|
115
101
|
});
|
|
116
102
|
|
|
117
|
-
describe("getBuiltInApprovalMessage", () => {
|
|
118
|
-
it("returns a category template for gated tools in EITHER taxonomy", () => {
|
|
119
|
-
expect(getBuiltInApprovalMessage("Write")).toContain("{{args.path}}");
|
|
120
|
-
expect(getBuiltInApprovalMessage("edit")).toContain("{{args.path}}");
|
|
121
|
-
expect(getBuiltInApprovalMessage("Shell")).toContain("{{args.command}}");
|
|
122
|
-
expect(getBuiltInApprovalMessage("shell")).toContain("{{args.command}}");
|
|
123
|
-
expect(getBuiltInApprovalMessage("Read")).toBeUndefined();
|
|
124
|
-
expect(getBuiltInApprovalMessage("read")).toBeUndefined();
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
103
|
describe("extractArgKey (spans both taxonomies' field names)", () => {
|
|
129
104
|
it("extracts the salient value regardless of field name (file_path or path)", () => {
|
|
130
105
|
expect(extractArgKey({ file_path: "a.txt" })).toBe("a.txt"); // hook shape
|