ai-maestro 1.0.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.
- package/CHANGELOG.md +11 -0
- package/LICENSE +15 -0
- package/README.md +727 -0
- package/bin/maestro.mjs +246 -0
- package/package.json +29 -0
- package/src/checkpoint.mjs +102 -0
- package/src/codex-diagnostics.mjs +682 -0
- package/src/codex-home-inspect.mjs +252 -0
- package/src/codex-home.mjs +258 -0
- package/src/commands.mjs +809 -0
- package/src/config.mjs +11 -0
- package/src/debug.mjs +164 -0
- package/src/encoding-guard.mjs +125 -0
- package/src/engines/ai-router-engine.mjs +37 -0
- package/src/engines/codex-engine.mjs +21 -0
- package/src/engines/engine.mjs +21 -0
- package/src/engines/registry.mjs +29 -0
- package/src/files.mjs +65 -0
- package/src/format.mjs +132 -0
- package/src/lock.mjs +439 -0
- package/src/memory-log.mjs +18 -0
- package/src/memory.mjs +1 -0
- package/src/orchestration/attempt-chain-runtime.mjs +627 -0
- package/src/orchestration/budget-manager.mjs +121 -0
- package/src/orchestration/capability-registry.mjs +108 -0
- package/src/orchestration/consolidator.mjs +772 -0
- package/src/orchestration/delegation-executor.mjs +262 -0
- package/src/orchestration/delegation-manager.mjs +116 -0
- package/src/orchestration/deployment-intent.mjs +36 -0
- package/src/orchestration/engine-history.mjs +110 -0
- package/src/orchestration/engine-policy.mjs +73 -0
- package/src/orchestration/engine-selector.mjs +187 -0
- package/src/orchestration/execution-context.mjs +45 -0
- package/src/orchestration/failure-classifier.mjs +136 -0
- package/src/orchestration/failure-evidence.mjs +237 -0
- package/src/orchestration/fallback-chain-lock.mjs +217 -0
- package/src/orchestration/fallback-chain-trail.mjs +218 -0
- package/src/orchestration/fallback-executor.mjs +146 -0
- package/src/orchestration/fallback-graph.mjs +106 -0
- package/src/orchestration/fallback-recommendation.mjs +73 -0
- package/src/orchestration/file-conflict-detector.mjs +126 -0
- package/src/orchestration/host-validation.mjs +241 -0
- package/src/orchestration/orchestration-loop.mjs +1971 -0
- package/src/orchestration/orchestration-runtime.mjs +1019 -0
- package/src/orchestration/orchestration-scheduler.mjs +135 -0
- package/src/orchestration/orchestration-trail.mjs +192 -0
- package/src/orchestration/preflight.mjs +212 -0
- package/src/orchestration/provider-health.mjs +566 -0
- package/src/orchestration/provider-router.mjs +352 -0
- package/src/orchestration/rc-check-adapters.mjs +817 -0
- package/src/orchestration/rc-check.mjs +544 -0
- package/src/orchestration/rc-policy.mjs +200 -0
- package/src/orchestration/runtime-gate.mjs +146 -0
- package/src/orchestration/sector-managers.mjs +215 -0
- package/src/orchestration/self-hosting-canary.mjs +231 -0
- package/src/orchestration/self-hosting-readiness.mjs +244 -0
- package/src/orchestration/spec-planner.mjs +877 -0
- package/src/orchestration/subtask-planner.mjs +176 -0
- package/src/orchestration/task-classifier.mjs +241 -0
- package/src/orchestration/verifier.mjs +1608 -0
- package/src/orchestration-commands.mjs +279 -0
- package/src/planner.mjs +38 -0
- package/src/project.mjs +1 -0
- package/src/run-diagnostics.mjs +641 -0
- package/src/runner.mjs +243 -0
- package/src/safety.mjs +116 -0
- package/src/schema.mjs +371 -0
- package/src/session-commands.mjs +521 -0
- package/src/shell.mjs +93 -0
- package/src/smart-planner.mjs +249 -0
- package/src/task-commands.mjs +1182 -0
- package/src/tasks.mjs +134 -0
- package/src/ui/commands.mjs +76 -0
- package/src/ui/events.mjs +45 -0
- package/src/ui/public/app.js +600 -0
- package/src/ui/public/index.html +88 -0
- package/src/ui/public/style.css +460 -0
- package/src/ui/server.mjs +112 -0
- package/src/ui/state.mjs +504 -0
- package/src/usage.mjs +178 -0
- package/src/workspace-diff.mjs +228 -0
package/bin/maestro.mjs
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { acquireLock, releaseLock } from '../src/lock.mjs';
|
|
4
|
+
import {
|
|
5
|
+
init, status, plan, startCommand, continueCommand, doctor, releaseCheck, stats, checkpoint, handoff, schemaCheck, printHelp, providerHealthCommand
|
|
6
|
+
} from '../src/session-commands.mjs';
|
|
7
|
+
import { runTask, runOne, runAll, retry, taskCommand, reconcileCrashedTasks } from '../src/task-commands.mjs';
|
|
8
|
+
import { runSerialOrchestration } from '../src/orchestration/orchestration-runtime.mjs';
|
|
9
|
+
import { runTaskWithFailover } from '../src/orchestration/attempt-chain-runtime.mjs';
|
|
10
|
+
import { readinessCommand } from '../src/orchestration/self-hosting-readiness.mjs';
|
|
11
|
+
import { rcCheckCommand } from '../src/orchestration/rc-check.mjs';
|
|
12
|
+
import { readRunArtifact } from '../src/runner.mjs';
|
|
13
|
+
import { redactCredentials } from '../src/format.mjs';
|
|
14
|
+
import {
|
|
15
|
+
codexHomeCommand, codexHomeDiff, codexHomeInventory, codexHomeProbe, codexHomeRepair,
|
|
16
|
+
codexCompare, codexTestInvocation, codexDebugCommand, codexSandboxTestCommand
|
|
17
|
+
} from '../src/codex-diagnostics.mjs';
|
|
18
|
+
import { startUiServer } from '../src/ui/server.mjs';
|
|
19
|
+
import {
|
|
20
|
+
enginesList, enginesShow, enginesHealth, enginesValidate, enginesResearch,
|
|
21
|
+
routeTask, preflightCommand, orchestraPlan, budgetCommand,
|
|
22
|
+
statsByEngine, statsByRunKind, statsCost, statsByGateDecision
|
|
23
|
+
} from '../src/orchestration-commands.mjs';
|
|
24
|
+
|
|
25
|
+
const MUTATING_TASK_SUBCOMMANDS = new Set([
|
|
26
|
+
'add', 'complete', 'fail', 'pending', 'archive-failed', 'archive-completed', 'clean-test'
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
const MUTATING_COMMANDS = new Set([
|
|
30
|
+
'init', 'start', 'plan', 'run-one', 'run-task', 'orchestrate', 'run-all', 'retry',
|
|
31
|
+
'recover', 'reconcile', 'checkpoint', 'handoff', 'codex-home-repair'
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
function needsLock(command, args) {
|
|
35
|
+
if (command === 'run-task' && args.includes('--failover')) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if ((command === 'recover' || command === 'reconcile') && args.includes('--dry-run')) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
if (command === 'task') {
|
|
42
|
+
return MUTATING_TASK_SUBCOMMANDS.has(args[0]);
|
|
43
|
+
}
|
|
44
|
+
return MUTATING_COMMANDS.has(command);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseArtifactArgs(args) {
|
|
48
|
+
let runId = null;
|
|
49
|
+
let taskId = null;
|
|
50
|
+
let lines = null;
|
|
51
|
+
for (let i = 0; i < args.length; i++) {
|
|
52
|
+
const arg = args[i];
|
|
53
|
+
if (arg === '--task') {
|
|
54
|
+
taskId = args[++i] || null;
|
|
55
|
+
} else if (arg === '--lines') {
|
|
56
|
+
lines = Number.parseInt(args[++i], 10);
|
|
57
|
+
} else if (!arg.startsWith('--') && !runId) {
|
|
58
|
+
runId = arg;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
runId,
|
|
63
|
+
taskId,
|
|
64
|
+
latest: args.includes('--latest'),
|
|
65
|
+
tail: args.includes('--tail'),
|
|
66
|
+
lines: Number.isFinite(lines) && lines > 0 ? lines : null
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function printArtifact(kind, args) {
|
|
71
|
+
const parsed = parseArtifactArgs(args);
|
|
72
|
+
const result = await readRunArtifact({ kind, ...parsed });
|
|
73
|
+
console.log(redactCredentials(result.content));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function parseOrchestrateArgs(args) {
|
|
77
|
+
let idArg = null;
|
|
78
|
+
let maxConcurrent;
|
|
79
|
+
const consumed = new Set();
|
|
80
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
81
|
+
const arg = args[index];
|
|
82
|
+
if (arg === '--max-concurrent') {
|
|
83
|
+
consumed.add(index);
|
|
84
|
+
consumed.add(index + 1);
|
|
85
|
+
maxConcurrent = args[index + 1];
|
|
86
|
+
} else if (arg.startsWith('--max-concurrent=')) {
|
|
87
|
+
consumed.add(index);
|
|
88
|
+
maxConcurrent = arg.slice('--max-concurrent='.length);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
92
|
+
const arg = args[index];
|
|
93
|
+
if (!consumed.has(index) && !arg.startsWith('--') && !idArg) {
|
|
94
|
+
idArg = arg;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const parallel = args.includes('--parallel');
|
|
98
|
+
return {
|
|
99
|
+
idArg,
|
|
100
|
+
parallel,
|
|
101
|
+
concurrency: parallel ? { enabled: true, maxConcurrent } : undefined
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function dispatch(command, args) {
|
|
106
|
+
switch (command) {
|
|
107
|
+
case undefined:
|
|
108
|
+
case 'help':
|
|
109
|
+
case '--help':
|
|
110
|
+
case '-h': return printHelp();
|
|
111
|
+
case 'init': return init();
|
|
112
|
+
case 'status': return status();
|
|
113
|
+
case 'start': {
|
|
114
|
+
const validateWorker = args.includes('--validate-worker');
|
|
115
|
+
const requestArgs = args.filter(arg => arg !== '--validate-worker');
|
|
116
|
+
return startCommand(requestArgs.join(' '), { validateWorker });
|
|
117
|
+
}
|
|
118
|
+
case 'continue': return continueCommand();
|
|
119
|
+
case 'doctor': return doctor();
|
|
120
|
+
case 'provider-health': return providerHealthCommand({ json: args.includes('--json') });
|
|
121
|
+
case 'rc-check': return rcCheckCommand(args);
|
|
122
|
+
case 'readiness': return readinessCommand();
|
|
123
|
+
case 'codex-home': return codexHomeCommand();
|
|
124
|
+
case 'codex-home-diff': return codexHomeDiff();
|
|
125
|
+
case 'codex-home-inventory': return codexHomeInventory();
|
|
126
|
+
case 'codex-home-probe': return codexHomeProbe();
|
|
127
|
+
case 'codex-home-repair': return codexHomeRepair();
|
|
128
|
+
case 'codex-compare': return codexCompare();
|
|
129
|
+
case 'codex-test': return codexTestInvocation();
|
|
130
|
+
case 'codex-sandbox-test': return codexSandboxTestCommand();
|
|
131
|
+
case 'codex-debug': return codexDebugCommand();
|
|
132
|
+
case 'stats': {
|
|
133
|
+
if (args.includes('--by-engine')) return statsByEngine();
|
|
134
|
+
if (args.includes('--by-run-kind')) return statsByRunKind();
|
|
135
|
+
if (args.includes('--cost')) return statsCost();
|
|
136
|
+
if (args.includes('--by-gate-decision')) return statsByGateDecision();
|
|
137
|
+
return stats();
|
|
138
|
+
}
|
|
139
|
+
case 'engines': {
|
|
140
|
+
const [sub, subArg] = args;
|
|
141
|
+
if (sub === 'list' || !sub) return enginesList();
|
|
142
|
+
if (sub === 'show') return enginesShow(subArg);
|
|
143
|
+
if (sub === 'health') return enginesHealth();
|
|
144
|
+
if (sub === 'validate') return enginesValidate(subArg);
|
|
145
|
+
if (sub === 'research') return enginesResearch();
|
|
146
|
+
console.log('Usage: maestro engines list | show <id> | health | validate <id> | research');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
case 'route-task': return routeTask(args[0]);
|
|
150
|
+
case 'preflight': return preflightCommand(args[0]);
|
|
151
|
+
case 'orchestra-plan': {
|
|
152
|
+
const dryRun = args.includes('--dry-run');
|
|
153
|
+
const idArg = args.find(arg => arg !== '--dry-run');
|
|
154
|
+
return orchestraPlan(idArg, { dryRun });
|
|
155
|
+
}
|
|
156
|
+
case 'budget': return budgetCommand();
|
|
157
|
+
case 'release-check': return releaseCheck();
|
|
158
|
+
case 'schema-check': return schemaCheck();
|
|
159
|
+
case 'run-log': return printArtifact('log', args);
|
|
160
|
+
case 'report': return printArtifact('report', args);
|
|
161
|
+
case 'plan': return args[0] ? plan(args.join(' ')) : console.log('Usage: maestro plan "<request>"');
|
|
162
|
+
case 'run-one': {
|
|
163
|
+
if (args.includes('--dry-run')) return orchestraPlan(undefined, { dryRun: true });
|
|
164
|
+
return runOne({ quiet: args.includes('--quiet'), force: args.includes('--force'), verbose: args.includes('--verbose'), debug: args.includes('--debug') });
|
|
165
|
+
}
|
|
166
|
+
case 'run-task': {
|
|
167
|
+
if (args.includes('--failover')) {
|
|
168
|
+
const idArg = args.find(arg => !arg.startsWith('--'));
|
|
169
|
+
const simulateArg = args.find(arg => arg.startsWith('--simulate-failure='));
|
|
170
|
+
const simulateFailure = simulateArg ? simulateArg.slice('--simulate-failure='.length) : null;
|
|
171
|
+
if (!idArg) return console.log('Usage: maestro run-task <id> --failover [--dry-run] [--resume] [--force]');
|
|
172
|
+
const result = await runTaskWithFailover(idArg, {
|
|
173
|
+
dryRun: args.includes('--dry-run'),
|
|
174
|
+
resume: args.includes('--resume'),
|
|
175
|
+
force: args.includes('--force'),
|
|
176
|
+
verbose: args.includes('--verbose'),
|
|
177
|
+
debug: args.includes('--debug'),
|
|
178
|
+
simulateFailure
|
|
179
|
+
});
|
|
180
|
+
console.log(redactCredentials(JSON.stringify(result, null, 2)));
|
|
181
|
+
if (result && result.status !== 'completed' && result.status !== 'completed_with_warnings' && result.dryRun !== true) {
|
|
182
|
+
process.exitCode = 1;
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (args.includes('--dry-run')) return orchestraPlan(args.find(arg => arg !== '--dry-run' && arg !== '--force' && arg !== '--verbose' && arg !== '--debug'), { dryRun: true });
|
|
187
|
+
const idArg = args.find(arg => !arg.startsWith('--'));
|
|
188
|
+
return idArg
|
|
189
|
+
? runTask(idArg, { quiet: args.includes('--quiet'), force: args.includes('--force'), verbose: args.includes('--verbose'), debug: args.includes('--debug') })
|
|
190
|
+
: console.log('Usage: maestro run-task <id> [--quiet] [--verbose] [--debug] [--dry-run] [--force]');
|
|
191
|
+
}
|
|
192
|
+
case 'canary': {
|
|
193
|
+
if (!args[0]) return console.log('Usage: maestro canary <path>');
|
|
194
|
+
const { canaryCommand } = await import('../src/orchestration/self-hosting-canary.mjs');
|
|
195
|
+
return canaryCommand(args[0]);
|
|
196
|
+
}
|
|
197
|
+
case 'orchestrate': {
|
|
198
|
+
const parsed = parseOrchestrateArgs(args);
|
|
199
|
+
if (!parsed.idArg) return console.log('Usage: maestro orchestrate <id> [--real] [--force] [--parallel] [--max-concurrent=N]');
|
|
200
|
+
const result = await runSerialOrchestration({
|
|
201
|
+
taskId: parsed.idArg,
|
|
202
|
+
mode: args.includes('--real') ? 'real' : 'dry-run',
|
|
203
|
+
force: args.includes('--force'),
|
|
204
|
+
suppressOutput: args.includes('--quiet'),
|
|
205
|
+
concurrency: parsed.concurrency
|
|
206
|
+
});
|
|
207
|
+
console.log(redactCredentials(JSON.stringify(result, null, 2)));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
case 'run-all': return runAll({ quiet: args.includes('--quiet'), force: args.includes('--force'), verbose: args.includes('--verbose'), debug: args.includes('--debug'), dryRun: args.includes('--dry-run') });
|
|
211
|
+
case 'recover':
|
|
212
|
+
case 'reconcile': return reconcileCrashedTasks({ dryRun: args.includes('--dry-run') });
|
|
213
|
+
case 'retry': return args[0] ? retry(args[0]) : console.log('Usage: maestro retry <id>');
|
|
214
|
+
case 'task': return taskCommand(args);
|
|
215
|
+
case 'checkpoint': return checkpoint();
|
|
216
|
+
case 'handoff': return handoff();
|
|
217
|
+
case 'ui': {
|
|
218
|
+
const result = await startUiServer();
|
|
219
|
+
console.log('Maestro UI: ' + result.url);
|
|
220
|
+
return new Promise(() => {});
|
|
221
|
+
}
|
|
222
|
+
default:
|
|
223
|
+
console.log('Unknown command. Available commands: init, status, start, continue, doctor, provider-health, rc-check, codex-home, codex-home-diff, codex-home-inventory, codex-home-probe, codex-home-repair, codex-compare, codex-test, codex-sandbox-test, codex-debug, stats, release-check, readiness, canary, schema-check, run-log, report, plan, run-one, run-task, orchestrate, run-all, recover, reconcile, retry, task, checkpoint, handoff, ui, engines, route-task, preflight, orchestra-plan, budget');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function main() {
|
|
228
|
+
const command = process.argv[2];
|
|
229
|
+
const args = process.argv.slice(3);
|
|
230
|
+
const locked = needsLock(command, args);
|
|
231
|
+
if (locked) {
|
|
232
|
+
await acquireLock(command + (args.length ? ' ' + args.join(' ') : ''));
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
await dispatch(command, args);
|
|
236
|
+
} finally {
|
|
237
|
+
if (locked) {
|
|
238
|
+
await releaseLock();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
main().catch(error => {
|
|
244
|
+
console.error(error.message || error);
|
|
245
|
+
process.exitCode = 1;
|
|
246
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ai-maestro",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Project-local multi-agent orchestration CLI backed by ai-universal-memory.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"author": "Kinzart",
|
|
8
|
+
"bin": {
|
|
9
|
+
"maestro": "bin/maestro.mjs"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"bin",
|
|
13
|
+
"src",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"CHANGELOG.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"check": "node --check bin/maestro.mjs && node --check src/config.mjs && node --check src/shell.mjs && node --check src/schema.mjs && node --check src/lock.mjs && node --check src/memory-log.mjs && node --check src/format.mjs && node --check src/codex-home-inspect.mjs && node --check src/codex-diagnostics.mjs && node --check src/task-commands.mjs && node --check src/session-commands.mjs && node --check src/codex-home.mjs && node --check src/commands.mjs && node --check src/debug.mjs && node --check src/encoding-guard.mjs && node --check src/ui/server.mjs && node --check src/ui/state.mjs && node --check src/ui/commands.mjs && node --check src/ui/events.mjs && node --check src/engines/engine.mjs && node --check src/engines/codex-engine.mjs && node --check src/engines/ai-router-engine.mjs && node --check src/engines/registry.mjs && node --check src/smart-planner.mjs && node --check src/run-diagnostics.mjs && node --check src/planner.mjs && node --check src/workspace-diff.mjs && node --check src/runner.mjs && node --check src/tasks.mjs && node --check src/usage.mjs && node --check src/orchestration-commands.mjs && node --check src/orchestration/capability-registry.mjs && node --check src/orchestration/task-classifier.mjs && node --check src/orchestration/preflight.mjs && node --check src/orchestration/engine-selector.mjs && node --check src/orchestration/sector-managers.mjs && node --check src/orchestration/delegation-manager.mjs && node --check src/orchestration/fallback-graph.mjs && node --check src/orchestration/budget-manager.mjs && node --check src/orchestration/verifier.mjs && node --check src/orchestration/engine-history.mjs && node --check src/orchestration/engine-policy.mjs && node --check src/orchestration/runtime-gate.mjs && node --check src/orchestration/execution-context.mjs && node --check src/orchestration/failure-classifier.mjs && node --check src/orchestration/failure-evidence.mjs && node --check src/orchestration/provider-health.mjs && node --check src/orchestration/fallback-recommendation.mjs && node --check src/orchestration/provider-router.mjs && node --check src/orchestration/attempt-chain-runtime.mjs && node --check src/orchestration/fallback-chain-trail.mjs && node --check src/orchestration/fallback-chain-lock.mjs && node --check src/orchestration/fallback-executor.mjs && node --check src/orchestration/host-validation.mjs && node --check src/orchestration/spec-planner.mjs && node --check src/orchestration/deployment-intent.mjs && node --check src/orchestration/subtask-planner.mjs && node --check src/orchestration/delegation-executor.mjs && node --check src/orchestration/file-conflict-detector.mjs && node --check src/orchestration/consolidator.mjs && node --check src/orchestration/orchestration-loop.mjs && node --check src/orchestration/orchestration-scheduler.mjs && node --check src/orchestration/orchestration-runtime.mjs && node --check src/orchestration/orchestration-trail.mjs && node --check src/orchestration/self-hosting-readiness.mjs && node --check src/orchestration/self-hosting-canary.mjs && node --check src/orchestration/rc-policy.mjs && node --check src/orchestration/rc-check-adapters.mjs && node --check src/orchestration/rc-check.mjs",
|
|
20
|
+
"test": "node --test tests/*.test.mjs"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"ai",
|
|
24
|
+
"cli",
|
|
25
|
+
"codex",
|
|
26
|
+
"agents",
|
|
27
|
+
"memory"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { CONFIG } from './config.mjs';
|
|
4
|
+
import { execFileRaw } from './shell.mjs';
|
|
5
|
+
import { getTasks } from './tasks.mjs';
|
|
6
|
+
import { getRecentRuns } from './runner.mjs';
|
|
7
|
+
import { writeTextWithBackup } from './files.mjs';
|
|
8
|
+
|
|
9
|
+
const checkpointFilePath = path.join(CONFIG.maestroPath, 'CHECKPOINT.md');
|
|
10
|
+
|
|
11
|
+
async function readLastLines(filePath, limit = 5) {
|
|
12
|
+
try {
|
|
13
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
14
|
+
return content.split(/\r?\n/).filter(Boolean).slice(-limit);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (error.code === 'ENOENT') {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function generateCheckpoint() {
|
|
24
|
+
let checkpointContent = '# AI Maestro Checkpoint\n\n';
|
|
25
|
+
checkpointContent += '## Date and Time\n';
|
|
26
|
+
checkpointContent += '- ' + new Date().toISOString() + '\n\n';
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const branch = await execFileRaw('git', ['branch', '--show-current'], { quiet: true });
|
|
30
|
+
const status = await execFileRaw('git', ['status', '--porcelain'], { quiet: true });
|
|
31
|
+
checkpointContent += '## Git\n';
|
|
32
|
+
checkpointContent += '- Branch: ' + (branch.stdout.trim() || 'unknown') + '\n';
|
|
33
|
+
const gitStatusOutput = status.stdout.trim();
|
|
34
|
+
if (gitStatusOutput.trim()) {
|
|
35
|
+
checkpointContent += '- Uncommitted changes:\n\n```text\n' + gitStatusOutput + '\n```\n\n';
|
|
36
|
+
} else {
|
|
37
|
+
checkpointContent += '- No uncommitted changes.\n\n';
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
checkpointContent += '## Git\n- Git not found or current directory is not a Git repository.\n\n';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const tasks = await getTasks();
|
|
44
|
+
const pendingTasks = tasks.filter(task => task.status === 'pending');
|
|
45
|
+
const inProgressTasks = tasks.filter(task => task.status === 'in_progress');
|
|
46
|
+
const completedTasks = tasks.filter(task => task.status === 'completed');
|
|
47
|
+
const failedTasks = tasks.filter(task => task.status === 'failed');
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
checkpointContent += '## Tasks Overview\n';
|
|
51
|
+
checkpointContent += '- Total tasks: ' + tasks.length + '\n';
|
|
52
|
+
checkpointContent += '- Pending: ' + pendingTasks.length + '\n';
|
|
53
|
+
checkpointContent += '- In Progress: ' + inProgressTasks.length + '\n';
|
|
54
|
+
checkpointContent += '- Completed: ' + completedTasks.length + '\n';
|
|
55
|
+
checkpointContent += '- Failed: ' + failedTasks.length + '\n\n';
|
|
56
|
+
|
|
57
|
+
const groups = [
|
|
58
|
+
['Pending Tasks', pendingTasks],
|
|
59
|
+
['In Progress Tasks', inProgressTasks],
|
|
60
|
+
['Failed Tasks', failedTasks]
|
|
61
|
+
];
|
|
62
|
+
for (const [title, group] of groups) {
|
|
63
|
+
if (group.length > 0) {
|
|
64
|
+
checkpointContent += '### ' + title + '\n';
|
|
65
|
+
group.forEach(task => {
|
|
66
|
+
checkpointContent += '- #' + task.id + ' ' + (task.title || task.description) + '\n';
|
|
67
|
+
});
|
|
68
|
+
checkpointContent += '\n';
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const recentRuns = await getRecentRuns(5);
|
|
73
|
+
checkpointContent += '## Recent Runs\n';
|
|
74
|
+
if (recentRuns.length === 0) {
|
|
75
|
+
checkpointContent += '- No runs logged yet.\n\n';
|
|
76
|
+
} else {
|
|
77
|
+
for (const run of recentRuns) {
|
|
78
|
+
checkpointContent += '- Task #' + run.taskId + ' ' + run.status + ' at ' + (run.endTime || run.startTime || 'unknown') + '\n';
|
|
79
|
+
}
|
|
80
|
+
checkpointContent += '\n';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const recentEvents = await readLastLines(path.join(CONFIG.memoryPath, 'events.jsonl'), 5);
|
|
84
|
+
checkpointContent += '## Recent Memory Events\n';
|
|
85
|
+
if (recentEvents.length === 0) {
|
|
86
|
+
checkpointContent += '- No events found.\n\n';
|
|
87
|
+
} else {
|
|
88
|
+
for (const event of recentEvents) {
|
|
89
|
+
checkpointContent += '- `' + event.replace(/`/g, '') + '`\n';
|
|
90
|
+
}
|
|
91
|
+
checkpointContent += '\n';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
checkpointContent += '## Recommended Commands\n';
|
|
95
|
+
checkpointContent += '- maestro status\n';
|
|
96
|
+
checkpointContent += '- maestro doctor\n';
|
|
97
|
+
checkpointContent += '- maestro run-one\n';
|
|
98
|
+
checkpointContent += '- maestro handoff\n\n';
|
|
99
|
+
|
|
100
|
+
await writeTextWithBackup(checkpointFilePath, checkpointContent);
|
|
101
|
+
return checkpointContent;
|
|
102
|
+
}
|