claude-code-swarm 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +22 -1
- package/.claude-plugin/run-agent-inbox-mcp.sh +76 -0
- package/.claude-plugin/run-minimem-mcp.sh +98 -0
- package/.claude-plugin/run-opentasks-mcp.sh +65 -0
- package/CLAUDE.md +200 -36
- package/README.md +65 -0
- package/e2e/helpers/cleanup.mjs +17 -3
- package/e2e/helpers/map-mock-server.mjs +201 -25
- package/e2e/helpers/sidecar.mjs +222 -0
- package/e2e/helpers/workspace.mjs +2 -1
- package/e2e/tier5-sidecar-inbox.test.mjs +900 -0
- package/e2e/tier6-inbox-mcp.test.mjs +173 -0
- package/e2e/tier6-live-agent.test.mjs +759 -0
- package/e2e/vitest.config.e2e.mjs +1 -1
- package/hooks/hooks.json +15 -8
- package/package.json +13 -1
- package/references/agent-inbox/CLAUDE.md +151 -0
- package/references/agent-inbox/README.md +238 -0
- package/references/agent-inbox/docs/CLAUDE-CODE-SWARM-PROPOSAL.md +137 -0
- package/references/agent-inbox/docs/DESIGN.md +1156 -0
- package/references/agent-inbox/hooks/inbox-hook.mjs +119 -0
- package/references/agent-inbox/hooks/register-hook.mjs +69 -0
- package/references/agent-inbox/package-lock.json +3347 -0
- package/references/agent-inbox/package.json +58 -0
- package/references/agent-inbox/rules/agent-inbox.md +78 -0
- package/references/agent-inbox/src/federation/address.ts +61 -0
- package/references/agent-inbox/src/federation/connection-manager.ts +573 -0
- package/references/agent-inbox/src/federation/delivery-queue.ts +222 -0
- package/references/agent-inbox/src/federation/index.ts +6 -0
- package/references/agent-inbox/src/federation/routing-engine.ts +188 -0
- package/references/agent-inbox/src/federation/trust.ts +71 -0
- package/references/agent-inbox/src/index.ts +390 -0
- package/references/agent-inbox/src/ipc/ipc-server.ts +207 -0
- package/references/agent-inbox/src/jsonrpc/mail-server.ts +382 -0
- package/references/agent-inbox/src/map/map-client.ts +414 -0
- package/references/agent-inbox/src/mcp/mcp-server.ts +272 -0
- package/references/agent-inbox/src/mesh/delivery-bridge.ts +110 -0
- package/references/agent-inbox/src/mesh/mesh-connector.ts +41 -0
- package/references/agent-inbox/src/mesh/mesh-transport.ts +157 -0
- package/references/agent-inbox/src/mesh/type-mapper.ts +239 -0
- package/references/agent-inbox/src/push/notifier.ts +233 -0
- package/references/agent-inbox/src/registry/warm-registry.ts +255 -0
- package/references/agent-inbox/src/router/message-router.ts +175 -0
- package/references/agent-inbox/src/storage/interface.ts +48 -0
- package/references/agent-inbox/src/storage/memory.ts +145 -0
- package/references/agent-inbox/src/storage/sqlite.ts +671 -0
- package/references/agent-inbox/src/traceability/traceability.ts +183 -0
- package/references/agent-inbox/src/types.ts +303 -0
- package/references/agent-inbox/test/federation/address.test.ts +101 -0
- package/references/agent-inbox/test/federation/connection-manager.test.ts +546 -0
- package/references/agent-inbox/test/federation/delivery-queue.test.ts +159 -0
- package/references/agent-inbox/test/federation/integration.test.ts +857 -0
- package/references/agent-inbox/test/federation/routing-engine.test.ts +117 -0
- package/references/agent-inbox/test/federation/sdk-integration.test.ts +744 -0
- package/references/agent-inbox/test/federation/trust.test.ts +89 -0
- package/references/agent-inbox/test/ipc-jsonrpc.test.ts +113 -0
- package/references/agent-inbox/test/ipc-server.test.ts +197 -0
- package/references/agent-inbox/test/mail-server.test.ts +285 -0
- package/references/agent-inbox/test/map-client.test.ts +408 -0
- package/references/agent-inbox/test/mesh/delivery-bridge.test.ts +178 -0
- package/references/agent-inbox/test/mesh/e2e-mesh.test.ts +527 -0
- package/references/agent-inbox/test/mesh/e2e-real-meshpeer.test.ts +629 -0
- package/references/agent-inbox/test/mesh/federation-mesh.test.ts +269 -0
- package/references/agent-inbox/test/mesh/mesh-connector.test.ts +66 -0
- package/references/agent-inbox/test/mesh/mesh-transport.test.ts +191 -0
- package/references/agent-inbox/test/mesh/meshpeer-integration.test.ts +442 -0
- package/references/agent-inbox/test/mesh/mock-mesh.ts +125 -0
- package/references/agent-inbox/test/mesh/mock-meshpeer.ts +266 -0
- package/references/agent-inbox/test/mesh/type-mapper.test.ts +226 -0
- package/references/agent-inbox/test/message-router.test.ts +184 -0
- package/references/agent-inbox/test/push-notifier.test.ts +139 -0
- package/references/agent-inbox/test/registry/warm-registry.test.ts +171 -0
- package/references/agent-inbox/test/sqlite-prefix.test.ts +192 -0
- package/references/agent-inbox/test/sqlite-storage.test.ts +243 -0
- package/references/agent-inbox/test/storage.test.ts +196 -0
- package/references/agent-inbox/test/traceability.test.ts +123 -0
- package/references/agent-inbox/test/wake.test.ts +330 -0
- package/references/agent-inbox/tsconfig.json +20 -0
- package/references/agent-inbox/tsup.config.ts +10 -0
- package/references/agent-inbox/vitest.config.ts +8 -0
- package/references/minimem/.claude/settings.json +7 -0
- package/references/minimem/.sudocode/issues.jsonl +18 -0
- package/references/minimem/.sudocode/specs.jsonl +1 -0
- package/references/minimem/CLAUDE.md +329 -0
- package/references/minimem/README.md +565 -0
- package/references/minimem/claude-plugin/.claude-plugin/plugin.json +10 -0
- package/references/minimem/claude-plugin/.mcp.json +7 -0
- package/references/minimem/claude-plugin/README.md +158 -0
- package/references/minimem/claude-plugin/commands/recall.md +47 -0
- package/references/minimem/claude-plugin/commands/remember.md +41 -0
- package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +272 -0
- package/references/minimem/claude-plugin/hooks/hooks.json +27 -0
- package/references/minimem/claude-plugin/hooks/session-end.sh +86 -0
- package/references/minimem/claude-plugin/hooks/session-start.sh +85 -0
- package/references/minimem/claude-plugin/skills/memory/SKILL.md +108 -0
- package/references/minimem/media/banner.png +0 -0
- package/references/minimem/package-lock.json +5373 -0
- package/references/minimem/package.json +76 -0
- package/references/minimem/scripts/postbuild.js +49 -0
- package/references/minimem/src/__tests__/edge-cases.test.ts +371 -0
- package/references/minimem/src/__tests__/errors.test.ts +265 -0
- package/references/minimem/src/__tests__/helpers.ts +199 -0
- package/references/minimem/src/__tests__/internal.test.ts +407 -0
- package/references/minimem/src/__tests__/knowledge-frontmatter.test.ts +148 -0
- package/references/minimem/src/__tests__/knowledge.test.ts +148 -0
- package/references/minimem/src/__tests__/minimem.integration.test.ts +1127 -0
- package/references/minimem/src/__tests__/session.test.ts +190 -0
- package/references/minimem/src/cli/__tests__/commands.test.ts +760 -0
- package/references/minimem/src/cli/__tests__/contained-layout.test.ts +286 -0
- package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +141 -0
- package/references/minimem/src/cli/commands/append.ts +76 -0
- package/references/minimem/src/cli/commands/config.ts +262 -0
- package/references/minimem/src/cli/commands/conflicts.ts +415 -0
- package/references/minimem/src/cli/commands/daemon.ts +169 -0
- package/references/minimem/src/cli/commands/index.ts +12 -0
- package/references/minimem/src/cli/commands/init.ts +166 -0
- package/references/minimem/src/cli/commands/mcp.ts +221 -0
- package/references/minimem/src/cli/commands/push-pull.ts +213 -0
- package/references/minimem/src/cli/commands/search.ts +223 -0
- package/references/minimem/src/cli/commands/status.ts +84 -0
- package/references/minimem/src/cli/commands/store.ts +189 -0
- package/references/minimem/src/cli/commands/sync-init.ts +290 -0
- package/references/minimem/src/cli/commands/sync.ts +70 -0
- package/references/minimem/src/cli/commands/upsert.ts +197 -0
- package/references/minimem/src/cli/config.ts +611 -0
- package/references/minimem/src/cli/index.ts +299 -0
- package/references/minimem/src/cli/shared.ts +189 -0
- package/references/minimem/src/cli/sync/__tests__/central.test.ts +152 -0
- package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +209 -0
- package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +118 -0
- package/references/minimem/src/cli/sync/__tests__/detection.test.ts +207 -0
- package/references/minimem/src/cli/sync/__tests__/integration.test.ts +476 -0
- package/references/minimem/src/cli/sync/__tests__/registry.test.ts +363 -0
- package/references/minimem/src/cli/sync/__tests__/state.test.ts +255 -0
- package/references/minimem/src/cli/sync/__tests__/validation.test.ts +193 -0
- package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +178 -0
- package/references/minimem/src/cli/sync/central.ts +292 -0
- package/references/minimem/src/cli/sync/conflicts.ts +205 -0
- package/references/minimem/src/cli/sync/daemon.ts +407 -0
- package/references/minimem/src/cli/sync/detection.ts +138 -0
- package/references/minimem/src/cli/sync/index.ts +107 -0
- package/references/minimem/src/cli/sync/operations.ts +373 -0
- package/references/minimem/src/cli/sync/registry.ts +279 -0
- package/references/minimem/src/cli/sync/state.ts +358 -0
- package/references/minimem/src/cli/sync/validation.ts +206 -0
- package/references/minimem/src/cli/sync/watcher.ts +237 -0
- package/references/minimem/src/cli/version.ts +34 -0
- package/references/minimem/src/core/index.ts +9 -0
- package/references/minimem/src/core/indexer.ts +628 -0
- package/references/minimem/src/core/searcher.ts +221 -0
- package/references/minimem/src/db/schema.ts +183 -0
- package/references/minimem/src/db/sqlite-vec.ts +24 -0
- package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +431 -0
- package/references/minimem/src/embeddings/batch-gemini.ts +392 -0
- package/references/minimem/src/embeddings/batch-openai.ts +409 -0
- package/references/minimem/src/embeddings/embeddings.ts +434 -0
- package/references/minimem/src/index.ts +132 -0
- package/references/minimem/src/internal.ts +299 -0
- package/references/minimem/src/minimem.ts +1291 -0
- package/references/minimem/src/search/__tests__/hybrid.test.ts +247 -0
- package/references/minimem/src/search/graph.ts +234 -0
- package/references/minimem/src/search/hybrid.ts +151 -0
- package/references/minimem/src/search/search.ts +256 -0
- package/references/minimem/src/server/__tests__/mcp.test.ts +347 -0
- package/references/minimem/src/server/__tests__/tools.test.ts +364 -0
- package/references/minimem/src/server/mcp.ts +326 -0
- package/references/minimem/src/server/tools.ts +720 -0
- package/references/minimem/src/session.ts +460 -0
- package/references/minimem/src/store/__tests__/manifest.test.ts +177 -0
- package/references/minimem/src/store/__tests__/materialize.test.ts +52 -0
- package/references/minimem/src/store/__tests__/store-graph.test.ts +228 -0
- package/references/minimem/src/store/index.ts +27 -0
- package/references/minimem/src/store/manifest.ts +203 -0
- package/references/minimem/src/store/materialize.ts +185 -0
- package/references/minimem/src/store/store-graph.ts +252 -0
- package/references/minimem/tsconfig.json +19 -0
- package/references/minimem/tsup.config.ts +26 -0
- package/references/minimem/vitest.config.ts +29 -0
- package/references/openteams/src/cli/generate.ts +23 -1
- package/references/openteams/src/generators/agent-prompt-generator.test.ts +94 -0
- package/references/openteams/src/generators/agent-prompt-generator.ts +42 -13
- package/references/openteams/src/generators/package-generator.ts +9 -1
- package/references/openteams/src/generators/skill-generator.test.ts +28 -0
- package/references/openteams/src/generators/skill-generator.ts +10 -4
- package/references/skill-tree/.claude/settings.json +6 -0
- package/references/skill-tree/.sudocode/issues.jsonl +19 -0
- package/references/skill-tree/.sudocode/specs.jsonl +3 -0
- package/references/skill-tree/CLAUDE.md +132 -0
- package/references/skill-tree/README.md +396 -0
- package/references/skill-tree/docs/GAPS_v1.md +221 -0
- package/references/skill-tree/docs/INTEGRATION_PLAN.md +467 -0
- package/references/skill-tree/docs/TODOS.md +91 -0
- package/references/skill-tree/docs/anthropic_skill_guide.md +1364 -0
- package/references/skill-tree/docs/design/federated-skill-trees.md +524 -0
- package/references/skill-tree/docs/design/multi-agent-sync.md +759 -0
- package/references/skill-tree/docs/scraper/BRAINSTORM.md +583 -0
- package/references/skill-tree/docs/scraper/POC_PLAN.md +420 -0
- package/references/skill-tree/docs/scraper/README.md +170 -0
- package/references/skill-tree/examples/basic-usage.ts +157 -0
- package/references/skill-tree/package-lock.json +1852 -0
- package/references/skill-tree/package.json +66 -0
- package/references/skill-tree/plan.md +78 -0
- package/references/skill-tree/scraper/README.md +123 -0
- package/references/skill-tree/scraper/docs/DESIGN.md +683 -0
- package/references/skill-tree/scraper/docs/PLAN.md +336 -0
- package/references/skill-tree/scraper/drizzle.config.ts +10 -0
- package/references/skill-tree/scraper/package-lock.json +6329 -0
- package/references/skill-tree/scraper/package.json +68 -0
- package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +7 -0
- package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +7 -0
- package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +27 -0
- package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +21 -0
- package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +54 -0
- package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +24 -0
- package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +93 -0
- package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +22 -0
- package/references/skill-tree/scraper/tsup.config.ts +14 -0
- package/references/skill-tree/scraper/vitest.config.ts +17 -0
- package/references/skill-tree/scripts/convert-to-vitest.ts +166 -0
- package/references/skill-tree/skills/skill-writer/SKILL.md +339 -0
- package/references/skill-tree/skills/skill-writer/references/examples.md +326 -0
- package/references/skill-tree/skills/skill-writer/references/patterns.md +210 -0
- package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +123 -0
- package/references/skill-tree/test/run-all.ts +106 -0
- package/references/skill-tree/test/utils.ts +128 -0
- package/references/skill-tree/vitest.config.ts +16 -0
- package/references/swarmkit/src/commands/init/phases/configure.ts +0 -22
- package/references/swarmkit/src/commands/init/phases/global-setup.ts +5 -3
- package/references/swarmkit/src/commands/init/wizard.ts +2 -2
- package/references/swarmkit/src/packages/setup.test.ts +53 -7
- package/references/swarmkit/src/packages/setup.ts +37 -1
- package/scripts/bootstrap.mjs +26 -1
- package/scripts/generate-agents.mjs +5 -1
- package/scripts/map-hook.mjs +97 -64
- package/scripts/map-sidecar.mjs +179 -25
- package/scripts/team-loader.mjs +12 -41
- package/skills/swarm/SKILL.md +89 -25
- package/src/__tests__/agent-generator.test.mjs +6 -13
- package/src/__tests__/bootstrap.test.mjs +124 -1
- package/src/__tests__/config.test.mjs +200 -27
- package/src/__tests__/e2e-live-map.test.mjs +536 -0
- package/src/__tests__/e2e-mesh-sidecar.test.mjs +570 -0
- package/src/__tests__/e2e-native-task-hooks.test.mjs +376 -0
- package/src/__tests__/e2e-sidecar-bridge.test.mjs +477 -0
- package/src/__tests__/helpers.mjs +13 -0
- package/src/__tests__/inbox.test.mjs +22 -89
- package/src/__tests__/index.test.mjs +35 -9
- package/src/__tests__/integration.test.mjs +513 -0
- package/src/__tests__/map-events.test.mjs +514 -150
- package/src/__tests__/mesh-connection.test.mjs +308 -0
- package/src/__tests__/opentasks-client.test.mjs +517 -0
- package/src/__tests__/paths.test.mjs +185 -41
- package/src/__tests__/sidecar-client.test.mjs +35 -0
- package/src/__tests__/sidecar-server.test.mjs +124 -0
- package/src/__tests__/skilltree-client.test.mjs +80 -0
- package/src/agent-generator.mjs +104 -33
- package/src/bootstrap.mjs +150 -10
- package/src/config.mjs +81 -17
- package/src/context-output.mjs +58 -8
- package/src/inbox.mjs +9 -54
- package/src/index.mjs +39 -8
- package/src/map-connection.mjs +4 -3
- package/src/map-events.mjs +350 -80
- package/src/mesh-connection.mjs +148 -0
- package/src/opentasks-client.mjs +269 -0
- package/src/paths.mjs +182 -27
- package/src/sessionlog.mjs +14 -9
- package/src/sidecar-client.mjs +81 -27
- package/src/sidecar-server.mjs +175 -16
- package/src/skilltree-client.mjs +173 -0
- package/src/template.mjs +68 -4
- package/vitest.config.mjs +1 -0
|
@@ -32,9 +32,13 @@ vi.mock("../paths.mjs", async () => {
|
|
|
32
32
|
PID_PATH: path.join(tmpDir, "sidecar.pid"),
|
|
33
33
|
MAP_DIR: path.join(tmpDir, "map"),
|
|
34
34
|
SIDECAR_LOG_PATH: path.join(tmpDir, "sidecar.log"),
|
|
35
|
+
OPENTASKS_DIR: path.join(tmpDir, "opentasks"),
|
|
35
36
|
teamDir: vi.fn((name) => `${tmpDir}/.swarm/claude-swarm/tmp/teams/${name}`),
|
|
36
37
|
ensureSwarmDir: vi.fn(),
|
|
37
38
|
ensureMapDir: vi.fn(),
|
|
39
|
+
ensureOpentasksDir: vi.fn(),
|
|
40
|
+
ensureSessionDir: vi.fn(),
|
|
41
|
+
listSessionDirs: vi.fn().mockReturnValue([]),
|
|
38
42
|
pluginDir: vi.fn(() => tmpDir),
|
|
39
43
|
};
|
|
40
44
|
});
|
|
@@ -54,6 +58,12 @@ const mockSwarmkit = {
|
|
|
54
58
|
initProjectPackage: vi.fn().mockResolvedValue({ package: "openteams", success: true }),
|
|
55
59
|
};
|
|
56
60
|
|
|
61
|
+
vi.mock("../opentasks-client.mjs", () => ({
|
|
62
|
+
findSocketPath: vi.fn(() => "/tmp/test-daemon.sock"),
|
|
63
|
+
isDaemonAlive: vi.fn().mockResolvedValue(false),
|
|
64
|
+
ensureDaemon: vi.fn().mockResolvedValue(true),
|
|
65
|
+
}));
|
|
66
|
+
|
|
57
67
|
vi.mock("../swarmkit-resolver.mjs", () => ({
|
|
58
68
|
resolveSwarmkit: vi.fn().mockResolvedValue(mockSwarmkit),
|
|
59
69
|
configureNodePath: vi.fn(),
|
|
@@ -63,7 +73,8 @@ const { bootstrap } = await import("../bootstrap.mjs");
|
|
|
63
73
|
const { readConfig } = await import("../config.mjs");
|
|
64
74
|
const { killSidecar, startSidecar } = await import("../sidecar-client.mjs");
|
|
65
75
|
const { checkSessionlogStatus, syncSessionlog } = await import("../sessionlog.mjs");
|
|
66
|
-
const { pluginDir } = await import("../paths.mjs");
|
|
76
|
+
const { pluginDir, ensureOpentasksDir, ensureSessionDir, listSessionDirs } = await import("../paths.mjs");
|
|
77
|
+
const { findSocketPath, isDaemonAlive, ensureDaemon } = await import("../opentasks-client.mjs");
|
|
67
78
|
const { resolveSwarmkit, configureNodePath } = await import("../swarmkit-resolver.mjs");
|
|
68
79
|
|
|
69
80
|
describe("bootstrap", () => {
|
|
@@ -350,4 +361,116 @@ describe("bootstrap", () => {
|
|
|
350
361
|
expect(ensureSwarmDir).toHaveBeenCalled();
|
|
351
362
|
});
|
|
352
363
|
});
|
|
364
|
+
|
|
365
|
+
describe("opentasks", () => {
|
|
366
|
+
it("returns opentasksStatus 'disabled' when not enabled", async () => {
|
|
367
|
+
readConfig.mockReturnValue(makeConfig({ opentasksEnabled: false }));
|
|
368
|
+
const result = await bootstrap();
|
|
369
|
+
expect(result.opentasksStatus).toBe("disabled");
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("calls ensureOpentasksDir when enabled", async () => {
|
|
373
|
+
readConfig.mockReturnValue(makeConfig({ opentasksEnabled: true }));
|
|
374
|
+
await bootstrap();
|
|
375
|
+
expect(ensureOpentasksDir).toHaveBeenCalled();
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("calls ensureDaemon when enabled with autoStart", async () => {
|
|
379
|
+
readConfig.mockReturnValue(makeConfig({ opentasksEnabled: true, opentasksAutoStart: true }));
|
|
380
|
+
await bootstrap();
|
|
381
|
+
expect(ensureDaemon).toHaveBeenCalled();
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it("returns 'connected' when ensureDaemon succeeds", async () => {
|
|
385
|
+
readConfig.mockReturnValue(makeConfig({ opentasksEnabled: true }));
|
|
386
|
+
ensureDaemon.mockResolvedValue(true);
|
|
387
|
+
const result = await bootstrap();
|
|
388
|
+
expect(result.opentasksStatus).toBe("connected");
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it("returns 'starting' when ensureDaemon fails", async () => {
|
|
392
|
+
readConfig.mockReturnValue(makeConfig({ opentasksEnabled: true }));
|
|
393
|
+
ensureDaemon.mockResolvedValue(false);
|
|
394
|
+
const result = await bootstrap();
|
|
395
|
+
expect(result.opentasksStatus).toBe("starting");
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it("calls isDaemonAlive when autoStart is false", async () => {
|
|
399
|
+
readConfig.mockReturnValue(makeConfig({ opentasksEnabled: true, opentasksAutoStart: false }));
|
|
400
|
+
isDaemonAlive.mockResolvedValue(true);
|
|
401
|
+
await bootstrap();
|
|
402
|
+
expect(isDaemonAlive).toHaveBeenCalled();
|
|
403
|
+
expect(ensureDaemon).not.toHaveBeenCalled();
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it("returns 'connected' when daemon is already alive (autoStart false)", async () => {
|
|
407
|
+
readConfig.mockReturnValue(makeConfig({ opentasksEnabled: true, opentasksAutoStart: false }));
|
|
408
|
+
isDaemonAlive.mockResolvedValue(true);
|
|
409
|
+
const result = await bootstrap();
|
|
410
|
+
expect(result.opentasksStatus).toBe("connected");
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it("returns 'not running' when daemon is not alive (autoStart false)", async () => {
|
|
414
|
+
readConfig.mockReturnValue(makeConfig({ opentasksEnabled: true, opentasksAutoStart: false }));
|
|
415
|
+
isDaemonAlive.mockResolvedValue(false);
|
|
416
|
+
const result = await bootstrap();
|
|
417
|
+
expect(result.opentasksStatus).toContain("not running");
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it("checks opentasks package via swarmkit when enabled", async () => {
|
|
421
|
+
readConfig.mockReturnValue(makeConfig({ opentasksEnabled: true }));
|
|
422
|
+
mockSwarmkit.getInstalledVersion.mockResolvedValue("1.0.0");
|
|
423
|
+
await bootstrap();
|
|
424
|
+
expect(mockSwarmkit.getInstalledVersion).toHaveBeenCalledWith("opentasks");
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it("does not check opentasks package when disabled", async () => {
|
|
428
|
+
readConfig.mockReturnValue(makeConfig({ opentasksEnabled: false }));
|
|
429
|
+
mockSwarmkit.getInstalledVersion.mockResolvedValue("1.0.0");
|
|
430
|
+
await bootstrap();
|
|
431
|
+
const calls = mockSwarmkit.getInstalledVersion.mock.calls.map((c) => c[0]);
|
|
432
|
+
expect(calls).not.toContain("opentasks");
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
describe("per-session sidecar", () => {
|
|
437
|
+
it("calls ensureSessionDir when sessionId provided and MAP enabled", async () => {
|
|
438
|
+
readConfig.mockReturnValue(makeConfig({ mapEnabled: true }));
|
|
439
|
+
await bootstrap(undefined, "session-abc");
|
|
440
|
+
expect(ensureSessionDir).toHaveBeenCalledWith("session-abc");
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
it("passes sessionId to killSidecar and startSidecar", async () => {
|
|
444
|
+
readConfig.mockReturnValue(makeConfig({ mapEnabled: true, sidecar: "session" }));
|
|
445
|
+
await bootstrap(undefined, "session-xyz");
|
|
446
|
+
expect(killSidecar).toHaveBeenCalledWith("session-xyz");
|
|
447
|
+
expect(startSidecar).toHaveBeenCalledWith(
|
|
448
|
+
expect.anything(),
|
|
449
|
+
expect.anything(),
|
|
450
|
+
"session-xyz"
|
|
451
|
+
);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it("passes sessionId to syncSessionlog", async () => {
|
|
455
|
+
readConfig.mockReturnValue(makeConfig({ mapEnabled: true, sessionlogSync: "full" }));
|
|
456
|
+
await bootstrap(undefined, "session-sync");
|
|
457
|
+
expect(syncSessionlog).toHaveBeenCalledWith(expect.anything(), "session-sync");
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
it("returns sessionId in result", async () => {
|
|
461
|
+
const result = await bootstrap(undefined, "session-ret");
|
|
462
|
+
expect(result.sessionId).toBe("session-ret");
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
it("returns null sessionId when not provided", async () => {
|
|
466
|
+
const result = await bootstrap();
|
|
467
|
+
expect(result.sessionId).toBeUndefined();
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it("calls listSessionDirs during cleanup (session sidecar mode)", async () => {
|
|
471
|
+
readConfig.mockReturnValue(makeConfig({ mapEnabled: true, sidecar: "session" }));
|
|
472
|
+
await bootstrap(undefined, "session-cleanup");
|
|
473
|
+
expect(listSessionDirs).toHaveBeenCalled();
|
|
474
|
+
});
|
|
475
|
+
});
|
|
353
476
|
});
|
|
@@ -16,7 +16,11 @@ describe("config", () => {
|
|
|
16
16
|
|
|
17
17
|
describe("readConfig", () => {
|
|
18
18
|
let tmpDir;
|
|
19
|
-
|
|
19
|
+
let noGlobal;
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
tmpDir = makeTmpDir();
|
|
22
|
+
noGlobal = path.join(tmpDir, "no-global.json");
|
|
23
|
+
});
|
|
20
24
|
afterEach(() => { cleanupTmpDir(tmpDir); });
|
|
21
25
|
|
|
22
26
|
it("reads and parses a valid config file", () => {
|
|
@@ -24,7 +28,7 @@ describe("config", () => {
|
|
|
24
28
|
template: "gsd",
|
|
25
29
|
map: { enabled: true, server: "ws://example.com:9090" },
|
|
26
30
|
}));
|
|
27
|
-
const config = readConfig(configPath);
|
|
31
|
+
const config = readConfig(configPath, noGlobal);
|
|
28
32
|
expect(config.template).toBe("gsd");
|
|
29
33
|
expect(config.map.enabled).toBe(true);
|
|
30
34
|
expect(config.map.server).toBe("ws://example.com:9090");
|
|
@@ -35,7 +39,7 @@ describe("config", () => {
|
|
|
35
39
|
template: "test",
|
|
36
40
|
map: { enabled: true },
|
|
37
41
|
}));
|
|
38
|
-
const config = readConfig(configPath);
|
|
42
|
+
const config = readConfig(configPath, noGlobal);
|
|
39
43
|
expect(config.map.server).toBe(DEFAULTS.mapServer);
|
|
40
44
|
expect(config.map.scope).toBe("");
|
|
41
45
|
expect(config.map.systemId).toBe(DEFAULTS.mapSystemId);
|
|
@@ -44,13 +48,38 @@ describe("config", () => {
|
|
|
44
48
|
|
|
45
49
|
it("normalizes sessionlog fields with defaults", () => {
|
|
46
50
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({ template: "test" }));
|
|
47
|
-
const config = readConfig(configPath);
|
|
51
|
+
const config = readConfig(configPath, noGlobal);
|
|
48
52
|
expect(config.sessionlog.enabled).toBe(false);
|
|
49
53
|
expect(config.sessionlog.sync).toBe("off");
|
|
50
54
|
});
|
|
51
55
|
|
|
56
|
+
it("normalizes opentasks fields with defaults", () => {
|
|
57
|
+
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({ template: "test" }));
|
|
58
|
+
const config = readConfig(configPath, noGlobal);
|
|
59
|
+
expect(config.opentasks.enabled).toBe(false);
|
|
60
|
+
expect(config.opentasks.autoStart).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("reads opentasks.enabled from config file", () => {
|
|
64
|
+
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
65
|
+
template: "test",
|
|
66
|
+
opentasks: { enabled: true },
|
|
67
|
+
}));
|
|
68
|
+
const config = readConfig(configPath, noGlobal);
|
|
69
|
+
expect(config.opentasks.enabled).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("reads opentasks.autoStart false from config file", () => {
|
|
73
|
+
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
74
|
+
template: "test",
|
|
75
|
+
opentasks: { enabled: true, autoStart: false },
|
|
76
|
+
}));
|
|
77
|
+
const config = readConfig(configPath, noGlobal);
|
|
78
|
+
expect(config.opentasks.autoStart).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
|
|
52
81
|
it("returns defaults when file does not exist", () => {
|
|
53
|
-
const config = readConfig(path.join(tmpDir, "nonexistent.json"));
|
|
82
|
+
const config = readConfig(path.join(tmpDir, "nonexistent.json"), noGlobal);
|
|
54
83
|
expect(config.template).toBe("");
|
|
55
84
|
expect(config.map.enabled).toBe(false);
|
|
56
85
|
expect(config.sessionlog.enabled).toBe(false);
|
|
@@ -58,20 +87,20 @@ describe("config", () => {
|
|
|
58
87
|
|
|
59
88
|
it("returns defaults when file contains invalid JSON", () => {
|
|
60
89
|
const configPath = writeFile(tmpDir, "config.json", "not json{{{");
|
|
61
|
-
const config = readConfig(configPath);
|
|
90
|
+
const config = readConfig(configPath, noGlobal);
|
|
62
91
|
expect(config.template).toBe("");
|
|
63
92
|
expect(config.map.enabled).toBe(false);
|
|
64
93
|
});
|
|
65
94
|
|
|
66
95
|
it("returns defaults when file is empty", () => {
|
|
67
96
|
const configPath = writeFile(tmpDir, "config.json", "");
|
|
68
|
-
const config = readConfig(configPath);
|
|
97
|
+
const config = readConfig(configPath, noGlobal);
|
|
69
98
|
expect(config.template).toBe("");
|
|
70
99
|
});
|
|
71
100
|
|
|
72
101
|
it("handles config with only template field", () => {
|
|
73
102
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({ template: "my-team" }));
|
|
74
|
-
const config = readConfig(configPath);
|
|
103
|
+
const config = readConfig(configPath, noGlobal);
|
|
75
104
|
expect(config.template).toBe("my-team");
|
|
76
105
|
expect(config.map.enabled).toBe(false);
|
|
77
106
|
});
|
|
@@ -81,7 +110,7 @@ describe("config", () => {
|
|
|
81
110
|
template: "test",
|
|
82
111
|
map: { enabled: true, scope: "custom:scope" },
|
|
83
112
|
}));
|
|
84
|
-
const config = readConfig(configPath);
|
|
113
|
+
const config = readConfig(configPath, noGlobal);
|
|
85
114
|
expect(config.map.scope).toBe("custom:scope");
|
|
86
115
|
});
|
|
87
116
|
|
|
@@ -89,7 +118,7 @@ describe("config", () => {
|
|
|
89
118
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
90
119
|
map: { server: "ws://example.com:9090" },
|
|
91
120
|
}));
|
|
92
|
-
const config = readConfig(configPath);
|
|
121
|
+
const config = readConfig(configPath, noGlobal);
|
|
93
122
|
expect(config.map.enabled).toBe(true);
|
|
94
123
|
});
|
|
95
124
|
|
|
@@ -97,8 +126,114 @@ describe("config", () => {
|
|
|
97
126
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
98
127
|
template: "test",
|
|
99
128
|
}));
|
|
100
|
-
const config = readConfig(configPath);
|
|
129
|
+
const config = readConfig(configPath, noGlobal);
|
|
130
|
+
expect(config.map.enabled).toBe(false);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe("global config fallthrough", () => {
|
|
135
|
+
let tmpDir;
|
|
136
|
+
beforeEach(() => { tmpDir = makeTmpDir(); });
|
|
137
|
+
afterEach(() => { cleanupTmpDir(tmpDir); });
|
|
138
|
+
|
|
139
|
+
it("uses global config values when project config is missing", () => {
|
|
140
|
+
const globalPath = writeFile(tmpDir, "global.json", JSON.stringify({
|
|
141
|
+
map: { server: "ws://global-server:9090", sidecar: "persistent" },
|
|
142
|
+
sessionlog: { sync: "full" },
|
|
143
|
+
}));
|
|
144
|
+
const projectPath = path.join(tmpDir, "nonexistent.json");
|
|
145
|
+
const config = readConfig(projectPath, globalPath);
|
|
146
|
+
expect(config.map.server).toBe("ws://global-server:9090");
|
|
147
|
+
expect(config.map.sidecar).toBe("persistent");
|
|
148
|
+
expect(config.sessionlog.sync).toBe("full");
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("project config overrides global config", () => {
|
|
152
|
+
const globalPath = writeFile(tmpDir, "global.json", JSON.stringify({
|
|
153
|
+
map: { server: "ws://global-server:9090", sidecar: "persistent" },
|
|
154
|
+
sessionlog: { sync: "full" },
|
|
155
|
+
}));
|
|
156
|
+
const projectPath = writeFile(tmpDir, "project.json", JSON.stringify({
|
|
157
|
+
map: { server: "ws://project-server:8080" },
|
|
158
|
+
sessionlog: { sync: "lifecycle" },
|
|
159
|
+
}));
|
|
160
|
+
const config = readConfig(projectPath, globalPath);
|
|
161
|
+
expect(config.map.server).toBe("ws://project-server:8080");
|
|
162
|
+
expect(config.map.sidecar).toBe("persistent"); // falls through from global
|
|
163
|
+
expect(config.sessionlog.sync).toBe("lifecycle");
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("project template overrides global template", () => {
|
|
167
|
+
const globalPath = writeFile(tmpDir, "global.json", JSON.stringify({
|
|
168
|
+
template: "global-template",
|
|
169
|
+
}));
|
|
170
|
+
const projectPath = writeFile(tmpDir, "project.json", JSON.stringify({
|
|
171
|
+
template: "project-template",
|
|
172
|
+
}));
|
|
173
|
+
const config = readConfig(projectPath, globalPath);
|
|
174
|
+
expect(config.template).toBe("project-template");
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("global template is used when project has no template", () => {
|
|
178
|
+
const globalPath = writeFile(tmpDir, "global.json", JSON.stringify({
|
|
179
|
+
template: "global-template",
|
|
180
|
+
}));
|
|
181
|
+
const projectPath = writeFile(tmpDir, "project.json", JSON.stringify({}));
|
|
182
|
+
const config = readConfig(projectPath, globalPath);
|
|
183
|
+
expect(config.template).toBe("global-template");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("global map.enabled enables MAP when project has no map config", () => {
|
|
187
|
+
const globalPath = writeFile(tmpDir, "global.json", JSON.stringify({
|
|
188
|
+
map: { enabled: true, server: "ws://global-server:9090" },
|
|
189
|
+
}));
|
|
190
|
+
const projectPath = path.join(tmpDir, "nonexistent.json");
|
|
191
|
+
const config = readConfig(projectPath, globalPath);
|
|
192
|
+
expect(config.map.enabled).toBe(true);
|
|
193
|
+
expect(config.map.server).toBe("ws://global-server:9090");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("global map.server implicitly enables MAP when project has no config", () => {
|
|
197
|
+
const globalPath = writeFile(tmpDir, "global.json", JSON.stringify({
|
|
198
|
+
map: { server: "ws://global-server:9090" },
|
|
199
|
+
}));
|
|
200
|
+
const projectPath = path.join(tmpDir, "nonexistent.json");
|
|
201
|
+
const config = readConfig(projectPath, globalPath);
|
|
202
|
+
expect(config.map.enabled).toBe(true);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("global sessionlog.enabled is used when project has no sessionlog config", () => {
|
|
206
|
+
const globalPath = writeFile(tmpDir, "global.json", JSON.stringify({
|
|
207
|
+
sessionlog: { enabled: true, sync: "metrics" },
|
|
208
|
+
}));
|
|
209
|
+
const projectPath = path.join(tmpDir, "nonexistent.json");
|
|
210
|
+
const config = readConfig(projectPath, globalPath);
|
|
211
|
+
expect(config.sessionlog.enabled).toBe(true);
|
|
212
|
+
expect(config.sessionlog.sync).toBe("metrics");
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("falls back to defaults when both configs are missing", () => {
|
|
216
|
+
const globalPath = path.join(tmpDir, "nonexistent-global.json");
|
|
217
|
+
const projectPath = path.join(tmpDir, "nonexistent-project.json");
|
|
218
|
+
const config = readConfig(projectPath, globalPath);
|
|
219
|
+
expect(config.template).toBe("");
|
|
101
220
|
expect(config.map.enabled).toBe(false);
|
|
221
|
+
expect(config.map.server).toBe(DEFAULTS.mapServer);
|
|
222
|
+
expect(config.sessionlog.enabled).toBe(false);
|
|
223
|
+
expect(config.sessionlog.sync).toBe(DEFAULTS.sessionlogSync);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("per-field fallthrough: project scope + global server", () => {
|
|
227
|
+
const globalPath = writeFile(tmpDir, "global.json", JSON.stringify({
|
|
228
|
+
map: { server: "ws://global-server:9090", systemId: "global-system" },
|
|
229
|
+
}));
|
|
230
|
+
const projectPath = writeFile(tmpDir, "project.json", JSON.stringify({
|
|
231
|
+
map: { scope: "my-project" },
|
|
232
|
+
}));
|
|
233
|
+
const config = readConfig(projectPath, globalPath);
|
|
234
|
+
expect(config.map.scope).toBe("my-project");
|
|
235
|
+
expect(config.map.server).toBe("ws://global-server:9090");
|
|
236
|
+
expect(config.map.systemId).toBe("global-system");
|
|
102
237
|
});
|
|
103
238
|
});
|
|
104
239
|
|
|
@@ -122,10 +257,12 @@ describe("config", () => {
|
|
|
122
257
|
|
|
123
258
|
describe("env var overrides", () => {
|
|
124
259
|
let tmpDir;
|
|
260
|
+
let noGlobal;
|
|
125
261
|
const savedEnv = {};
|
|
126
262
|
|
|
127
263
|
beforeEach(() => {
|
|
128
264
|
tmpDir = makeTmpDir();
|
|
265
|
+
noGlobal = path.join(tmpDir, "no-global.json");
|
|
129
266
|
for (const key of Object.keys(process.env)) {
|
|
130
267
|
if (key.startsWith("SWARM_")) {
|
|
131
268
|
savedEnv[key] = process.env[key];
|
|
@@ -152,7 +289,7 @@ describe("config", () => {
|
|
|
152
289
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
153
290
|
template: "file-template",
|
|
154
291
|
}));
|
|
155
|
-
const config = readConfig(configPath);
|
|
292
|
+
const config = readConfig(configPath, noGlobal);
|
|
156
293
|
expect(config.template).toBe("env-template");
|
|
157
294
|
});
|
|
158
295
|
|
|
@@ -161,7 +298,7 @@ describe("config", () => {
|
|
|
161
298
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
162
299
|
map: { enabled: false },
|
|
163
300
|
}));
|
|
164
|
-
const config = readConfig(configPath);
|
|
301
|
+
const config = readConfig(configPath, noGlobal);
|
|
165
302
|
expect(config.map.enabled).toBe(true);
|
|
166
303
|
});
|
|
167
304
|
|
|
@@ -169,13 +306,13 @@ describe("config", () => {
|
|
|
169
306
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({}));
|
|
170
307
|
|
|
171
308
|
process.env.SWARM_MAP_ENABLED = "1";
|
|
172
|
-
expect(readConfig(configPath).map.enabled).toBe(true);
|
|
309
|
+
expect(readConfig(configPath, noGlobal).map.enabled).toBe(true);
|
|
173
310
|
|
|
174
311
|
process.env.SWARM_MAP_ENABLED = "yes";
|
|
175
|
-
expect(readConfig(configPath).map.enabled).toBe(true);
|
|
312
|
+
expect(readConfig(configPath, noGlobal).map.enabled).toBe(true);
|
|
176
313
|
|
|
177
314
|
process.env.SWARM_MAP_ENABLED = "YES";
|
|
178
|
-
expect(readConfig(configPath).map.enabled).toBe(true);
|
|
315
|
+
expect(readConfig(configPath, noGlobal).map.enabled).toBe(true);
|
|
179
316
|
});
|
|
180
317
|
|
|
181
318
|
it("SWARM_MAP_ENABLED=false overrides true in config", () => {
|
|
@@ -183,7 +320,7 @@ describe("config", () => {
|
|
|
183
320
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
184
321
|
map: { enabled: true },
|
|
185
322
|
}));
|
|
186
|
-
expect(readConfig(configPath).map.enabled).toBe(false);
|
|
323
|
+
expect(readConfig(configPath, noGlobal).map.enabled).toBe(false);
|
|
187
324
|
});
|
|
188
325
|
|
|
189
326
|
it("SWARM_MAP_ENABLED=false disables even when server is configured", () => {
|
|
@@ -191,13 +328,13 @@ describe("config", () => {
|
|
|
191
328
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
192
329
|
map: { server: "ws://example.com:9090" },
|
|
193
330
|
}));
|
|
194
|
-
expect(readConfig(configPath).map.enabled).toBe(false);
|
|
331
|
+
expect(readConfig(configPath, noGlobal).map.enabled).toBe(false);
|
|
195
332
|
});
|
|
196
333
|
|
|
197
334
|
it("SWARM_MAP_SERVER implicitly enables MAP", () => {
|
|
198
335
|
process.env.SWARM_MAP_SERVER = "ws://env-server:9090";
|
|
199
336
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({}));
|
|
200
|
-
const config = readConfig(configPath);
|
|
337
|
+
const config = readConfig(configPath, noGlobal);
|
|
201
338
|
expect(config.map.enabled).toBe(true);
|
|
202
339
|
expect(config.map.server).toBe("ws://env-server:9090");
|
|
203
340
|
});
|
|
@@ -207,7 +344,7 @@ describe("config", () => {
|
|
|
207
344
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
208
345
|
map: { server: "ws://file-server:8080" },
|
|
209
346
|
}));
|
|
210
|
-
expect(readConfig(configPath).map.server).toBe("ws://env-server:9090");
|
|
347
|
+
expect(readConfig(configPath, noGlobal).map.server).toBe("ws://env-server:9090");
|
|
211
348
|
});
|
|
212
349
|
|
|
213
350
|
it("SWARM_MAP_SCOPE overrides config file", () => {
|
|
@@ -215,7 +352,7 @@ describe("config", () => {
|
|
|
215
352
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
216
353
|
map: { scope: "custom:file-scope" },
|
|
217
354
|
}));
|
|
218
|
-
expect(readConfig(configPath).map.scope).toBe("custom:env-scope");
|
|
355
|
+
expect(readConfig(configPath, noGlobal).map.scope).toBe("custom:env-scope");
|
|
219
356
|
});
|
|
220
357
|
|
|
221
358
|
it("SWARM_MAP_SYSTEM_ID overrides config file", () => {
|
|
@@ -223,7 +360,7 @@ describe("config", () => {
|
|
|
223
360
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
224
361
|
map: { systemId: "file-system" },
|
|
225
362
|
}));
|
|
226
|
-
expect(readConfig(configPath).map.systemId).toBe("env-system");
|
|
363
|
+
expect(readConfig(configPath, noGlobal).map.systemId).toBe("env-system");
|
|
227
364
|
});
|
|
228
365
|
|
|
229
366
|
it("SWARM_MAP_SIDECAR overrides config file", () => {
|
|
@@ -231,7 +368,7 @@ describe("config", () => {
|
|
|
231
368
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
232
369
|
map: { sidecar: "session" },
|
|
233
370
|
}));
|
|
234
|
-
expect(readConfig(configPath).map.sidecar).toBe("persistent");
|
|
371
|
+
expect(readConfig(configPath, noGlobal).map.sidecar).toBe("persistent");
|
|
235
372
|
});
|
|
236
373
|
|
|
237
374
|
it("SWARM_SESSIONLOG_ENABLED overrides config file", () => {
|
|
@@ -239,7 +376,7 @@ describe("config", () => {
|
|
|
239
376
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
240
377
|
sessionlog: { enabled: false },
|
|
241
378
|
}));
|
|
242
|
-
expect(readConfig(configPath).sessionlog.enabled).toBe(true);
|
|
379
|
+
expect(readConfig(configPath, noGlobal).sessionlog.enabled).toBe(true);
|
|
243
380
|
});
|
|
244
381
|
|
|
245
382
|
it("SWARM_SESSIONLOG_SYNC overrides config file", () => {
|
|
@@ -247,13 +384,27 @@ describe("config", () => {
|
|
|
247
384
|
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
248
385
|
sessionlog: { sync: "off" },
|
|
249
386
|
}));
|
|
250
|
-
expect(readConfig(configPath).sessionlog.sync).toBe("full");
|
|
387
|
+
expect(readConfig(configPath, noGlobal).sessionlog.sync).toBe("full");
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("SWARM_OPENTASKS_ENABLED overrides config file", () => {
|
|
391
|
+
process.env.SWARM_OPENTASKS_ENABLED = "true";
|
|
392
|
+
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({
|
|
393
|
+
opentasks: { enabled: false },
|
|
394
|
+
}));
|
|
395
|
+
expect(readConfig(configPath, noGlobal).opentasks.enabled).toBe(true);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it("SWARM_OPENTASKS_AUTOSTART overrides default", () => {
|
|
399
|
+
process.env.SWARM_OPENTASKS_AUTOSTART = "false";
|
|
400
|
+
const configPath = writeFile(tmpDir, "config.json", JSON.stringify({}));
|
|
401
|
+
expect(readConfig(configPath, noGlobal).opentasks.autoStart).toBe(false);
|
|
251
402
|
});
|
|
252
403
|
|
|
253
404
|
it("env vars override defaults when no config file exists", () => {
|
|
254
405
|
process.env.SWARM_MAP_SERVER = "ws://env-server:9090";
|
|
255
406
|
process.env.SWARM_MAP_SYSTEM_ID = "env-system";
|
|
256
|
-
const config = readConfig(path.join(tmpDir, "nonexistent.json"));
|
|
407
|
+
const config = readConfig(path.join(tmpDir, "nonexistent.json"), noGlobal);
|
|
257
408
|
expect(config.map.enabled).toBe(true);
|
|
258
409
|
expect(config.map.server).toBe("ws://env-server:9090");
|
|
259
410
|
expect(config.map.systemId).toBe("env-system");
|
|
@@ -264,10 +415,32 @@ describe("config", () => {
|
|
|
264
415
|
template: "file-template",
|
|
265
416
|
map: { server: "ws://file-server:8080" },
|
|
266
417
|
}));
|
|
267
|
-
const config = readConfig(configPath);
|
|
418
|
+
const config = readConfig(configPath, noGlobal);
|
|
268
419
|
expect(config.template).toBe("file-template");
|
|
269
420
|
expect(config.map.server).toBe("ws://file-server:8080");
|
|
270
421
|
});
|
|
422
|
+
|
|
423
|
+
it("env vars override global config values", () => {
|
|
424
|
+
process.env.SWARM_MAP_SERVER = "ws://env-server:9090";
|
|
425
|
+
const globalPath = writeFile(tmpDir, "global.json", JSON.stringify({
|
|
426
|
+
map: { server: "ws://global-server:8080" },
|
|
427
|
+
}));
|
|
428
|
+
const projectPath = path.join(tmpDir, "nonexistent.json");
|
|
429
|
+
const config = readConfig(projectPath, globalPath);
|
|
430
|
+
expect(config.map.server).toBe("ws://env-server:9090");
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it("env vars override both project and global config", () => {
|
|
434
|
+
process.env.SWARM_MAP_SIDECAR = "persistent";
|
|
435
|
+
const globalPath = writeFile(tmpDir, "global.json", JSON.stringify({
|
|
436
|
+
map: { sidecar: "session" },
|
|
437
|
+
}));
|
|
438
|
+
const projectPath = writeFile(tmpDir, "project.json", JSON.stringify({
|
|
439
|
+
map: { sidecar: "session" },
|
|
440
|
+
}));
|
|
441
|
+
const config = readConfig(projectPath, globalPath);
|
|
442
|
+
expect(config.map.sidecar).toBe("persistent");
|
|
443
|
+
});
|
|
271
444
|
});
|
|
272
445
|
|
|
273
446
|
describe("resolveTeamName", () => {
|