swarmdo 1.4.8 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/.claude/helpers/statusline.cjs +7 -7
  2. package/README.md +3 -1
  3. package/package.json +5 -3
  4. package/v3/@swarmdo/cli/dist/src/commands/hooks.js +26 -24
  5. package/v3/@swarmdo/cli/dist/src/commands/index.js +4 -0
  6. package/v3/@swarmdo/cli/dist/src/commands/integrations.d.ts +14 -0
  7. package/v3/@swarmdo/cli/dist/src/commands/integrations.js +158 -0
  8. package/v3/@swarmdo/cli/dist/src/commands/memory.js +50 -1
  9. package/v3/@swarmdo/cli/dist/src/commands/providers.js +3 -0
  10. package/v3/@swarmdo/cli/dist/src/commands/release.d.ts +15 -0
  11. package/v3/@swarmdo/cli/dist/src/commands/release.js +224 -0
  12. package/v3/@swarmdo/cli/dist/src/commands/security.js +14 -0
  13. package/v3/@swarmdo/cli/dist/src/commands/transcript.js +82 -1
  14. package/v3/@swarmdo/cli/dist/src/commands/usage.js +80 -1
  15. package/v3/@swarmdo/cli/dist/src/config-lint/lint.js +11 -1
  16. package/v3/@swarmdo/cli/dist/src/init/statusline-generator.js +6 -6
  17. package/v3/@swarmdo/cli/dist/src/integrations/integrations.d.ts +54 -0
  18. package/v3/@swarmdo/cli/dist/src/integrations/integrations.js +162 -0
  19. package/v3/@swarmdo/cli/dist/src/mcp-tools/agent-execute-core.js +25 -3
  20. package/v3/@swarmdo/cli/dist/src/mcp-tools/agentdb-tools.js +8 -8
  21. package/v3/@swarmdo/cli/dist/src/memory/graph-edge-writer.d.ts +12 -0
  22. package/v3/@swarmdo/cli/dist/src/memory/graph-edge-writer.js +32 -1
  23. package/v3/@swarmdo/cli/dist/src/memory-vault/watch.d.ts +32 -0
  24. package/v3/@swarmdo/cli/dist/src/memory-vault/watch.js +66 -0
  25. package/v3/@swarmdo/cli/dist/src/providers/openrouter-config.d.ts +91 -0
  26. package/v3/@swarmdo/cli/dist/src/providers/openrouter-config.js +186 -0
  27. package/v3/@swarmdo/cli/dist/src/release/release.d.ts +72 -0
  28. package/v3/@swarmdo/cli/dist/src/release/release.js +86 -0
  29. package/v3/@swarmdo/cli/dist/src/resilience/backoff.d.ts +23 -0
  30. package/v3/@swarmdo/cli/dist/src/resilience/backoff.js +30 -0
  31. package/v3/@swarmdo/cli/dist/src/swarmvector/model-router.js +14 -0
  32. package/v3/@swarmdo/cli/dist/src/transcript/search.d.ts +39 -0
  33. package/v3/@swarmdo/cli/dist/src/transcript/search.js +67 -0
  34. package/v3/@swarmdo/cli/dist/src/usage/diff.d.ts +69 -0
  35. package/v3/@swarmdo/cli/dist/src/usage/diff.js +112 -0
  36. package/v3/@swarmdo/cli/package.json +4 -4
  37. package/v3/@swarmdo/cli-core/dist/src/index.js +1 -1
  38. package/v3/@swarmdo/codex/dist/cli.js +0 -0
  39. package/v3/@swarmdo/hooks/dist/cli/guidance-cli.js +0 -0
  40. package/v3/@swarmdo/hooks/dist/statusline/index.d.ts +3 -3
  41. package/v3/@swarmdo/hooks/dist/statusline/index.js +3 -3
  42. package/v3/@swarmdo/integration/dist/__tests__/agentic-flow-agent.test.js +4 -1
  43. package/v3/@swarmdo/neural/dist/flash-attention.d.ts +1 -1
  44. package/v3/@swarmdo/neural/dist/flash-attention.js +1 -1
  45. package/v3/@swarmdo/plugin-agent-federation/dist/plugin.js +1 -1
  46. package/v3/@swarmdo/plugin-agent-federation/dist/transport/midstream-aware-loader.js +2 -2
  47. package/v3/@swarmdo/providers/dist/swarmvector-provider.d.ts +1 -1
  48. package/v3/@swarmdo/providers/dist/swarmvector-provider.js +1 -1
  49. package/v3/@swarmdo/security/dist/input-validator.d.ts +6 -6
  50. package/v3/@swarmdo/shared/dist/hooks/safety/git-commit.js +1 -1
  51. package/v3/@swarmdo/shared/dist/mcp/transport/http.js +8 -1
  52. package/v3/vendor/agentdb/package.json +0 -1
  53. package/v3/vendor/agentic-flow/package.json +0 -1
  54. package/.claude/scheduled_tasks.lock +0 -1
  55. package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  56. package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/__main__.cpython-314.pyc +0 -0
  57. package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/cli.cpython-314.pyc +0 -0
  58. package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/compress.cpython-314.pyc +0 -0
  59. package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/detect.cpython-314.pyc +0 -0
  60. package/.claude/skills/sdo-caveman-compress/scripts/__pycache__/validate.cpython-314.pyc +0 -0
  61. package/v3/@swarmdo/plugin-iot-cognitum/dist/application/index.d.ts +0 -2
  62. package/v3/@swarmdo/plugin-iot-cognitum/dist/application/index.js +0 -2
  63. package/v3/@swarmdo/plugin-iot-cognitum/dist/application/iot-coordinator.d.ts +0 -138
  64. package/v3/@swarmdo/plugin-iot-cognitum/dist/application/iot-coordinator.js +0 -418
  65. package/v3/@swarmdo/plugin-iot-cognitum/dist/bin.d.ts +0 -15
  66. package/v3/@swarmdo/plugin-iot-cognitum/dist/bin.js +0 -240
  67. package/v3/@swarmdo/plugin-iot-cognitum/dist/cli-commands.d.ts +0 -7
  68. package/v3/@swarmdo/plugin-iot-cognitum/dist/cli-commands.js +0 -508
  69. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-agent.d.ts +0 -54
  70. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-agent.js +0 -2
  71. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-fleet.d.ts +0 -46
  72. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-fleet.js +0 -2
  73. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-trust-level.d.ts +0 -18
  74. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/device-trust-level.js +0 -28
  75. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/index.d.ts +0 -5
  76. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/index.js +0 -2
  77. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/telemetry.d.ts +0 -35
  78. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/entities/telemetry.js +0 -2
  79. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/device-repository.d.ts +0 -11
  80. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/device-repository.js +0 -2
  81. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/fleet-repository.d.ts +0 -9
  82. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/fleet-repository.js +0 -2
  83. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/index.d.ts +0 -5
  84. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/index.js +0 -2
  85. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/telemetry-repository.d.ts +0 -12
  86. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/telemetry-repository.js +0 -2
  87. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/trust-history-repository.d.ts +0 -19
  88. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/repositories/trust-history-repository.js +0 -2
  89. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/anomaly-detection-service.d.ts +0 -44
  90. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/anomaly-detection-service.js +0 -117
  91. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/device-lifecycle-service.d.ts +0 -70
  92. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/device-lifecycle-service.js +0 -194
  93. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/firmware-orchestration-service.d.ts +0 -69
  94. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/firmware-orchestration-service.js +0 -139
  95. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/fleet-topology-service.d.ts +0 -34
  96. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/fleet-topology-service.js +0 -101
  97. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/index.d.ts +0 -10
  98. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/index.js +0 -10
  99. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/mesh-service.d.ts +0 -64
  100. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/mesh-service.js +0 -70
  101. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/sona-integration-service.d.ts +0 -44
  102. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/sona-integration-service.js +0 -79
  103. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-ingestion-service.d.ts +0 -37
  104. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-ingestion-service.js +0 -39
  105. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-service.d.ts +0 -67
  106. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/telemetry-service.js +0 -58
  107. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/witness-verification-service.d.ts +0 -45
  108. package/v3/@swarmdo/plugin-iot-cognitum/dist/domain/services/witness-verification-service.js +0 -63
  109. package/v3/@swarmdo/plugin-iot-cognitum/dist/index.d.ts +0 -26
  110. package/v3/@swarmdo/plugin-iot-cognitum/dist/index.js +0 -17
  111. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/agentdb-telemetry-repository.d.ts +0 -51
  112. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/agentdb-telemetry-repository.js +0 -110
  113. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-device-repository.d.ts +0 -13
  114. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-device-repository.js +0 -25
  115. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-fleet-repository.d.ts +0 -11
  116. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-fleet-repository.js +0 -19
  117. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-trust-history-repository.d.ts +0 -11
  118. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/in-memory-trust-history-repository.js +0 -27
  119. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/index.d.ts +0 -6
  120. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/index.js +0 -6
  121. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/seed-client-factory.d.ts +0 -41
  122. package/v3/@swarmdo/plugin-iot-cognitum/dist/infrastructure/seed-client-factory.js +0 -64
  123. package/v3/@swarmdo/plugin-iot-cognitum/dist/mcp-tools.d.ts +0 -8
  124. package/v3/@swarmdo/plugin-iot-cognitum/dist/mcp-tools.js +0 -703
  125. package/v3/@swarmdo/plugin-iot-cognitum/dist/plugin.d.ts +0 -23
  126. package/v3/@swarmdo/plugin-iot-cognitum/dist/plugin.js +0 -239
  127. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/anomaly-scan-worker.d.ts +0 -17
  128. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/anomaly-scan-worker.js +0 -42
  129. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/firmware-watch-worker.d.ts +0 -18
  130. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/firmware-watch-worker.js +0 -45
  131. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/health-probe-worker.d.ts +0 -19
  132. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/health-probe-worker.js +0 -50
  133. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/mesh-sync-worker.d.ts +0 -19
  134. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/mesh-sync-worker.js +0 -47
  135. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/telemetry-ingest-worker.d.ts +0 -17
  136. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/telemetry-ingest-worker.js +0 -40
  137. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/witness-audit-worker.d.ts +0 -18
  138. package/v3/@swarmdo/plugin-iot-cognitum/dist/workers/witness-audit-worker.js +0 -51
  139. package/v3/@swarmdo/testing/dist/fixtures/agent-fixtures.d.ts +0 -214
  140. package/v3/@swarmdo/testing/dist/fixtures/agent-fixtures.js +0 -595
  141. package/v3/@swarmdo/testing/dist/fixtures/agents.d.ts +0 -76
  142. package/v3/@swarmdo/testing/dist/fixtures/agents.js +0 -158
  143. package/v3/@swarmdo/testing/dist/fixtures/configurations.d.ts +0 -157
  144. package/v3/@swarmdo/testing/dist/fixtures/configurations.js +0 -337
  145. package/v3/@swarmdo/testing/dist/fixtures/index.d.ts +0 -10
  146. package/v3/@swarmdo/testing/dist/fixtures/index.js +0 -17
  147. package/v3/@swarmdo/testing/dist/fixtures/mcp-fixtures.d.ts +0 -329
  148. package/v3/@swarmdo/testing/dist/fixtures/mcp-fixtures.js +0 -714
  149. package/v3/@swarmdo/testing/dist/fixtures/memory-entries.d.ts +0 -159
  150. package/v3/@swarmdo/testing/dist/fixtures/memory-entries.js +0 -262
  151. package/v3/@swarmdo/testing/dist/fixtures/memory-fixtures.d.ts +0 -290
  152. package/v3/@swarmdo/testing/dist/fixtures/memory-fixtures.js +0 -547
  153. package/v3/@swarmdo/testing/dist/fixtures/swarm-fixtures.d.ts +0 -289
  154. package/v3/@swarmdo/testing/dist/fixtures/swarm-fixtures.js +0 -534
  155. package/v3/@swarmdo/testing/dist/fixtures/tasks.d.ts +0 -106
  156. package/v3/@swarmdo/testing/dist/fixtures/tasks.js +0 -229
  157. package/v3/@swarmdo/testing/dist/helpers/assertion-helpers.d.ts +0 -213
  158. package/v3/@swarmdo/testing/dist/helpers/assertion-helpers.js +0 -435
  159. package/v3/@swarmdo/testing/dist/helpers/assertions.d.ts +0 -135
  160. package/v3/@swarmdo/testing/dist/helpers/assertions.js +0 -217
  161. package/v3/@swarmdo/testing/dist/helpers/create-mock.d.ts +0 -96
  162. package/v3/@swarmdo/testing/dist/helpers/create-mock.js +0 -164
  163. package/v3/@swarmdo/testing/dist/helpers/index.d.ts +0 -14
  164. package/v3/@swarmdo/testing/dist/helpers/index.js +0 -22
  165. package/v3/@swarmdo/testing/dist/helpers/mock-factory.d.ts +0 -323
  166. package/v3/@swarmdo/testing/dist/helpers/mock-factory.js +0 -350
  167. package/v3/@swarmdo/testing/dist/helpers/setup-teardown.d.ts +0 -271
  168. package/v3/@swarmdo/testing/dist/helpers/setup-teardown.js +0 -446
  169. package/v3/@swarmdo/testing/dist/helpers/swarm-instance.d.ts +0 -142
  170. package/v3/@swarmdo/testing/dist/helpers/swarm-instance.js +0 -205
  171. package/v3/@swarmdo/testing/dist/helpers/test-application.d.ts +0 -190
  172. package/v3/@swarmdo/testing/dist/helpers/test-application.js +0 -138
  173. package/v3/@swarmdo/testing/dist/helpers/test-utils.d.ts +0 -274
  174. package/v3/@swarmdo/testing/dist/helpers/test-utils.js +0 -456
  175. package/v3/@swarmdo/testing/dist/index.d.ts +0 -42
  176. package/v3/@swarmdo/testing/dist/index.js +0 -66
  177. package/v3/@swarmdo/testing/dist/mocks/index.d.ts +0 -8
  178. package/v3/@swarmdo/testing/dist/mocks/index.js +0 -10
  179. package/v3/@swarmdo/testing/dist/mocks/mock-mcp-client.d.ts +0 -206
  180. package/v3/@swarmdo/testing/dist/mocks/mock-mcp-client.js +0 -575
  181. package/v3/@swarmdo/testing/dist/mocks/mock-services.d.ts +0 -287
  182. package/v3/@swarmdo/testing/dist/mocks/mock-services.js +0 -563
  183. package/v3/@swarmdo/testing/dist/regression/api-contract.d.ts +0 -109
  184. package/v3/@swarmdo/testing/dist/regression/api-contract.js +0 -374
  185. package/v3/@swarmdo/testing/dist/regression/index.d.ts +0 -18
  186. package/v3/@swarmdo/testing/dist/regression/index.js +0 -18
  187. package/v3/@swarmdo/testing/dist/regression/integration-regression.d.ts +0 -67
  188. package/v3/@swarmdo/testing/dist/regression/integration-regression.js +0 -334
  189. package/v3/@swarmdo/testing/dist/regression/performance-baseline.d.ts +0 -106
  190. package/v3/@swarmdo/testing/dist/regression/performance-baseline.js +0 -268
  191. package/v3/@swarmdo/testing/dist/regression/regression-runner.d.ts +0 -124
  192. package/v3/@swarmdo/testing/dist/regression/regression-runner.js +0 -227
  193. package/v3/@swarmdo/testing/dist/regression/security-regression.d.ts +0 -73
  194. package/v3/@swarmdo/testing/dist/regression/security-regression.js +0 -258
  195. package/v3/@swarmdo/testing/dist/setup.d.ts +0 -43
  196. package/v3/@swarmdo/testing/dist/setup.js +0 -91
  197. package/v3/@swarmdo/testing/dist/v2-compat/api-compat.test.d.ts +0 -10
  198. package/v3/@swarmdo/testing/dist/v2-compat/api-compat.test.js +0 -433
  199. package/v3/@swarmdo/testing/dist/v2-compat/cli-compat.test.d.ts +0 -10
  200. package/v3/@swarmdo/testing/dist/v2-compat/cli-compat.test.js +0 -352
  201. package/v3/@swarmdo/testing/dist/v2-compat/compatibility-validator.d.ts +0 -206
  202. package/v3/@swarmdo/testing/dist/v2-compat/compatibility-validator.js +0 -839
  203. package/v3/@swarmdo/testing/dist/v2-compat/hooks-compat.test.d.ts +0 -10
  204. package/v3/@swarmdo/testing/dist/v2-compat/hooks-compat.test.js +0 -428
  205. package/v3/@swarmdo/testing/dist/v2-compat/index.d.ts +0 -38
  206. package/v3/@swarmdo/testing/dist/v2-compat/index.js +0 -41
  207. package/v3/@swarmdo/testing/dist/v2-compat/mcp-compat.test.d.ts +0 -10
  208. package/v3/@swarmdo/testing/dist/v2-compat/mcp-compat.test.js +0 -419
  209. package/v3/@swarmdo/testing/dist/v2-compat/report-generator.d.ts +0 -34
  210. package/v3/@swarmdo/testing/dist/v2-compat/report-generator.js +0 -372
