-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.ts
More file actions
executable file
·207 lines (184 loc) · 6.45 KB
/
index.ts
File metadata and controls
executable file
·207 lines (184 loc) · 6.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#!/usr/bin/env bun
import { init } from "./src/commands/init";
import { run } from "./src/commands/run";
import { status } from "./src/commands/status";
import { iterate } from "./src/commands/iterate";
import { plan } from "./src/commands/plan";
import { prune } from "./src/commands/prune";
import { DEFAULT_MODEL } from "./src/constants";
import { migrateTasksToDexIfNeeded } from "./src/migrate-to-dex";
import { validateModel, SUPPORTED_PROVIDERS } from "./src/model";
// ANSI colors
const colors = {
reset: "\x1b[0m",
bold: "\x1b[1m",
dim: "\x1b[2m",
red: "\x1b[31m",
green: "\x1b[32m",
yellow: "\x1b[33m",
blue: "\x1b[34m",
cyan: "\x1b[36m",
};
function printHelp() {
console.log(`
${colors.bold}math${colors.reset} - Multi-Agent Task Harness
A light meta agent orchestration harness designed to coordinate multiple AI
agents working together to accomplish tasks managed by dex.
${colors.bold}USAGE${colors.reset}
math <command> [options]
${colors.bold}COMMANDS${colors.reset}
${colors.cyan}init${colors.reset} Initialize dex and create .math/todo/ with template files
${colors.cyan}plan${colors.reset} Run planning mode to flesh out tasks
${colors.cyan}run${colors.reset} Start the agent loop until all tasks complete
${colors.cyan}status${colors.reset} Show current task counts from dex
${colors.cyan}iterate${colors.reset} Archive completed tasks and reset for a new sprint
${colors.cyan}prune${colors.reset} Delete backup artifacts from .math/backups/
${colors.cyan}help${colors.reset} Show this help message
${colors.bold}OPTIONS${colors.reset}
${colors.dim}-m, --model <model>${colors.reset} Model to use in provider/model format
(e.g., openai/gpt-4, anthropic/claude-3-opus)
Supported providers: ${SUPPORTED_PROVIDERS.join(", ")}
Default: ${DEFAULT_MODEL}
${colors.dim}--max-iterations <n>${colors.reset} Safety limit (default: 100)
${colors.dim}--pause <seconds>${colors.reset} Pause between iterations (default: 3)
${colors.dim}--no-plan${colors.reset} Skip planning mode after init/iterate
${colors.dim}--ui${colors.reset} Enable web UI server (run command only)
${colors.dim}--quick${colors.reset} Skip clarifying questions in plan mode
${colors.dim}--force${colors.reset} Skip confirmation prompts (prune)
${colors.bold}TASK MANAGEMENT${colors.reset}
Tasks are managed by dex. Use dex commands directly to view and manage tasks:
${colors.dim}dex list --ready${colors.reset} Show tasks ready to work on
${colors.dim}dex status${colors.reset} Show overall progress
${colors.dim}dex show <id>${colors.reset} Get full task details
${colors.dim}dex create "<name>"${colors.reset} Create a new task
${colors.bold}EXAMPLES${colors.reset}
${colors.dim}# Initialize and plan a new project${colors.reset}
math init
${colors.dim}# Initialize without planning${colors.reset}
math init --no-plan
${colors.dim}# Run planning mode on existing tasks${colors.reset}
math plan
${colors.dim}# Quick planning without clarifying questions${colors.reset}
math plan --quick
${colors.dim}# Run the agent loop${colors.reset}
math run
${colors.dim}# Run with web UI${colors.reset}
math run --ui
${colors.dim}# Check task status${colors.reset}
math status
${colors.dim}# Start a new sprint (archive completed, reset learnings, plan)${colors.reset}
math iterate
`);
}
// Map short flags to their long equivalents
const SHORT_FLAGS: Record<string, string> = {
m: "model",
};
function parseArgs(args: string[]): Record<string, string | boolean> {
const parsed: Record<string, string | boolean> = {};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (!arg) continue;
if (arg.startsWith("--")) {
const key = arg.slice(2);
const next = args[i + 1];
if (next && !next.startsWith("-")) {
parsed[key] = next;
i++;
} else {
parsed[key] = true;
}
} else if (arg.startsWith("-") && arg.length === 2) {
// Short flag like -m
const shortKey = arg.slice(1);
const longKey = SHORT_FLAGS[shortKey] ?? shortKey;
const next = args[i + 1];
if (next && !next.startsWith("-")) {
parsed[longKey] = next;
i++;
} else {
parsed[longKey] = true;
}
}
}
return parsed;
}
/**
* Validate the model argument if provided. Exits with code 1 if invalid.
*/
function validateModelOrExit(model: string | boolean | undefined): string | undefined {
if (typeof model !== "string") {
// No model provided or --model without value, use default
return undefined;
}
const result = validateModel(model);
if (!result.valid) {
console.error(`${colors.red}Error: ${result.error}${colors.reset}`);
process.exit(1);
}
return model;
}
async function main() {
const [command, ...rest] = Bun.argv.slice(2);
const options = parseArgs(rest);
// Check for migration before any command except help
const isHelpCommand =
command === "help" || command === "--help" || command === "-h" || command === undefined;
if (!isHelpCommand) {
await migrateTasksToDexIfNeeded();
}
try {
switch (command) {
case "init":
await init({
skipPlan: !!options["no-plan"],
model: validateModelOrExit(options.model),
});
break;
case "plan":
await plan({
model: validateModelOrExit(options.model),
quick: !!options.quick,
});
break;
case "run":
validateModelOrExit(options.model);
await run(options);
break;
case "status":
await status();
break;
case "iterate":
await iterate({
skipPlan: !!options["no-plan"],
model: validateModelOrExit(options.model),
});
break;
case "prune":
await prune({
force: !!options.force,
});
break;
case "help":
case "--help":
case "-h":
case undefined:
printHelp();
break;
default:
console.error(
`${colors.red}Unknown command: ${command}${colors.reset}`
);
printHelp();
process.exit(1);
}
} catch (error) {
console.error(
`${colors.red}Error: ${error instanceof Error ? error.message : error}${
colors.reset
}`
);
process.exit(1);
}
}
main();