@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.
Files changed (115) hide show
  1. package/README.md +1 -1
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/activities/discover-mcp-server.js +24 -0
  4. package/dist/activities/discover-mcp-server.js.map +1 -1
  5. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +5 -2
  6. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
  7. package/dist/activities/execute-cursor/approval-state.d.ts +58 -10
  8. package/dist/activities/execute-cursor/approval-state.js +37 -8
  9. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  10. package/dist/activities/execute-cursor/env-resolver.js +7 -1
  11. package/dist/activities/execute-cursor/env-resolver.js.map +1 -1
  12. package/dist/activities/execute-cursor/hook-script.d.ts +16 -3
  13. package/dist/activities/execute-cursor/hook-script.js +66 -21
  14. package/dist/activities/execute-cursor/hook-script.js.map +1 -1
  15. package/dist/activities/execute-cursor/index.js +59 -0
  16. package/dist/activities/execute-cursor/index.js.map +1 -1
  17. package/dist/activities/execute-cursor/message-translator.d.ts +52 -0
  18. package/dist/activities/execute-cursor/message-translator.js +107 -1
  19. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  20. package/dist/activities/execute-cursor/turn-boundary.d.ts +25 -3
  21. package/dist/activities/execute-cursor/turn-boundary.js +46 -8
  22. package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
  23. package/dist/activities/execute-cursor/turn-stream.js +6 -2
  24. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  25. package/dist/activities/execute-cursor/workspace-setup.d.ts +16 -2
  26. package/dist/activities/execute-cursor/workspace-setup.js +22 -12
  27. package/dist/activities/execute-cursor/workspace-setup.js.map +1 -1
  28. package/dist/activities/execute-deep-agent/environment.js +7 -1
  29. package/dist/activities/execute-deep-agent/environment.js.map +1 -1
  30. package/dist/activities/execute-deep-agent/hitl.d.ts +23 -14
  31. package/dist/activities/execute-deep-agent/hitl.js +42 -37
  32. package/dist/activities/execute-deep-agent/hitl.js.map +1 -1
  33. package/dist/activities/execute-deep-agent/index.js +35 -26
  34. package/dist/activities/execute-deep-agent/index.js.map +1 -1
  35. package/dist/activities/execute-deep-agent/setup.d.ts +7 -0
  36. package/dist/activities/execute-deep-agent/setup.js +9 -2
  37. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  38. package/dist/activities/hydrate-workflow-execution.js +8 -1
  39. package/dist/activities/hydrate-workflow-execution.js.map +1 -1
  40. package/dist/client/stigmer-client.d.ts +69 -1
  41. package/dist/client/stigmer-client.js +108 -4
  42. package/dist/client/stigmer-client.js.map +1 -1
  43. package/dist/client/token-claims.d.ts +22 -0
  44. package/dist/client/token-claims.js +40 -0
  45. package/dist/client/token-claims.js.map +1 -0
  46. package/dist/config.d.ts +11 -1
  47. package/dist/config.js +5 -1
  48. package/dist/config.js.map +1 -1
  49. package/dist/middleware/approval-gate.js +9 -2
  50. package/dist/middleware/approval-gate.js.map +1 -1
  51. package/dist/runner-manager.d.ts +4 -2
  52. package/dist/runner-manager.js +20 -7
  53. package/dist/runner-manager.js.map +1 -1
  54. package/dist/runner.d.ts +2 -2
  55. package/dist/runner.js +1 -1
  56. package/dist/shared/checkpointer/factory.d.ts +11 -7
  57. package/dist/shared/checkpointer/factory.js +21 -8
  58. package/dist/shared/checkpointer/factory.js.map +1 -1
  59. package/dist/shared/checkpointer/sqlite-saver.d.ts +54 -0
  60. package/dist/shared/checkpointer/sqlite-saver.js +272 -0
  61. package/dist/shared/checkpointer/sqlite-saver.js.map +1 -0
  62. package/dist/shared/checkpointer/types.d.ts +8 -4
  63. package/dist/shared/mcp-oauth-detect.d.ts +53 -0
  64. package/dist/shared/mcp-oauth-detect.js +99 -0
  65. package/dist/shared/mcp-oauth-detect.js.map +1 -0
  66. package/dist/shared/tool-row.js +14 -1
  67. package/dist/shared/tool-row.js.map +1 -1
  68. package/dist/shared/workspace/platform-dir.d.ts +18 -0
  69. package/dist/shared/workspace/platform-dir.js +23 -0
  70. package/dist/shared/workspace/platform-dir.js.map +1 -1
  71. package/package.json +3 -3
  72. package/src/__test-utils__/mock-client.ts +3 -0
  73. package/src/activities/__tests__/hydrate-workflow-execution.test.ts +2 -0
  74. package/src/activities/discover-mcp-server.ts +26 -0
  75. package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +5 -3
  76. package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +272 -14
  77. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +72 -16
  78. package/src/activities/execute-cursor/__tests__/message-translator.test.ts +65 -0
  79. package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +128 -1
  80. package/src/activities/execute-cursor/__tests__/workspace-setup.test.ts +95 -0
  81. package/src/activities/execute-cursor/approval-state.ts +75 -11
  82. package/src/activities/execute-cursor/env-resolver.ts +8 -1
  83. package/src/activities/execute-cursor/hook-script.ts +66 -21
  84. package/src/activities/execute-cursor/index.ts +61 -0
  85. package/src/activities/execute-cursor/message-translator.ts +124 -1
  86. package/src/activities/execute-cursor/turn-boundary.ts +79 -6
  87. package/src/activities/execute-cursor/turn-stream.ts +6 -2
  88. package/src/activities/execute-cursor/workspace-setup.ts +42 -14
  89. package/src/activities/execute-deep-agent/__tests__/environment.test.ts +5 -0
  90. package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +314 -0
  91. package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +64 -46
  92. package/src/activities/execute-deep-agent/environment.ts +8 -1
  93. package/src/activities/execute-deep-agent/hitl.ts +43 -45
  94. package/src/activities/execute-deep-agent/index.ts +36 -27
  95. package/src/activities/execute-deep-agent/setup.ts +15 -2
  96. package/src/activities/hydrate-workflow-execution.ts +9 -1
  97. package/src/client/__tests__/stigmer-client.test.ts +239 -2
  98. package/src/client/__tests__/token-claims.test.ts +45 -0
  99. package/src/client/stigmer-client.ts +152 -3
  100. package/src/client/token-claims.ts +42 -0
  101. package/src/config.ts +16 -3
  102. package/src/middleware/__tests__/approval-gate.test.ts +8 -1
  103. package/src/middleware/approval-gate.ts +9 -2
  104. package/src/runner-manager.ts +22 -8
  105. package/src/runner.ts +3 -3
  106. package/src/shared/__tests__/mcp-oauth-detect.test.ts +147 -0
  107. package/src/shared/__tests__/tool-row.test.ts +35 -0
  108. package/src/shared/checkpointer/__tests__/factory.test.ts +27 -1
  109. package/src/shared/checkpointer/__tests__/sqlite-saver.test.ts +212 -0
  110. package/src/shared/checkpointer/factory.ts +25 -8
  111. package/src/shared/checkpointer/sqlite-saver.ts +384 -0
  112. package/src/shared/checkpointer/types.ts +8 -4
  113. package/src/shared/mcp-oauth-detect.ts +112 -0
  114. package/src/shared/tool-row.ts +14 -1
  115. 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
+ }
@@ -187,11 +187,24 @@ export function collectSubAgentToolCallIds(
187
187
  return ids;
188
188
  }
189
189
 
190
- /** Terminal tool-call statuses — a row that has finished (however it finished). */
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
  *