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,113 @@
1
+ /**
2
+ * End-of-session summary — shows a clean recap of what happened.
3
+ */
4
+ import { getLogLevel, isJsonMode, logJson, logSeparator } from "./log.js";
5
+ import { bold, dim, green, red, symbols, yellow } from "./theme.js";
6
+ /** Render the end-of-session summary. */
7
+ export function renderSummary(summary) {
8
+ if (isJsonMode()) {
9
+ logJson({
10
+ success: summary.completed,
11
+ elapsed_s: summary.elapsed,
12
+ iterations: summary.iterations,
13
+ sub_queries: summary.subQueries,
14
+ threads: {
15
+ total: summary.threads.length,
16
+ completed: summary.threads.filter((t) => t.status === "completed").length,
17
+ failed: summary.threads.filter((t) => t.status === "failed").length,
18
+ cancelled: summary.threads.filter((t) => t.status === "cancelled").length,
19
+ },
20
+ budget: {
21
+ spent_usd: summary.budget.totalSpentUsd,
22
+ limit_usd: summary.budget.sessionLimitUsd,
23
+ actual_cost_threads: summary.budget.actualCostThreads,
24
+ estimated_cost_threads: summary.budget.estimatedCostThreads,
25
+ },
26
+ tokens: summary.budget.totalTokens
27
+ ? {
28
+ input: summary.budget.totalTokens.input,
29
+ output: summary.budget.totalTokens.output,
30
+ total: summary.budget.totalTokens.input + summary.budget.totalTokens.output,
31
+ }
32
+ : undefined,
33
+ cache: summary.cacheStats
34
+ ? {
35
+ hits: summary.cacheStats.hits,
36
+ misses: summary.cacheStats.misses,
37
+ saved_ms: summary.cacheStats.totalSavedMs,
38
+ }
39
+ : undefined,
40
+ episodes: summary.episodeCount,
41
+ answer: summary.answer,
42
+ });
43
+ return;
44
+ }
45
+ if (getLogLevel() === "quiet")
46
+ return;
47
+ process.stderr.write("\n");
48
+ logSeparator();
49
+ // Overall status
50
+ const status = summary.completed ? green("completed") : yellow("incomplete");
51
+ const elapsed = `${summary.elapsed.toFixed(1)}s`;
52
+ process.stderr.write(` ${bold(status)} in ${bold(elapsed)}`);
53
+ process.stderr.write(` ${dim(symbols.dot)} ${summary.iterations} iterations`);
54
+ process.stderr.write(` ${dim(symbols.dot)} ${summary.subQueries} sub-queries\n`);
55
+ // Thread breakdown
56
+ if (summary.threads.length > 0) {
57
+ const completed = summary.threads.filter((t) => t.status === "completed").length;
58
+ const failed = summary.threads.filter((t) => t.status === "failed").length;
59
+ const cancelled = summary.threads.filter((t) => t.status === "cancelled").length;
60
+ const parts = [];
61
+ if (completed > 0)
62
+ parts.push(green(`${completed} completed`));
63
+ if (failed > 0)
64
+ parts.push(red(`${failed} failed`));
65
+ if (cancelled > 0)
66
+ parts.push(yellow(`${cancelled} cancelled`));
67
+ process.stderr.write(` ${dim("Threads")} ${parts.join(dim(` ${symbols.dot} `))}\n`);
68
+ // Budget with actual vs estimated breakdown
69
+ const spent = summary.budget.totalSpentUsd;
70
+ const limit = summary.budget.sessionLimitUsd;
71
+ const pct = limit > 0 ? ((spent / limit) * 100).toFixed(0) : "0";
72
+ const budgetColor = spent > limit * 0.8 ? yellow : dim;
73
+ const costSource = summary.budget.actualCostThreads > 0
74
+ ? dim(` (${summary.budget.actualCostThreads} actual, ${summary.budget.estimatedCostThreads} estimated)`)
75
+ : dim(" (estimated)");
76
+ process.stderr.write(` ${dim("Budget")} ${budgetColor(`$${spent.toFixed(4)} / $${limit.toFixed(2)} (${pct}%)`)}${costSource}\n`);
77
+ // Token usage (if any real usage data)
78
+ const tokens = summary.budget.totalTokens;
79
+ if (tokens && (tokens.input > 0 || tokens.output > 0)) {
80
+ const totalK = ((tokens.input + tokens.output) / 1000).toFixed(1);
81
+ process.stderr.write(` ${dim("Tokens")} ${dim(`${tokens.input.toLocaleString()} in + ${tokens.output.toLocaleString()} out (${totalK}K total)`)}\n`);
82
+ }
83
+ // Cache stats
84
+ if (summary.cacheStats && (summary.cacheStats.hits > 0 || summary.cacheStats.size > 0)) {
85
+ const c = summary.cacheStats;
86
+ const saved = c.totalSavedMs > 0 ? `, saved ${(c.totalSavedMs / 1000).toFixed(1)}s` : "";
87
+ process.stderr.write(` ${dim("Cache")} ${dim(`${c.hits} hits, ${c.misses} misses${saved}`)}\n`);
88
+ }
89
+ // Episodic memory
90
+ if (summary.episodeCount !== undefined && summary.episodeCount > 0) {
91
+ process.stderr.write(` ${dim("Memory")} ${dim(`${summary.episodeCount} episodes`)}\n`);
92
+ }
93
+ // Per-thread detail table (if verbose or few threads)
94
+ if (summary.threads.length <= 10 || getLogLevel() === "verbose") {
95
+ process.stderr.write("\n");
96
+ for (const t of summary.threads) {
97
+ const icon = t.status === "completed"
98
+ ? green(symbols.check)
99
+ : t.status === "failed"
100
+ ? red(symbols.cross)
101
+ : yellow(symbols.dash);
102
+ const id = dim(t.id.slice(0, 8));
103
+ const dur = t.completedAt && t.startedAt ? dim(`${((t.completedAt - t.startedAt) / 1000).toFixed(1)}s`) : dim("--");
104
+ const task = t.config.task.length > 50 ? `${t.config.task.slice(0, 49)}\u2026` : t.config.task;
105
+ const files = t.result?.filesChanged.length ?? 0;
106
+ const fileStr = files > 0 ? dim(`${files} files`) : "";
107
+ process.stderr.write(` ${icon} ${id} ${dur} ${fileStr} ${dim(task)}\n`);
108
+ }
109
+ }
110
+ }
111
+ logSeparator();
112
+ }
113
+ //# sourceMappingURL=summary.js.map
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Centralized color/formatting system with TTY detection.
3
+ *
4
+ * All terminal styling flows through this module. When output is piped
5
+ * (not a TTY), colors are automatically stripped.
6
+ */
7
+ declare const isTTY: boolean;
8
+ declare const stdoutTTY: boolean;
9
+ /** Brand coral — spinner, accents (inspired by Claude Code's coral orange). */
10
+ export declare const coral: (text: string) => string;
11
+ /** Primary accent — headers, borders. */
12
+ export declare const cyan: (text: string) => string;
13
+ /** Success — completed operations. */
14
+ export declare const green: (text: string) => string;
15
+ /** Warning — non-fatal issues. */
16
+ export declare const yellow: (text: string) => string;
17
+ /** Error — failures. */
18
+ export declare const red: (text: string) => string;
19
+ /** Secondary info — timestamps, ids, hints. */
20
+ export declare const dim: (text: string) => string;
21
+ /** Emphasis. */
22
+ export declare const bold: (text: string) => string;
23
+ /** Subtle emphasis. */
24
+ export declare const italic: (text: string) => string;
25
+ /** De-emphasized text. */
26
+ export declare const gray: (text: string) => string;
27
+ /** Magenta — sub-queries, memory. */
28
+ export declare const magenta: (text: string) => string;
29
+ /** White — primary content. */
30
+ export declare const white: (text: string) => string;
31
+ export declare const heading: (text: string) => string;
32
+ export declare const success: (text: string) => string;
33
+ export declare const warn: (text: string) => string;
34
+ export declare const error: (text: string) => string;
35
+ export declare const info: (text: string) => string;
36
+ export declare const hint: (text: string) => string;
37
+ export declare const symbols: {
38
+ readonly check: "✔" | "[OK]";
39
+ readonly cross: "✘" | "[ERR]";
40
+ readonly warn: "⚠" | "[WARN]";
41
+ readonly info: "●" | "[*]";
42
+ readonly arrow: "▶" | ">";
43
+ readonly dot: "." | "·";
44
+ readonly dash: "-" | "─";
45
+ readonly vertLine: "│" | "|";
46
+ readonly topLeft: "╭" | "+";
47
+ readonly topRight: "+" | "╮";
48
+ readonly bottomLeft: "+" | "╰";
49
+ readonly bottomRight: "+" | "╯";
50
+ readonly horizontal: "-" | "─";
51
+ readonly spinner: string[];
52
+ };
53
+ /** Get terminal width, with a sensible fallback. */
54
+ export declare function termWidth(): number;
55
+ /** Draw a horizontal rule. */
56
+ export declare function hr(char?: string): string;
57
+ /** Right-pad a string to a given width. */
58
+ export declare function pad(text: string, width: number): string;
59
+ /** Strip ANSI escape codes from a string. */
60
+ export declare function stripAnsi(text: string): string;
61
+ /** Truncate a string to maxLen, adding ellipsis if needed. */
62
+ export declare function truncate(text: string, maxLen: number): string;
63
+ export { isTTY, stdoutTTY };
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Centralized color/formatting system with TTY detection.
3
+ *
4
+ * All terminal styling flows through this module. When output is piped
5
+ * (not a TTY), colors are automatically stripped.
6
+ */
7
+ const isTTY = process.stderr.isTTY ?? false;
8
+ const stdoutTTY = process.stdout.isTTY ?? false;
9
+ // ── ANSI helpers ────────────────────────────────────────────────────────────
10
+ function ansi(code) {
11
+ if (!isTTY)
12
+ return (text) => text;
13
+ return (text) => `\x1b[${code}m${text}\x1b[0m`;
14
+ }
15
+ function ansiFg(r, g, b) {
16
+ if (!isTTY)
17
+ return (text) => text;
18
+ return (text) => `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`;
19
+ }
20
+ // ── Theme colors ────────────────────────────────────────────────────────────
21
+ /** Brand coral — spinner, accents (inspired by Claude Code's coral orange). */
22
+ export const coral = ansiFg(215, 119, 87);
23
+ /** Primary accent — headers, borders. */
24
+ export const cyan = ansi("36");
25
+ /** Success — completed operations. */
26
+ export const green = ansi("32");
27
+ /** Warning — non-fatal issues. */
28
+ export const yellow = ansi("33");
29
+ /** Error — failures. */
30
+ export const red = ansi("31");
31
+ /** Secondary info — timestamps, ids, hints. */
32
+ export const dim = ansi("2");
33
+ /** Emphasis. */
34
+ export const bold = ansi("1");
35
+ /** Subtle emphasis. */
36
+ export const italic = ansi("3");
37
+ /** De-emphasized text. */
38
+ export const gray = ansiFg(128, 128, 128);
39
+ /** Magenta — sub-queries, memory. */
40
+ export const magenta = ansi("35");
41
+ /** White — primary content. */
42
+ export const white = ansi("37");
43
+ // ── Compound styles ─────────────────────────────────────────────────────────
44
+ export const heading = (text) => bold(cyan(text));
45
+ export const success = (text) => green(`${symbols.check} ${text}`);
46
+ export const warn = (text) => yellow(`${symbols.warn} ${text}`);
47
+ export const error = (text) => red(`${symbols.cross} ${text}`);
48
+ export const info = (text) => cyan(`${symbols.info} ${text}`);
49
+ export const hint = (text) => dim(` ${text}`);
50
+ // ── Symbols ─────────────────────────────────────────────────────────────────
51
+ export const symbols = {
52
+ check: isTTY ? "\u2714" : "[OK]",
53
+ cross: isTTY ? "\u2718" : "[ERR]",
54
+ warn: isTTY ? "\u26A0" : "[WARN]",
55
+ info: isTTY ? "\u25CF" : "[*]",
56
+ arrow: isTTY ? "\u25B6" : ">",
57
+ dot: isTTY ? "\u00B7" : ".",
58
+ dash: isTTY ? "\u2500" : "-",
59
+ vertLine: isTTY ? "\u2502" : "|",
60
+ topLeft: isTTY ? "\u256D" : "+",
61
+ topRight: isTTY ? "\u256E" : "+",
62
+ bottomLeft: isTTY ? "\u2570" : "+",
63
+ bottomRight: isTTY ? "\u256F" : "+",
64
+ horizontal: isTTY ? "\u2500" : "-",
65
+ spinner: isTTY ? ["\u00B7", "\u2726", "\u2733", "\u2736", "\u273B", "\u273D"] : ["*"],
66
+ };
67
+ // ── Layout helpers ──────────────────────────────────────────────────────────
68
+ /** Get terminal width, with a sensible fallback. */
69
+ export function termWidth() {
70
+ return process.stderr.columns || 80;
71
+ }
72
+ /** Draw a horizontal rule. */
73
+ export function hr(char) {
74
+ const c = char || symbols.horizontal;
75
+ return dim(c.repeat(Math.min(termWidth(), 60)));
76
+ }
77
+ /** Right-pad a string to a given width. */
78
+ export function pad(text, width) {
79
+ const stripped = stripAnsi(text);
80
+ if (stripped.length >= width)
81
+ return text;
82
+ return text + " ".repeat(width - stripped.length);
83
+ }
84
+ /** Strip ANSI escape codes from a string. */
85
+ export function stripAnsi(text) {
86
+ // eslint-disable-next-line no-control-regex
87
+ return text.replace(/\x1b\[[0-9;]*m/g, "");
88
+ }
89
+ /** Truncate a string to maxLen, adding ellipsis if needed. */
90
+ export function truncate(text, maxLen) {
91
+ if (text.length <= maxLen)
92
+ return text;
93
+ return `${text.slice(0, maxLen - 1)}\u2026`;
94
+ }
95
+ // ── Exports ─────────────────────────────────────────────────────────────────
96
+ export { isTTY, stdoutTTY };
97
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * RLM Trajectory Viewer — interactive TUI for browsing saved trajectory JSON files.
4
+ *
5
+ * Navigate through iterations with arrow keys, view code, REPL output,
6
+ * sub-queries, and the final answer in a beautifully formatted display.
7
+ *
8
+ * Usage:
9
+ * rlm viewer # pick from list
10
+ * rlm viewer trajectories/file.json # open specific file
11
+ */
12
+ export {};