@synergenius/flow-weaver-pack-weaver 0.9.0 → 0.9.4
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/dist/bot/ai-client.d.ts +22 -2
- package/dist/bot/ai-client.d.ts.map +1 -1
- package/dist/bot/ai-client.js +168 -20
- package/dist/bot/ai-client.js.map +1 -1
- package/dist/bot/ansi.d.ts +13 -0
- package/dist/bot/ansi.d.ts.map +1 -0
- package/dist/bot/ansi.js +13 -0
- package/dist/bot/ansi.js.map +1 -0
- package/dist/bot/assistant-core.d.ts +25 -0
- package/dist/bot/assistant-core.d.ts.map +1 -0
- package/dist/bot/assistant-core.js +272 -0
- package/dist/bot/assistant-core.js.map +1 -0
- package/dist/bot/assistant-tools.d.ts +10 -0
- package/dist/bot/assistant-tools.d.ts.map +1 -0
- package/dist/bot/assistant-tools.js +324 -0
- package/dist/bot/assistant-tools.js.map +1 -0
- package/dist/bot/audit-logger.d.ts.map +1 -1
- package/dist/bot/audit-logger.js +9 -5
- package/dist/bot/audit-logger.js.map +1 -1
- package/dist/bot/bot-manager.d.ts +49 -0
- package/dist/bot/bot-manager.d.ts.map +1 -0
- package/dist/bot/bot-manager.js +279 -0
- package/dist/bot/bot-manager.js.map +1 -0
- package/dist/bot/child-process-tracker.d.ts +6 -0
- package/dist/bot/child-process-tracker.d.ts.map +1 -0
- package/dist/bot/child-process-tracker.js +35 -0
- package/dist/bot/child-process-tracker.js.map +1 -0
- package/dist/bot/cli-provider.d.ts.map +1 -1
- package/dist/bot/cli-provider.js +13 -8
- package/dist/bot/cli-provider.js.map +1 -1
- package/dist/bot/conversation-store.d.ts +40 -0
- package/dist/bot/conversation-store.d.ts.map +1 -0
- package/dist/bot/conversation-store.js +182 -0
- package/dist/bot/conversation-store.js.map +1 -0
- package/dist/bot/error-classifier.d.ts +27 -0
- package/dist/bot/error-classifier.d.ts.map +1 -0
- package/dist/bot/error-classifier.js +71 -0
- package/dist/bot/error-classifier.js.map +1 -0
- package/dist/bot/error-guide.d.ts +5 -0
- package/dist/bot/error-guide.d.ts.map +1 -0
- package/dist/bot/error-guide.js +5 -0
- package/dist/bot/error-guide.js.map +1 -0
- package/dist/bot/knowledge-store.d.ts +17 -0
- package/dist/bot/knowledge-store.d.ts.map +1 -0
- package/dist/bot/knowledge-store.js +53 -0
- package/dist/bot/knowledge-store.js.map +1 -0
- package/dist/bot/paths.d.ts +11 -0
- package/dist/bot/paths.d.ts.map +1 -0
- package/dist/bot/paths.js +26 -0
- package/dist/bot/paths.js.map +1 -0
- package/dist/bot/retry-utils.d.ts +5 -0
- package/dist/bot/retry-utils.d.ts.map +1 -0
- package/dist/bot/retry-utils.js +5 -0
- package/dist/bot/retry-utils.js.map +1 -0
- package/dist/bot/runner.d.ts.map +1 -1
- package/dist/bot/runner.js +12 -1
- package/dist/bot/runner.js.map +1 -1
- package/dist/bot/safety.d.ts +10 -0
- package/dist/bot/safety.d.ts.map +1 -0
- package/dist/bot/safety.js +14 -0
- package/dist/bot/safety.js.map +1 -0
- package/dist/bot/session-state.d.ts.map +1 -1
- package/dist/bot/session-state.js +3 -1
- package/dist/bot/session-state.js.map +1 -1
- package/dist/bot/steering.js +2 -2
- package/dist/bot/steering.js.map +1 -1
- package/dist/bot/step-executor.d.ts +10 -5
- package/dist/bot/step-executor.d.ts.map +1 -1
- package/dist/bot/step-executor.js +252 -3
- package/dist/bot/step-executor.js.map +1 -1
- package/dist/bot/system-prompt.d.ts +1 -1
- package/dist/bot/system-prompt.d.ts.map +1 -1
- package/dist/bot/system-prompt.js +69 -43
- package/dist/bot/system-prompt.js.map +1 -1
- package/dist/bot/task-decomposer.d.ts +24 -0
- package/dist/bot/task-decomposer.d.ts.map +1 -0
- package/dist/bot/task-decomposer.js +75 -0
- package/dist/bot/task-decomposer.js.map +1 -0
- package/dist/bot/task-queue.d.ts +17 -4
- package/dist/bot/task-queue.d.ts.map +1 -1
- package/dist/bot/task-queue.js +83 -5
- package/dist/bot/task-queue.js.map +1 -1
- package/dist/bot/terminal-renderer.d.ts +60 -0
- package/dist/bot/terminal-renderer.d.ts.map +1 -0
- package/dist/bot/terminal-renderer.js +204 -0
- package/dist/bot/terminal-renderer.js.map +1 -0
- package/dist/bot/tool-registry.d.ts +24 -0
- package/dist/bot/tool-registry.d.ts.map +1 -0
- package/dist/bot/tool-registry.js +458 -0
- package/dist/bot/tool-registry.js.map +1 -0
- package/dist/bot/types.d.ts +7 -0
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/bot/weaver-tools.d.ts +18 -0
- package/dist/bot/weaver-tools.d.ts.map +1 -0
- package/dist/bot/weaver-tools.js +124 -0
- package/dist/bot/weaver-tools.js.map +1 -0
- package/dist/cli-bridge.d.ts.map +1 -1
- package/dist/cli-bridge.js +5 -1
- package/dist/cli-bridge.js.map +1 -1
- package/dist/cli-handlers.d.ts +13 -1
- package/dist/cli-handlers.d.ts.map +1 -1
- package/dist/cli-handlers.js +615 -48
- package/dist/cli-handlers.js.map +1 -1
- package/dist/mcp-tools.js +2 -2
- package/dist/mcp-tools.js.map +1 -1
- package/dist/node-types/abort-task.d.ts.map +1 -1
- package/dist/node-types/abort-task.js +4 -3
- package/dist/node-types/abort-task.js.map +1 -1
- package/dist/node-types/agent-execute.d.ts +38 -0
- package/dist/node-types/agent-execute.d.ts.map +1 -0
- package/dist/node-types/agent-execute.js +252 -0
- package/dist/node-types/agent-execute.js.map +1 -0
- package/dist/node-types/bot-report.d.ts +5 -3
- package/dist/node-types/bot-report.d.ts.map +1 -1
- package/dist/node-types/bot-report.js +39 -7
- package/dist/node-types/bot-report.js.map +1 -1
- package/dist/node-types/build-context.d.ts +3 -3
- package/dist/node-types/build-context.d.ts.map +1 -1
- package/dist/node-types/build-context.js +108 -24
- package/dist/node-types/build-context.js.map +1 -1
- package/dist/node-types/detect-provider.d.ts +2 -2
- package/dist/node-types/detect-provider.d.ts.map +1 -1
- package/dist/node-types/detect-provider.js +3 -1
- package/dist/node-types/detect-provider.js.map +1 -1
- package/dist/node-types/exec-validate-retry.d.ts.map +1 -1
- package/dist/node-types/exec-validate-retry.js +43 -6
- package/dist/node-types/exec-validate-retry.js.map +1 -1
- package/dist/node-types/execute-plan.d.ts.map +1 -1
- package/dist/node-types/execute-plan.js +31 -8
- package/dist/node-types/execute-plan.js.map +1 -1
- package/dist/node-types/execute-target.d.ts.map +1 -1
- package/dist/node-types/execute-target.js +3 -1
- package/dist/node-types/execute-target.js.map +1 -1
- package/dist/node-types/fix-errors.d.ts.map +1 -1
- package/dist/node-types/fix-errors.js +21 -5
- package/dist/node-types/fix-errors.js.map +1 -1
- package/dist/node-types/genesis-observe.d.ts.map +1 -1
- package/dist/node-types/genesis-observe.js +3 -1
- package/dist/node-types/genesis-observe.js.map +1 -1
- package/dist/node-types/genesis-report.js +4 -1
- package/dist/node-types/genesis-report.js.map +1 -1
- package/dist/node-types/git-ops.d.ts.map +1 -1
- package/dist/node-types/git-ops.js +98 -4
- package/dist/node-types/git-ops.js.map +1 -1
- package/dist/node-types/index.d.ts +2 -0
- package/dist/node-types/index.d.ts.map +1 -1
- package/dist/node-types/index.js +2 -0
- package/dist/node-types/index.js.map +1 -1
- package/dist/node-types/load-config.d.ts +2 -2
- package/dist/node-types/load-config.d.ts.map +1 -1
- package/dist/node-types/load-config.js.map +1 -1
- package/dist/node-types/plan-task.d.ts.map +1 -1
- package/dist/node-types/plan-task.js +14 -2
- package/dist/node-types/plan-task.js.map +1 -1
- package/dist/node-types/read-workflow.js +8 -2
- package/dist/node-types/read-workflow.js.map +1 -1
- package/dist/node-types/receive-task.d.ts.map +1 -1
- package/dist/node-types/receive-task.js +35 -26
- package/dist/node-types/receive-task.js.map +1 -1
- package/dist/node-types/send-notify.js +2 -1
- package/dist/node-types/send-notify.js.map +1 -1
- package/dist/node-types/validate-gate.d.ts +18 -0
- package/dist/node-types/validate-gate.d.ts.map +1 -0
- package/dist/node-types/validate-gate.js +96 -0
- package/dist/node-types/validate-gate.js.map +1 -0
- package/dist/workflows/genesis-task.d.ts +20 -12
- package/dist/workflows/genesis-task.d.ts.map +1 -1
- package/dist/workflows/genesis-task.js +20 -12
- package/dist/workflows/genesis-task.js.map +1 -1
- package/dist/workflows/weaver-agent.d.ts +35 -0
- package/dist/workflows/weaver-agent.d.ts.map +1 -0
- package/dist/workflows/weaver-agent.js +777 -0
- package/dist/workflows/weaver-agent.js.map +1 -0
- package/dist/workflows/weaver-bot-batch.d.ts +19 -26
- package/dist/workflows/weaver-bot-batch.d.ts.map +1 -1
- package/dist/workflows/weaver-bot-batch.js +1043 -27
- package/dist/workflows/weaver-bot-batch.js.map +1 -1
- package/dist/workflows/weaver-bot.d.ts +21 -35
- package/dist/workflows/weaver-bot.d.ts.map +1 -1
- package/dist/workflows/weaver-bot.js +1119 -36
- package/dist/workflows/weaver-bot.js.map +1 -1
- package/flowweaver.manifest.json +21 -1
- package/package.json +5 -2
- package/src/bot/ai-client.ts +180 -19
- package/src/bot/ansi.ts +12 -0
- package/src/bot/assistant-core.ts +312 -0
- package/src/bot/assistant-tools.ts +318 -0
- package/src/bot/audit-logger.ts +6 -5
- package/src/bot/bot-manager.ts +293 -0
- package/src/bot/child-process-tracker.ts +40 -0
- package/src/bot/cli-provider.ts +13 -8
- package/src/bot/conversation-store.ts +222 -0
- package/src/bot/error-classifier.ts +90 -0
- package/src/bot/error-guide.ts +4 -0
- package/src/bot/knowledge-store.ts +59 -0
- package/src/bot/paths.ts +27 -0
- package/src/bot/retry-utils.ts +4 -0
- package/src/bot/runner.ts +12 -1
- package/src/bot/safety.ts +16 -0
- package/src/bot/session-state.ts +2 -1
- package/src/bot/steering.ts +2 -2
- package/src/bot/step-executor.ts +313 -5
- package/src/bot/system-prompt.ts +70 -47
- package/src/bot/task-decomposer.ts +100 -0
- package/src/bot/task-queue.ts +100 -8
- package/src/bot/terminal-renderer.ts +238 -0
- package/src/bot/tool-registry.ts +477 -0
- package/src/bot/types.ts +8 -0
- package/src/bot/weaver-tools.ts +134 -0
- package/src/cli-bridge.ts +7 -1
- package/src/cli-handlers.ts +624 -48
- package/src/mcp-tools.ts +2 -2
- package/src/node-types/abort-task.ts +5 -4
- package/src/node-types/agent-execute.ts +303 -0
- package/src/node-types/bot-report.ts +40 -9
- package/src/node-types/build-context.ts +112 -25
- package/src/node-types/detect-provider.ts +4 -3
- package/src/node-types/exec-validate-retry.ts +47 -8
- package/src/node-types/execute-plan.ts +32 -8
- package/src/node-types/execute-target.ts +2 -1
- package/src/node-types/fix-errors.ts +20 -5
- package/src/node-types/genesis-observe.ts +2 -1
- package/src/node-types/genesis-report.ts +1 -1
- package/src/node-types/git-ops.ts +93 -4
- package/src/node-types/index.ts +2 -0
- package/src/node-types/load-config.ts +3 -3
- package/src/node-types/plan-task.ts +15 -3
- package/src/node-types/read-workflow.ts +2 -2
- package/src/node-types/receive-task.ts +31 -26
- package/src/node-types/send-notify.ts +1 -1
- package/src/node-types/validate-gate.ts +112 -0
- package/src/workflows/genesis-task.ts +20 -12
- package/src/workflows/weaver-agent.ts +799 -0
- package/src/workflows/weaver-bot-batch.ts +1049 -27
- package/src/workflows/weaver-bot.ts +1123 -36
package/dist/cli-handlers.js
CHANGED
|
@@ -32,6 +32,7 @@ export function parseArgs(argv) {
|
|
|
32
32
|
autoApprove: false,
|
|
33
33
|
genesisInit: false,
|
|
34
34
|
genesisWatch: false,
|
|
35
|
+
sessionContinuous: false,
|
|
35
36
|
};
|
|
36
37
|
const args = argv.slice(2);
|
|
37
38
|
let i = 0;
|
|
@@ -176,6 +177,18 @@ export function parseArgs(argv) {
|
|
|
176
177
|
else if (arg === 'session') {
|
|
177
178
|
result.command = 'session';
|
|
178
179
|
}
|
|
180
|
+
else if (arg === 'assistant') {
|
|
181
|
+
result.command = 'assistant';
|
|
182
|
+
}
|
|
183
|
+
else if (arg === 'examples') {
|
|
184
|
+
result.command = 'examples';
|
|
185
|
+
}
|
|
186
|
+
else if (arg === 'doctor') {
|
|
187
|
+
result.command = 'doctor';
|
|
188
|
+
}
|
|
189
|
+
else if (arg === 'status') {
|
|
190
|
+
result.command = 'status';
|
|
191
|
+
}
|
|
179
192
|
else if (arg === 'steer') {
|
|
180
193
|
result.command = 'steer';
|
|
181
194
|
// Next arg is the subcommand
|
|
@@ -237,6 +250,35 @@ export function parseArgs(argv) {
|
|
|
237
250
|
else if (arg === '--watch') {
|
|
238
251
|
result.genesisWatch = true;
|
|
239
252
|
}
|
|
253
|
+
else if (arg === '--new') {
|
|
254
|
+
result.assistantNew = true;
|
|
255
|
+
}
|
|
256
|
+
else if (arg === '--resume' && i + 1 < args.length) {
|
|
257
|
+
i++;
|
|
258
|
+
result.assistantResume = args[i];
|
|
259
|
+
}
|
|
260
|
+
else if (arg === '--list') {
|
|
261
|
+
result.assistantList = true;
|
|
262
|
+
}
|
|
263
|
+
else if (arg === '--delete' && i + 1 < args.length) {
|
|
264
|
+
i++;
|
|
265
|
+
result.assistantDelete = args[i];
|
|
266
|
+
}
|
|
267
|
+
else if (arg === '--continuous') {
|
|
268
|
+
result.sessionContinuous = true;
|
|
269
|
+
}
|
|
270
|
+
else if (arg === '--until' && i + 1 < args.length) {
|
|
271
|
+
i++;
|
|
272
|
+
result.sessionUntil = args[i];
|
|
273
|
+
}
|
|
274
|
+
else if (arg === '--max-tasks' && i + 1 < args.length) {
|
|
275
|
+
i++;
|
|
276
|
+
result.sessionMaxTasks = parseInt(args[i], 10) || undefined;
|
|
277
|
+
}
|
|
278
|
+
else if (arg === '--parallel' && i + 1 < args.length) {
|
|
279
|
+
i++;
|
|
280
|
+
result.sessionParallel = Math.min(Math.max(parseInt(args[i], 10) || 1, 1), 5);
|
|
281
|
+
}
|
|
240
282
|
else if (arg === '--project-dir' && i + 1 < args.length) {
|
|
241
283
|
i++;
|
|
242
284
|
result.file = args[i];
|
|
@@ -326,6 +368,14 @@ function printRunDetail(r) {
|
|
|
326
368
|
if (r.params) {
|
|
327
369
|
console.log(` Params: ${JSON.stringify(r.params)}`);
|
|
328
370
|
}
|
|
371
|
+
if (r.stepLog && r.stepLog.length > 0) {
|
|
372
|
+
console.log(`\n Steps (${r.stepLog.length}):`);
|
|
373
|
+
for (const entry of r.stepLog) {
|
|
374
|
+
const icon = entry.status === 'ok' ? '\x1b[32m+\x1b[0m' : entry.status === 'blocked' ? '\x1b[33m⚠\x1b[0m' : '\x1b[31m✗\x1b[0m';
|
|
375
|
+
const detail = entry.detail ? ` — ${entry.detail}` : '';
|
|
376
|
+
console.log(` ${icon} ${entry.step}${detail}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
329
379
|
console.log('');
|
|
330
380
|
}
|
|
331
381
|
function parseSince(spec) {
|
|
@@ -426,10 +476,20 @@ export async function handleCosts(opts) {
|
|
|
426
476
|
const sinceTs = parseSince(opts.costsSince);
|
|
427
477
|
const summary = store.summarize({ since: sinceTs, model: opts.costsModel });
|
|
428
478
|
if (summary.totalRuns === 0) {
|
|
429
|
-
|
|
479
|
+
if (opts.historyJson) {
|
|
480
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
console.log('No cost data found.');
|
|
484
|
+
}
|
|
430
485
|
return;
|
|
431
486
|
}
|
|
432
|
-
|
|
487
|
+
if (opts.historyJson) {
|
|
488
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
console.log(formatCostTable(summary));
|
|
492
|
+
}
|
|
433
493
|
}
|
|
434
494
|
export async function handleWatch(opts) {
|
|
435
495
|
if (!opts.file) {
|
|
@@ -653,6 +713,7 @@ export async function handleProviders() {
|
|
|
653
713
|
// --- Workflow map for eject and resolution ---
|
|
654
714
|
const MANAGED_WORKFLOWS = {
|
|
655
715
|
bot: 'weaver-bot',
|
|
716
|
+
agent: 'weaver-agent',
|
|
656
717
|
batch: 'weaver-bot-batch',
|
|
657
718
|
genesis: 'genesis-task',
|
|
658
719
|
};
|
|
@@ -1130,31 +1191,304 @@ export async function handleBot(opts) {
|
|
|
1130
1191
|
}
|
|
1131
1192
|
}
|
|
1132
1193
|
export async function handleSession(opts) {
|
|
1133
|
-
const
|
|
1194
|
+
const projectDir = opts.file ?? process.cwd();
|
|
1195
|
+
// Set project dir for per-project queue isolation
|
|
1196
|
+
process.env.WEAVER_PROJECT_DIR = projectDir;
|
|
1134
1197
|
const config = await loadConfig(opts.configPath);
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
}
|
|
1198
|
+
const workflowPath = resolveWorkflowPath('agent', projectDir);
|
|
1199
|
+
// Create terminal renderer for all session output
|
|
1200
|
+
const { TerminalRenderer } = await import('./bot/terminal-renderer.js');
|
|
1201
|
+
const renderer = new TerminalRenderer({ verbose: opts.verbose, quiet: opts.quiet });
|
|
1202
|
+
// Parse --until HH:MM into a deadline timestamp
|
|
1203
|
+
let deadline;
|
|
1204
|
+
let deadlineStr;
|
|
1205
|
+
if (opts.sessionUntil) {
|
|
1206
|
+
const match = opts.sessionUntil.match(/^(\d{1,2}):(\d{2})$/);
|
|
1207
|
+
if (match) {
|
|
1208
|
+
const now = new Date();
|
|
1209
|
+
const target = new Date(now);
|
|
1210
|
+
target.setHours(parseInt(match[1], 10), parseInt(match[2], 10), 0, 0);
|
|
1211
|
+
if (target.getTime() <= now.getTime())
|
|
1212
|
+
target.setDate(target.getDate() + 1);
|
|
1213
|
+
deadline = target.getTime();
|
|
1214
|
+
deadlineStr = target.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
const maxTasks = opts.sessionMaxTasks ?? Infinity;
|
|
1218
|
+
const continuous = opts.sessionContinuous || !!opts.sessionUntil || maxTasks < Infinity;
|
|
1219
|
+
const parallelism = opts.sessionParallel ?? 1;
|
|
1220
|
+
// Crash recovery
|
|
1221
|
+
if (continuous) {
|
|
1222
|
+
const { TaskQueue } = await import('./bot/task-queue.js');
|
|
1223
|
+
const recoveryQueue = new TaskQueue();
|
|
1224
|
+
const recovered = await recoveryQueue.recoverOrphans();
|
|
1225
|
+
if (recovered > 0)
|
|
1226
|
+
renderer.info(`Recovered ${recovered} orphaned task(s)`);
|
|
1227
|
+
}
|
|
1228
|
+
// Clean stale cache files
|
|
1139
1229
|
try {
|
|
1140
|
-
const
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1230
|
+
const { execSync: execSyncClean } = await import('node:child_process');
|
|
1231
|
+
const staleOutput = execSyncClean(`find "${projectDir}" -name "fw-exec-*" -type f`, { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
1232
|
+
if (staleOutput) {
|
|
1233
|
+
const staleFiles = staleOutput.split('\n').filter(Boolean);
|
|
1234
|
+
for (const f of staleFiles) {
|
|
1235
|
+
try {
|
|
1236
|
+
fs.unlinkSync(f);
|
|
1237
|
+
}
|
|
1238
|
+
catch { }
|
|
1239
|
+
}
|
|
1149
1240
|
}
|
|
1150
|
-
process.exit(result.success ? 0 : 1);
|
|
1151
1241
|
}
|
|
1152
|
-
catch
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1242
|
+
catch { /* non-fatal */ }
|
|
1243
|
+
// Detect provider label for session start
|
|
1244
|
+
const providerType = config?.provider ?? 'auto';
|
|
1245
|
+
const providerLabel = typeof providerType === 'object' ? providerType.name : String(providerType);
|
|
1246
|
+
const sessionStartTime = Date.now();
|
|
1247
|
+
renderer.sessionStart({ provider: providerLabel, parallel: parallelism, deadline: deadlineStr });
|
|
1248
|
+
// Single-run mode (backwards compatible)
|
|
1249
|
+
if (!continuous) {
|
|
1250
|
+
try {
|
|
1251
|
+
const result = await runWorkflow(workflowPath, {
|
|
1252
|
+
params: { projectDir },
|
|
1253
|
+
verbose: opts.verbose,
|
|
1254
|
+
dryRun: opts.dryRun,
|
|
1255
|
+
config,
|
|
1256
|
+
});
|
|
1257
|
+
if (!opts.quiet) {
|
|
1258
|
+
const color = result.success ? '\x1b[32m' : '\x1b[31m';
|
|
1259
|
+
console.log(`${color}Session: ${result.outcome}\x1b[0m`);
|
|
1260
|
+
}
|
|
1261
|
+
process.exit(result.success ? 0 : 1);
|
|
1262
|
+
}
|
|
1263
|
+
catch (err) {
|
|
1264
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1265
|
+
console.error(`\x1b[31m[weaver] Fatal: ${msg}\x1b[0m`);
|
|
1266
|
+
process.exit(1);
|
|
1267
|
+
}
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
// Continuous mode: loop until deadline/maxTasks/interrupt
|
|
1271
|
+
const { TaskQueue } = await import('./bot/task-queue.js');
|
|
1272
|
+
const { isTransientError, getErrorGuidance } = await import('./bot/error-classifier.js');
|
|
1273
|
+
const queue = new TaskQueue();
|
|
1274
|
+
let taskCount = 0;
|
|
1275
|
+
let interrupted = false;
|
|
1276
|
+
let consecutiveErrors = 0;
|
|
1277
|
+
let consecutiveNoOps = 0;
|
|
1278
|
+
const MAX_CONSECUTIVE_ERRORS = 3;
|
|
1279
|
+
const MAX_CONSECUTIVE_NO_OPS = 5;
|
|
1280
|
+
// Session stats
|
|
1281
|
+
let sessionCompleted = 0, sessionFailed = 0, sessionNoOp = 0;
|
|
1282
|
+
let sessionInputTokens = 0, sessionOutputTokens = 0, sessionCost = 0;
|
|
1283
|
+
process.on('SIGINT', () => { interrupted = true; });
|
|
1284
|
+
process.on('SIGTERM', () => { interrupted = true; });
|
|
1285
|
+
// Parallel task tracking
|
|
1286
|
+
const running = new Map();
|
|
1287
|
+
const filesInUse = new Set();
|
|
1288
|
+
const processTask = async (task) => {
|
|
1289
|
+
try {
|
|
1290
|
+
const result = await runWorkflow(workflowPath, {
|
|
1291
|
+
params: { projectDir, taskJson: JSON.stringify(task) },
|
|
1292
|
+
verbose: opts.verbose,
|
|
1293
|
+
dryRun: opts.dryRun,
|
|
1294
|
+
config,
|
|
1295
|
+
});
|
|
1296
|
+
// Classify outcome: the summary contains "no changes" or "0 files" for no-ops
|
|
1297
|
+
const isNoOp = result.success && (result.summary.includes('no changes') ||
|
|
1298
|
+
result.summary.includes('0 file') ||
|
|
1299
|
+
result.summary.includes("doesn't exist") ||
|
|
1300
|
+
result.summary.includes('does not exist') ||
|
|
1301
|
+
result.summary.includes('nothing to') ||
|
|
1302
|
+
result.outcome === 'no-op');
|
|
1303
|
+
if (isNoOp) {
|
|
1304
|
+
await queue.markNoOp(task.id);
|
|
1305
|
+
sessionNoOp++;
|
|
1306
|
+
consecutiveNoOps++;
|
|
1307
|
+
consecutiveErrors = 0;
|
|
1308
|
+
}
|
|
1309
|
+
else if (result.success) {
|
|
1310
|
+
await queue.markComplete(task.id);
|
|
1311
|
+
sessionCompleted++;
|
|
1312
|
+
consecutiveErrors = 0;
|
|
1313
|
+
consecutiveNoOps = 0;
|
|
1314
|
+
}
|
|
1315
|
+
else {
|
|
1316
|
+
await queue.markFailed(task.id, result.summary || result.outcome || 'unknown error');
|
|
1317
|
+
sessionFailed++;
|
|
1318
|
+
consecutiveErrors++;
|
|
1319
|
+
consecutiveNoOps = 0;
|
|
1320
|
+
}
|
|
1321
|
+
// Track cost from workflow result
|
|
1322
|
+
if (result.cost) {
|
|
1323
|
+
sessionInputTokens += result.cost.totalInputTokens ?? 0;
|
|
1324
|
+
sessionOutputTokens += result.cost.totalOutputTokens ?? 0;
|
|
1325
|
+
sessionCost += result.cost.totalCost ?? 0;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
catch (err) {
|
|
1329
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1330
|
+
const guidance = getErrorGuidance(msg);
|
|
1331
|
+
renderer.error(`Task ${task.id.slice(0, 8)} error`, guidance ? `${msg}\n Hint: ${guidance}` : msg);
|
|
1332
|
+
await queue.markFailed(task.id, msg);
|
|
1333
|
+
sessionFailed++;
|
|
1334
|
+
if (!isTransientError(err)) {
|
|
1335
|
+
consecutiveErrors++;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
finally {
|
|
1339
|
+
for (const f of task.targets ?? [])
|
|
1340
|
+
filesInUse.delete(f);
|
|
1341
|
+
running.delete(task.id);
|
|
1342
|
+
}
|
|
1343
|
+
};
|
|
1344
|
+
while (taskCount < maxTasks && !interrupted) {
|
|
1345
|
+
if (deadline && Date.now() >= deadline) {
|
|
1346
|
+
renderer.info('Deadline reached, stopping session.');
|
|
1347
|
+
break;
|
|
1348
|
+
}
|
|
1349
|
+
if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
|
|
1350
|
+
renderer.error('Session stopped', `${MAX_CONSECUTIVE_ERRORS} consecutive errors — check your API key or provider config.`);
|
|
1351
|
+
break;
|
|
1352
|
+
}
|
|
1353
|
+
// Pause on consecutive no-ops (bot is spinning without doing anything)
|
|
1354
|
+
if (consecutiveNoOps >= MAX_CONSECUTIVE_NO_OPS) {
|
|
1355
|
+
renderer.warn(`${MAX_CONSECUTIVE_NO_OPS} consecutive no-op tasks — pausing 60s`);
|
|
1356
|
+
await new Promise(r => setTimeout(r, 60_000));
|
|
1357
|
+
consecutiveNoOps = 0;
|
|
1358
|
+
}
|
|
1359
|
+
// Wait if at capacity
|
|
1360
|
+
if (running.size >= parallelism) {
|
|
1361
|
+
await Promise.race(running.values());
|
|
1362
|
+
continue;
|
|
1363
|
+
}
|
|
1364
|
+
const task = await queue.next();
|
|
1365
|
+
if (!task) {
|
|
1366
|
+
if (running.size > 0) {
|
|
1367
|
+
// Tasks still running — wait for one to finish
|
|
1368
|
+
await Promise.race(running.values());
|
|
1369
|
+
continue;
|
|
1370
|
+
}
|
|
1371
|
+
// No pending or running tasks — wait and retry
|
|
1372
|
+
await new Promise(r => setTimeout(r, 5_000));
|
|
1373
|
+
continue;
|
|
1374
|
+
}
|
|
1375
|
+
// Auto-decompose broad tasks into per-file tasks
|
|
1376
|
+
const { decomposeTask } = await import('./bot/task-decomposer.js');
|
|
1377
|
+
const { decomposed, tasks: subtasks } = decomposeTask(task, projectDir);
|
|
1378
|
+
if (decomposed && subtasks.length > 1) {
|
|
1379
|
+
// Replace the broad task with per-file tasks
|
|
1380
|
+
await queue.markComplete(task.id);
|
|
1381
|
+
let decomposedCount = 0;
|
|
1382
|
+
for (const st of subtasks) {
|
|
1383
|
+
const { duplicate } = await queue.add({ instruction: st.instruction, mode: st.mode, targets: st.targets, priority: st.priority ?? 0 });
|
|
1384
|
+
if (!duplicate)
|
|
1385
|
+
decomposedCount++;
|
|
1386
|
+
}
|
|
1387
|
+
renderer.info(`Decomposed into ${subtasks.length} per-file tasks`);
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1390
|
+
// File conflict check: if task targets overlap with files in use, wait
|
|
1391
|
+
const taskTargets = task.targets ?? [];
|
|
1392
|
+
const hasConflict = taskTargets.some(f => filesInUse.has(f));
|
|
1393
|
+
if (hasConflict && running.size > 0) {
|
|
1394
|
+
await Promise.race(running.values());
|
|
1395
|
+
continue;
|
|
1396
|
+
}
|
|
1397
|
+
taskCount++;
|
|
1398
|
+
if (opts.verbose)
|
|
1399
|
+
process.env.WEAVER_VERBOSE = '1';
|
|
1400
|
+
renderer.taskStart(taskCount, task.instruction ?? task.id);
|
|
1401
|
+
await queue.markRunning(task.id);
|
|
1402
|
+
// Reserve files
|
|
1403
|
+
for (const f of taskTargets)
|
|
1404
|
+
filesInUse.add(f);
|
|
1405
|
+
// Launch task (parallel or sequential based on parallelism setting)
|
|
1406
|
+
const promise = processTask(task);
|
|
1407
|
+
running.set(task.id, promise);
|
|
1408
|
+
// In sequential mode (parallelism=1), await immediately
|
|
1409
|
+
if (parallelism <= 1) {
|
|
1410
|
+
await promise;
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
// Wait for all remaining parallel tasks
|
|
1414
|
+
if (running.size > 0) {
|
|
1415
|
+
await Promise.allSettled(running.values());
|
|
1416
|
+
}
|
|
1417
|
+
const elapsed = Date.now() - sessionStartTime;
|
|
1418
|
+
renderer.sessionEnd({
|
|
1419
|
+
tasks: taskCount,
|
|
1420
|
+
completed: sessionCompleted,
|
|
1421
|
+
failed: sessionFailed,
|
|
1422
|
+
totalInputTokens: sessionInputTokens,
|
|
1423
|
+
totalOutputTokens: sessionOutputTokens,
|
|
1424
|
+
totalCost: sessionCost,
|
|
1425
|
+
elapsed,
|
|
1426
|
+
});
|
|
1427
|
+
// Desktop notification on session end (cross-platform)
|
|
1428
|
+
if (taskCount > 0) {
|
|
1429
|
+
try {
|
|
1430
|
+
const { sendDesktopNotification } = await import('./bot/bot-manager.js');
|
|
1431
|
+
sendDesktopNotification('Weaver Session Complete', `${sessionCompleted} done, ${sessionFailed} failed, ${sessionNoOp} no-op`);
|
|
1432
|
+
}
|
|
1433
|
+
catch { /* non-fatal */ }
|
|
1156
1434
|
}
|
|
1157
1435
|
}
|
|
1436
|
+
export async function handleAssistant(opts) {
|
|
1437
|
+
const projectDir = opts.file ?? process.cwd();
|
|
1438
|
+
// Handle --list and --delete before creating provider
|
|
1439
|
+
if (opts.assistantList) {
|
|
1440
|
+
const { ConversationStore } = await import('./bot/conversation-store.js');
|
|
1441
|
+
const { formatTokens, formatElapsed } = await import('./bot/terminal-renderer.js');
|
|
1442
|
+
const store = new ConversationStore();
|
|
1443
|
+
const convos = store.list();
|
|
1444
|
+
if (convos.length === 0) {
|
|
1445
|
+
console.log(' No conversations yet.');
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
console.log(` Conversations (${convos.length}):\n`);
|
|
1449
|
+
for (const c of convos) {
|
|
1450
|
+
const ago = formatElapsed(Date.now() - c.lastMessageAt) + ' ago';
|
|
1451
|
+
const title = c.title ? `"${c.title}"` : '(untitled)';
|
|
1452
|
+
console.log(` ${c.id} ${title.padEnd(45)} ${String(c.messageCount).padStart(3)} msgs ${formatTokens(c.totalTokens).padStart(5)} tokens ${ago}`);
|
|
1453
|
+
}
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
if (opts.assistantDelete) {
|
|
1457
|
+
const { ConversationStore } = await import('./bot/conversation-store.js');
|
|
1458
|
+
const store = new ConversationStore();
|
|
1459
|
+
store.delete(opts.assistantDelete);
|
|
1460
|
+
console.log(` Deleted conversation ${opts.assistantDelete}`);
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
const config = await loadConfig(opts.configPath);
|
|
1464
|
+
// Create provider
|
|
1465
|
+
const { createAnthropicProvider, createClaudeCliProvider } = await import('@synergenius/flow-weaver/agent');
|
|
1466
|
+
const providerSetting = config?.provider ?? 'auto';
|
|
1467
|
+
const providerType = typeof providerSetting === 'object' ? providerSetting.name : String(providerSetting);
|
|
1468
|
+
let provider;
|
|
1469
|
+
if (providerType === 'anthropic' || (providerType === 'auto' && process.env.ANTHROPIC_API_KEY)) {
|
|
1470
|
+
const apiKey = process.env.ANTHROPIC_API_KEY ?? (typeof providerSetting === 'object' ? providerSetting.apiKey : undefined);
|
|
1471
|
+
if (!apiKey) {
|
|
1472
|
+
console.error('ANTHROPIC_API_KEY required for anthropic provider');
|
|
1473
|
+
process.exit(1);
|
|
1474
|
+
}
|
|
1475
|
+
provider = createAnthropicProvider({ apiKey, model: typeof providerSetting === 'object' ? providerSetting.model : undefined });
|
|
1476
|
+
}
|
|
1477
|
+
else {
|
|
1478
|
+
provider = createClaudeCliProvider({ model: typeof providerSetting === 'object' ? providerSetting.model : undefined });
|
|
1479
|
+
}
|
|
1480
|
+
const { ASSISTANT_TOOLS, createAssistantExecutor } = await import('./bot/assistant-tools.js');
|
|
1481
|
+
const { runAssistant } = await import('./bot/assistant-core.js');
|
|
1482
|
+
const executor = createAssistantExecutor(projectDir);
|
|
1483
|
+
await runAssistant({
|
|
1484
|
+
provider,
|
|
1485
|
+
tools: ASSISTANT_TOOLS,
|
|
1486
|
+
executor,
|
|
1487
|
+
projectDir,
|
|
1488
|
+
resumeId: opts.assistantResume,
|
|
1489
|
+
newConversation: opts.assistantNew,
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1158
1492
|
export async function handleSteer(opts) {
|
|
1159
1493
|
const { SteeringController } = await import('./bot/steering.js');
|
|
1160
1494
|
const controller = new SteeringController();
|
|
@@ -1175,8 +1509,8 @@ export async function handleQueue(opts) {
|
|
|
1175
1509
|
const { TaskQueue } = await import('./bot/task-queue.js');
|
|
1176
1510
|
const queue = new TaskQueue();
|
|
1177
1511
|
const action = opts.botTask;
|
|
1178
|
-
if (!action || !['add', 'list', 'clear', 'remove'].includes(action)) {
|
|
1179
|
-
console.error('[weaver] Usage: flow-weaver weaver queue <add|list|clear|remove> [task|id]');
|
|
1512
|
+
if (!action || !['add', 'list', 'clear', 'remove', 'retry'].includes(action)) {
|
|
1513
|
+
console.error('[weaver] Usage: flow-weaver weaver queue <add|list|clear|remove|retry> [task|id]');
|
|
1180
1514
|
process.exit(1);
|
|
1181
1515
|
}
|
|
1182
1516
|
switch (action) {
|
|
@@ -1186,19 +1520,27 @@ export async function handleQueue(opts) {
|
|
|
1186
1520
|
console.error('[weaver] Usage: flow-weaver weaver queue add "task instruction"');
|
|
1187
1521
|
process.exit(1);
|
|
1188
1522
|
}
|
|
1189
|
-
const id = await queue.add({ instruction, priority: 0 });
|
|
1190
|
-
|
|
1523
|
+
const { id, duplicate } = await queue.add({ instruction, priority: 0 });
|
|
1524
|
+
if (duplicate) {
|
|
1525
|
+
console.log(`[weaver] Task already queued (${id}).`);
|
|
1526
|
+
}
|
|
1527
|
+
else {
|
|
1528
|
+
console.log(`[weaver] Task added: ${id}`);
|
|
1529
|
+
}
|
|
1191
1530
|
break;
|
|
1192
1531
|
}
|
|
1193
1532
|
case 'list': {
|
|
1194
1533
|
const tasks = await queue.list();
|
|
1195
|
-
if (
|
|
1534
|
+
if (opts.historyJson) {
|
|
1535
|
+
console.log(JSON.stringify(tasks, null, 2));
|
|
1536
|
+
}
|
|
1537
|
+
else if (tasks.length === 0) {
|
|
1196
1538
|
console.log('No tasks in queue.');
|
|
1197
1539
|
}
|
|
1198
1540
|
else {
|
|
1199
|
-
console.log('ID'.padEnd(10) + 'STATUS'.padEnd(12) + 'INSTRUCTION');
|
|
1541
|
+
console.log('ID'.padEnd(10) + 'STATUS'.padEnd(12) + 'PRIORITY'.padEnd(10) + 'INSTRUCTION');
|
|
1200
1542
|
for (const t of tasks) {
|
|
1201
|
-
console.log(t.id.padEnd(10) + t.status.padEnd(12) + t.instruction.slice(0, 60));
|
|
1543
|
+
console.log(t.id.padEnd(10) + t.status.padEnd(12) + String(t.priority).padEnd(10) + t.instruction.slice(0, 60));
|
|
1202
1544
|
}
|
|
1203
1545
|
}
|
|
1204
1546
|
break;
|
|
@@ -1218,7 +1560,60 @@ export async function handleQueue(opts) {
|
|
|
1218
1560
|
console.log(removed ? `Removed task ${id}.` : `No task found with id "${id}".`);
|
|
1219
1561
|
break;
|
|
1220
1562
|
}
|
|
1563
|
+
case 'retry': {
|
|
1564
|
+
const id = opts.botFile;
|
|
1565
|
+
if (id) {
|
|
1566
|
+
// Retry a specific task
|
|
1567
|
+
const retried = await queue.retry(id);
|
|
1568
|
+
console.log(retried ? `Task ${id} reset to pending.` : `No failed/running task found with id "${id}".`);
|
|
1569
|
+
}
|
|
1570
|
+
else {
|
|
1571
|
+
// Retry all failed tasks
|
|
1572
|
+
const count = await queue.retryAll();
|
|
1573
|
+
console.log(`Reset ${count} failed task(s) to pending.`);
|
|
1574
|
+
}
|
|
1575
|
+
break;
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
export async function handleStatus(opts) {
|
|
1580
|
+
const store = new RunStore();
|
|
1581
|
+
const { TaskQueue } = await import('./bot/task-queue.js');
|
|
1582
|
+
const queue = new TaskQueue();
|
|
1583
|
+
const orphans = store.checkOrphans();
|
|
1584
|
+
const recentRuns = store.list({ limit: 5 });
|
|
1585
|
+
const tasks = await queue.list();
|
|
1586
|
+
const pending = tasks.filter(t => t.status === 'pending').length;
|
|
1587
|
+
const running = tasks.filter(t => t.status === 'running').length;
|
|
1588
|
+
const completed = tasks.filter(t => t.status === 'completed').length;
|
|
1589
|
+
const failed = tasks.filter(t => t.status === 'failed').length;
|
|
1590
|
+
if (opts.historyJson) {
|
|
1591
|
+
console.log(JSON.stringify({
|
|
1592
|
+
queue: { pending, running, completed, failed, total: tasks.length },
|
|
1593
|
+
orphanedRuns: orphans.length,
|
|
1594
|
+
recentRuns: recentRuns.map(r => ({
|
|
1595
|
+
id: r.id, outcome: r.outcome, summary: r.summary,
|
|
1596
|
+
startedAt: r.startedAt, durationMs: r.durationMs,
|
|
1597
|
+
})),
|
|
1598
|
+
}, null, 2));
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
console.log('\n\x1b[1mWeaver Status\x1b[0m\n');
|
|
1602
|
+
console.log(` Queue: ${pending} pending, ${running} running, ${completed} completed, ${failed} failed`);
|
|
1603
|
+
if (orphans.length > 0) {
|
|
1604
|
+
console.log(` \x1b[33mOrphaned runs: ${orphans.length} (recovered)\x1b[0m`);
|
|
1605
|
+
}
|
|
1606
|
+
if (recentRuns.length > 0) {
|
|
1607
|
+
console.log(`\n Recent runs:`);
|
|
1608
|
+
for (const r of recentRuns) {
|
|
1609
|
+
const icon = r.success ? '\x1b[32m✓\x1b[0m' : '\x1b[31m✗\x1b[0m';
|
|
1610
|
+
console.log(` ${icon} ${r.id.slice(0, 8)} ${r.outcome.padEnd(9)} ${formatDuration(r.durationMs).padEnd(8)} ${r.summary.slice(0, 60)}`);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
else {
|
|
1614
|
+
console.log('\n No recent runs.');
|
|
1221
1615
|
}
|
|
1616
|
+
console.log('');
|
|
1222
1617
|
}
|
|
1223
1618
|
export async function handleGenesis(opts) {
|
|
1224
1619
|
const projectDir = opts.file ?? process.cwd();
|
|
@@ -1353,6 +1748,7 @@ const COMMAND_HELP = {
|
|
|
1353
1748
|
genesis: 'genesis [--init] [--watch] Run self-evolution cycle',
|
|
1354
1749
|
eject: 'eject [--workflow bot|genesis] Export managed workflows',
|
|
1355
1750
|
audit: 'audit [runId] [--limit N] View audit log',
|
|
1751
|
+
assistant: 'assistant AI-powered assistant for managing bots and workflows',
|
|
1356
1752
|
};
|
|
1357
1753
|
export function printHelp(command) {
|
|
1358
1754
|
if (command && command !== 'help' && COMMAND_HELP[command]) {
|
|
@@ -1440,28 +1836,34 @@ export async function handleInit(opts) {
|
|
|
1440
1836
|
console.log(' Edit it directly or delete it to regenerate.');
|
|
1441
1837
|
return;
|
|
1442
1838
|
}
|
|
1443
|
-
// Detect best available provider
|
|
1839
|
+
// Detect best available provider (priority: Anthropic API > OpenAI API > Claude CLI > Copilot CLI)
|
|
1444
1840
|
let provider = 'auto';
|
|
1841
|
+
const detected = [];
|
|
1445
1842
|
try {
|
|
1446
1843
|
if (process.env.ANTHROPIC_API_KEY) {
|
|
1447
1844
|
provider = 'anthropic';
|
|
1845
|
+
detected.push('Anthropic API (ANTHROPIC_API_KEY)');
|
|
1448
1846
|
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1847
|
+
if (process.env.OPENAI_API_KEY) {
|
|
1848
|
+
if (provider === 'auto')
|
|
1849
|
+
provider = 'openai';
|
|
1850
|
+
detected.push('OpenAI API (OPENAI_API_KEY)');
|
|
1851
|
+
}
|
|
1852
|
+
const { execFileSync } = await import('node:child_process');
|
|
1853
|
+
try {
|
|
1854
|
+
execFileSync('claude', ['--version'], { stdio: 'pipe' });
|
|
1855
|
+
if (provider === 'auto')
|
|
1453
1856
|
provider = 'claude-cli';
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1857
|
+
detected.push('Claude CLI');
|
|
1858
|
+
}
|
|
1859
|
+
catch { /* not found */ }
|
|
1860
|
+
try {
|
|
1861
|
+
execFileSync('copilot', ['--version'], { stdio: 'pipe' });
|
|
1862
|
+
if (provider === 'auto')
|
|
1863
|
+
provider = 'copilot-cli';
|
|
1864
|
+
detected.push('Copilot CLI');
|
|
1464
1865
|
}
|
|
1866
|
+
catch { /* not found */ }
|
|
1465
1867
|
}
|
|
1466
1868
|
catch {
|
|
1467
1869
|
// Stay with auto
|
|
@@ -1471,11 +1873,176 @@ export async function handleInit(opts) {
|
|
|
1471
1873
|
approval: 'auto',
|
|
1472
1874
|
};
|
|
1473
1875
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
1474
|
-
console.log(`\x1b[32m✓\x1b[0m Created ${configPath}`);
|
|
1475
|
-
console.log(` Provider: ${provider}`);
|
|
1476
1876
|
console.log('');
|
|
1477
|
-
console.log('
|
|
1478
|
-
console.log('
|
|
1479
|
-
console.log('
|
|
1877
|
+
console.log(' \x1b[1mWelcome to Weaver\x1b[0m — your AI workflow companion.');
|
|
1878
|
+
console.log('');
|
|
1879
|
+
console.log(' \x1b[2mDetecting providers...\x1b[0m');
|
|
1880
|
+
if (detected.length > 0) {
|
|
1881
|
+
for (const d of detected)
|
|
1882
|
+
console.log(` \x1b[32m✓\x1b[0m ${d}`);
|
|
1883
|
+
}
|
|
1884
|
+
else {
|
|
1885
|
+
console.log(' \x1b[33m⚠\x1b[0m No provider detected');
|
|
1886
|
+
console.log(' Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or install Claude CLI');
|
|
1887
|
+
}
|
|
1888
|
+
console.log('');
|
|
1889
|
+
// Test connection if possible
|
|
1890
|
+
if (provider === 'claude-cli') {
|
|
1891
|
+
try {
|
|
1892
|
+
const { execFileSync: testExec } = await import('node:child_process');
|
|
1893
|
+
testExec('claude', ['--version'], { stdio: 'pipe', timeout: 5000 });
|
|
1894
|
+
console.log(' \x1b[2mTesting connection...\x1b[0m');
|
|
1895
|
+
console.log(' \x1b[32m✓\x1b[0m Claude CLI: connected');
|
|
1896
|
+
}
|
|
1897
|
+
catch {
|
|
1898
|
+
console.log(' \x1b[33m⚠\x1b[0m Could not verify Claude CLI connection');
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
console.log('');
|
|
1902
|
+
console.log(` \x1b[32m✓\x1b[0m Config written to .weaver.json`);
|
|
1903
|
+
console.log(` provider: ${provider}`);
|
|
1904
|
+
console.log(' approval: auto');
|
|
1905
|
+
console.log('');
|
|
1906
|
+
console.log(' Try it now:');
|
|
1907
|
+
console.log(' \x1b[36mweaver bot "Create a hello world workflow"\x1b[0m');
|
|
1908
|
+
console.log(' \x1b[36mweaver assistant\x1b[0m');
|
|
1909
|
+
console.log('');
|
|
1910
|
+
console.log(' Learn more:');
|
|
1911
|
+
console.log(' weaver examples \x1b[2m# see what weaver can do\x1b[0m');
|
|
1912
|
+
console.log(' weaver doctor \x1b[2m# validate your setup\x1b[0m');
|
|
1913
|
+
console.log('');
|
|
1914
|
+
}
|
|
1915
|
+
export async function handleExamples(_opts) {
|
|
1916
|
+
console.log('');
|
|
1917
|
+
console.log(' \x1b[1mWeaver Examples\x1b[0m');
|
|
1918
|
+
console.log('');
|
|
1919
|
+
console.log(' \x1b[36mCreate workflows:\x1b[0m');
|
|
1920
|
+
console.log(' weaver bot "Create a workflow that validates user input and sends email"');
|
|
1921
|
+
console.log(' weaver bot "Create a data pipeline that reads CSV, transforms, and writes JSON"');
|
|
1922
|
+
console.log(' weaver bot "Create an AI agent with retry and fallback providers"');
|
|
1923
|
+
console.log(' weaver bot "Create a webhook handler that processes Stripe events"');
|
|
1924
|
+
console.log(' weaver bot "Create a RAG pipeline with document chunking and embedding"');
|
|
1925
|
+
console.log('');
|
|
1926
|
+
console.log(' \x1b[36mModify existing workflows:\x1b[0m');
|
|
1927
|
+
console.log(' weaver bot "Add error handling to my-workflow.ts" --file src/my-workflow.ts');
|
|
1928
|
+
console.log(' weaver bot "Add a validation step before the API call" --file src/pipeline.ts');
|
|
1929
|
+
console.log(' weaver bot "Make the retry node use exponential backoff" --file src/agent.ts');
|
|
1930
|
+
console.log('');
|
|
1931
|
+
console.log(' \x1b[36mInteractive assistant:\x1b[0m');
|
|
1932
|
+
console.log(' weaver assistant \x1b[2m# AI assistant with tools\x1b[0m');
|
|
1933
|
+
console.log(' weaver assistant --new \x1b[2m# fresh conversation\x1b[0m');
|
|
1934
|
+
console.log(' weaver assistant --list \x1b[2m# saved conversations\x1b[0m');
|
|
1935
|
+
console.log('');
|
|
1936
|
+
console.log(' \x1b[36mAutonomous mode:\x1b[0m');
|
|
1937
|
+
console.log(' weaver session --continuous \x1b[2m# process task queue\x1b[0m');
|
|
1938
|
+
console.log(' weaver queue add "Fix all validation errors"');
|
|
1939
|
+
console.log(' weaver session --continuous --until 10:00 --parallel 3');
|
|
1940
|
+
console.log('');
|
|
1941
|
+
console.log(' \x1b[36mInspect and debug:\x1b[0m');
|
|
1942
|
+
console.log(' flow-weaver validate src/*.ts \x1b[2m# check all workflows\x1b[0m');
|
|
1943
|
+
console.log(' flow-weaver diagram src/my-workflow.ts \x1b[2m# visual diagram\x1b[0m');
|
|
1944
|
+
console.log(' flow-weaver describe src/my-workflow.ts \x1b[2m# natural language description\x1b[0m');
|
|
1945
|
+
console.log('');
|
|
1946
|
+
console.log(' \x1b[36mCustomize the bot:\x1b[0m');
|
|
1947
|
+
console.log(' weaver eject \x1b[2m# get editable bot workflow\x1b[0m');
|
|
1948
|
+
console.log(' weaver eject --workflow bot \x1b[2m# eject specific workflow\x1b[0m');
|
|
1949
|
+
console.log('');
|
|
1950
|
+
}
|
|
1951
|
+
export async function handleDoctor(opts) {
|
|
1952
|
+
const dir = opts.file ?? process.cwd();
|
|
1953
|
+
const checks = [];
|
|
1954
|
+
// Config check
|
|
1955
|
+
const configPath = path.join(dir, '.weaver.json');
|
|
1956
|
+
if (fs.existsSync(configPath)) {
|
|
1957
|
+
checks.push({ label: 'Config', status: 'ok', detail: '.weaver.json found' });
|
|
1958
|
+
}
|
|
1959
|
+
else {
|
|
1960
|
+
checks.push({ label: 'Config', status: 'warn', detail: 'No .weaver.json — run "weaver init"' });
|
|
1961
|
+
}
|
|
1962
|
+
// Provider check
|
|
1963
|
+
const config = await loadConfig(opts.configPath);
|
|
1964
|
+
const providerSetting = config?.provider ?? 'auto';
|
|
1965
|
+
const providerName = typeof providerSetting === 'object' ? providerSetting.name : String(providerSetting);
|
|
1966
|
+
let providerDetail = providerName;
|
|
1967
|
+
if (providerName === 'anthropic' || process.env.ANTHROPIC_API_KEY) {
|
|
1968
|
+
providerDetail = 'anthropic (API key set)';
|
|
1969
|
+
checks.push({ label: 'Provider', status: 'ok', detail: providerDetail });
|
|
1970
|
+
}
|
|
1971
|
+
else {
|
|
1972
|
+
try {
|
|
1973
|
+
const { execFileSync: provCheck } = await import('node:child_process');
|
|
1974
|
+
provCheck('claude', ['--version'], { stdio: 'pipe', timeout: 5000 });
|
|
1975
|
+
providerDetail = 'claude-cli';
|
|
1976
|
+
checks.push({ label: 'Provider', status: 'ok', detail: providerDetail });
|
|
1977
|
+
}
|
|
1978
|
+
catch {
|
|
1979
|
+
checks.push({ label: 'Provider', status: 'fail', detail: 'No provider found — set ANTHROPIC_API_KEY or install Claude CLI' });
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
// Connection test
|
|
1983
|
+
if (providerName === 'claude-cli' || (!process.env.ANTHROPIC_API_KEY && providerName === 'auto')) {
|
|
1984
|
+
try {
|
|
1985
|
+
const { execFileSync: connCheck } = await import('node:child_process');
|
|
1986
|
+
const start = Date.now();
|
|
1987
|
+
connCheck('claude', ['-p', '--max-turns', '1', 'say ok'], { stdio: 'pipe', timeout: 15000 });
|
|
1988
|
+
checks.push({ label: 'Connection', status: 'ok', detail: `OK (${((Date.now() - start) / 1000).toFixed(1)}s)` });
|
|
1989
|
+
}
|
|
1990
|
+
catch {
|
|
1991
|
+
checks.push({ label: 'Connection', status: 'warn', detail: 'Could not verify (Claude CLI may need auth)' });
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
else if (process.env.ANTHROPIC_API_KEY) {
|
|
1995
|
+
checks.push({ label: 'Connection', status: 'ok', detail: 'API key configured' });
|
|
1996
|
+
}
|
|
1997
|
+
else {
|
|
1998
|
+
checks.push({ label: 'Connection', status: 'warn', detail: 'Not tested' });
|
|
1999
|
+
}
|
|
2000
|
+
// Flow Weaver version
|
|
2001
|
+
try {
|
|
2002
|
+
const { execFileSync: fwCheck } = await import('node:child_process');
|
|
2003
|
+
const version = fwCheck('npx', ['flow-weaver', '--version'], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 10000, cwd: dir }).trim();
|
|
2004
|
+
checks.push({ label: 'Flow Weaver', status: 'ok', detail: version });
|
|
2005
|
+
}
|
|
2006
|
+
catch {
|
|
2007
|
+
checks.push({ label: 'Flow Weaver', status: 'fail', detail: 'Not installed — run "npm install @synergenius/flow-weaver"' });
|
|
2008
|
+
}
|
|
2009
|
+
// Queue status
|
|
2010
|
+
try {
|
|
2011
|
+
const { TaskQueue } = await import('./bot/task-queue.js');
|
|
2012
|
+
process.env.WEAVER_PROJECT_DIR = dir;
|
|
2013
|
+
const queue = new TaskQueue();
|
|
2014
|
+
const tasks = await queue.list();
|
|
2015
|
+
const pending = tasks.filter(t => t.status === 'pending').length;
|
|
2016
|
+
const running = tasks.filter(t => t.status === 'running').length;
|
|
2017
|
+
checks.push({ label: 'Queue', status: 'ok', detail: `${pending} pending, ${running} running` });
|
|
2018
|
+
}
|
|
2019
|
+
catch {
|
|
2020
|
+
checks.push({ label: 'Queue', status: 'ok', detail: 'Empty (no queue file)' });
|
|
2021
|
+
}
|
|
2022
|
+
// Plan file
|
|
2023
|
+
const planPath = path.join(dir, '.weaver-plan.md');
|
|
2024
|
+
if (fs.existsSync(planPath)) {
|
|
2025
|
+
checks.push({ label: 'Plan', status: 'ok', detail: '.weaver-plan.md found' });
|
|
2026
|
+
}
|
|
2027
|
+
else {
|
|
2028
|
+
checks.push({ label: 'Plan', status: 'warn', detail: 'No .weaver-plan.md — optional, guides bot behavior' });
|
|
2029
|
+
}
|
|
2030
|
+
// Output
|
|
2031
|
+
console.log('');
|
|
2032
|
+
console.log(' \x1b[1mWeaver Doctor\x1b[0m');
|
|
2033
|
+
console.log('');
|
|
2034
|
+
const icons = { ok: '\x1b[32m✓\x1b[0m', warn: '\x1b[33m⚠\x1b[0m', fail: '\x1b[31m✗\x1b[0m' };
|
|
2035
|
+
for (const check of checks) {
|
|
2036
|
+
console.log(` ${icons[check.status]} ${check.label.padEnd(14)} ${check.detail}`);
|
|
2037
|
+
}
|
|
2038
|
+
console.log('');
|
|
2039
|
+
const failures = checks.filter(c => c.status === 'fail');
|
|
2040
|
+
if (failures.length > 0) {
|
|
2041
|
+
console.log(` \x1b[31m${failures.length} issue(s) found.\x1b[0m`);
|
|
2042
|
+
}
|
|
2043
|
+
else {
|
|
2044
|
+
console.log(' \x1b[32mAll checks passed.\x1b[0m');
|
|
2045
|
+
}
|
|
2046
|
+
console.log('');
|
|
1480
2047
|
}
|
|
1481
2048
|
//# sourceMappingURL=cli-handlers.js.map
|