swarm-code 0.1.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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +384 -0
  3. package/bin/swarm.mjs +45 -0
  4. package/dist/agents/aider.d.ts +12 -0
  5. package/dist/agents/aider.js +182 -0
  6. package/dist/agents/claude-code.d.ts +9 -0
  7. package/dist/agents/claude-code.js +216 -0
  8. package/dist/agents/codex.d.ts +14 -0
  9. package/dist/agents/codex.js +193 -0
  10. package/dist/agents/direct-llm.d.ts +9 -0
  11. package/dist/agents/direct-llm.js +78 -0
  12. package/dist/agents/mock.d.ts +9 -0
  13. package/dist/agents/mock.js +77 -0
  14. package/dist/agents/opencode.d.ts +23 -0
  15. package/dist/agents/opencode.js +571 -0
  16. package/dist/agents/provider.d.ts +11 -0
  17. package/dist/agents/provider.js +31 -0
  18. package/dist/cli.d.ts +15 -0
  19. package/dist/cli.js +285 -0
  20. package/dist/compression/compressor.d.ts +28 -0
  21. package/dist/compression/compressor.js +265 -0
  22. package/dist/config.d.ts +42 -0
  23. package/dist/config.js +170 -0
  24. package/dist/core/repl.d.ts +69 -0
  25. package/dist/core/repl.js +336 -0
  26. package/dist/core/rlm.d.ts +63 -0
  27. package/dist/core/rlm.js +409 -0
  28. package/dist/core/runtime.py +335 -0
  29. package/dist/core/types.d.ts +131 -0
  30. package/dist/core/types.js +19 -0
  31. package/dist/env.d.ts +10 -0
  32. package/dist/env.js +75 -0
  33. package/dist/interactive-swarm.d.ts +20 -0
  34. package/dist/interactive-swarm.js +1041 -0
  35. package/dist/interactive.d.ts +10 -0
  36. package/dist/interactive.js +1765 -0
  37. package/dist/main.d.ts +15 -0
  38. package/dist/main.js +242 -0
  39. package/dist/mcp/server.d.ts +15 -0
  40. package/dist/mcp/server.js +72 -0
  41. package/dist/mcp/session.d.ts +73 -0
  42. package/dist/mcp/session.js +184 -0
  43. package/dist/mcp/tools.d.ts +15 -0
  44. package/dist/mcp/tools.js +377 -0
  45. package/dist/memory/episodic.d.ts +132 -0
  46. package/dist/memory/episodic.js +390 -0
  47. package/dist/prompts/orchestrator.d.ts +5 -0
  48. package/dist/prompts/orchestrator.js +191 -0
  49. package/dist/routing/model-router.d.ts +130 -0
  50. package/dist/routing/model-router.js +515 -0
  51. package/dist/swarm.d.ts +14 -0
  52. package/dist/swarm.js +557 -0
  53. package/dist/threads/cache.d.ts +58 -0
  54. package/dist/threads/cache.js +198 -0
  55. package/dist/threads/manager.d.ts +85 -0
  56. package/dist/threads/manager.js +659 -0
  57. package/dist/ui/banner.d.ts +14 -0
  58. package/dist/ui/banner.js +42 -0
  59. package/dist/ui/dashboard.d.ts +33 -0
  60. package/dist/ui/dashboard.js +151 -0
  61. package/dist/ui/index.d.ts +10 -0
  62. package/dist/ui/index.js +11 -0
  63. package/dist/ui/log.d.ts +39 -0
  64. package/dist/ui/log.js +126 -0
  65. package/dist/ui/onboarding.d.ts +14 -0
  66. package/dist/ui/onboarding.js +518 -0
  67. package/dist/ui/spinner.d.ts +25 -0
  68. package/dist/ui/spinner.js +113 -0
  69. package/dist/ui/summary.d.ts +18 -0
  70. package/dist/ui/summary.js +113 -0
  71. package/dist/ui/theme.d.ts +63 -0
  72. package/dist/ui/theme.js +97 -0
  73. package/dist/viewer.d.ts +12 -0
  74. package/dist/viewer.js +1284 -0
  75. package/dist/worktree/manager.d.ts +45 -0
  76. package/dist/worktree/manager.js +266 -0
  77. package/dist/worktree/merge.d.ts +28 -0
  78. package/dist/worktree/merge.js +138 -0
  79. package/package.json +69 -0
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Startup banner — the first thing users see when running swarm.
3
+ */
4
+ import { getLogLevel, isJsonMode, logKeyValue } from "./log.js";
5
+ import { bold, coral, cyan, dim, isTTY, symbols, termWidth } from "./theme.js";
6
+ const VERSION = "0.1.0";
7
+ /** Render the swarm startup banner. */
8
+ export function renderBanner(config) {
9
+ if (isJsonMode() || getLogLevel() === "quiet")
10
+ return;
11
+ const w = Math.max(Math.min(termWidth(), 60), 24);
12
+ if (isTTY) {
13
+ const title = " swarm ";
14
+ const version = ` v${VERSION} `;
15
+ const padLen = Math.max(0, w - title.length - version.length - 4);
16
+ const leftPad = symbols.horizontal.repeat(Math.floor(padLen / 2));
17
+ const rightPad = symbols.horizontal.repeat(Math.ceil(padLen / 2));
18
+ process.stderr.write("\n");
19
+ process.stderr.write(` ${cyan(`${symbols.topLeft}${leftPad}`)}${bold(coral(title))}${dim(version)}${cyan(`${rightPad}${symbols.topRight}`)}\n`);
20
+ process.stderr.write(` ${cyan(symbols.vertLine)}${" ".repeat(Math.max(0, w - 2))}${cyan(symbols.vertLine)}\n`);
21
+ }
22
+ else {
23
+ process.stderr.write(`\nswarm v${VERSION}\n`);
24
+ }
25
+ logKeyValue("Directory", config.dir);
26
+ logKeyValue("Model", `${config.model} ${dim(`(${config.provider})`)}`);
27
+ logKeyValue("Agent", config.agent);
28
+ logKeyValue("Routing", config.routing);
29
+ if (config.memorySize !== undefined && config.memorySize > 0) {
30
+ logKeyValue("Memory", `${config.memorySize} episodes`);
31
+ }
32
+ if (config.dryRun) {
33
+ logKeyValue("Mode", bold("DRY RUN"));
34
+ }
35
+ if (isTTY) {
36
+ process.stderr.write(` ${cyan(symbols.vertLine)}${" ".repeat(Math.max(0, w - 2))}${cyan(symbols.vertLine)}\n`);
37
+ process.stderr.write(` ${cyan(symbols.bottomLeft)}${cyan(symbols.horizontal.repeat(Math.max(0, w - 2)))}${cyan(symbols.bottomRight)}\n`);
38
+ }
39
+ // Query on its own line, slightly emphasized
40
+ process.stderr.write(`\n ${dim(symbols.arrow)} ${config.query}\n\n`);
41
+ }
42
+ //# sourceMappingURL=banner.js.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Live thread status dashboard — shows running/queued/completed threads.
3
+ *
4
+ * Inspired by Claude Code's collapsed tool results: shows concise status
5
+ * per thread, color-coded by phase, with elapsed time and file counts.
6
+ * Uses in-place terminal updates for a live-updating display.
7
+ */
8
+ /**
9
+ * Thread dashboard — manages a live-updating display of thread states.
10
+ * Renders below the spinner line using ANSI cursor movement.
11
+ */
12
+ export declare class ThreadDashboard {
13
+ private threads;
14
+ private pendingTimers;
15
+ private lastLineCount;
16
+ private enabled;
17
+ constructor();
18
+ /** Update a thread's status. */
19
+ update(id: string, phase: string, detail?: string, extra?: {
20
+ task?: string;
21
+ agent?: string;
22
+ model?: string;
23
+ filesChanged?: number;
24
+ }): void;
25
+ /** Remove a thread from the dashboard (when done). */
26
+ complete(id: string, phase: string, detail?: string): void;
27
+ /** Clear all dashboard output and cancel pending timers. */
28
+ clear(): void;
29
+ private render;
30
+ private clearLines;
31
+ private buildLines;
32
+ private formatPhase;
33
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Live thread status dashboard — shows running/queued/completed threads.
3
+ *
4
+ * Inspired by Claude Code's collapsed tool results: shows concise status
5
+ * per thread, color-coded by phase, with elapsed time and file counts.
6
+ * Uses in-place terminal updates for a live-updating display.
7
+ */
8
+ import { getLogLevel, isJsonMode } from "./log.js";
9
+ import { coral, cyan, dim, green, isTTY, red, stripAnsi, symbols, termWidth, truncate, yellow } from "./theme.js";
10
+ /**
11
+ * Thread dashboard — manages a live-updating display of thread states.
12
+ * Renders below the spinner line using ANSI cursor movement.
13
+ */
14
+ export class ThreadDashboard {
15
+ threads = new Map();
16
+ pendingTimers = new Set();
17
+ lastLineCount = 0;
18
+ enabled;
19
+ constructor() {
20
+ this.enabled = isTTY && !isJsonMode() && getLogLevel() !== "quiet";
21
+ }
22
+ /** Update a thread's status. */
23
+ update(id, phase, detail, extra) {
24
+ const existing = this.threads.get(id);
25
+ if (existing) {
26
+ existing.phase = phase;
27
+ if (detail)
28
+ existing.detail = detail;
29
+ if (extra?.filesChanged !== undefined)
30
+ existing.filesChanged = extra.filesChanged;
31
+ }
32
+ else {
33
+ this.threads.set(id, {
34
+ id,
35
+ task: extra?.task || "",
36
+ phase,
37
+ agent: extra?.agent || "",
38
+ model: extra?.model || "",
39
+ startedAt: Date.now(),
40
+ filesChanged: extra?.filesChanged,
41
+ detail,
42
+ });
43
+ }
44
+ this.render();
45
+ }
46
+ /** Remove a thread from the dashboard (when done). */
47
+ complete(id, phase, detail) {
48
+ const existing = this.threads.get(id);
49
+ if (existing) {
50
+ existing.phase = phase;
51
+ if (detail)
52
+ existing.detail = detail;
53
+ }
54
+ this.render();
55
+ // Remove completed/failed threads after a brief display
56
+ const timer = setTimeout(() => {
57
+ this.pendingTimers.delete(timer);
58
+ this.threads.delete(id);
59
+ this.render();
60
+ }, 1500);
61
+ this.pendingTimers.add(timer);
62
+ }
63
+ /** Clear all dashboard output and cancel pending timers. */
64
+ clear() {
65
+ for (const timer of this.pendingTimers)
66
+ clearTimeout(timer);
67
+ this.pendingTimers.clear();
68
+ if (!this.enabled)
69
+ return;
70
+ this.clearLines();
71
+ this.threads.clear();
72
+ this.lastLineCount = 0;
73
+ }
74
+ render() {
75
+ if (!this.enabled)
76
+ return;
77
+ // Clear previous output
78
+ this.clearLines();
79
+ const lines = this.buildLines();
80
+ if (lines.length === 0) {
81
+ this.lastLineCount = 0;
82
+ return;
83
+ }
84
+ // Write new lines
85
+ process.stderr.write(`${lines.join("\n")}\n`);
86
+ this.lastLineCount = lines.length;
87
+ }
88
+ clearLines() {
89
+ if (this.lastLineCount <= 0)
90
+ return;
91
+ // Move up and clear each line
92
+ for (let i = 0; i < this.lastLineCount; i++) {
93
+ process.stderr.write("\x1b[1A\x1b[K");
94
+ }
95
+ }
96
+ buildLines() {
97
+ const w = Math.min(termWidth(), 80);
98
+ const lines = [];
99
+ const now = Date.now();
100
+ for (const [, t] of this.threads) {
101
+ const elapsed = ((now - t.startedAt) / 1000).toFixed(1);
102
+ const tag = dim(t.id.slice(0, 8));
103
+ const phase = this.formatPhase(t.phase);
104
+ const time = dim(`${elapsed}s`);
105
+ const task = t.task ? truncate(t.task, 40) : "";
106
+ const detail = t.detail ? dim(t.detail) : "";
107
+ let line;
108
+ if (t.phase === "completed") {
109
+ const files = t.filesChanged !== undefined ? dim(`${t.filesChanged} files`) : "";
110
+ line = ` ${tag} ${phase} ${time} ${files} ${detail}`;
111
+ }
112
+ else if (t.phase === "failed" || t.phase === "cancelled") {
113
+ line = ` ${tag} ${phase} ${time} ${detail}`;
114
+ }
115
+ else {
116
+ line = ` ${tag} ${phase} ${time} ${dim(task)}`;
117
+ }
118
+ // Truncate to terminal width
119
+ if (stripAnsi(line).length > w) {
120
+ line = line.slice(0, w + (line.length - stripAnsi(line).length) - 1);
121
+ }
122
+ lines.push(line);
123
+ }
124
+ return lines;
125
+ }
126
+ formatPhase(phase) {
127
+ switch (phase) {
128
+ case "queued":
129
+ return dim("queued");
130
+ case "creating_worktree":
131
+ return cyan("creating worktree");
132
+ case "agent_running":
133
+ return coral("running agent");
134
+ case "capturing_diff":
135
+ return cyan("capturing diff");
136
+ case "compressing":
137
+ return dim("compressing");
138
+ case "completed":
139
+ return green(`${symbols.check} completed`);
140
+ case "failed":
141
+ return red(`${symbols.cross} failed`);
142
+ case "cancelled":
143
+ return yellow("cancelled");
144
+ case "retrying":
145
+ return yellow("retrying");
146
+ default:
147
+ return dim(phase);
148
+ }
149
+ }
150
+ }
151
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * UI module — barrel export for all UI components.
3
+ */
4
+ export * from "./banner.js";
5
+ export * from "./dashboard.js";
6
+ export * from "./log.js";
7
+ export * from "./onboarding.js";
8
+ export * from "./spinner.js";
9
+ export * from "./summary.js";
10
+ export * from "./theme.js";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * UI module — barrel export for all UI components.
3
+ */
4
+ export * from "./banner.js";
5
+ export * from "./dashboard.js";
6
+ export * from "./log.js";
7
+ export * from "./onboarding.js";
8
+ export * from "./spinner.js";
9
+ export * from "./summary.js";
10
+ export * from "./theme.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Structured logging — consistent formatting for all terminal output.
3
+ *
4
+ * All swarm-code output flows through these functions to ensure consistent
5
+ * formatting, TTY-awareness, and proper stdout/stderr separation.
6
+ *
7
+ * Convention: progress/status → stderr, final answer → stdout.
8
+ */
9
+ export type LogLevel = "quiet" | "normal" | "verbose";
10
+ export declare function setLogLevel(level: LogLevel): void;
11
+ export declare function setJsonMode(enabled: boolean): void;
12
+ export declare function getLogLevel(): LogLevel;
13
+ export declare function isJsonMode(): boolean;
14
+ /** Standard info line. */
15
+ export declare function logInfo(message: string): void;
16
+ /** Success line with checkmark. */
17
+ export declare function logSuccess(message: string): void;
18
+ /** Warning line — always shown (never suppressed by quiet or JSON mode). */
19
+ export declare function logWarn(message: string): void;
20
+ /** Error line — always shown (never suppressed by quiet or JSON mode). */
21
+ export declare function logError(message: string, hint?: string): void;
22
+ /** Verbose-only line — only shown with --verbose. */
23
+ export declare function logVerbose(message: string): void;
24
+ /** Debug/dim secondary information. */
25
+ export declare function logDim(message: string): void;
26
+ /** Section header. */
27
+ export declare function logHeader(message: string): void;
28
+ /** Horizontal rule separator. */
29
+ export declare function logSeparator(): void;
30
+ /** Key-value pair (for config display). */
31
+ export declare function logKeyValue(key: string, value: string, keyWidth?: number): void;
32
+ /** Thread progress line with color-coded phase. */
33
+ export declare function logThread(threadId: string, phase: string, detail?: string): void;
34
+ /** Router/memory verbose info. */
35
+ export declare function logRouter(message: string): void;
36
+ /** Write the final answer to stdout. */
37
+ export declare function logAnswer(answer: string): void;
38
+ /** Write structured JSON output. */
39
+ export declare function logJson(data: Record<string, unknown>): void;
package/dist/ui/log.js ADDED
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Structured logging — consistent formatting for all terminal output.
3
+ *
4
+ * All swarm-code output flows through these functions to ensure consistent
5
+ * formatting, TTY-awareness, and proper stdout/stderr separation.
6
+ *
7
+ * Convention: progress/status → stderr, final answer → stdout.
8
+ */
9
+ import { bold, cyan, dim, gray, green, hr, magenta, red, symbols, yellow } from "./theme.js";
10
+ let _level = "normal";
11
+ let _jsonMode = false;
12
+ export function setLogLevel(level) {
13
+ _level = level;
14
+ }
15
+ export function setJsonMode(enabled) {
16
+ _jsonMode = enabled;
17
+ }
18
+ export function getLogLevel() {
19
+ return _level;
20
+ }
21
+ export function isJsonMode() {
22
+ return _jsonMode;
23
+ }
24
+ // ── Core log functions ──────────────────────────────────────────────────────
25
+ /** Standard info line. */
26
+ export function logInfo(message) {
27
+ if (_level === "quiet" || _jsonMode)
28
+ return;
29
+ process.stderr.write(` ${cyan(symbols.info)} ${message}\n`);
30
+ }
31
+ /** Success line with checkmark. */
32
+ export function logSuccess(message) {
33
+ if (_level === "quiet" || _jsonMode)
34
+ return;
35
+ process.stderr.write(` ${green(symbols.check)} ${message}\n`);
36
+ }
37
+ /** Warning line — always shown (never suppressed by quiet or JSON mode). */
38
+ export function logWarn(message) {
39
+ if (_jsonMode) {
40
+ process.stderr.write(`warning: ${message}\n`);
41
+ return;
42
+ }
43
+ process.stderr.write(` ${yellow(symbols.warn)} ${message}\n`);
44
+ }
45
+ /** Error line — always shown (never suppressed by quiet or JSON mode). */
46
+ export function logError(message, hint) {
47
+ if (_jsonMode) {
48
+ process.stderr.write(`error: ${message}${hint ? ` (${hint})` : ""}\n`);
49
+ return;
50
+ }
51
+ process.stderr.write(` ${red(symbols.cross)} ${message}\n`);
52
+ if (hint) {
53
+ process.stderr.write(` ${dim(hint)}\n`);
54
+ }
55
+ }
56
+ /** Verbose-only line — only shown with --verbose. */
57
+ export function logVerbose(message) {
58
+ if (_level !== "verbose" || _jsonMode)
59
+ return;
60
+ process.stderr.write(` ${gray(message)}\n`);
61
+ }
62
+ /** Debug/dim secondary information. */
63
+ export function logDim(message) {
64
+ if (_level === "quiet" || _jsonMode)
65
+ return;
66
+ process.stderr.write(` ${dim(message)}\n`);
67
+ }
68
+ /** Section header. */
69
+ export function logHeader(message) {
70
+ if (_level === "quiet" || _jsonMode)
71
+ return;
72
+ process.stderr.write(`\n ${bold(cyan(message))}\n`);
73
+ }
74
+ /** Horizontal rule separator. */
75
+ export function logSeparator() {
76
+ if (_level === "quiet" || _jsonMode)
77
+ return;
78
+ process.stderr.write(` ${hr()}\n`);
79
+ }
80
+ /** Key-value pair (for config display). */
81
+ export function logKeyValue(key, value, keyWidth = 12) {
82
+ if (_level === "quiet" || _jsonMode)
83
+ return;
84
+ const paddedKey = key.padEnd(keyWidth);
85
+ process.stderr.write(` ${dim(paddedKey)} ${value}\n`);
86
+ }
87
+ /** Thread progress line with color-coded phase. */
88
+ export function logThread(threadId, phase, detail) {
89
+ if (_level === "quiet" || _jsonMode)
90
+ return;
91
+ const tag = dim(`[${threadId.slice(0, 8)}]`);
92
+ const phaseColor = PHASE_COLORS[phase] || ((s) => s);
93
+ const suffix = detail ? dim(` ${detail}`) : "";
94
+ process.stderr.write(` ${tag} ${phaseColor(phase)}${suffix}\n`);
95
+ }
96
+ /** Router/memory verbose info. */
97
+ export function logRouter(message) {
98
+ if (_level !== "verbose" || _jsonMode)
99
+ return;
100
+ process.stderr.write(` ${magenta(symbols.arrow)} ${dim(message)}\n`);
101
+ }
102
+ /** Write the final answer to stdout. */
103
+ export function logAnswer(answer) {
104
+ if (_jsonMode)
105
+ return;
106
+ process.stdout.write(answer);
107
+ if (!answer.endsWith("\n"))
108
+ process.stdout.write("\n");
109
+ }
110
+ /** Write structured JSON output. */
111
+ export function logJson(data) {
112
+ process.stdout.write(`${JSON.stringify(data, null, 2)}\n`);
113
+ }
114
+ // ── Phase color mapping ────────────────────────────────────────────────────
115
+ const PHASE_COLORS = {
116
+ queued: dim,
117
+ creating_worktree: cyan,
118
+ agent_running: bold,
119
+ capturing_diff: cyan,
120
+ compressing: dim,
121
+ completed: green,
122
+ failed: red,
123
+ cancelled: yellow,
124
+ retrying: yellow,
125
+ };
126
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * First-run onboarding — welcome screen + interactive agent setup wizard.
3
+ *
4
+ * Two-column layout: left has greeting + swarm mesh art + version info,
5
+ * right has tips + environment checks. Then an interactive wizard to:
6
+ * 1. Pick default coding agent from detected backends
7
+ * 2. Configure API keys for required providers
8
+ * 3. Choose default model
9
+ * 4. Save preferences to ~/.swarm/config.yaml
10
+ *
11
+ * Triggered once on first `swarm --dir` invocation. Saves ~/.swarm/.initialized marker.
12
+ */
13
+ export declare function isFirstRun(): boolean;
14
+ export declare function runOnboarding(): Promise<void>;