@desplega.ai/agent-swarm 1.91.0 → 1.92.1
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 -2
- package/openapi.json +1005 -152
- package/package.json +6 -6
- package/plugin/skills/pages/SKILL.md +5 -2
- package/src/be/db.ts +662 -19
- package/src/be/memory/constants.ts +2 -1
- package/src/be/memory/providers/openai-embedding.ts +2 -5
- package/src/be/memory/providers/sqlite-store.ts +293 -76
- package/src/be/memory/types.ts +35 -0
- package/src/be/migrations/083_script_workflows.sql +51 -0
- package/src/be/migrations/084_script_run_journal_duration.sql +5 -0
- package/src/be/migrations/085_script_runs_kind.sql +9 -0
- package/src/be/migrations/086_pages_default_authed.sql +64 -0
- package/src/be/migrations/087_skill_files.sql +19 -0
- package/src/be/modelsdev-cache.json +42310 -38617
- package/src/be/scripts/typecheck.ts +49 -0
- package/src/be/seed-scripts/catalog/boot-triage.ts +221 -0
- package/src/be/seed-scripts/catalog/catalog-report.ts +457 -0
- package/src/be/seed-scripts/catalog/compound-insights.ts +310 -6
- package/src/be/seed-scripts/catalog/gh-pr-snapshot.ts +1 -1
- package/src/be/seed-scripts/catalog/memory-eval.ts +1059 -0
- package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +506 -0
- package/src/be/seed-scripts/catalog/schedule-health.ts +78 -2
- package/src/be/seed-scripts/catalog/task-context-gathering.ts +92 -0
- package/src/be/seed-scripts/catalog/task-failure-audit.ts +48 -1
- package/src/be/seed-scripts/catalog/tool-usage.ts +6 -3
- package/src/be/seed-scripts/index.ts +51 -5
- package/src/be/seed-skills/index.ts +3 -3
- package/src/be/skill-sync.ts +91 -7
- package/src/be/swarm-config-guard.ts +17 -0
- package/src/commands/runner.ts +49 -4
- package/src/heartbeat/templates.ts +20 -16
- package/src/http/db-query.ts +20 -5
- package/src/http/index.ts +51 -7
- package/src/http/mcp-user.ts +23 -0
- package/src/http/mcp.ts +58 -0
- package/src/http/memory.ts +58 -0
- package/src/http/pages.ts +1 -1
- package/src/http/script-runs.ts +557 -0
- package/src/http/scripts.ts +39 -2
- package/src/http/skills.ts +225 -0
- package/src/prompts/session-templates.ts +24 -4
- package/src/providers/claude-adapter.ts +107 -28
- package/src/script-workflows/executor.ts +110 -0
- package/src/script-workflows/harness.ts +73 -0
- package/src/script-workflows/label-lint.ts +51 -0
- package/src/script-workflows/limits.ts +22 -0
- package/src/script-workflows/supervisor.ts +139 -0
- package/src/script-workflows/workflow-ctx.ts +209 -0
- package/src/scripts-runtime/sdk-allowlist.ts +4 -0
- package/src/scripts-runtime/swarm-sdk.ts +13 -0
- package/src/scripts-runtime/types/stdlib.d.ts +61 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +61 -0
- package/src/server.ts +4 -0
- package/src/slack/handlers.ts +11 -4
- package/src/slack/message-text.ts +98 -0
- package/src/slack/thread-buffer.ts +5 -3
- package/src/tests/claude-adapter-binary.test.ts +271 -74
- package/src/tests/create-page-tool.test.ts +19 -2
- package/src/tests/db-query.test.ts +28 -0
- package/src/tests/error-tracker.test.ts +121 -0
- package/src/tests/harness-provider-resolution.test.ts +33 -0
- package/src/tests/heartbeat-checklist.test.ts +36 -0
- package/src/tests/mcp-tools.test.ts +6 -0
- package/src/tests/mcp-transport-gc.test.ts +58 -0
- package/src/tests/memory-health-endpoint.test.ts +78 -0
- package/src/tests/memory-store.test.ts +221 -1
- package/src/tests/pages-http.test.ts +20 -2
- package/src/tests/pages-storage.test.ts +26 -0
- package/src/tests/prompt-template-session.test.ts +34 -5
- package/src/tests/script-runs-http.test.ts +278 -0
- package/src/tests/script-workflows-label-lint.test.ts +43 -0
- package/src/tests/script-workflows-runtime-e2e.test.ts +170 -0
- package/src/tests/scripts-mcp-e2e.test.ts +102 -2
- package/src/tests/seed-scripts.test.ts +468 -3
- package/src/tests/skill-files-http.test.ts +171 -0
- package/src/tests/skill-files.test.ts +162 -0
- package/src/tests/skill-get-file-tool.test.ts +110 -0
- package/src/tests/skill-sync.test.ts +125 -6
- package/src/tests/slack-message-text.test.ts +250 -0
- package/src/tests/system-default-skills.test.ts +40 -0
- package/src/tools/create-page.ts +2 -2
- package/src/tools/db-query.ts +16 -6
- package/src/tools/script-runs.ts +123 -0
- package/src/tools/skills/index.ts +1 -0
- package/src/tools/skills/skill-get-file.ts +80 -0
- package/src/tools/slack-read.ts +12 -3
- package/src/tools/tool-config.ts +6 -2
- package/src/types.ts +72 -0
- package/src/utils/error-tracker.ts +40 -1
- package/src/utils/internal-ai/complete-structured.ts +10 -4
- package/src/workflows/executors/raw-llm.ts +76 -59
- package/templates/schedules/daily-blocker-digest/content.md +68 -54
- package/templates/schedules/daily-compounding-reflection/content.md +4 -4
- package/templates/schedules/daily-hn-briefing/content.md +5 -5
- package/templates/schedules/daily-workflow-health-audit/content.md +6 -6
- package/templates/schedules/gtm-weekly-review/content.md +9 -9
- package/templates/schedules/weekly-dependabot-triage/content.md +24 -20
- package/templates/skills/agentmail-sending/content.md +6 -7
- package/templates/skills/desloppify/content.md +8 -9
- package/templates/skills/jira-interaction/content.md +25 -33
- package/templates/skills/kapso-whatsapp/content.md +29 -30
- package/templates/skills/linear-interaction/content.md +8 -9
- package/templates/skills/pages/content.md +205 -55
- package/templates/skills/profile-corruption-escalation/content.md +44 -85
- package/templates/skills/script-workflows/config.json +14 -0
- package/templates/skills/script-workflows/content.md +68 -0
- package/templates/skills/sprite-cli/content.md +4 -5
- package/templates/skills/swarm-scripts/content.md +2 -3
- package/templates/skills/turso-interaction/content.md +14 -17
- package/templates/skills/workflow-iterate/content.md +38 -391
- package/templates/skills/x-api-interactions/content.md +4 -6
- package/templates/skills/scheduled-task-resilience/config.json +0 -14
- package/templates/skills/scheduled-task-resilience/content.md +0 -95
|
@@ -5,13 +5,17 @@
|
|
|
5
5
|
* Behaviors under test:
|
|
6
6
|
* 1. Binary resolution — argv[0..n] tracks `parseClaudeBinary(process.env.CLAUDE_BINARY)`,
|
|
7
7
|
* with `["claude"]` as the default. Same flags follow. Supports
|
|
8
|
-
* whitespace-separated command strings
|
|
9
|
-
* 2.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* 3.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
8
|
+
* whitespace-separated command strings.
|
|
9
|
+
* 2. Claude Bridge routing — SWARM_USE_CLAUDE_BRIDGE=true/1 forces the
|
|
10
|
+
* installed `claude-bridge` argv prefix and wins over
|
|
11
|
+
* `CLAUDE_BINARY`.
|
|
12
|
+
* 3. Tmux fail-fast — when the resolved binary string uses the legacy
|
|
13
|
+
* bridge compatibility path or claude-bridge is enabled, createSession
|
|
14
|
+
* throws if `tmux` is not on PATH.
|
|
15
|
+
* 4. Trust pre-seed — when the resolved path drives interactive claude in
|
|
16
|
+
* tmux, the adapter writes
|
|
17
|
+
* `projects[cwd].hasTrustDialogAccepted: true` to `$HOME/.claude.json`
|
|
18
|
+
* before spawning. Idempotent. No-op for "claude".
|
|
15
19
|
*
|
|
16
20
|
* `Bun.spawn` is stubbed so the tests don't actually exec anything; we read
|
|
17
21
|
* the argv off the call args. `Bun.which` is stubbed for the tmux gate so
|
|
@@ -27,11 +31,17 @@ import { join } from "node:path";
|
|
|
27
31
|
import {
|
|
28
32
|
ClaudeAdapter,
|
|
29
33
|
parseClaudeBinary,
|
|
34
|
+
parseClaudeBridgeEnabled,
|
|
30
35
|
preseedClaudeTrustDialog,
|
|
31
36
|
resolveClaudeBinary,
|
|
37
|
+
resolveClaudeBridgeEnabled,
|
|
32
38
|
} from "../providers/claude-adapter";
|
|
33
39
|
import type { ProviderSessionConfig } from "../providers/types";
|
|
34
40
|
|
|
41
|
+
const LEGACY_BRIDGE_COMPAT_BINARY = "shan" + "non";
|
|
42
|
+
const LEGACY_BRIDGE_COMPAT_PACKAGE = `@dexh/${LEGACY_BRIDGE_COMPAT_BINARY}`;
|
|
43
|
+
const LEGACY_BRIDGE_COMPAT_COMMAND = `bunx ${LEGACY_BRIDGE_COMPAT_PACKAGE}`;
|
|
44
|
+
|
|
35
45
|
/** Minimal config — empty apiUrl/apiKey/agentId skips the MCP-server fetch. */
|
|
36
46
|
function makeConfig(overrides: Partial<ProviderSessionConfig> = {}): ProviderSessionConfig {
|
|
37
47
|
return {
|
|
@@ -79,36 +89,54 @@ describe("parseClaudeBinary", () => {
|
|
|
79
89
|
|
|
80
90
|
test("single token → one-element array", () => {
|
|
81
91
|
expect(parseClaudeBinary("claude")).toEqual(["claude"]);
|
|
82
|
-
expect(parseClaudeBinary(
|
|
83
|
-
expect(parseClaudeBinary(
|
|
92
|
+
expect(parseClaudeBinary(LEGACY_BRIDGE_COMPAT_BINARY)).toEqual([LEGACY_BRIDGE_COMPAT_BINARY]);
|
|
93
|
+
expect(parseClaudeBinary(`/usr/local/bin/${LEGACY_BRIDGE_COMPAT_BINARY}`)).toEqual([
|
|
94
|
+
`/usr/local/bin/${LEGACY_BRIDGE_COMPAT_BINARY}`,
|
|
95
|
+
]);
|
|
84
96
|
});
|
|
85
97
|
|
|
86
98
|
test("command string → whitespace-split argv", () => {
|
|
87
|
-
expect(parseClaudeBinary(
|
|
88
|
-
|
|
99
|
+
expect(parseClaudeBinary(LEGACY_BRIDGE_COMPAT_COMMAND)).toEqual([
|
|
100
|
+
"bunx",
|
|
101
|
+
LEGACY_BRIDGE_COMPAT_PACKAGE,
|
|
102
|
+
]);
|
|
103
|
+
expect(parseClaudeBinary(`npx -y ${LEGACY_BRIDGE_COMPAT_PACKAGE}`)).toEqual([
|
|
104
|
+
"npx",
|
|
105
|
+
"-y",
|
|
106
|
+
LEGACY_BRIDGE_COMPAT_PACKAGE,
|
|
107
|
+
]);
|
|
89
108
|
});
|
|
90
109
|
|
|
91
110
|
test("version-pinned → preserves the version suffix", () => {
|
|
92
|
-
expect(parseClaudeBinary(
|
|
111
|
+
expect(parseClaudeBinary(`${LEGACY_BRIDGE_COMPAT_COMMAND}@1.2.3`)).toEqual([
|
|
112
|
+
"bunx",
|
|
113
|
+
`${LEGACY_BRIDGE_COMPAT_PACKAGE}@1.2.3`,
|
|
114
|
+
]);
|
|
93
115
|
});
|
|
94
116
|
|
|
95
117
|
test("multiple-space tolerance → trims + collapses", () => {
|
|
96
|
-
expect(parseClaudeBinary(
|
|
97
|
-
|
|
118
|
+
expect(parseClaudeBinary(` bunx ${LEGACY_BRIDGE_COMPAT_BINARY} `)).toEqual([
|
|
119
|
+
"bunx",
|
|
120
|
+
LEGACY_BRIDGE_COMPAT_BINARY,
|
|
121
|
+
]);
|
|
122
|
+
expect(parseClaudeBinary(`\tbunx\t${LEGACY_BRIDGE_COMPAT_PACKAGE}\n`)).toEqual([
|
|
123
|
+
"bunx",
|
|
124
|
+
LEGACY_BRIDGE_COMPAT_PACKAGE,
|
|
125
|
+
]);
|
|
98
126
|
});
|
|
99
127
|
});
|
|
100
128
|
|
|
101
129
|
describe("resolveClaudeBinary precedence", () => {
|
|
102
130
|
test("resolvedEnv wins over fallbackEnv (swarm_config overrides process.env)", () => {
|
|
103
|
-
const resolvedEnv = { CLAUDE_BINARY:
|
|
131
|
+
const resolvedEnv = { CLAUDE_BINARY: LEGACY_BRIDGE_COMPAT_BINARY };
|
|
104
132
|
const fallbackEnv = { CLAUDE_BINARY: "claude" };
|
|
105
|
-
expect(resolveClaudeBinary(resolvedEnv, fallbackEnv)).toBe(
|
|
133
|
+
expect(resolveClaudeBinary(resolvedEnv, fallbackEnv)).toBe(LEGACY_BRIDGE_COMPAT_BINARY);
|
|
106
134
|
});
|
|
107
135
|
|
|
108
136
|
test("falls back to fallbackEnv when resolvedEnv is absent", () => {
|
|
109
137
|
const resolvedEnv = {};
|
|
110
|
-
const fallbackEnv = { CLAUDE_BINARY:
|
|
111
|
-
expect(resolveClaudeBinary(resolvedEnv, fallbackEnv)).toBe(
|
|
138
|
+
const fallbackEnv = { CLAUDE_BINARY: LEGACY_BRIDGE_COMPAT_COMMAND };
|
|
139
|
+
expect(resolveClaudeBinary(resolvedEnv, fallbackEnv)).toBe(LEGACY_BRIDGE_COMPAT_COMMAND);
|
|
112
140
|
});
|
|
113
141
|
|
|
114
142
|
test("both absent → 'claude' default", () => {
|
|
@@ -117,12 +145,12 @@ describe("resolveClaudeBinary precedence", () => {
|
|
|
117
145
|
|
|
118
146
|
test("empty / whitespace-only resolvedEnv value falls through to fallbackEnv", () => {
|
|
119
147
|
// `.trim() || …` falls through on empty/whitespace.
|
|
120
|
-
expect(
|
|
121
|
-
"
|
|
122
|
-
);
|
|
123
|
-
expect(
|
|
124
|
-
"
|
|
125
|
-
);
|
|
148
|
+
expect(
|
|
149
|
+
resolveClaudeBinary({ CLAUDE_BINARY: "" }, { CLAUDE_BINARY: LEGACY_BRIDGE_COMPAT_BINARY }),
|
|
150
|
+
).toBe(LEGACY_BRIDGE_COMPAT_BINARY);
|
|
151
|
+
expect(
|
|
152
|
+
resolveClaudeBinary({ CLAUDE_BINARY: " " }, { CLAUDE_BINARY: LEGACY_BRIDGE_COMPAT_BINARY }),
|
|
153
|
+
).toBe(LEGACY_BRIDGE_COMPAT_BINARY);
|
|
126
154
|
});
|
|
127
155
|
|
|
128
156
|
test("empty fallback after empty resolved → 'claude' default", () => {
|
|
@@ -130,8 +158,8 @@ describe("resolveClaudeBinary precedence", () => {
|
|
|
130
158
|
});
|
|
131
159
|
|
|
132
160
|
test("command-string passes through unchanged (caller does the argv split)", () => {
|
|
133
|
-
const resolvedEnv = { CLAUDE_BINARY:
|
|
134
|
-
expect(resolveClaudeBinary(resolvedEnv, {})).toBe(
|
|
161
|
+
const resolvedEnv = { CLAUDE_BINARY: `${LEGACY_BRIDGE_COMPAT_COMMAND}@1.2.3` };
|
|
162
|
+
expect(resolveClaudeBinary(resolvedEnv, {})).toBe(`${LEGACY_BRIDGE_COMPAT_COMMAND}@1.2.3`);
|
|
135
163
|
});
|
|
136
164
|
|
|
137
165
|
test("fallbackEnv defaults to process.env when omitted", () => {
|
|
@@ -150,6 +178,45 @@ describe("resolveClaudeBinary precedence", () => {
|
|
|
150
178
|
});
|
|
151
179
|
});
|
|
152
180
|
|
|
181
|
+
describe("SWARM_USE_CLAUDE_BRIDGE boolean parsing", () => {
|
|
182
|
+
test("true/1 enable claude-bridge", () => {
|
|
183
|
+
expect(parseClaudeBridgeEnabled("true")).toBe(true);
|
|
184
|
+
expect(parseClaudeBridgeEnabled("TRUE")).toBe(true);
|
|
185
|
+
expect(parseClaudeBridgeEnabled(" 1 ")).toBe(true);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("false/0/unset and invalid values are disabled", () => {
|
|
189
|
+
expect(parseClaudeBridgeEnabled("false")).toBe(false);
|
|
190
|
+
expect(parseClaudeBridgeEnabled("0")).toBe(false);
|
|
191
|
+
expect(parseClaudeBridgeEnabled(undefined)).toBe(false);
|
|
192
|
+
expect(parseClaudeBridgeEnabled("yes")).toBe(false);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("resolvedEnv wins over fallbackEnv", () => {
|
|
196
|
+
expect(
|
|
197
|
+
resolveClaudeBridgeEnabled(
|
|
198
|
+
{ SWARM_USE_CLAUDE_BRIDGE: "false" },
|
|
199
|
+
{ SWARM_USE_CLAUDE_BRIDGE: "true" },
|
|
200
|
+
),
|
|
201
|
+
).toBe(false);
|
|
202
|
+
expect(
|
|
203
|
+
resolveClaudeBridgeEnabled(
|
|
204
|
+
{ SWARM_USE_CLAUDE_BRIDGE: "1" },
|
|
205
|
+
{ SWARM_USE_CLAUDE_BRIDGE: "0" },
|
|
206
|
+
),
|
|
207
|
+
).toBe(true);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("empty resolvedEnv value falls through to fallbackEnv", () => {
|
|
211
|
+
expect(
|
|
212
|
+
resolveClaudeBridgeEnabled(
|
|
213
|
+
{ SWARM_USE_CLAUDE_BRIDGE: " " },
|
|
214
|
+
{ SWARM_USE_CLAUDE_BRIDGE: "true" },
|
|
215
|
+
),
|
|
216
|
+
).toBe(true);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
153
220
|
describe("preseedClaudeTrustDialog", () => {
|
|
154
221
|
let homeDir: string;
|
|
155
222
|
|
|
@@ -241,26 +308,32 @@ describe("preseedClaudeTrustDialog", () => {
|
|
|
241
308
|
describe("CLAUDE_BINARY env override", () => {
|
|
242
309
|
// Cache the originals and restore after each test so the suite stays clean.
|
|
243
310
|
let originalClaudeBinary: string | undefined;
|
|
311
|
+
let originalUseClaudeBridge: string | undefined;
|
|
244
312
|
let originalOauthToken: string | undefined;
|
|
245
313
|
let originalHome: string | undefined;
|
|
246
314
|
let homeDir: string;
|
|
247
315
|
let spawnSpy: ReturnType<typeof spyOn>;
|
|
248
316
|
let whichSpy: ReturnType<typeof spyOn>;
|
|
249
317
|
let spawnedArgs: Array<readonly string[]>;
|
|
318
|
+
let spawnedEnvs: Array<Record<string, string> | undefined>;
|
|
250
319
|
|
|
251
320
|
beforeEach(async () => {
|
|
252
321
|
originalClaudeBinary = process.env.CLAUDE_BINARY;
|
|
322
|
+
originalUseClaudeBridge = process.env.SWARM_USE_CLAUDE_BRIDGE;
|
|
253
323
|
originalOauthToken = process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
254
324
|
originalHome = process.env.HOME;
|
|
255
325
|
homeDir = await mkdtemp(join(tmpdir(), "claude-adapter-test-home-"));
|
|
256
326
|
process.env.HOME = homeDir;
|
|
257
327
|
delete process.env.CLAUDE_BINARY;
|
|
328
|
+
delete process.env.SWARM_USE_CLAUDE_BRIDGE;
|
|
258
329
|
// Credential check runs before binary resolution; satisfy it.
|
|
259
330
|
process.env.CLAUDE_CODE_OAUTH_TOKEN = "test-token";
|
|
260
331
|
|
|
261
332
|
spawnedArgs = [];
|
|
262
|
-
|
|
333
|
+
spawnedEnvs = [];
|
|
334
|
+
spawnSpy = spyOn(Bun, "spawn").mockImplementation(((cmd: readonly string[], opts?: unknown) => {
|
|
263
335
|
spawnedArgs.push(cmd);
|
|
336
|
+
spawnedEnvs.push((opts as { env?: Record<string, string> } | undefined)?.env);
|
|
264
337
|
return makeFakeProc();
|
|
265
338
|
}) as typeof Bun.spawn);
|
|
266
339
|
|
|
@@ -285,6 +358,11 @@ describe("CLAUDE_BINARY env override", () => {
|
|
|
285
358
|
} else {
|
|
286
359
|
process.env.CLAUDE_BINARY = originalClaudeBinary;
|
|
287
360
|
}
|
|
361
|
+
if (originalUseClaudeBridge === undefined) {
|
|
362
|
+
delete process.env.SWARM_USE_CLAUDE_BRIDGE;
|
|
363
|
+
} else {
|
|
364
|
+
process.env.SWARM_USE_CLAUDE_BRIDGE = originalUseClaudeBridge;
|
|
365
|
+
}
|
|
288
366
|
if (originalOauthToken === undefined) {
|
|
289
367
|
delete process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
290
368
|
} else {
|
|
@@ -301,68 +379,68 @@ describe("CLAUDE_BINARY env override", () => {
|
|
|
301
379
|
expect(argv[0]).toBe("claude");
|
|
302
380
|
});
|
|
303
381
|
|
|
304
|
-
test("override: argv[0]
|
|
305
|
-
process.env.CLAUDE_BINARY =
|
|
382
|
+
test("legacy bridge override: argv[0] comes from CLAUDE_BINARY", async () => {
|
|
383
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_BINARY;
|
|
306
384
|
|
|
307
385
|
const adapter = new ClaudeAdapter();
|
|
308
386
|
await adapter.createSession(makeConfig());
|
|
309
387
|
|
|
310
388
|
const argv = spawnedArgs[0];
|
|
311
|
-
expect(argv[0]).toBe(
|
|
389
|
+
expect(argv[0]).toBe(LEGACY_BRIDGE_COMPAT_BINARY);
|
|
312
390
|
});
|
|
313
391
|
|
|
314
|
-
test("custom path: argv[0] is the absolute path
|
|
315
|
-
process.env.CLAUDE_BINARY =
|
|
392
|
+
test("custom legacy bridge path: argv[0] is the absolute path", async () => {
|
|
393
|
+
process.env.CLAUDE_BINARY = `/usr/local/bin/${LEGACY_BRIDGE_COMPAT_BINARY}`;
|
|
316
394
|
|
|
317
395
|
const adapter = new ClaudeAdapter();
|
|
318
396
|
await adapter.createSession(makeConfig());
|
|
319
397
|
|
|
320
|
-
expect(spawnedArgs[0][0]).toBe(
|
|
398
|
+
expect(spawnedArgs[0][0]).toBe(`/usr/local/bin/${LEGACY_BRIDGE_COMPAT_BINARY}`);
|
|
321
399
|
});
|
|
322
400
|
|
|
323
|
-
test("command string
|
|
324
|
-
process.env.CLAUDE_BINARY =
|
|
401
|
+
test("legacy bridge command string → argv[0..1] is split", async () => {
|
|
402
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_COMMAND;
|
|
325
403
|
|
|
326
404
|
const adapter = new ClaudeAdapter();
|
|
327
405
|
await adapter.createSession(makeConfig());
|
|
328
406
|
|
|
329
407
|
const argv = spawnedArgs[0];
|
|
330
408
|
expect(argv[0]).toBe("bunx");
|
|
331
|
-
expect(argv[1]).toBe(
|
|
409
|
+
expect(argv[1]).toBe(LEGACY_BRIDGE_COMPAT_PACKAGE);
|
|
332
410
|
// Claude args follow.
|
|
333
411
|
expect(argv).toContain("--model");
|
|
334
412
|
expect(argv).toContain("-p");
|
|
335
413
|
});
|
|
336
414
|
|
|
337
|
-
test("version-pinned command string
|
|
338
|
-
process.env.CLAUDE_BINARY =
|
|
415
|
+
test("version-pinned legacy bridge command string keeps package suffix", async () => {
|
|
416
|
+
process.env.CLAUDE_BINARY = `${LEGACY_BRIDGE_COMPAT_COMMAND}@1.2.3`;
|
|
339
417
|
|
|
340
418
|
const adapter = new ClaudeAdapter();
|
|
341
419
|
await adapter.createSession(makeConfig());
|
|
342
420
|
|
|
343
421
|
const argv = spawnedArgs[0];
|
|
344
422
|
expect(argv[0]).toBe("bunx");
|
|
345
|
-
expect(argv[1]).toBe(
|
|
423
|
+
expect(argv[1]).toBe(`${LEGACY_BRIDGE_COMPAT_PACKAGE}@1.2.3`);
|
|
346
424
|
});
|
|
347
425
|
|
|
348
|
-
test("multiple-space tolerance
|
|
349
|
-
process.env.CLAUDE_BINARY =
|
|
426
|
+
test("multiple-space tolerance for legacy bridge command", async () => {
|
|
427
|
+
process.env.CLAUDE_BINARY = ` bunx ${LEGACY_BRIDGE_COMPAT_BINARY} `;
|
|
350
428
|
|
|
351
429
|
const adapter = new ClaudeAdapter();
|
|
352
430
|
await adapter.createSession(makeConfig());
|
|
353
431
|
|
|
354
432
|
const argv = spawnedArgs[0];
|
|
355
433
|
expect(argv[0]).toBe("bunx");
|
|
356
|
-
expect(argv[1]).toBe(
|
|
434
|
+
expect(argv[1]).toBe(LEGACY_BRIDGE_COMPAT_BINARY);
|
|
357
435
|
expect(argv).toContain("--model");
|
|
358
436
|
});
|
|
359
437
|
|
|
360
|
-
test("argv[1..]
|
|
361
|
-
process.env.CLAUDE_BINARY =
|
|
438
|
+
test("argv[1..] after prefix matches between default and legacy bridge command", async () => {
|
|
439
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_COMMAND;
|
|
362
440
|
const adapter = new ClaudeAdapter();
|
|
363
441
|
await adapter.createSession(makeConfig());
|
|
364
442
|
// Drop the 2-element prefix.
|
|
365
|
-
const
|
|
443
|
+
const argvLegacyBridge = spawnedArgs[0].slice(2);
|
|
366
444
|
|
|
367
445
|
spawnedArgs = [];
|
|
368
446
|
delete process.env.CLAUDE_BINARY;
|
|
@@ -370,47 +448,47 @@ describe("CLAUDE_BINARY env override", () => {
|
|
|
370
448
|
// Drop the 1-element prefix.
|
|
371
449
|
const argvClaude = spawnedArgs[0].slice(1);
|
|
372
450
|
|
|
373
|
-
expect(
|
|
451
|
+
expect(argvLegacyBridge).toEqual(argvClaude);
|
|
374
452
|
});
|
|
375
453
|
|
|
376
454
|
test("swarm_config overlay (config.env) wins over process.env CLAUDE_BINARY", async () => {
|
|
377
455
|
// process.env says "claude" — but the runner's resolvedEnv overlay (passed
|
|
378
|
-
// through config.env) says
|
|
456
|
+
// through config.env) says a legacy bridge binary. The overlay must win, mirroring the
|
|
379
457
|
// HARNESS_PROVIDER reload path.
|
|
380
458
|
process.env.CLAUDE_BINARY = "claude";
|
|
381
459
|
|
|
382
460
|
const adapter = new ClaudeAdapter();
|
|
383
461
|
await adapter.createSession(
|
|
384
462
|
makeConfig({
|
|
385
|
-
env: {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
>,
|
|
463
|
+
env: {
|
|
464
|
+
CLAUDE_BINARY: LEGACY_BRIDGE_COMPAT_BINARY,
|
|
465
|
+
CLAUDE_CODE_OAUTH_TOKEN: "test-token",
|
|
466
|
+
} as Record<string, string>,
|
|
389
467
|
}),
|
|
390
468
|
);
|
|
391
469
|
|
|
392
|
-
expect(spawnedArgs[0][0]).toBe(
|
|
470
|
+
expect(spawnedArgs[0][0]).toBe(LEGACY_BRIDGE_COMPAT_BINARY);
|
|
393
471
|
});
|
|
394
472
|
|
|
395
|
-
test("config.env
|
|
473
|
+
test("config.env legacy bridge command override splits + spawns correctly", async () => {
|
|
396
474
|
delete process.env.CLAUDE_BINARY;
|
|
397
475
|
|
|
398
476
|
const adapter = new ClaudeAdapter();
|
|
399
477
|
await adapter.createSession(
|
|
400
478
|
makeConfig({
|
|
401
479
|
env: {
|
|
402
|
-
CLAUDE_BINARY:
|
|
480
|
+
CLAUDE_BINARY: LEGACY_BRIDGE_COMPAT_COMMAND,
|
|
403
481
|
CLAUDE_CODE_OAUTH_TOKEN: "test-token",
|
|
404
482
|
} as Record<string, string>,
|
|
405
483
|
}),
|
|
406
484
|
);
|
|
407
485
|
|
|
408
486
|
expect(spawnedArgs[0][0]).toBe("bunx");
|
|
409
|
-
expect(spawnedArgs[0][1]).toBe(
|
|
487
|
+
expect(spawnedArgs[0][1]).toBe(LEGACY_BRIDGE_COMPAT_PACKAGE);
|
|
410
488
|
});
|
|
411
489
|
|
|
412
490
|
test("config.env without CLAUDE_BINARY falls back to process.env", async () => {
|
|
413
|
-
process.env.CLAUDE_BINARY =
|
|
491
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_BINARY;
|
|
414
492
|
|
|
415
493
|
const adapter = new ClaudeAdapter();
|
|
416
494
|
await adapter.createSession(
|
|
@@ -420,12 +498,94 @@ describe("CLAUDE_BINARY env override", () => {
|
|
|
420
498
|
}),
|
|
421
499
|
);
|
|
422
500
|
|
|
423
|
-
expect(spawnedArgs[0][0]).toBe(
|
|
501
|
+
expect(spawnedArgs[0][0]).toBe(LEGACY_BRIDGE_COMPAT_BINARY);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
test("SWARM_USE_CLAUDE_BRIDGE=true routes through installed claude-bridge", async () => {
|
|
505
|
+
process.env.SWARM_USE_CLAUDE_BRIDGE = "true";
|
|
506
|
+
|
|
507
|
+
const adapter = new ClaudeAdapter();
|
|
508
|
+
await adapter.createSession(makeConfig());
|
|
509
|
+
|
|
510
|
+
const argv = spawnedArgs[0];
|
|
511
|
+
expect(argv[0]).toBe("claude-bridge");
|
|
512
|
+
expect(argv).toContain("--model");
|
|
513
|
+
expect(argv).toContain("-p");
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
test("SWARM_USE_CLAUDE_BRIDGE=true passes OAuth token to the bridge process", async () => {
|
|
517
|
+
process.env.SWARM_USE_CLAUDE_BRIDGE = "true";
|
|
518
|
+
|
|
519
|
+
const adapter = new ClaudeAdapter();
|
|
520
|
+
await adapter.createSession(makeConfig());
|
|
521
|
+
|
|
522
|
+
expect(spawnedArgs[0][0]).toBe("claude-bridge");
|
|
523
|
+
expect(spawnedEnvs[0]?.CLAUDE_CODE_OAUTH_TOKEN).toBe("test-token");
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
test("SWARM_USE_CLAUDE_BRIDGE=true forwards Anthropic local auth through bridge flag", async () => {
|
|
527
|
+
const adapter = new ClaudeAdapter();
|
|
528
|
+
await adapter.createSession(
|
|
529
|
+
makeConfig({
|
|
530
|
+
env: {
|
|
531
|
+
SWARM_USE_CLAUDE_BRIDGE: "true",
|
|
532
|
+
ANTHROPIC_API_KEY: "sk-ant-test",
|
|
533
|
+
} as Record<string, string>,
|
|
534
|
+
}),
|
|
535
|
+
);
|
|
536
|
+
|
|
537
|
+
expect(spawnedArgs[0][0]).toBe("claude-bridge");
|
|
538
|
+
expect(spawnedArgs[0]).toContain("--desplega-local-auth");
|
|
539
|
+
expect(spawnedEnvs[0]?.ANTHROPIC_API_KEY).toBe("sk-ant-test");
|
|
540
|
+
expect(spawnedEnvs[0]?.CLAUDE_CODE_OAUTH_TOKEN).toBeUndefined();
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
test("SWARM_USE_CLAUDE_BRIDGE=1 wins over legacy CLAUDE_BINARY", async () => {
|
|
544
|
+
process.env.SWARM_USE_CLAUDE_BRIDGE = "1";
|
|
545
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_BINARY;
|
|
546
|
+
|
|
547
|
+
const adapter = new ClaudeAdapter();
|
|
548
|
+
await adapter.createSession(makeConfig());
|
|
549
|
+
|
|
550
|
+
expect(spawnedArgs[0][0]).toBe("claude-bridge");
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
test("config.env SWARM_USE_CLAUDE_BRIDGE=true is reloadable and wins over process.env false", async () => {
|
|
554
|
+
process.env.SWARM_USE_CLAUDE_BRIDGE = "false";
|
|
555
|
+
|
|
556
|
+
const adapter = new ClaudeAdapter();
|
|
557
|
+
await adapter.createSession(
|
|
558
|
+
makeConfig({
|
|
559
|
+
env: {
|
|
560
|
+
SWARM_USE_CLAUDE_BRIDGE: "true",
|
|
561
|
+
CLAUDE_CODE_OAUTH_TOKEN: "test-token",
|
|
562
|
+
} as Record<string, string>,
|
|
563
|
+
}),
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
expect(spawnedArgs[0][0]).toBe("claude-bridge");
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
test("config.env SWARM_USE_CLAUDE_BRIDGE=false disables process.env true", async () => {
|
|
570
|
+
process.env.SWARM_USE_CLAUDE_BRIDGE = "true";
|
|
571
|
+
|
|
572
|
+
const adapter = new ClaudeAdapter();
|
|
573
|
+
await adapter.createSession(
|
|
574
|
+
makeConfig({
|
|
575
|
+
env: {
|
|
576
|
+
SWARM_USE_CLAUDE_BRIDGE: "false",
|
|
577
|
+
CLAUDE_CODE_OAUTH_TOKEN: "test-token",
|
|
578
|
+
} as Record<string, string>,
|
|
579
|
+
}),
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
expect(spawnedArgs[0][0]).toBe("claude");
|
|
424
583
|
});
|
|
425
584
|
});
|
|
426
585
|
|
|
427
|
-
describe("
|
|
586
|
+
describe("Claude Bridge tmux fail-fast gate", () => {
|
|
428
587
|
let originalClaudeBinary: string | undefined;
|
|
588
|
+
let originalUseClaudeBridge: string | undefined;
|
|
429
589
|
let originalOauthToken: string | undefined;
|
|
430
590
|
let originalHome: string | undefined;
|
|
431
591
|
let homeDir: string;
|
|
@@ -434,11 +594,13 @@ describe("Shannon tmux fail-fast gate", () => {
|
|
|
434
594
|
|
|
435
595
|
beforeEach(async () => {
|
|
436
596
|
originalClaudeBinary = process.env.CLAUDE_BINARY;
|
|
597
|
+
originalUseClaudeBridge = process.env.SWARM_USE_CLAUDE_BRIDGE;
|
|
437
598
|
originalOauthToken = process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
438
599
|
originalHome = process.env.HOME;
|
|
439
600
|
homeDir = await mkdtemp(join(tmpdir(), "claude-adapter-test-home-"));
|
|
440
601
|
process.env.HOME = homeDir;
|
|
441
602
|
delete process.env.CLAUDE_BINARY;
|
|
603
|
+
delete process.env.SWARM_USE_CLAUDE_BRIDGE;
|
|
442
604
|
process.env.CLAUDE_CODE_OAUTH_TOKEN = "test-token";
|
|
443
605
|
spawnSpy = spyOn(Bun, "spawn").mockImplementation((() => makeFakeProc()) as typeof Bun.spawn);
|
|
444
606
|
whichSpy = spyOn(Bun, "which");
|
|
@@ -458,6 +620,11 @@ describe("Shannon tmux fail-fast gate", () => {
|
|
|
458
620
|
} else {
|
|
459
621
|
process.env.CLAUDE_BINARY = originalClaudeBinary;
|
|
460
622
|
}
|
|
623
|
+
if (originalUseClaudeBridge === undefined) {
|
|
624
|
+
delete process.env.SWARM_USE_CLAUDE_BRIDGE;
|
|
625
|
+
} else {
|
|
626
|
+
process.env.SWARM_USE_CLAUDE_BRIDGE = originalUseClaudeBridge;
|
|
627
|
+
}
|
|
461
628
|
if (originalOauthToken === undefined) {
|
|
462
629
|
delete process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
463
630
|
} else {
|
|
@@ -465,8 +632,8 @@ describe("Shannon tmux fail-fast gate", () => {
|
|
|
465
632
|
}
|
|
466
633
|
});
|
|
467
634
|
|
|
468
|
-
test("sad path: rejects with tmux-mentioning error when CLAUDE_BINARY
|
|
469
|
-
process.env.CLAUDE_BINARY =
|
|
635
|
+
test("sad path: rejects with tmux-mentioning error when legacy CLAUDE_BINARY is set and tmux is missing", async () => {
|
|
636
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_BINARY;
|
|
470
637
|
whichSpy.mockImplementation((name: string) => {
|
|
471
638
|
if (name === "tmux") return null;
|
|
472
639
|
return `/usr/bin/${name}`;
|
|
@@ -476,8 +643,8 @@ describe("Shannon tmux fail-fast gate", () => {
|
|
|
476
643
|
await expect(adapter.createSession(makeConfig())).rejects.toThrow(/tmux/i);
|
|
477
644
|
});
|
|
478
645
|
|
|
479
|
-
test("happy path: does not throw when CLAUDE_BINARY
|
|
480
|
-
process.env.CLAUDE_BINARY =
|
|
646
|
+
test("happy path: does not throw when legacy CLAUDE_BINARY is set and tmux IS on PATH", async () => {
|
|
647
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_BINARY;
|
|
481
648
|
whichSpy.mockImplementation((name: string) => {
|
|
482
649
|
if (name === "tmux") return "/usr/bin/tmux";
|
|
483
650
|
return null;
|
|
@@ -487,7 +654,7 @@ describe("Shannon tmux fail-fast gate", () => {
|
|
|
487
654
|
await expect(adapter.createSession(makeConfig())).resolves.toBeDefined();
|
|
488
655
|
});
|
|
489
656
|
|
|
490
|
-
test("
|
|
657
|
+
test("default binary skips the tmux check (no Bun.which call for tmux)", async () => {
|
|
491
658
|
process.env.CLAUDE_BINARY = "claude";
|
|
492
659
|
whichSpy.mockImplementation((name: string) => {
|
|
493
660
|
if (name === "tmux") return null;
|
|
@@ -499,8 +666,8 @@ describe("Shannon tmux fail-fast gate", () => {
|
|
|
499
666
|
await expect(adapter.createSession(makeConfig())).resolves.toBeDefined();
|
|
500
667
|
});
|
|
501
668
|
|
|
502
|
-
test("custom
|
|
503
|
-
process.env.CLAUDE_BINARY =
|
|
669
|
+
test("custom legacy bridge path still triggers the tmux check", async () => {
|
|
670
|
+
process.env.CLAUDE_BINARY = `/usr/local/bin/${LEGACY_BRIDGE_COMPAT_BINARY}`;
|
|
504
671
|
whichSpy.mockImplementation((name: string) => {
|
|
505
672
|
if (name === "tmux") return null;
|
|
506
673
|
return null;
|
|
@@ -510,8 +677,8 @@ describe("Shannon tmux fail-fast gate", () => {
|
|
|
510
677
|
await expect(adapter.createSession(makeConfig())).rejects.toThrow(/tmux/i);
|
|
511
678
|
});
|
|
512
679
|
|
|
513
|
-
test("command
|
|
514
|
-
process.env.CLAUDE_BINARY =
|
|
680
|
+
test("legacy bridge command string still triggers the tmux check", async () => {
|
|
681
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_COMMAND;
|
|
515
682
|
whichSpy.mockImplementation((name: string) => {
|
|
516
683
|
if (name === "tmux") return null;
|
|
517
684
|
return null;
|
|
@@ -520,10 +687,22 @@ describe("Shannon tmux fail-fast gate", () => {
|
|
|
520
687
|
const adapter = new ClaudeAdapter();
|
|
521
688
|
await expect(adapter.createSession(makeConfig())).rejects.toThrow(/tmux/i);
|
|
522
689
|
});
|
|
690
|
+
|
|
691
|
+
test("SWARM_USE_CLAUDE_BRIDGE=true triggers the tmux check", async () => {
|
|
692
|
+
process.env.SWARM_USE_CLAUDE_BRIDGE = "true";
|
|
693
|
+
whichSpy.mockImplementation((name: string) => {
|
|
694
|
+
if (name === "tmux") return null;
|
|
695
|
+
return null;
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
const adapter = new ClaudeAdapter();
|
|
699
|
+
await expect(adapter.createSession(makeConfig())).rejects.toThrow(/SWARM_USE_CLAUDE_BRIDGE/);
|
|
700
|
+
});
|
|
523
701
|
});
|
|
524
702
|
|
|
525
703
|
describe("Trust pre-seed via ClaudeAdapter.createSession", () => {
|
|
526
704
|
let originalClaudeBinary: string | undefined;
|
|
705
|
+
let originalUseClaudeBridge: string | undefined;
|
|
527
706
|
let originalOauthToken: string | undefined;
|
|
528
707
|
let originalHome: string | undefined;
|
|
529
708
|
let homeDir: string;
|
|
@@ -532,11 +711,13 @@ describe("Trust pre-seed via ClaudeAdapter.createSession", () => {
|
|
|
532
711
|
|
|
533
712
|
beforeEach(async () => {
|
|
534
713
|
originalClaudeBinary = process.env.CLAUDE_BINARY;
|
|
714
|
+
originalUseClaudeBridge = process.env.SWARM_USE_CLAUDE_BRIDGE;
|
|
535
715
|
originalOauthToken = process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
536
716
|
originalHome = process.env.HOME;
|
|
537
717
|
homeDir = await mkdtemp(join(tmpdir(), "claude-adapter-trust-test-"));
|
|
538
718
|
process.env.HOME = homeDir;
|
|
539
719
|
delete process.env.CLAUDE_BINARY;
|
|
720
|
+
delete process.env.SWARM_USE_CLAUDE_BRIDGE;
|
|
540
721
|
process.env.CLAUDE_CODE_OAUTH_TOKEN = "test-token";
|
|
541
722
|
spawnSpy = spyOn(Bun, "spawn").mockImplementation((() => makeFakeProc()) as typeof Bun.spawn);
|
|
542
723
|
whichSpy = spyOn(Bun, "which").mockImplementation((name: string) => {
|
|
@@ -559,6 +740,11 @@ describe("Trust pre-seed via ClaudeAdapter.createSession", () => {
|
|
|
559
740
|
} else {
|
|
560
741
|
process.env.CLAUDE_BINARY = originalClaudeBinary;
|
|
561
742
|
}
|
|
743
|
+
if (originalUseClaudeBridge === undefined) {
|
|
744
|
+
delete process.env.SWARM_USE_CLAUDE_BRIDGE;
|
|
745
|
+
} else {
|
|
746
|
+
process.env.SWARM_USE_CLAUDE_BRIDGE = originalUseClaudeBridge;
|
|
747
|
+
}
|
|
562
748
|
if (originalOauthToken === undefined) {
|
|
563
749
|
delete process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
564
750
|
} else {
|
|
@@ -566,8 +752,8 @@ describe("Trust pre-seed via ClaudeAdapter.createSession", () => {
|
|
|
566
752
|
}
|
|
567
753
|
});
|
|
568
754
|
|
|
569
|
-
test("CLAUDE_BINARY
|
|
570
|
-
process.env.CLAUDE_BINARY =
|
|
755
|
+
test("legacy CLAUDE_BINARY writes hasTrustDialogAccepted for config.cwd", async () => {
|
|
756
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_BINARY;
|
|
571
757
|
const cwd = "/some/abs/cwd";
|
|
572
758
|
const adapter = new ClaudeAdapter();
|
|
573
759
|
await adapter.createSession(makeConfig({ cwd }));
|
|
@@ -577,8 +763,8 @@ describe("Trust pre-seed via ClaudeAdapter.createSession", () => {
|
|
|
577
763
|
expect(data.projects[cwd].hasCompletedProjectOnboarding).toBe(true);
|
|
578
764
|
});
|
|
579
765
|
|
|
580
|
-
test("CLAUDE_BINARY
|
|
581
|
-
process.env.CLAUDE_BINARY =
|
|
766
|
+
test("legacy CLAUDE_BINARY command string also triggers the pre-seed", async () => {
|
|
767
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_COMMAND;
|
|
582
768
|
const cwd = "/some/other/cwd";
|
|
583
769
|
const adapter = new ClaudeAdapter();
|
|
584
770
|
await adapter.createSession(makeConfig({ cwd }));
|
|
@@ -587,8 +773,8 @@ describe("Trust pre-seed via ClaudeAdapter.createSession", () => {
|
|
|
587
773
|
expect(data.projects[cwd].hasTrustDialogAccepted).toBe(true);
|
|
588
774
|
});
|
|
589
775
|
|
|
590
|
-
test("idempotent: re-creating
|
|
591
|
-
process.env.CLAUDE_BINARY =
|
|
776
|
+
test("idempotent: re-creating legacy bridge session does not rewrite the file", async () => {
|
|
777
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_BINARY;
|
|
592
778
|
const cwd = "/some/abs/cwd";
|
|
593
779
|
const adapter = new ClaudeAdapter();
|
|
594
780
|
await adapter.createSession(makeConfig({ cwd }));
|
|
@@ -607,7 +793,7 @@ describe("Trust pre-seed via ClaudeAdapter.createSession", () => {
|
|
|
607
793
|
},
|
|
608
794
|
}),
|
|
609
795
|
);
|
|
610
|
-
process.env.CLAUDE_BINARY =
|
|
796
|
+
process.env.CLAUDE_BINARY = LEGACY_BRIDGE_COMPAT_BINARY;
|
|
611
797
|
const adapter = new ClaudeAdapter();
|
|
612
798
|
await adapter.createSession(makeConfig({ cwd: "/new/cwd" }));
|
|
613
799
|
|
|
@@ -625,4 +811,15 @@ describe("Trust pre-seed via ClaudeAdapter.createSession", () => {
|
|
|
625
811
|
const exists = await Bun.file(join(homeDir, ".claude.json")).exists();
|
|
626
812
|
expect(exists).toBe(false);
|
|
627
813
|
});
|
|
814
|
+
|
|
815
|
+
test("SWARM_USE_CLAUDE_BRIDGE=true writes hasTrustDialogAccepted for config.cwd", async () => {
|
|
816
|
+
process.env.SWARM_USE_CLAUDE_BRIDGE = "true";
|
|
817
|
+
const cwd = "/some/bridge/cwd";
|
|
818
|
+
const adapter = new ClaudeAdapter();
|
|
819
|
+
await adapter.createSession(makeConfig({ cwd }));
|
|
820
|
+
|
|
821
|
+
const data = JSON.parse(await readFile(join(homeDir, ".claude.json"), "utf-8"));
|
|
822
|
+
expect(data.projects[cwd].hasTrustDialogAccepted).toBe(true);
|
|
823
|
+
expect(data.projects[cwd].hasCompletedProjectOnboarding).toBe(true);
|
|
824
|
+
});
|
|
628
825
|
});
|