@stigmer/runner 3.1.6 → 3.1.8
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 +1 -1
- package/dist/.build-fingerprint +1 -1
- package/dist/activities/discover-mcp-server.js +24 -0
- package/dist/activities/discover-mcp-server.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +5 -2
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
- package/dist/activities/execute-cursor/approval-state.d.ts +58 -10
- package/dist/activities/execute-cursor/approval-state.js +37 -8
- package/dist/activities/execute-cursor/approval-state.js.map +1 -1
- package/dist/activities/execute-cursor/env-resolver.js +7 -1
- package/dist/activities/execute-cursor/env-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/hook-script.d.ts +16 -3
- package/dist/activities/execute-cursor/hook-script.js +66 -21
- package/dist/activities/execute-cursor/hook-script.js.map +1 -1
- package/dist/activities/execute-cursor/index.js +59 -0
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/message-translator.d.ts +52 -0
- package/dist/activities/execute-cursor/message-translator.js +107 -1
- package/dist/activities/execute-cursor/message-translator.js.map +1 -1
- package/dist/activities/execute-cursor/turn-boundary.d.ts +25 -3
- package/dist/activities/execute-cursor/turn-boundary.js +46 -8
- package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
- package/dist/activities/execute-cursor/turn-stream.js +6 -2
- package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
- package/dist/activities/execute-cursor/workspace-setup.d.ts +16 -2
- package/dist/activities/execute-cursor/workspace-setup.js +22 -12
- package/dist/activities/execute-cursor/workspace-setup.js.map +1 -1
- package/dist/activities/execute-deep-agent/environment.js +7 -1
- package/dist/activities/execute-deep-agent/environment.js.map +1 -1
- package/dist/activities/execute-deep-agent/hitl.d.ts +23 -14
- package/dist/activities/execute-deep-agent/hitl.js +42 -37
- package/dist/activities/execute-deep-agent/hitl.js.map +1 -1
- package/dist/activities/execute-deep-agent/index.js +35 -26
- package/dist/activities/execute-deep-agent/index.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.d.ts +7 -0
- package/dist/activities/execute-deep-agent/setup.js +9 -2
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/activities/hydrate-workflow-execution.js +8 -1
- package/dist/activities/hydrate-workflow-execution.js.map +1 -1
- package/dist/client/stigmer-client.d.ts +69 -1
- package/dist/client/stigmer-client.js +108 -4
- package/dist/client/stigmer-client.js.map +1 -1
- package/dist/client/token-claims.d.ts +22 -0
- package/dist/client/token-claims.js +40 -0
- package/dist/client/token-claims.js.map +1 -0
- package/dist/config.d.ts +11 -1
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/middleware/approval-gate.js +9 -2
- package/dist/middleware/approval-gate.js.map +1 -1
- package/dist/runner-manager.d.ts +4 -2
- package/dist/runner-manager.js +20 -7
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.d.ts +2 -2
- package/dist/runner.js +1 -1
- package/dist/shared/checkpointer/factory.d.ts +11 -7
- package/dist/shared/checkpointer/factory.js +21 -8
- package/dist/shared/checkpointer/factory.js.map +1 -1
- package/dist/shared/checkpointer/sqlite-saver.d.ts +54 -0
- package/dist/shared/checkpointer/sqlite-saver.js +272 -0
- package/dist/shared/checkpointer/sqlite-saver.js.map +1 -0
- package/dist/shared/checkpointer/types.d.ts +8 -4
- package/dist/shared/mcp-oauth-detect.d.ts +53 -0
- package/dist/shared/mcp-oauth-detect.js +99 -0
- package/dist/shared/mcp-oauth-detect.js.map +1 -0
- package/dist/shared/tool-row.js +14 -1
- package/dist/shared/tool-row.js.map +1 -1
- package/dist/shared/workspace/platform-dir.d.ts +18 -0
- package/dist/shared/workspace/platform-dir.js +23 -0
- package/dist/shared/workspace/platform-dir.js.map +1 -1
- package/package.json +3 -3
- package/src/__test-utils__/mock-client.ts +3 -0
- package/src/activities/__tests__/hydrate-workflow-execution.test.ts +2 -0
- package/src/activities/discover-mcp-server.ts +26 -0
- package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +5 -3
- package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +272 -14
- package/src/activities/execute-cursor/__tests__/hook-script.test.ts +72 -16
- package/src/activities/execute-cursor/__tests__/message-translator.test.ts +65 -0
- package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +128 -1
- package/src/activities/execute-cursor/__tests__/workspace-setup.test.ts +95 -0
- package/src/activities/execute-cursor/approval-state.ts +75 -11
- package/src/activities/execute-cursor/env-resolver.ts +8 -1
- package/src/activities/execute-cursor/hook-script.ts +66 -21
- package/src/activities/execute-cursor/index.ts +61 -0
- package/src/activities/execute-cursor/message-translator.ts +124 -1
- package/src/activities/execute-cursor/turn-boundary.ts +79 -6
- package/src/activities/execute-cursor/turn-stream.ts +6 -2
- package/src/activities/execute-cursor/workspace-setup.ts +42 -14
- package/src/activities/execute-deep-agent/__tests__/environment.test.ts +5 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +314 -0
- package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +64 -46
- package/src/activities/execute-deep-agent/environment.ts +8 -1
- package/src/activities/execute-deep-agent/hitl.ts +43 -45
- package/src/activities/execute-deep-agent/index.ts +36 -27
- package/src/activities/execute-deep-agent/setup.ts +15 -2
- package/src/activities/hydrate-workflow-execution.ts +9 -1
- package/src/client/__tests__/stigmer-client.test.ts +239 -2
- package/src/client/__tests__/token-claims.test.ts +45 -0
- package/src/client/stigmer-client.ts +152 -3
- package/src/client/token-claims.ts +42 -0
- package/src/config.ts +16 -3
- package/src/middleware/__tests__/approval-gate.test.ts +8 -1
- package/src/middleware/approval-gate.ts +9 -2
- package/src/runner-manager.ts +22 -8
- package/src/runner.ts +3 -3
- package/src/shared/__tests__/mcp-oauth-detect.test.ts +147 -0
- package/src/shared/__tests__/tool-row.test.ts +35 -0
- package/src/shared/checkpointer/__tests__/factory.test.ts +27 -1
- package/src/shared/checkpointer/__tests__/sqlite-saver.test.ts +212 -0
- package/src/shared/checkpointer/factory.ts +25 -8
- package/src/shared/checkpointer/sqlite-saver.ts +384 -0
- package/src/shared/checkpointer/types.ts +8 -4
- package/src/shared/mcp-oauth-detect.ts +112 -0
- package/src/shared/tool-row.ts +14 -1
- package/src/shared/workspace/platform-dir.ts +25 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth-challenge classification for HTTP MCP endpoints.
|
|
3
|
+
*
|
|
4
|
+
* When an HTTP MCP endpoint requires OAuth (per the MCP Authorization spec /
|
|
5
|
+
* RFC 9728), an unauthenticated or statically-tokened request is answered with
|
|
6
|
+
* `401` and a `WWW-Authenticate: Bearer ...` header pointing at OAuth protected
|
|
7
|
+
* resource metadata. The MCP client SDK surfaces this only as an opaque
|
|
8
|
+
* aggregate error ("unhandled errors in a TaskGroup"), which tells the user
|
|
9
|
+
* nothing.
|
|
10
|
+
*
|
|
11
|
+
* This module turns that opaque failure into a precise, actionable signal: it
|
|
12
|
+
* re-probes the endpoint once (only on the failure path, so the happy path pays
|
|
13
|
+
* nothing) and, if it sees an OAuth challenge, returns an {@link
|
|
14
|
+
* OAuthRequiredError} whose message tells the user to connect via OAuth instead
|
|
15
|
+
* of a manual token.
|
|
16
|
+
*
|
|
17
|
+
* Kept transport-library-agnostic (uses global `fetch`) so it is reusable by
|
|
18
|
+
* connect-time discovery, execution-time error enrichment, and any other caller
|
|
19
|
+
* that holds an MCP endpoint URL + headers.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const OAUTH_PROBE_TIMEOUT_MS = 10_000;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Raised when an HTTP MCP endpoint answers with an OAuth authentication
|
|
26
|
+
* challenge. The message is self-contained and user-facing: it survives the
|
|
27
|
+
* Temporal boundary and is shown by the connect error wrappers verbatim.
|
|
28
|
+
*
|
|
29
|
+
* The literal phrase "requires OAuth" is a stable marker the Go/Java connect
|
|
30
|
+
* wrappers match to avoid appending a generic "check your credentials" suffix.
|
|
31
|
+
*/
|
|
32
|
+
export class OAuthRequiredError extends Error {
|
|
33
|
+
constructor(
|
|
34
|
+
public readonly serverSlug: string,
|
|
35
|
+
public readonly resourceMetadataUrl?: string,
|
|
36
|
+
) {
|
|
37
|
+
super(
|
|
38
|
+
`MCP server '${serverSlug}' requires OAuth: its endpoint returned an ` +
|
|
39
|
+
`authentication challenge (HTTP 401). A manually-entered API token will ` +
|
|
40
|
+
`not work here — connect it with the OAuth "Sign in" flow instead.`,
|
|
41
|
+
);
|
|
42
|
+
this.name = "OAuthRequiredError";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Whether a `WWW-Authenticate` header value is an OAuth challenge.
|
|
48
|
+
*
|
|
49
|
+
* The MCP auth spec emits `Bearer realm="OAuth", resource_metadata="..."`. We
|
|
50
|
+
* require the `Bearer` scheme plus either an OAuth realm or a resource-metadata
|
|
51
|
+
* pointer, so a plain `Bearer` 401 from a static-token API (an invalid key, not
|
|
52
|
+
* an OAuth requirement) is not misclassified.
|
|
53
|
+
*/
|
|
54
|
+
export function isOAuthChallenge(wwwAuthenticate: string): boolean {
|
|
55
|
+
const value = wwwAuthenticate.toLowerCase();
|
|
56
|
+
if (!value.includes("bearer")) return false;
|
|
57
|
+
return value.includes("oauth") || value.includes("resource_metadata");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Extract the `resource_metadata` URL from a `WWW-Authenticate` value, if present. */
|
|
61
|
+
export function parseResourceMetadataUrl(
|
|
62
|
+
wwwAuthenticate: string,
|
|
63
|
+
): string | undefined {
|
|
64
|
+
const match = /resource_metadata="([^"]+)"/i.exec(wwwAuthenticate);
|
|
65
|
+
return match?.[1];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Probe an HTTP MCP endpoint once to decide whether its failure is an OAuth
|
|
70
|
+
* challenge. Returns an {@link OAuthRequiredError} to throw, or `null` when the
|
|
71
|
+
* endpoint is not asking for OAuth (so the caller rethrows the original error).
|
|
72
|
+
*
|
|
73
|
+
* Never throws: any probe/network failure returns `null` so this classification
|
|
74
|
+
* step can never mask or replace the original discovery error.
|
|
75
|
+
*/
|
|
76
|
+
export async function detectOAuthChallenge(
|
|
77
|
+
url: string,
|
|
78
|
+
headers: Record<string, string> | undefined,
|
|
79
|
+
slug: string,
|
|
80
|
+
): Promise<OAuthRequiredError | null> {
|
|
81
|
+
try {
|
|
82
|
+
const response = await fetch(url, {
|
|
83
|
+
method: "POST",
|
|
84
|
+
headers: {
|
|
85
|
+
"Content-Type": "application/json",
|
|
86
|
+
Accept: "application/json, text/event-stream",
|
|
87
|
+
...(headers ?? {}),
|
|
88
|
+
},
|
|
89
|
+
// A minimal MCP initialize request — enough to trigger the endpoint's
|
|
90
|
+
// auth check without establishing a session.
|
|
91
|
+
body: JSON.stringify({
|
|
92
|
+
jsonrpc: "2.0",
|
|
93
|
+
id: 1,
|
|
94
|
+
method: "initialize",
|
|
95
|
+
params: {},
|
|
96
|
+
}),
|
|
97
|
+
signal: AbortSignal.timeout(OAUTH_PROBE_TIMEOUT_MS),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (response.status !== 401) return null;
|
|
101
|
+
|
|
102
|
+
const wwwAuthenticate = response.headers.get("www-authenticate") ?? "";
|
|
103
|
+
if (!isOAuthChallenge(wwwAuthenticate)) return null;
|
|
104
|
+
|
|
105
|
+
return new OAuthRequiredError(
|
|
106
|
+
slug,
|
|
107
|
+
parseResourceMetadataUrl(wwwAuthenticate),
|
|
108
|
+
);
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
package/src/shared/tool-row.ts
CHANGED
|
@@ -187,11 +187,24 @@ export function collectSubAgentToolCallIds(
|
|
|
187
187
|
return ids;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
/**
|
|
190
|
+
/**
|
|
191
|
+
* Terminal tool-call statuses — a row that has finished (however it finished).
|
|
192
|
+
*
|
|
193
|
+
* Includes TOOL_CALL_INTERRUPTED (server-authored when an execution
|
|
194
|
+
* terminalized with the call in flight): for the provenance scoping below, a
|
|
195
|
+
* settled row from a prior (failed, then recovered) invocation is PRIOR-turn
|
|
196
|
+
* history and must not be attributed to the resuming turn. This is the
|
|
197
|
+
* opposite call from the Cursor translator's isTerminalToolStatus, which
|
|
198
|
+
* EXCLUDES interrupted so a recovery-replayed event can advance the row in
|
|
199
|
+
* place (the enum's recovery supersede rule) — that guard asks "may this row
|
|
200
|
+
* still move?", this set asks "had this row finished before the turn?", and an
|
|
201
|
+
* interrupted row answers yes to both.
|
|
202
|
+
*/
|
|
191
203
|
const TERMINAL_TOOL_CALL_STATUSES: ReadonlySet<ToolCallStatus> = new Set([
|
|
192
204
|
ToolCallStatus.TOOL_CALL_COMPLETED,
|
|
193
205
|
ToolCallStatus.TOOL_CALL_FAILED,
|
|
194
206
|
ToolCallStatus.TOOL_CALL_SKIPPED,
|
|
207
|
+
ToolCallStatus.TOOL_CALL_INTERRUPTED,
|
|
195
208
|
]);
|
|
196
209
|
|
|
197
210
|
/**
|
|
@@ -73,6 +73,31 @@ export function getPlatformDir(sessionId: string): string {
|
|
|
73
73
|
return join(getSessionDir(sessionId), "platform");
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Compute the durable-checkpoint database path for a session — the SQLite file
|
|
78
|
+
* backing the local LangGraph checkpointer (see shared/checkpointer/sqlite-saver.ts).
|
|
79
|
+
*
|
|
80
|
+
* Session-scoped by design: a session has exactly one LangGraph thread
|
|
81
|
+
* (`thread-{sessionId}`), so one DB per session keeps checkpoint lifetime bound
|
|
82
|
+
* to session lifetime (retention becomes "remove the session dir") and mirrors
|
|
83
|
+
* the sibling `platform/` and `hitl/` trees. Pure function — performs no I/O.
|
|
84
|
+
*/
|
|
85
|
+
export function getCheckpointDbPath(sessionId: string): string {
|
|
86
|
+
return join(getSessionDir(sessionId), "checkpoints.db");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Ensure the session directory exists and return the checkpoint DB path.
|
|
91
|
+
*
|
|
92
|
+
* Creates the session directory tree if needed (the SQLite driver requires the
|
|
93
|
+
* parent directory to exist before opening the file). Idempotent — safe across
|
|
94
|
+
* executions, HITL reinvocations, and activity retries.
|
|
95
|
+
*/
|
|
96
|
+
export async function ensureCheckpointDbPath(sessionId: string): Promise<string> {
|
|
97
|
+
await mkdir(getSessionDir(sessionId), { recursive: true });
|
|
98
|
+
return getCheckpointDbPath(sessionId);
|
|
99
|
+
}
|
|
100
|
+
|
|
76
101
|
/**
|
|
77
102
|
* Ensure the platform directory exists and return its path.
|
|
78
103
|
*
|