@@ -0,0 +1,162 @@
1
+ /**
2
+ * integrations.ts — wire swarmdo into agent CLIs beyond Claude Code.
3
+ *
4
+ * Targets: OpenAI Codex CLI, GitHub Copilot CLI, pi. Two standards do the
5
+ * heavy lifting: AGENTS.md (the cross-agent instructions file all three
6
+ * read) and MCP (swarmdo already ships a stdio server — `swarmdo mcp
7
+ * start`). Each merge below is PURE (string/JSON in → out), additive, and
8
+ * idempotent, so the whole surface is unit-testable and re-running install
9
+ * never duplicates or clobbers.
10
+ *
11
+ * INVARIANT (do-not-break-Claude): nothing in this module produces content
12
+ * for `.claude/**`, `.mcp.json`, or `CLAUDE.md` — the Claude Code surfaces
13
+ * are owned by init/mcp-generator and are only ever READ for status here.
14
+ */
15
+ export const MCP_COMMAND = 'npx';
16
+ export const MCP_ARGS = ['-y', 'swarmdo@latest', 'mcp', 'start'];
17
+ const TOML_BEGIN = '# >>> swarmdo mcp (managed by `swarmdo integrations`) >>>';
18
+ const TOML_END = '# <<< swarmdo mcp <<<';
19
+ /** Codex CLI (~/.codex/config.toml): add the marked [mcp_servers.swarmdo]
20
+ * block when absent. Existing content — including a user's own hand-written
21
+ * swarmdo server — is left untouched. */
22
+ export function mergeCodexToml(existing) {
23
+ const base = existing ?? '';
24
+ if (base.includes(TOML_BEGIN) || /\[mcp_servers\.swarmdo\]/.test(base)) {
25
+ return { content: base, changed: false };
26
+ }
27
+ const block = [
28
+ TOML_BEGIN,
29
+ '[mcp_servers.swarmdo]',
30
+ `command = "${MCP_COMMAND}"`,
31
+ `args = [${MCP_ARGS.map((a) => `"${a}"`).join(', ')}]`,
32
+ TOML_END,
33
+ '',
34
+ ].join('\n');
35
+ const sep = base.length > 0 && !base.endsWith('\n\n') ? (base.endsWith('\n') ? '\n' : '\n\n') : '';
36
+ return { content: base + sep + block, changed: true };
37
+ }
38
+ /** Copilot CLI (~/.copilot/mcp-config.json): same mcpServers schema Claude
39
+ * uses. Adds the swarmdo entry when absent; other servers preserved. */
40
+ export function mergeCopilotMcpJson(existing) {
41
+ let cfg;
42
+ try {
43
+ cfg = existing ? JSON.parse(existing) : {};
44
+ }
45
+ catch {
46
+ // never clobber an unparseable user file
47
+ return { content: existing ?? '', changed: false };
48
+ }
49
+ if (cfg.mcpServers && Object.prototype.hasOwnProperty.call(cfg.mcpServers, 'swarmdo')) {
50
+ return { content: JSON.stringify(cfg, null, 2) + '\n', changed: false };
51
+ }
52
+ cfg.mcpServers = { ...(cfg.mcpServers ?? {}), swarmdo: { type: 'local', command: MCP_COMMAND, args: MCP_ARGS, tools: ['*'] } };
53
+ return { content: JSON.stringify(cfg, null, 2) + '\n', changed: true };
54
+ }
55
+ /** Cross-agent AGENTS.md for projects that don't have one. Existing files
56
+ * are never rewritten (report-only) — teams own their AGENTS.md. */
57
+ export function crossAgentAgentsMd() {
58
+ return `# AGENTS.md — swarmdo project
59
+
60
+ > Read by Codex CLI, GitHub Copilot CLI, pi, and other AGENTS.md-aware
61
+ > agents. Claude Code uses CLAUDE.md instead — both coexist in this repo.
62
+
63
+ ## What swarmdo gives you
64
+
65
+ This project is wired to **swarmdo** — agent orchestration with persistent
66
+ vector memory, swarm coordination, and 300+ MCP tools.
67
+
68
+ - **MCP server**: \`swarmdo mcp start\` (stdio). If your CLI supports MCP,
69
+ \`swarmdo integrations install <your-cli>\` wires it; key tools:
70
+ \`memory_search\`, \`memory_store\`, \`swarm_init\`, \`agent_spawn\`.
71
+ - **CLI**: \`npx swarmdo@latest <command>\` — \`memory search -q "topic"\`,
72
+ \`usage\`, \`task\`, \`hud\`, \`security scan\`, \`config lint\`.
73
+
74
+ ## Working agreement (any agent)
75
+
76
+ 1. **Search memory BEFORE starting**: \`memory_search(query="task keywords")\`
77
+ — patterns with score > 0.7 are load-bearing precedent.
78
+ 2. **You are the executor** — swarmdo coordinates and remembers; it never
79
+ writes your code for you.
80
+ 3. **Store what worked AFTER success**:
81
+ \`memory_store(key="pattern-…", value="what worked", namespace="patterns")\`.
82
+ 4. Claude Code users: the same surfaces are namespaced under \`/sDo:\`
83
+ commands and \`/sdo-\` skills.
84
+
85
+ ## Do not
86
+
87
+ - Do not commit secrets or .env files.
88
+ - Do not edit \`.claude/\`, \`.mcp.json\`, or \`CLAUDE.md\` — those belong to
89
+ the Claude Code integration and are managed by \`swarmdo init\`.
90
+ `;
91
+ }
92
+ /** .github/copilot-instructions.md — Copilot reads this per-repo. Kept as a
93
+ * thin pointer so AGENTS.md stays the single source of truth. */
94
+ export function copilotInstructionsMd() {
95
+ return `# Copilot instructions
96
+
97
+ This repository uses **swarmdo** for agent orchestration and persistent
98
+ memory. Follow \`AGENTS.md\` at the repo root — it is the canonical
99
+ cross-agent working agreement (memory-first workflow, executor role, MCP
100
+ tools). The swarmdo MCP server (\`swarmdo mcp start\`) provides
101
+ memory_search / memory_store / swarm_init; wire it with
102
+ \`swarmdo integrations install copilot\`.
103
+ `;
104
+ }
105
+ export const INSTALLABLE = ['codex', 'copilot', 'pi'];
106
+ /** Pure status evaluation over pre-read file contents (null = absent). */
107
+ export function evaluateStatus(files) {
108
+ const agentsOk = files.agentsMd !== null;
109
+ const codexMcp = !!files.codexToml && /\[mcp_servers\.swarmdo\]/.test(files.codexToml);
110
+ const copilotMcp = (() => {
111
+ try {
112
+ return !!files.copilotJson && 'swarmdo' in (JSON.parse(files.copilotJson).mcpServers ?? {});
113
+ }
114
+ catch {
115
+ return false;
116
+ }
117
+ })();
118
+ const hasSwarmdoServer = (raw) => {
119
+ try {
120
+ return !!raw && 'swarmdo' in (JSON.parse(raw).mcpServers ?? {});
121
+ }
122
+ catch {
123
+ return false;
124
+ }
125
+ };
126
+ const claudeProject = hasSwarmdoServer(files.claudeMcpJson);
127
+ const claudeUser = hasSwarmdoServer(files.claudeUserJson);
128
+ const claudeMcp = claudeProject || claudeUser;
129
+ return [
130
+ {
131
+ target: 'claude', ok: files.claudeDirExists && claudeMcp,
132
+ details: [
133
+ `.claude/ ${files.claudeDirExists ? 'present' : 'MISSING'}`,
134
+ `swarmdo MCP server ${claudeMcp ? `wired (${claudeProject ? '.mcp.json' : '~/.claude.json'})` : 'missing from .mcp.json and ~/.claude.json'}`,
135
+ '(read-only here — managed by `swarmdo init`)',
136
+ ],
137
+ },
138
+ {
139
+ target: 'codex', ok: agentsOk && codexMcp,
140
+ details: [
141
+ `AGENTS.md ${agentsOk ? 'present' : 'missing'}`,
142
+ `~/.codex/config.toml [mcp_servers.swarmdo] ${codexMcp ? 'wired' : 'missing'}`,
143
+ ],
144
+ },
145
+ {
146
+ target: 'copilot', ok: agentsOk && copilotMcp && files.copilotInstructions !== null,
147
+ details: [
148
+ `AGENTS.md ${agentsOk ? 'present' : 'missing'}`,
149
+ `.github/copilot-instructions.md ${files.copilotInstructions !== null ? 'present' : 'missing'}`,
150
+ `~/.copilot/mcp-config.json swarmdo server ${copilotMcp ? 'wired' : 'missing'}`,
151
+ ],
152
+ },
153
+ {
154
+ target: 'pi', ok: agentsOk,
155
+ details: [
156
+ `AGENTS.md ${agentsOk ? 'present (pi reads it natively)' : 'missing'}`,
157
+ 'MCP: point pi at `npx -y swarmdo@latest mcp start` if your pi build supports MCP servers',
158
+ ],
159
+ },
160
+ ];
161
+ }
162
+ //# sourceMappingURL=integrations.js.map
@@ -80,16 +80,34 @@ export async function callAnthropicMessages(input) {
80
80
  const useOpenRouter = explicitProvider === 'openrouter' || (!anthropicKey && !!openrouterKey);
81
81
  const useOllama = explicitProvider === 'ollama' || (!anthropicKey && !!ollamaKey && !openrouterKey);
82
82
  if (useOpenRouter && openrouterKey) {
83
+ // Configurable model pool: swarmdo.config.json `openrouter` section lets
84
+ // the swarm draw from user-configured models (explicit slug > tier pick
85
+ // via Thompson sampling > config defaultModel). Env vars still win for
86
+ // base URL and as the final default for un-configured projects.
87
+ let configuredModel;
88
+ let configuredBaseUrl;
89
+ try {
90
+ const { loadOpenRouterConfig, resolveOpenRouterModel } = await import('../providers/openrouter-config.js');
91
+ const { config } = loadOpenRouterConfig();
92
+ if (config.enabled) {
93
+ configuredBaseUrl = config.baseUrl;
94
+ configuredModel = resolveOpenRouterModel({ requested: input.model, cfg: config })?.model;
95
+ }
96
+ }
97
+ catch { /* config unreadable — env-only behavior */ }
83
98
  return callOpenAICompat({
84
99
  ...input,
100
+ // a resolved pool pick replaces tier words / Anthropic ids; explicit
101
+ // slugs pass through resolveOpenRouterModel unchanged
102
+ model: configuredModel ?? input.model,
85
103
  apiKey: openrouterKey,
86
- baseUrl: process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api',
104
+ baseUrl: process.env.OPENROUTER_BASE_URL || configuredBaseUrl || 'https://openrouter.ai/api',
87
105
  providerLabel: 'openrouter',
88
106
  // #2357 Finding C: anthropic/claude-3.5-sonnet was retired Oct 2025.
89
107
  // Default to the same canonical family the rest of the resolver uses
90
108
  // (MODEL_MAP). `OPENROUTER_DEFAULT_MODEL` still wins for callers who
91
109
  // want to pin a specific OpenRouter slug.
92
- defaultModel: process.env.OPENROUTER_DEFAULT_MODEL || 'anthropic/claude-sonnet-4-6',
110
+ defaultModel: process.env.OPENROUTER_DEFAULT_MODEL || configuredModel || 'anthropic/claude-sonnet-4-6',
93
111
  });
94
112
  }
95
113
  if (useOllama && ollamaKey) {
@@ -445,7 +463,8 @@ export async function executeAgentTask(input) {
445
463
  const fallbackBudget = Math.max(0, parseInt(process.env.SWARMDO_ROUTER_FALLBACK_MAX_RETRIES ?? '1', 10) || 1);
446
464
  const fallbackHistory = [];
447
465
  if (!result.success && agent.modelId && fallbackBudget > 0) {
448
- const isRetryable = /\b(429|500|502|503|504|timeout|ECONNRESET|ETIMEDOUT)\b/i.test(result.error ?? '');
466
+ const { isRetryableError, computeBackoffMs, sleep } = await import('../resilience/backoff.js');
467
+ const isRetryable = isRetryableError(result.error);
449
468
  if (isRetryable) {
450
469
  try {
451
470
  const { nextCostOptimalAlternative } = await import('../swarmvector/neural-router.js');
@@ -459,6 +478,9 @@ export async function executeAgentTask(input) {
459
478
  const excludeIds = [agent.modelId];
460
479
  for (let attempt = 0; attempt < fallbackBudget && !result.success; attempt++) {
461
480
  fallbackHistory.push({ modelId: excludeIds[excludeIds.length - 1], error: result.error ?? '' });
481
+ // full-jitter exponential backoff — a 429 is usually account-wide,
482
+ // so an instant re-call against the same provider burns the attempt
483
+ await sleep(computeBackoffMs(attempt));
462
484
  const alt = await nextCostOptimalAlternative(embedding, excludeIds);
463
485
  if (!alt || !alt.modelId)
464
486
  break;
@@ -996,11 +996,11 @@ export const agentdbGraphQuery = {
996
996
  catch { /* fall through to sql.js */ }
997
997
  // SQL CTE fallback for k-hop up to depth 3
998
998
  try {
999
- const { getBridgeDb } = await import('../memory/graph-edge-writer.js');
999
+ const { getBridgeDb, execRows } = await import('../memory/graph-edge-writer.js');
1000
1000
  const db = await getBridgeDb();
1001
1001
  if (db) {
1002
1002
  const cteSql = buildKHopCTE(nodeId, Math.min(depth, 3), relation, budget.maxNodesVisited);
1003
- const result = db.exec(cteSql);
1003
+ const result = execRows(db, cteSql);
1004
1004
  const rows = result?.[0]?.values ?? [];
1005
1005
  return {
1006
1006
  success: true, mode, nodeId, depth,
@@ -1021,14 +1021,14 @@ export const agentdbGraphQuery = {
1021
1021
  const queryEmb = await generateEmbedding(nodeId);
1022
1022
  if (!queryEmb)
1023
1023
  throw new Error('embedding failed');
1024
- const { getBridgeDb } = await import('../memory/graph-edge-writer.js');
1024
+ const { getBridgeDb, execRows } = await import('../memory/graph-edge-writer.js');
1025
1025
  // #2246 fix: lazy-create memory.db on first pathfinder call so
1026
1026
  // fresh environments work without a pre-existing memory init.
1027
1027
  const db = await getBridgeDb(undefined, { createIfMissing: true });
1028
1028
  if (!db)
1029
1029
  return { success: false, error: 'graph_edges DB unavailable (sql.js could not load)', hint: 'Check Node version + try `swarmdo memory init` to initialize manually.', mode, nodeId };
1030
1030
  // Load all rows with embedding_ref and score by cosine
1031
- const rowResult = db.exec(`SELECT id, source_id, target_id, relation, weight, embedding_ref FROM graph_edges WHERE embedding_ref IS NOT NULL LIMIT ?`, [budget.maxNodesVisited]);
1031
+ const rowResult = execRows(db, `SELECT id, source_id, target_id, relation, weight, embedding_ref FROM graph_edges WHERE embedding_ref IS NOT NULL LIMIT ?`, [budget.maxNodesVisited]);
1032
1032
  const rows = rowResult?.[0]?.values ?? [];
1033
1033
  const { decodeEmbedding } = await import('../memory/embedding-quantization.js');
1034
1034
  const scored = [];
@@ -1061,13 +1061,13 @@ export const agentdbGraphQuery = {
1061
1061
  // ── pagerank mode ────────────────────────────────────────────────────────
1062
1062
  if (mode === 'pagerank') {
1063
1063
  try {
1064
- const { getBridgeDb } = await import('../memory/graph-edge-writer.js');
1064
+ const { getBridgeDb, execRows } = await import('../memory/graph-edge-writer.js');
1065
1065
  // #2246 fix: lazy-create memory.db on first pathfinder call so
1066
1066
  // fresh environments work without a pre-existing memory init.
1067
1067
  const db = await getBridgeDb(undefined, { createIfMissing: true });
1068
1068
  if (!db)
1069
1069
  return { success: false, error: 'graph_edges DB unavailable (sql.js could not load)', hint: 'Check Node version + try `swarmdo memory init` to initialize manually.', mode, nodeId };
1070
- const edgeResult = db.exec(`SELECT source_id, target_id, weight FROM graph_edges LIMIT ?`, [budget.maxNodesVisited]);
1070
+ const edgeResult = execRows(db, `SELECT source_id, target_id, weight FROM graph_edges LIMIT ?`, [budget.maxNodesVisited]);
1071
1071
  const edges = edgeResult?.[0]?.values ?? [];
1072
1072
  if (edges.length === 0) {
1073
1073
  return { success: true, mode, nodeId, results: [], count: 0, message: 'graph_edges is empty', elapsedMs: Date.now() - t0 };
@@ -1248,7 +1248,7 @@ export const agentdbGraphPathfinder = {
1248
1248
  return { success: false, error: `Unknown algorithm: ${algorithm}. Valid: ${validAlgorithms.join(', ')}` };
1249
1249
  }
1250
1250
  // Load edges from graph_edges
1251
- const { getBridgeDb } = await import('../memory/graph-edge-writer.js');
1251
+ const { getBridgeDb, execRows } = await import('../memory/graph-edge-writer.js');
1252
1252
  // #2246 fix: lazy-create memory.db on first pathfinder call.
1253
1253
  const db = await getBridgeDb(undefined, { createIfMissing: true });
1254
1254
  if (!db)
@@ -1258,7 +1258,7 @@ export const agentdbGraphPathfinder = {
1258
1258
  : algorithm === 'temporal-centrality'
1259
1259
  ? 'source_id, target_id, weight, last_reinforced, confidence'
1260
1260
  : 'source_id, target_id, weight';
1261
- const edgeResult = db.exec(`SELECT ${colsSql} FROM graph_edges LIMIT ?`, [budget.maxNodesVisited]);
1261
+ const edgeResult = execRows(db, `SELECT ${colsSql} FROM graph_edges LIMIT ?`, [budget.maxNodesVisited]);
1262
1262
  const rawEdges = edgeResult?.[0]?.values ?? [];
1263
1263
  if (rawEdges.length === 0) {
1264
1264
  return { success: true, paths: [], count: 0, message: `no edges found from seedNodeId`, seedNodeId, algorithm, elapsedMs: Date.now() - t0 };
@@ -58,6 +58,18 @@ export interface GraphEdgeInput {
58
58
  metadata?: Record<string, unknown>;
59
59
  dbPath?: string;
60
60
  }
61
+ /**
62
+ * Engine-compat read: run a SELECT and return rows in sql.js exec() shape
63
+ * ([{columns, values}] or [] when no rows). getBridgeDb returned sql.js
64
+ * historically and better-sqlite3 since #2431 — readers written against the
65
+ * old shape (agentdb graph query/pathfinder) go through this shim so they
66
+ * work on either engine. better-sqlite3's own exec() neither binds params
67
+ * nor returns rows, which surfaced as "datatype mismatch" on every LIMIT ?.
68
+ */
69
+ export declare function execRows(db: any, sql: string, params?: unknown[]): Array<{
70
+ columns: string[];
71
+ values: unknown[][];
72
+ }>;
61
73
  /**
62
74
  * Insert a single edge into graph_edges.
63
75
  * Fire-and-forget — errors are suppressed.
@@ -123,6 +123,26 @@ export async function getBridgeDb(customDbPath, opts) {
123
123
  _dbInitializing = false;
124
124
  }
125
125
  }
126
+ /**
127
+ * Engine-compat read: run a SELECT and return rows in sql.js exec() shape
128
+ * ([{columns, values}] or [] when no rows). getBridgeDb returned sql.js
129
+ * historically and better-sqlite3 since #2431 — readers written against the
130
+ * old shape (agentdb graph query/pathfinder) go through this shim so they
131
+ * work on either engine. better-sqlite3's own exec() neither binds params
132
+ * nor returns rows, which surfaced as "datatype mismatch" on every LIMIT ?.
133
+ */
134
+ export function execRows(db, sql, params = []) {
135
+ if (db && typeof db.prepare === 'function') {
136
+ const stmt = db.prepare(sql);
137
+ const values = stmt.raw(true).all(...params);
138
+ if (values.length === 0)
139
+ return [];
140
+ const columns = stmt.columns().map((c) => c.name);
141
+ return [{ columns, values }];
142
+ }
143
+ // sql.js fallback (legacy)
144
+ return db.exec(sql, params);
145
+ }
126
146
  /**
127
147
  * Insert a single edge into graph_edges.
128
148
  * Fire-and-forget — errors are suppressed.
@@ -140,6 +160,17 @@ export async function insertGraphEdge(input) {
140
160
  return false;
141
161
  const id = `edge-${crypto.randomUUID()}`;
142
162
  const createdAt = new Date().toISOString();
163
+ // ADR-130 §Phase 1 criterion 3: legacy unprefixed node ids (no `kind:`
164
+ // namespace) are auto-prefixed as `mem:` with a deprecation warning so
165
+ // old callers keep working while the graph converges on prefixed ids.
166
+ const normalizeId = (raw) => {
167
+ if (raw.includes(':'))
168
+ return raw;
169
+ console.warn(`[graph-edge-writer] DEPRECATED: unprefixed node id "${raw}" — auto-prefixing as "mem:${raw}" (ADR-130)`);
170
+ return `mem:${raw}`;
171
+ };
172
+ const sourceId = normalizeId(input.sourceId);
173
+ const targetId = normalizeId(input.targetId);
143
174
  let embeddingRef = null;
144
175
  if (input.embedding && input.embedding.length > 0) {
145
176
  embeddingRef = encodeEmbedding(input.embedding);
@@ -148,7 +179,7 @@ export async function insertGraphEdge(input) {
148
179
  db.prepare(`INSERT OR IGNORE INTO graph_edges
149
180
  (id, source_id, target_id, relation, weight, confidence, decay_rate,
150
181
  last_reinforced, witness_id, embedding_ref, metadata, created_at)
151
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.sourceId, input.targetId, input.relation, input.weight ?? 1.0, input.confidence ?? 1.0, input.decayRate ?? 0.0, input.lastReinforced ?? null, input.witnessId ?? null, embeddingRef, metaStr, createdAt);
182
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, sourceId, targetId, input.relation, input.weight ?? 1.0, input.confidence ?? 1.0, input.decayRate ?? 0.0, input.lastReinforced ?? null, input.witnessId ?? null, embeddingRef, metaStr, createdAt);
152
183
  return true;
153
184
  }
154
185
  catch {
@@ -0,0 +1,32 @@
1
+ /**
2
+ * watch.ts — debounced change collection for vault auto-sync (phase 2 of the
3
+ * dual-plane memory strategy: edit notes in Obsidian, they sync back to the
4
+ * vector DB as you save).
5
+ *
6
+ * Editors fire bursts of fs events per save (write + rename + metadata);
7
+ * the collector coalesces them into one flush after a quiet window, filters
8
+ * to real notes (.md, not INDEX.md, not dotfiles), and hands relative paths
9
+ * to the sync callback. Pure timing via an injectable scheduler so tests run
10
+ * on fake clocks.
11
+ */
12
+ export interface Scheduler {
13
+ set(fn: () => void, ms: number): unknown;
14
+ clear(handle: unknown): void;
15
+ }
16
+ /** Should this relative path participate in a sync? */
17
+ export declare function isSyncablePath(relPath: string): boolean;
18
+ export declare class ChangeCollector {
19
+ private readonly flush;
20
+ private readonly quietMs;
21
+ private readonly scheduler;
22
+ private pending;
23
+ private handle;
24
+ constructor(flush: (paths: string[]) => void, quietMs?: number, scheduler?: Scheduler);
25
+ /** Record a change; (re)arms the quiet-window timer. */
26
+ add(relPath: string): void;
27
+ /** Flush immediately (shutdown path). No-op when empty. */
28
+ drain(): void;
29
+ get size(): number;
30
+ private fire;
31
+ }
32
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1,66 @@
1
+ /**
2
+ * watch.ts — debounced change collection for vault auto-sync (phase 2 of the
3
+ * dual-plane memory strategy: edit notes in Obsidian, they sync back to the
4
+ * vector DB as you save).
5
+ *
6
+ * Editors fire bursts of fs events per save (write + rename + metadata);
7
+ * the collector coalesces them into one flush after a quiet window, filters
8
+ * to real notes (.md, not INDEX.md, not dotfiles), and hands relative paths
9
+ * to the sync callback. Pure timing via an injectable scheduler so tests run
10
+ * on fake clocks.
11
+ */
12
+ const realScheduler = {
13
+ set: (fn, ms) => setTimeout(fn, ms),
14
+ clear: (h) => clearTimeout(h),
15
+ };
16
+ /** Should this relative path participate in a sync? */
17
+ export function isSyncablePath(relPath) {
18
+ const base = relPath.split('/').pop() ?? relPath;
19
+ if (!base.endsWith('.md'))
20
+ return false;
21
+ if (base === 'INDEX.md')
22
+ return false;
23
+ if (relPath.split('/').some((seg) => seg.startsWith('.')))
24
+ return false;
25
+ return true;
26
+ }
27
+ export class ChangeCollector {
28
+ flush;
29
+ quietMs;
30
+ scheduler;
31
+ pending = new Set();
32
+ handle = null;
33
+ constructor(flush, quietMs = 1500, scheduler = realScheduler) {
34
+ this.flush = flush;
35
+ this.quietMs = quietMs;
36
+ this.scheduler = scheduler;
37
+ }
38
+ /** Record a change; (re)arms the quiet-window timer. */
39
+ add(relPath) {
40
+ if (!isSyncablePath(relPath))
41
+ return;
42
+ this.pending.add(relPath);
43
+ if (this.handle !== null)
44
+ this.scheduler.clear(this.handle);
45
+ this.handle = this.scheduler.set(() => this.fire(), this.quietMs);
46
+ }
47
+ /** Flush immediately (shutdown path). No-op when empty. */
48
+ drain() {
49
+ if (this.handle !== null)
50
+ this.scheduler.clear(this.handle);
51
+ this.handle = null;
52
+ this.fire();
53
+ }
54
+ get size() {
55
+ return this.pending.size;
56
+ }
57
+ fire() {
58
+ this.handle = null;
59
+ if (this.pending.size === 0)
60
+ return;
61
+ const batch = [...this.pending].sort();
62
+ this.pending.clear();
63
+ this.flush(batch);
64
+ }
65
+ }
66
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1,91 @@
1
+ /**
2
+ * openrouter-config.ts — configurable OpenRouter model pool for swarms.
3
+ *
4
+ * The execution core has dispatched to OpenRouter since #2042, but only via
5
+ * env vars and a single default slug. This module makes the integration
6
+ * CONFIGURABLE: users declare the OpenRouter models they want their agent
7
+ * swarms to draw from in swarmdo.config.json, each mapped to a routing tier,
8
+ * and the router selects among same-tier candidates by Thompson sampling —
9
+ * the concrete consumer for the ADR-149 per-modelId priors.
10
+ *
11
+ * "openrouter": {
12
+ * "enabled": true,
13
+ * "models": [
14
+ * { "id": "meta-llama/llama-3.3-70b-instruct", "tier": "haiku" },
15
+ * { "id": "deepseek/deepseek-chat", "tier": "sonnet" },
16
+ * { "id": "anthropic/claude-opus-4-5", "tier": "opus" }
17
+ * ],
18
+ * "defaultModel": "anthropic/claude-sonnet-4-6"
19
+ * }
20
+ *
21
+ * Everything here is pure (validation, filtering, sampling with injectable
22
+ * randomness) except loadOpenRouterConfig, a thin fs reader.
23
+ */
24
+ export type RoutingTier = 'haiku' | 'sonnet' | 'opus';
25
+ export interface OpenRouterModelEntry {
26
+ /** OpenRouter slug, e.g. 'meta-llama/llama-3.3-70b-instruct' */
27
+ id: string;
28
+ /** Which routing tier this model can serve. Untiered models are only
29
+ * reachable as defaultModel or by explicit slug. */
30
+ tier?: RoutingTier;
31
+ /** Free-form operator note (why it's in the pool, cost expectations…) */
32
+ note?: string;
33
+ }
34
+ export interface OpenRouterConfig {
35
+ enabled: boolean;
36
+ /** env var holding the key (default OPENROUTER_API_KEY) */
37
+ apiKeyEnv: string;
38
+ baseUrl: string;
39
+ defaultModel?: string;
40
+ models: OpenRouterModelEntry[];
41
+ }
42
+ export interface ParseResult {
43
+ config: OpenRouterConfig;
44
+ /** human-readable reasons for every entry/field that was dropped */
45
+ warnings: string[];
46
+ }
47
+ /** OpenRouter slugs are provider/model paths ('org/name[:variant]'). */
48
+ export declare function isOpenRouterSlug(model: string | undefined | null): boolean;
49
+ /** Validate the raw `openrouter` config section. Tolerant at the boundary:
50
+ * bad entries are dropped with a warning, never thrown. */
51
+ export declare function parseOpenRouterConfig(raw: unknown): ParseResult;
52
+ /** Models eligible to serve a tier. */
53
+ export declare function modelsForTier(cfg: OpenRouterConfig, tier: RoutingTier): OpenRouterModelEntry[];
54
+ export interface BetaPrior {
55
+ alpha: number;
56
+ beta: number;
57
+ }
58
+ export type BetaSampler = (alpha: number, beta: number) => number;
59
+ /** Default Beta sampler via two Gamma(α,1)/Gamma(β,1) draws (Marsaglia-Tsang
60
+ * for shape ≥ 1, boost trick below 1). Deterministic tests inject their own. */
61
+ export declare const defaultBetaSampler: BetaSampler;
62
+ export interface PickInput {
63
+ cfg: OpenRouterConfig;
64
+ tier: RoutingTier;
65
+ /** per-modelId Beta priors (ADR-149 shape) — absent models get uniform Beta(1,1) */
66
+ priors?: Record<string, BetaPrior>;
67
+ sample?: BetaSampler;
68
+ }
69
+ export interface PickResult {
70
+ model: string;
71
+ reason: string;
72
+ candidates: number;
73
+ }
74
+ /** Thompson-sample a concrete OpenRouter model for a tier from the
75
+ * user-configured pool. Returns null when disabled or no tier candidates. */
76
+ export declare function pickOpenRouterModel({ cfg, tier, priors, sample }: PickInput): PickResult | null;
77
+ export interface ResolveInput extends Omit<PickInput, 'tier'> {
78
+ /** caller-supplied model: OpenRouter slug passes through; tier word routes via the pool */
79
+ requested?: string;
80
+ tier?: RoutingTier;
81
+ }
82
+ /** Full precedence for the execution path:
83
+ * explicit slug > tier pick from the configured pool > config defaultModel > null. */
84
+ export declare function resolveOpenRouterModel({ requested, tier, cfg, priors, sample }: ResolveInput): {
85
+ model: string;
86
+ source: string;
87
+ } | null;
88
+ /** Thin reader: swarmdo.config.json's `openrouter` section from cwd (or an
89
+ * ancestor repo root). Absent/broken files yield the disabled default. */
90
+ export declare function loadOpenRouterConfig(cwd?: string): ParseResult;
91
+ //# sourceMappingURL=openrouter-config.d.ts.map