@wrongstack/cli 0.6.3 → 0.6.5

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/index.js CHANGED
@@ -3,7 +3,7 @@ import * as path23 from 'path';
3
3
  import { join } from 'path';
4
4
  import * as fsp2 from 'fs/promises';
5
5
  import { readdir, readFile } from 'fs/promises';
6
- import { color, DefaultPathResolver, TOKENS, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, EventBus, SlashCommandRegistry, createDelegateTool, FLEET_ROSTER, createMcpControlTool, EternalAutonomyEngine, DefaultLogger, DefaultModelsRegistry, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, AutoCompactionMiddleware, estimateRequestTokens, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeAgentSubagentRunner, NULL_FLEET_BUS, resolveWstackPaths, DefaultSecretVault, migratePlaintextSecrets, DefaultConfigLoader, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, atomicWrite, DefaultPluginAPI, AutoApprovePermissionPolicy, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, resolveContextWindowPolicy, formatTodosList, emptyPlan, clearPlan, savePlan, formatPlanTemplates, getPlanTemplate, addPlanItem, formatPlan, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, SpecStore, TaskGraphStore, SpecVersioning, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, loadGoal, goalFilePath, summarizeUsage, emptyGoal, saveGoal, buildGoalPreamble, formatGoal, InputBuilder, projectHash, defaultOrchestrator, decryptConfigSecrets, encryptConfigSecrets as encryptConfigSecrets$1, allServers as allServers$1 } from '@wrongstack/core';
6
+ import { color, DefaultPathResolver, TOKENS, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, EventBus, SlashCommandRegistry, createDelegateTool, FLEET_ROSTER, createMcpControlTool, EternalAutonomyEngine, DefaultLogger, DefaultModelsRegistry, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, AutoCompactionMiddleware, estimateRequestTokens, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeAgentSubagentRunner, NULL_FLEET_BUS, resolveWstackPaths, DefaultSecretVault, migratePlaintextSecrets, DefaultConfigLoader, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, atomicWrite, DefaultPluginAPI, AutoApprovePermissionPolicy, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, resolveContextWindowPolicy, formatTodosList, emptyPlan, clearPlan, savePlan, formatPlanTemplates, getPlanTemplate, addPlanItem, formatPlan, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, SpecStore, TaskGraphStore, SpecVersioning, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, InputBuilder, projectHash, defaultOrchestrator, decryptConfigSecrets, encryptConfigSecrets as encryptConfigSecrets$1, ParallelEternalEngine, allServers as allServers$1 } from '@wrongstack/core';
7
7
  import { createRequire } from 'module';
8
8
  import * as os6 from 'os';
9
9
  import os6__default from 'os';
@@ -1687,6 +1687,7 @@ ${diff}`;
1687
1687
  // src/arg-parser.ts
1688
1688
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
1689
1689
  "yolo",
1690
+ "force-all-yolo",
1690
1691
  "verbose",
1691
1692
  "trace",
1692
1693
  "help",
@@ -2886,8 +2887,9 @@ function buildClearCommand(opts) {
2886
2887
  " /clear",
2887
2888
  "",
2888
2889
  "Wipes everything in the current REPL state: messages, todos, read-file tracking,",
2889
- "file mtimes, meta. Memory store entries (all scopes) are cleared too. The terminal",
2890
- "is wiped. Use this when you want a fresh conversation without restarting `wstack`."
2890
+ "file mtimes, meta. Memory store entries (all scopes) are cleared too. Chat",
2891
+ "history on disk is reset. The terminal is wiped.",
2892
+ "Use this when you want a fresh conversation without restarting `wstack`."
2891
2893
  ].join("\n"),
2892
2894
  async run(_args, ctx) {
2893
2895
  if (ctx) {
@@ -2897,6 +2899,12 @@ function buildClearCommand(opts) {
2897
2899
  ctx.fileMtimes.clear();
2898
2900
  for (const key of Object.keys(ctx.meta)) ctx.state.deleteMeta(key);
2899
2901
  }
2902
+ if (ctx?.session) {
2903
+ await ctx.session.clearSession();
2904
+ }
2905
+ if (opts.sessionStore) {
2906
+ await opts.sessionStore.clearHistory(ctx?.session.id ?? "");
2907
+ }
2900
2908
  await opts.memoryStore?.clear();
2901
2909
  opts.onClear?.();
2902
2910
  opts.renderer.clear();
@@ -3230,99 +3238,226 @@ function buildStatsCommand(opts) {
3230
3238
  }
3231
3239
  };
3232
3240
  }
3233
-
3234
- // src/slash-commands/fleet.ts
3235
3241
  function buildFleetCommand(opts) {
3236
3242
  return {
3237
3243
  name: "fleet",
3238
- description: "Inspect or control the subagent fleet: /fleet [status|usage|kill <id>|manifest|concurrency [N]|retry [taskId]|log <id>|stream on|off|help]",
3244
+ description: "Inspect and control the agent fleet (subagents, parallel slots).",
3239
3245
  help: [
3240
3246
  "Usage:",
3241
- " /fleet Show fleet status (alias for /fleet status).",
3242
- " /fleet status Pending + completed subagent task table.",
3243
- " /fleet usage Per-subagent runtime cost.",
3244
- " /fleet kill <id> Terminate a running subagent.",
3245
- " /fleet manifest Print the director manifest.",
3246
- " /fleet concurrency Show the current concurrent-subagent ceiling.",
3247
- " /fleet concurrency N Set the ceiling to N (>= 1). Lowering does not preempt running tasks.",
3248
- " /fleet retry List interrupted tasks from the last run.",
3249
- " /fleet retry <taskId> Re-spawn the matching subagent and re-assign the task.",
3250
- " /fleet retry all Re-assign every interrupted task at once.",
3251
- " /fleet log List subagent transcripts available on disk.",
3252
- " /fleet log <id> Print a compact summary of a subagent transcript.",
3253
- " /fleet log <id> raw Dump the full per-subagent JSONL.",
3254
- " /fleet stream on|off Show/hide subagent activity in the main history.",
3255
- " /fleet help Show this help."
3247
+ " /fleet Show fleet status (default)",
3248
+ " /fleet status Same as /fleet (verbose status)",
3249
+ " /fleet spawn <role> [count] Spawn N subagents of a role (default 1)",
3250
+ " /fleet terminate <subagentId> Stop a specific subagent by id",
3251
+ " /fleet kill Stop all running subagents",
3252
+ " /fleet usage Token and cost breakdown across the fleet",
3253
+ " /fleet journal Show recent journal entries from /goal journal",
3254
+ "",
3255
+ "Works during /autonomy parallel mode and standalone director sessions."
3256
3256
  ].join("\n"),
3257
3257
  async run(args) {
3258
- if (!opts.onFleet) return { message: "Multi-agent is not enabled in this session." };
3259
- const trimmed = args.trim();
3260
- const [verb, ...rest] = trimmed.length === 0 ? ["status"] : trimmed.split(/\s+/);
3261
- const target = rest.join(" ").trim() || void 0;
3262
- switch (verb) {
3263
- case "status":
3264
- case "usage":
3265
- case "manifest": {
3266
- const out = await opts.onFleet(verb, void 0);
3267
- return { message: out };
3268
- }
3269
- case "kill": {
3270
- if (!target) return { message: "Usage: /fleet kill <subagent-id>" };
3271
- return { message: await opts.onFleet("kill", target) };
3272
- }
3273
- case "concurrency": {
3274
- return { message: await opts.onFleet("concurrency", target) };
3275
- }
3276
- case "retry": {
3277
- if (!opts.onFleetRetry) {
3278
- return { message: "Retry is only available when director mode is active." };
3258
+ const parts = args.trim().split(/\s+/);
3259
+ const cmd = parts[0]?.toLowerCase() ?? "";
3260
+ const subargs = parts.slice(1);
3261
+ if (!cmd || cmd === "status" || cmd === "info" || cmd === "manifest") {
3262
+ if (opts.onFleetStatus) {
3263
+ const status = opts.onFleetStatus();
3264
+ if (!status) {
3265
+ const msg4 = `${color.amber("\u26A0 No fleet active.")} Start /autonomy parallel first, or pass --director to a session.`;
3266
+ opts.renderer.write(msg4);
3267
+ return { message: msg4 };
3279
3268
  }
3280
- const msg = await opts.onFleetRetry(target);
3281
- return { message: msg };
3282
- }
3283
- case "log": {
3284
- if (!opts.onFleetLog) {
3285
- return { message: "Log inspection is only available when a fleet root is configured." };
3269
+ const lines = [];
3270
+ lines.push(`${color.bold("Fleet Status")}`);
3271
+ lines.push(
3272
+ color.dim(
3273
+ ` coordinator: ${status.coordinatorId} \xB7 pending: ${status.pendingTasks} \xB7 done: ${status.completedTasks}`
3274
+ )
3275
+ );
3276
+ if (status.subagents.length === 0) {
3277
+ lines.push(color.dim(" No active subagents."));
3278
+ } else {
3279
+ lines.push("");
3280
+ lines.push(
3281
+ ` ${color.bold("ID").padEnd(36)} ${color.bold("NAME").padEnd(16)} ${color.bold("STATUS").padEnd(10)} ${color.bold("TASK")}`
3282
+ );
3283
+ lines.push(color.dim(" " + "\u2500".repeat(80)));
3284
+ for (const sa of status.subagents) {
3285
+ const id = sa.id?.padEnd(36) ?? "".padEnd(36);
3286
+ const name = (sa.name ?? "worker").padEnd(16);
3287
+ const statusColor = sa.status === "running" ? color.green(sa.status.padEnd(10)) : sa.status === "idle" ? color.dim(sa.status.padEnd(10)) : color.dim(sa.status.padEnd(10));
3288
+ const task = sa.currentTask ?? color.dim("\u2014");
3289
+ lines.push(` ${id} ${name} ${statusColor} ${task}`);
3290
+ }
3286
3291
  }
3287
- const [id, ...modeRest] = rest;
3288
- const mode = modeRest.join(" ").trim() === "raw" ? "raw" : "summary";
3289
- return { message: await opts.onFleetLog(id, mode) };
3290
- }
3291
- case "stream": {
3292
- const ctrl = opts.fleetStreamController;
3293
- if (!ctrl) {
3294
- return { message: "Stream toggle is only available in the TUI." };
3292
+ const msg3 = lines.join("\n");
3293
+ opts.renderer.write(msg3);
3294
+ return { message: msg3 };
3295
+ }
3296
+ if (opts.onFleet) {
3297
+ const msg3 = await opts.onFleet(cmd || "status", void 0);
3298
+ return { message: msg3 };
3299
+ }
3300
+ const msg2 = `${color.amber("\u26A0 No fleet active.")} Start /autonomy parallel first, or pass --director to a session.`;
3301
+ opts.renderer.write(msg2);
3302
+ return { message: msg2 };
3303
+ }
3304
+ if (cmd === "usage" || cmd === "cost" || cmd === "tokens") {
3305
+ if (opts.onFleetUsage) {
3306
+ const usage = opts.onFleetUsage();
3307
+ if (!usage) {
3308
+ const msg4 = `${color.amber("\u26A0 No fleet usage data.")} Start /autonomy parallel first.`;
3309
+ opts.renderer.write(msg4);
3310
+ return { message: msg4 };
3295
3311
  }
3296
- const arg = (target ?? "").toLowerCase();
3297
- if (arg === "" || arg === "status") {
3298
- return { message: `Fleet streaming is ${ctrl.enabled ? "on" : "off"}.` };
3312
+ const totalCost = usage.total?.cost ?? 0;
3313
+ const totalIn = usage.total?.input ?? 0;
3314
+ const totalOut = usage.total?.output ?? 0;
3315
+ const lines = [];
3316
+ lines.push(`${color.bold("Fleet Usage")}`);
3317
+ lines.push(
3318
+ ` ${color.dim("Total:")} ${color.green(`${totalCost.toFixed(4)}`)} \xB7 ${color.cyan(totalIn.toLocaleString())} in \xB7 ${color.cyan(totalOut.toLocaleString())} out`
3319
+ );
3320
+ const subagents = Object.values(usage.perSubagent);
3321
+ if (subagents.length > 0) {
3322
+ lines.push("");
3323
+ for (const sa of subagents) {
3324
+ const name = (sa.subagentId ?? "?").padEnd(20);
3325
+ const cost = `${(sa.cost ?? 0).toFixed(4)}`.padStart(10);
3326
+ const tokens = `${sa.input ?? 0} in / ${sa.output ?? 0} out`.padEnd(30);
3327
+ lines.push(` ${color.dim(name)} ${color.cyan(cost)} ${color.dim(tokens)}`);
3328
+ }
3299
3329
  }
3300
- if (arg !== "on" && arg !== "off") {
3301
- return { message: "Usage: /fleet stream on|off" };
3330
+ const msg3 = lines.join("\n");
3331
+ opts.renderer.write(msg3);
3332
+ return { message: msg3 };
3333
+ }
3334
+ if (opts.onFleet) {
3335
+ const msg3 = await opts.onFleet("usage", void 0);
3336
+ return { message: msg3 };
3337
+ }
3338
+ const msg2 = `${color.amber("\u26A0 No fleet usage data.")} Start /autonomy parallel first.`;
3339
+ opts.renderer.write(msg2);
3340
+ return { message: msg2 };
3341
+ }
3342
+ if (cmd === "retry") {
3343
+ if (opts.onFleetRetry) {
3344
+ const targetId = subargs[0];
3345
+ const msg3 = await opts.onFleetRetry(targetId);
3346
+ return { message: msg3 };
3347
+ }
3348
+ if (opts.onFleet) {
3349
+ const msg3 = await opts.onFleet("retry", subargs[0]);
3350
+ return { message: msg3 };
3351
+ }
3352
+ const msg2 = `Retry is only available when director mode is active.`;
3353
+ opts.renderer.writeWarning(msg2);
3354
+ return { message: msg2 };
3355
+ }
3356
+ if (cmd === "journal" || cmd === "log") {
3357
+ if (opts.onFleetLog) {
3358
+ const subagentId = subargs[0];
3359
+ const mode = subargs[1] === "raw" ? "raw" : "summary";
3360
+ const msg3 = await opts.onFleetLog(subagentId, mode);
3361
+ return { message: msg3 };
3362
+ }
3363
+ if (opts.onFleet) {
3364
+ const msg3 = await opts.onFleet("log", subargs[0]);
3365
+ return { message: msg3 };
3366
+ }
3367
+ const msg2 = `${color.dim("No journal entries yet.")}`;
3368
+ opts.renderer.write(msg2);
3369
+ return { message: msg2 };
3370
+ }
3371
+ if (cmd === "kill" || cmd === "stop-all") {
3372
+ const targetId = subargs[0];
3373
+ if (!targetId) {
3374
+ const msg3 = `Usage: /fleet kill <subagent-id>`;
3375
+ opts.renderer.writeWarning(msg3);
3376
+ return { message: msg3 };
3377
+ }
3378
+ if (opts.onFleetKill) {
3379
+ const killed = opts.onFleetKill();
3380
+ const msg3 = `${color.red("\u2717 Killed")} ${killed} subagent(s).`;
3381
+ opts.renderer.write(msg3);
3382
+ return { message: msg3 };
3383
+ }
3384
+ if (opts.onFleet) {
3385
+ const msg3 = await opts.onFleet("kill", targetId);
3386
+ return { message: msg3 };
3387
+ }
3388
+ const msg2 = `${color.amber("\u26A0 /fleet kill is not wired in this session.")}`;
3389
+ opts.renderer.writeWarning(msg2);
3390
+ return { message: msg2 };
3391
+ }
3392
+ if (cmd === "terminate" || cmd === "stop") {
3393
+ const targetId = subargs[0];
3394
+ if (!targetId) {
3395
+ const msg2 = `${color.amber("\u26A0 /fleet terminate requires a subagentId.")} Use /fleet to see active ids.`;
3396
+ opts.renderer.writeWarning(msg2);
3397
+ return { message: msg2 };
3398
+ }
3399
+ if (!opts.onFleetTerminate) {
3400
+ const msg2 = `${color.amber("\u26A0 /fleet terminate is not wired in this session.")}`;
3401
+ opts.renderer.writeWarning(msg2);
3402
+ return { message: msg2 };
3403
+ }
3404
+ const ok = opts.onFleetTerminate(targetId);
3405
+ if (ok) {
3406
+ const msg2 = `${color.green("\u2713 Terminated")} subagent ${color.bold(targetId)}.`;
3407
+ opts.renderer.write(msg2);
3408
+ return { message: msg2 };
3409
+ } else {
3410
+ const msg2 = `${color.red("\u2717 Failed")} to terminate ${color.bold(targetId)}. Subagent may already be stopped.`;
3411
+ opts.renderer.writeWarning(msg2);
3412
+ return { message: msg2 };
3413
+ }
3414
+ }
3415
+ if (cmd === "spawn" || cmd === "add") {
3416
+ const role = subargs[0] ?? "worker";
3417
+ const count = Math.min(16, Math.max(1, parseInt(subargs[1] ?? "1", 10) || 1));
3418
+ if (!opts.onFleetSpawn) {
3419
+ const msg3 = `${color.amber("\u26A0 /fleet spawn is not wired in this session.")}`;
3420
+ opts.renderer.writeWarning(msg3);
3421
+ return { message: msg3 };
3422
+ }
3423
+ const spawned = [];
3424
+ let msg2;
3425
+ for (let i = 0; i < count; i++) {
3426
+ try {
3427
+ const id = await opts.onFleetSpawn(role);
3428
+ spawned.push(id);
3429
+ } catch (err) {
3430
+ const msg3 = `${color.red("\u2717 Spawn failed")} for slot ${i + 1}: ${err instanceof Error ? err.message : String(err)}`;
3431
+ opts.renderer.writeWarning(msg3);
3302
3432
  }
3303
- const enabled = arg === "on";
3304
- ctrl.setEnabled(enabled);
3305
- ctrl.enabled = enabled;
3306
- return { message: `Fleet streaming ${enabled ? "enabled" : "disabled"}.` };
3307
3433
  }
3308
- case "help":
3309
- case "?":
3310
- return {
3311
- message: [
3312
- "/fleet \u2014 inspect or control the subagent fleet",
3313
- "",
3314
- " /fleet \u2192 status (default)",
3315
- " /fleet status pending + completed tasks per subagent",
3316
- " /fleet usage iterations, tool calls, duration roll-up",
3317
- " /fleet kill <id> terminate a subagent",
3318
- " /fleet manifest director manifest (requires --director)"
3319
- ].join("\n")
3320
- };
3321
- default:
3322
- return {
3323
- message: `Unknown subcommand "${verb}". Try: status | usage | kill <id> | manifest | help`
3324
- };
3434
+ if (spawned.length === count) {
3435
+ msg2 = `${color.green("\u2713 Spawned")} ${count} subagent(s) of role ${color.bold(role)}.`;
3436
+ opts.renderer.write(msg2);
3437
+ } else {
3438
+ msg2 = `${color.amber("\u26A0 Spawned")} ${spawned.length}/${count} subagent(s). Check /fleet for details.`;
3439
+ opts.renderer.writeWarning(msg2);
3440
+ }
3441
+ return { message: msg2 };
3442
+ }
3443
+ if (cmd === "help" || cmd === "?") {
3444
+ const msg2 = [
3445
+ `${color.bold("Fleet Commands")}`,
3446
+ ` ${color.dim("/fleet")} Show fleet status (default)`,
3447
+ ` ${color.dim("/fleet status")} Same as /fleet (verbose status)`,
3448
+ ` ${color.dim("/fleet spawn <role> [count]")} Spawn N subagents of a role (default 1)`,
3449
+ ` ${color.dim("/fleet terminate <subagentId>")} Stop a specific subagent by id`,
3450
+ ` ${color.dim("/fleet kill")} Stop all running subagents`,
3451
+ ` ${color.dim("/fleet usage")} Token and cost breakdown across the fleet`,
3452
+ ` ${color.dim("/fleet journal")} Show recent journal entries from /goal journal`
3453
+ ].join("\n");
3454
+ opts.renderer.write(msg2);
3455
+ return { message: msg2 };
3325
3456
  }
3457
+ const valid = ["status", "usage", "spawn", "terminate", "kill", "retry", "journal"];
3458
+ const msg = `Unknown subcommand "${cmd}". Valid subcommands: ${valid.join(", ")}. Run /fleet with no args to see status, or /fleet help for usage.`;
3459
+ opts.renderer.writeWarning(msg);
3460
+ return { message: msg };
3326
3461
  }
3327
3462
  };
3328
3463
  }
@@ -4128,8 +4263,9 @@ function buildAutonomyCommand(opts) {
4128
4263
  " /autonomy suggest Show next-step suggestions after each turn",
4129
4264
  " /autonomy on Auto-continue \u2014 agent picks next step and proceeds",
4130
4265
  " /autonomy eternal Sittin-sene mode \u2014 runs forever against /goal",
4266
+ " /autonomy parallel Parallel mode \u2014 4-8 agents per tick, fan-out parallelism",
4131
4267
  " /autonomy stop Stop eternal mode (no-op for other modes)",
4132
- " /autonomy toggle Cycle: off \u2192 suggest \u2192 auto \u2192 eternal \u2192 off",
4268
+ " /autonomy toggle Cycle: off \u2192 suggest \u2192 auto \u2192 eternal \u2192 parallel \u2192 off",
4133
4269
  "",
4134
4270
  "Modes:",
4135
4271
  " off \u2014 Normal interactive mode. Agent stops and waits.",
@@ -4138,8 +4274,11 @@ function buildAutonomyCommand(opts) {
4138
4274
  " Runs indefinitely until you press Esc or Ctrl+C.",
4139
4275
  " eternal \u2014 Goal-driven sense/decide/execute/reflect loop. Requires /goal.",
4140
4276
  " Force-enables YOLO. Runs until /autonomy stop or Ctrl+C twice.",
4277
+ " parallel \u2014 Fan-out 4\u20138 subagents per tick. Each tick decomposes the goal,",
4278
+ " spawns N agents, awaits results, aggregates. Requires /goal.",
4279
+ " Force-enables YOLO. Runs until /autonomy stop or Ctrl+C twice.",
4141
4280
  "",
4142
- "In auto/eternal modes the agent works autonomously. Press Esc to redirect,",
4281
+ "In auto/eternal/parallel modes the agent works autonomously. Press Esc to redirect,",
4143
4282
  "Ctrl+C to stop the active iteration. /autonomy stop ends the eternal loop."
4144
4283
  ].join("\n"),
4145
4284
  async run(args) {
@@ -4155,9 +4294,10 @@ function buildAutonomyCommand(opts) {
4155
4294
  off: `${color.green("OFF")} ${color.dim("(agent stops after each turn)")}`,
4156
4295
  suggest: `${color.cyan("SUGGEST")} ${color.dim("(shows next-step suggestions)")}`,
4157
4296
  auto: `${color.yellow("AUTO")} ${color.dim("(self-driving \u2014 Esc to redirect, Ctrl+C to stop)")}`,
4158
- eternal: `${color.red("ETERNAL")} ${color.dim("(sittin-sene \u2014 goal-driven, YOLO, until /autonomy stop)")}`
4297
+ eternal: `${color.red("ETERNAL")} ${color.dim("(sittin-sene \u2014 goal-driven, YOLO, until /autonomy stop)")}`,
4298
+ "eternal-parallel": `${color.magenta("PARALLEL")} ${color.dim("(4-8 subagents per tick \u2014 fan-out, until /autonomy stop)")}`
4159
4299
  };
4160
- const lines = [`Autonomy mode: ${labels2[current]}`];
4300
+ const lines = [`Autonomy mode: ${labels2[current] ?? current}`];
4161
4301
  try {
4162
4302
  const goal = await loadGoal(goalFilePath(opts.projectRoot));
4163
4303
  if (goal) {
@@ -4189,6 +4329,8 @@ function buildAutonomyCommand(opts) {
4189
4329
  opts.renderer.writeWarning(msg3);
4190
4330
  return { message: msg3 };
4191
4331
  }
4332
+ opts.getEternalEngine?.()?.stop();
4333
+ opts.getParallelEngine?.()?.stop();
4192
4334
  opts.onEternalStop();
4193
4335
  opts.onAutonomy("off");
4194
4336
  let summaryLine = "";
@@ -4206,7 +4348,7 @@ function buildAutonomyCommand(opts) {
4206
4348
  }
4207
4349
  } catch {
4208
4350
  }
4209
- const msg2 = `${color.amber("Eternal mode stop requested.")} The current iteration will finish, then the loop exits.${summaryLine}`;
4351
+ const msg2 = `${color.amber("Eternal/parallel mode stop requested.")} The current iteration will finish, then the loop exits.${summaryLine}`;
4210
4352
  opts.renderer.write(msg2);
4211
4353
  return { message: msg2 };
4212
4354
  }
@@ -4219,19 +4361,27 @@ function buildAutonomyCommand(opts) {
4219
4361
  newMode = "suggest";
4220
4362
  } else if (arg === "eternal" || arg === "forever" || arg === "infinite" || arg === "sittinsene") {
4221
4363
  newMode = "eternal";
4364
+ } else if (arg === "parallel" || arg === "eternal-parallel" || arg === "fanout") {
4365
+ newMode = "eternal-parallel";
4222
4366
  } else if (arg === "toggle" || arg === "cycle") {
4223
4367
  const current = opts.onAutonomy() ?? "off";
4224
4368
  const cycle = ["off", "suggest", "auto", "eternal"];
4225
4369
  newMode = cycle[(cycle.indexOf(current) + 1) % cycle.length] ?? "off";
4226
4370
  } else {
4227
- const msg2 = `Unknown argument: ${arg}. Use /autonomy on, off, suggest, eternal, stop, or toggle.`;
4371
+ const msg2 = `Unknown argument: ${arg}. Use /autonomy on, off, suggest, eternal, parallel, stop, or toggle.`;
4228
4372
  opts.renderer.writeWarning(msg2);
4229
4373
  return { message: msg2 };
4230
4374
  }
4231
- if (newMode === "eternal") {
4375
+ if (newMode === "eternal" || newMode === "eternal-parallel") {
4232
4376
  const goal = await loadGoal(goalFilePath(opts.projectRoot));
4233
4377
  if (!goal) {
4234
- const msg3 = `${color.red("Eternal mode requires a goal.")} Run \`/goal set <mission>\` first.`;
4378
+ const msg3 = `${color.red("Eternal/parallel mode requires a goal.")} Run \`/goal set <mission>\` first.`;
4379
+ opts.renderer.writeWarning(msg3);
4380
+ return { message: msg3 };
4381
+ }
4382
+ const isStale = goal.iterations > 0 || goal.engineState === "running";
4383
+ if (isStale) {
4384
+ const msg3 = `${color.amber("Stale goal detected.")} Previous mission has ${goal.iterations} iterations (engineState: ${goal.engineState}). Clear it first: ${color.bold("/goal clear")}, then set a new one: ${color.bold("/goal set <mission>")}.`;
4235
4385
  opts.renderer.writeWarning(msg3);
4236
4386
  return { message: msg3 };
4237
4387
  }
@@ -4242,14 +4392,15 @@ function buildAutonomyCommand(opts) {
4242
4392
  }
4243
4393
  if (opts.onYolo) opts.onYolo(true);
4244
4394
  opts.onAutonomy(newMode);
4245
- opts.onEternalStart();
4246
- const msg2 = `${color.red("Autonomy mode: ETERNAL")} \u2014 engine launching against goal: ${color.bold(goal.goal)}
4395
+ opts.onEternalStart(newMode);
4396
+ const modeLabel = newMode === "eternal-parallel" ? `${color.magenta("PARALLEL")} mode` : `${color.red("ETERNAL")} mode`;
4397
+ const msg2 = `Autonomy mode: ${modeLabel} \u2014 engine launching against goal: ${color.bold(goal.goal)}
4247
4398
  ${color.dim("YOLO forced ON. Use /autonomy stop to end. Journal at /goal journal.")}`;
4248
4399
  opts.renderer.write(msg2);
4249
4400
  return { message: msg2 };
4250
4401
  }
4251
4402
  const previous = opts.onAutonomy();
4252
- if (previous === "eternal" && opts.onEternalStop) {
4403
+ if ((previous === "eternal" || previous === "eternal-parallel") && opts.onEternalStop) {
4253
4404
  opts.onEternalStop();
4254
4405
  }
4255
4406
  opts.onAutonomy(newMode);
@@ -4257,7 +4408,8 @@ ${color.dim("YOLO forced ON. Use /autonomy stop to end. Journal at /goal journal
4257
4408
  off: `${color.green("OFF")} \u2014 agent stops after each turn`,
4258
4409
  suggest: `${color.cyan("SUGGEST")} \u2014 shows next-step suggestions after each turn`,
4259
4410
  auto: `${color.yellow("AUTO")} \u2014 self-driving, agent continues automatically`,
4260
- eternal: `${color.red("ETERNAL")} \u2014 goal-driven sittin-sene loop`
4411
+ eternal: `${color.red("ETERNAL")} \u2014 goal-driven sittin-sene loop`,
4412
+ "eternal-parallel": `${color.magenta("PARALLEL")} \u2014 fan-out 4-8 subagents per tick`
4261
4413
  };
4262
4414
  const msg = `Autonomy mode: ${labels[newMode]}`;
4263
4415
  opts.renderer.write(msg);
@@ -4338,13 +4490,15 @@ ${color.dim(`Stored in ${goalPath} \u2014 Esc / /steer to redirect, Ctrl+C to st
4338
4490
  opts.renderer.write(msg2);
4339
4491
  return { message: msg2 };
4340
4492
  }
4493
+ const abandoned = { ...existing, goalState: "abandoned" };
4494
+ await saveGoal(goalPath, abandoned);
4341
4495
  const { unlink: unlink4 } = await import('fs/promises');
4342
4496
  try {
4343
4497
  await unlink4(goalPath);
4344
4498
  } catch {
4345
4499
  }
4346
4500
  if (opts.onEternalStop) opts.onEternalStop();
4347
- const msg = `${color.amber("Goal cleared.")} Eternal mode will stop on next cycle.`;
4501
+ const msg = `${color.amber("Goal cleared.")} Previous goal marked abandoned; eternal mode will stop.`;
4348
4502
  opts.renderer.write(msg);
4349
4503
  return { message: msg };
4350
4504
  }
@@ -4819,6 +4973,821 @@ function buildStatuslineCommand(deps) {
4819
4973
  }
4820
4974
  };
4821
4975
  }
4976
+
4977
+ // src/slash-commands/fix-classifier.ts
4978
+ var TS = ["typescript-strict"];
4979
+ var BH = ["bug-hunter"];
4980
+ var SS = ["security-scanner"];
4981
+ var NM = ["node-modern"];
4982
+ var RM = ["react-modern"];
4983
+ var P = [
4984
+ // ── TypeScript ──────────────────────────────────────────────────────────────
4985
+ {
4986
+ pat: /\bTS\d+\b/,
4987
+ cat: "ts",
4988
+ sub: "typescript",
4989
+ lang: "typescript",
4990
+ hints: TS,
4991
+ detail: "TypeScript error",
4992
+ code: (m) => m[0],
4993
+ conf: 1
4994
+ },
4995
+ {
4996
+ pat: /\btypescript\b.*\berror\b|\berror\b.*\btypescript\b/i,
4997
+ cat: "ts",
4998
+ sub: "typescript",
4999
+ lang: "typescript",
5000
+ hints: TS,
5001
+ detail: "TypeScript error",
5002
+ conf: 0.9
5003
+ },
5004
+ {
5005
+ pat: /\b: any\b|\bas any\b/,
5006
+ cat: "ts",
5007
+ sub: "unsafe-any",
5008
+ lang: "typescript",
5009
+ hints: TS,
5010
+ detail: "Unsafe `any` cast \u2014 type safety violation",
5011
+ conf: 0.85
5012
+ },
5013
+ {
5014
+ pat: /\bnoimplicit|\bstrict\b.*\bcheck\b|\btsconfig\b/i,
5015
+ cat: "ts",
5016
+ sub: "strict-mode",
5017
+ lang: "typescript",
5018
+ hints: TS,
5019
+ detail: "TypeScript strict mode configuration issue",
5020
+ conf: 0.8
5021
+ },
5022
+ // ── Rust ───────────────────────────────────────────────────────────────────
5023
+ {
5024
+ pat: /\bE\d{4,}\b/,
5025
+ cat: "runtime",
5026
+ sub: "panic",
5027
+ lang: "rust",
5028
+ hints: BH,
5029
+ detail: "Rust error",
5030
+ conf: 1,
5031
+ code: (m) => m[0]
5032
+ },
5033
+ {
5034
+ pat: /\bthread.*panicked|panicked at /i,
5035
+ cat: "runtime",
5036
+ sub: "panic",
5037
+ lang: "rust",
5038
+ hints: BH,
5039
+ detail: "Rust panic",
5040
+ conf: 1
5041
+ },
5042
+ {
5043
+ pat: /\brustc.*error|compilation failed.*rust/i,
5044
+ cat: "compile",
5045
+ sub: "rust-compile",
5046
+ lang: "rust",
5047
+ hints: BH,
5048
+ detail: "Rust compiler error",
5049
+ conf: 1
5050
+ },
5051
+ // ── Go ──────────────────────────────────────────────────────────────────────
5052
+ {
5053
+ pat: /\bgo build\b.*fail|golang.*error/i,
5054
+ cat: "compile",
5055
+ sub: "go-compile",
5056
+ lang: "go",
5057
+ hints: BH,
5058
+ detail: "Go build error",
5059
+ conf: 0.95
5060
+ },
5061
+ {
5062
+ pat: /\bnil pointer|nil dereference|invalid memory address/i,
5063
+ cat: "runtime",
5064
+ sub: "nil-pointer",
5065
+ lang: "go",
5066
+ hints: BH,
5067
+ detail: "Go nil pointer dereference",
5068
+ conf: 0.9
5069
+ },
5070
+ // ── Python ────────────────────────────────────────────────────────────────
5071
+ {
5072
+ pat: /\btraceback \(most recent call last\)/i,
5073
+ cat: "runtime",
5074
+ sub: "python-traceback",
5075
+ lang: "python",
5076
+ hints: BH,
5077
+ detail: "Python runtime error / traceback",
5078
+ conf: 1
5079
+ },
5080
+ {
5081
+ pat: /\bpython.*error|python.*exception|modulenot founderror|importerror/i,
5082
+ cat: "runtime",
5083
+ sub: "python-traceback",
5084
+ lang: "python",
5085
+ hints: BH,
5086
+ detail: "Python runtime error",
5087
+ conf: 1
5088
+ },
5089
+ {
5090
+ pat: /\battributeerror\b|\btypeerror\b.*python|python.*type error/i,
5091
+ cat: "runtime",
5092
+ sub: "python-type",
5093
+ lang: "python",
5094
+ hints: BH,
5095
+ detail: "Python type/error",
5096
+ conf: 0.9
5097
+ },
5098
+ {
5099
+ pat: /\bpip install|requirement.*not found|package.*not found.*python/i,
5100
+ cat: "dep",
5101
+ sub: "python-dep",
5102
+ lang: "python",
5103
+ hints: BH,
5104
+ detail: "Python dependency error",
5105
+ conf: 0.9
5106
+ },
5107
+ {
5108
+ pat: /\bpylint|pyright|mypy.*error|flake8/i,
5109
+ cat: "lint",
5110
+ sub: "python-lint",
5111
+ lang: "python",
5112
+ hints: BH,
5113
+ detail: "Python linter error",
5114
+ conf: 0.85
5115
+ },
5116
+ // ── Ruby ──────────────────────────────────────────────────────────────────
5117
+ {
5118
+ pat: /\b(nomethoderror|noconversion|undefined method|private method|rbenv|rubygems)/i,
5119
+ cat: "runtime",
5120
+ sub: "ruby-error",
5121
+ lang: "ruby",
5122
+ hints: BH,
5123
+ detail: (m) => `Ruby error: ${m[1] ?? m[0]}`,
5124
+ conf: 0.9
5125
+ },
5126
+ {
5127
+ pat: /\bgem install|bundler.*error|gemspec.*error/i,
5128
+ cat: "dep",
5129
+ sub: "ruby-dep",
5130
+ lang: "ruby",
5131
+ hints: BH,
5132
+ detail: "Ruby gem/bundler error",
5133
+ conf: 0.85
5134
+ },
5135
+ // ── Java / Kotlin ────────────────────────────────────────────────────────
5136
+ {
5137
+ pat: /\bnullpointerexception|npe\b/i,
5138
+ cat: "runtime",
5139
+ sub: "null-pointer",
5140
+ lang: "java",
5141
+ hints: BH,
5142
+ detail: "NullPointerException",
5143
+ conf: 1
5144
+ },
5145
+ {
5146
+ pat: /\bjava\.lang\.|exception in thread|java\.util\.|java\.io\./i,
5147
+ cat: "runtime",
5148
+ sub: "java-exception",
5149
+ lang: "java",
5150
+ hints: BH,
5151
+ detail: "Java/Kotlin runtime exception",
5152
+ conf: 1
5153
+ },
5154
+ {
5155
+ pat: /\b(maven|gradle|ant).*error|dependency.*not found|compile.*fail.*java/i,
5156
+ cat: "dep",
5157
+ sub: "java-build",
5158
+ lang: "java",
5159
+ hints: BH,
5160
+ detail: "Java build/dependency error",
5161
+ conf: 0.9
5162
+ },
5163
+ {
5164
+ pat: /\bkotlin\b.*\berror\b|\bkotlin compiler\b/i,
5165
+ cat: "compile",
5166
+ sub: "kotlin-compile",
5167
+ lang: "kotlin",
5168
+ hints: BH,
5169
+ detail: "Kotlin compiler error",
5170
+ conf: 0.95
5171
+ },
5172
+ // ── C / C++ ─────────────────────────────────────────────────────────────
5173
+ {
5174
+ pat: /\bc\d+\b/i,
5175
+ cat: "compile",
5176
+ sub: "c-compile",
5177
+ lang: "c",
5178
+ hints: BH,
5179
+ detail: "C/C++ compiler error",
5180
+ conf: 1,
5181
+ code: (m) => m[0]
5182
+ },
5183
+ {
5184
+ pat: /\b(gcc|g\+\+|clang|msvc|visual studio).*error|fatal error c\d+/i,
5185
+ cat: "compile",
5186
+ sub: "c-compile",
5187
+ lang: "c",
5188
+ hints: BH,
5189
+ detail: "C/C++ compiler error",
5190
+ conf: 1
5191
+ },
5192
+ {
5193
+ pat: /\bsegmentation fault|segfault|sigsegv|core dumped/i,
5194
+ cat: "runtime",
5195
+ sub: "segfault",
5196
+ lang: "c",
5197
+ hints: BH,
5198
+ detail: "Segmentation fault (C/C++)",
5199
+ conf: 1
5200
+ },
5201
+ // ── C# ──────────────────────────────────────────────────────────────────
5202
+ {
5203
+ pat: /\b(csharp|dotnet|\.net).*error|cs\d+\b|nullable warning/i,
5204
+ cat: "compile",
5205
+ sub: "csharp-compile",
5206
+ lang: "csharp",
5207
+ hints: BH,
5208
+ detail: "C# / .NET compile error",
5209
+ conf: 0.9
5210
+ },
5211
+ // ── PHP ────────────────────────────────────────────────────────────────
5212
+ {
5213
+ pat: /\bphp.*error|fatal error.*php|parse error.*php/i,
5214
+ cat: "runtime",
5215
+ sub: "php-error",
5216
+ lang: "php",
5217
+ hints: BH,
5218
+ detail: "PHP runtime/parse error",
5219
+ conf: 1
5220
+ },
5221
+ // ── Scala ─────────────────────────────────────────────────────────────
5222
+ {
5223
+ pat: /\bscala.*error|type mismatch.*scala|could not find.*scala/i,
5224
+ cat: "compile",
5225
+ sub: "scala-compile",
5226
+ lang: "scala",
5227
+ hints: BH,
5228
+ detail: "Scala compile error",
5229
+ conf: 0.9
5230
+ },
5231
+ // ── Node.js / JavaScript Runtime ────────────────────────────────────────
5232
+ {
5233
+ pat: /\b(node:|node\.js|err_)/i,
5234
+ cat: "runtime",
5235
+ sub: "node-runtime",
5236
+ lang: "javascript",
5237
+ hints: NM,
5238
+ detail: "Node.js runtime error",
5239
+ conf: 1
5240
+ },
5241
+ {
5242
+ pat: /\bcannot read property|cannot set property|cannot call method/i,
5243
+ cat: "runtime",
5244
+ sub: "undefined-call",
5245
+ lang: "javascript",
5246
+ hints: NM,
5247
+ detail: "JavaScript undefined access error",
5248
+ conf: 0.95
5249
+ },
5250
+ {
5251
+ pat: /\beconnrefused|etimedout|enotfound|econnreset|dns lookup/i,
5252
+ cat: "infra",
5253
+ sub: "network",
5254
+ lang: "javascript",
5255
+ hints: NM,
5256
+ detail: "Node.js network error",
5257
+ conf: 0.95
5258
+ },
5259
+ {
5260
+ pat: /\beacces|eisdir|eperm/i,
5261
+ cat: "infra",
5262
+ sub: "file-system",
5263
+ lang: "javascript",
5264
+ hints: NM,
5265
+ detail: "File system / OS error",
5266
+ conf: 0.95
5267
+ },
5268
+ // ── React / Next.js ──────────────────────────────────────────────────────
5269
+ {
5270
+ pat: /\breact-dom|react\.development|invalid hook call/i,
5271
+ cat: "runtime",
5272
+ sub: "react-error",
5273
+ lang: "javascript",
5274
+ hints: RM,
5275
+ detail: "React runtime error",
5276
+ conf: 0.9
5277
+ },
5278
+ {
5279
+ pat: /\bnext\.js|nextjs|error in.*next|getstaticpaths|getserversideprops/i,
5280
+ cat: "runtime",
5281
+ sub: "nextjs-error",
5282
+ lang: "javascript",
5283
+ hints: RM,
5284
+ detail: "Next.js error",
5285
+ conf: 0.95
5286
+ },
5287
+ // ── Security — BEFORE generic catch-alls ─────────────────────────────
5288
+ {
5289
+ pat: /\b(sql injection|xss|csrf|injection)\b/i,
5290
+ cat: "security",
5291
+ sub: "injection",
5292
+ lang: void 0,
5293
+ hints: SS,
5294
+ detail: "Injection vulnerability",
5295
+ conf: 1
5296
+ },
5297
+ {
5298
+ pat: /\b(secret|apikey|api_key|token|password|credential|jwt)\b/i,
5299
+ cat: "security",
5300
+ sub: "secret-exposure",
5301
+ lang: void 0,
5302
+ hints: SS,
5303
+ detail: "Secret / credential exposure",
5304
+ conf: 1
5305
+ },
5306
+ {
5307
+ pat: /\b(eval|innerhtml|document\.write| dangerouslysetinnerhtml)\b/i,
5308
+ cat: "security",
5309
+ sub: "injection",
5310
+ lang: void 0,
5311
+ hints: SS,
5312
+ detail: "Injection vulnerability",
5313
+ conf: 1
5314
+ },
5315
+ {
5316
+ pat: /\bcors.*misconfig|access-control-allow-origin/i,
5317
+ cat: "security",
5318
+ sub: "cors-misconfig",
5319
+ lang: void 0,
5320
+ hints: SS,
5321
+ detail: "CORS misconfiguration",
5322
+ conf: 0.9
5323
+ },
5324
+ {
5325
+ pat: /\bapikey\b|\bapi_key\b|\bhardcoded\b.*\bkey\b/i,
5326
+ cat: "security",
5327
+ sub: "secret-exposure",
5328
+ lang: void 0,
5329
+ hints: SS,
5330
+ detail: "Secret / credential exposure",
5331
+ conf: 1
5332
+ },
5333
+ // ── Null/undefined access — BEFORE generic typeerror catch-all ─────────────
5334
+ {
5335
+ pat: /\b(null is not|null.*not.*function|undefined is not|is not a function)\b/i,
5336
+ cat: "runtime",
5337
+ sub: "null-undefined-access",
5338
+ lang: "javascript",
5339
+ hints: BH,
5340
+ detail: "Null/undefined access error",
5341
+ conf: 0.9
5342
+ },
5343
+ // ── Generic JS errors ────────────────────────────────────────────────
5344
+ {
5345
+ pat: /\b(typeerror|referenceerror|syntaxerror|urierror|rangeerror|evalerror)\b/i,
5346
+ cat: "runtime",
5347
+ sub: "js-error",
5348
+ lang: "javascript",
5349
+ hints: NM,
5350
+ detail: "JavaScript runtime error",
5351
+ conf: 0.95
5352
+ },
5353
+ // ── Dependency / Import ───────────────────────────────────────────────
5354
+ {
5355
+ pat: /\bcannot find module|modulenotfounderror|no such module|missing module/i,
5356
+ cat: "dep",
5357
+ sub: "module-not-found",
5358
+ lang: void 0,
5359
+ hints: BH,
5360
+ detail: "Module / import resolution failure",
5361
+ conf: 0.9
5362
+ },
5363
+ {
5364
+ pat: /\bfailed to resolve|resolves to|dependency.*not found/i,
5365
+ cat: "dep",
5366
+ sub: "module-not-found",
5367
+ lang: void 0,
5368
+ hints: BH,
5369
+ detail: "Dependency resolution failure",
5370
+ conf: 0.85
5371
+ },
5372
+ // ── Lint ────────────────────────────────────────────────────────────────
5373
+ {
5374
+ pat: /\b(lint|warning|eslint|prettier|ruff|pylint|golangci-lint).*(error|fail|warn)/i,
5375
+ cat: "lint",
5376
+ sub: "linter-error",
5377
+ lang: void 0,
5378
+ hints: BH,
5379
+ detail: "Linter error / warning",
5380
+ conf: 0.85
5381
+ },
5382
+ // ── Performance ────────────────────────────────────────────────────────
5383
+ {
5384
+ pat: /\b(memory leak|oom|out of memory|heap overflow|stack overflow|infinite loop|bottleneck|performance issue)\b/i,
5385
+ cat: "perf",
5386
+ sub: "performance-issue",
5387
+ lang: void 0,
5388
+ hints: BH,
5389
+ detail: "Performance / memory issue",
5390
+ conf: 0.85
5391
+ },
5392
+ // ── Logic / wrong behavior ─────────────────────────────────────────────
5393
+ {
5394
+ pat: /\b(wrong|incorrect|unexpected|silent fail|bug|defect|logic error)\b/i,
5395
+ cat: "logic",
5396
+ sub: "wrong-behavior",
5397
+ lang: void 0,
5398
+ hints: BH,
5399
+ detail: "Logic / behavioral bug",
5400
+ conf: 0.8
5401
+ },
5402
+ {
5403
+ pat: /\b(off.?by.?one|boundary error|index error)\b/i,
5404
+ cat: "logic",
5405
+ sub: "wrong-behavior",
5406
+ lang: void 0,
5407
+ hints: BH,
5408
+ detail: "Off-by-one error",
5409
+ conf: 0.9
5410
+ },
5411
+ // ── C memory-safety (specific, after generic memory leak patterns above) ─
5412
+ {
5413
+ pat: /\b(heap-buffer-overflow|use-after-free|double-free)\b/i,
5414
+ cat: "perf",
5415
+ sub: "memory-safety",
5416
+ lang: "c",
5417
+ hints: BH,
5418
+ detail: "Memory safety issue (C/C++)",
5419
+ conf: 1
5420
+ },
5421
+ // ── Infra — AFTER more specific categories ─────────────────────────────
5422
+ {
5423
+ pat: /\b(env|environment|config|dotenv|yml|yaml|json.*config|docker|k8s|kubernetes)\b/i,
5424
+ cat: "infra",
5425
+ sub: "config-error",
5426
+ lang: void 0,
5427
+ hints: BH,
5428
+ detail: "Infrastructure / configuration error",
5429
+ conf: 0.8
5430
+ },
5431
+ {
5432
+ pat: /\b(git.*conflict|merge conflict|rebase.*fail|branch.*error|git.*error)\b/i,
5433
+ cat: "infra",
5434
+ sub: "git-error",
5435
+ lang: void 0,
5436
+ hints: BH,
5437
+ detail: "Git error",
5438
+ conf: 0.9
5439
+ },
5440
+ {
5441
+ pat: /\b(ci.?cd|pipeline|github action|circleci|jenkins|gitlab ci)\b/i,
5442
+ cat: "infra",
5443
+ sub: "config-error",
5444
+ lang: void 0,
5445
+ hints: BH,
5446
+ detail: "CI/CD pipeline error",
5447
+ conf: 0.9
5448
+ }
5449
+ ];
5450
+ function classifyError(input) {
5451
+ const s = input.trim();
5452
+ for (const p of P) {
5453
+ const m = p.pat.exec(s);
5454
+ if (!m) continue;
5455
+ const detailStr = typeof p.detail === "function" ? p.detail(m) : p.detail;
5456
+ return {
5457
+ category: p.cat,
5458
+ subcategory: p.sub,
5459
+ language: p.lang ?? "unknown",
5460
+ framework: p.fw,
5461
+ skillHints: p.hints,
5462
+ errorCode: p.code ? p.code(m) : extractCode(s),
5463
+ confidence: p.conf ?? 0.8,
5464
+ detail: detailStr
5465
+ };
5466
+ }
5467
+ return {
5468
+ category: "general",
5469
+ subcategory: "unknown",
5470
+ language: "unknown",
5471
+ skillHints: BH,
5472
+ confidence: 0.3,
5473
+ detail: "General problem (unclassified)"
5474
+ };
5475
+ }
5476
+ function extractCode(s) {
5477
+ const ts = /\bTS\d+\b|\bCS\d+\b/.exec(s);
5478
+ if (ts) return ts[0];
5479
+ const rust = /\bE\d{4,}\b/.exec(s);
5480
+ if (rust) return rust[0];
5481
+ const c = /\bc\d+\b/i.exec(s);
5482
+ if (c) return c[0];
5483
+ return void 0;
5484
+ }
5485
+ function needsSubagent(c) {
5486
+ return c.confidence < 0.85;
5487
+ }
5488
+ function isSimpleFix(c) {
5489
+ return c.category === "ts" && c.confidence >= 0.9 || c.category === "runtime" && c.subcategory === "null-undefined-access" && c.confidence >= 0.85;
5490
+ }
5491
+
5492
+ // src/slash-commands/fix.ts
5493
+ function buildDirective(cli, errorText) {
5494
+ const lang = cli.language === "unknown" ? "" : ` (language: ${cli.language})`;
5495
+ switch (cli.category) {
5496
+ case "ts":
5497
+ return [
5498
+ `## Fix: TypeScript Error${lang}`,
5499
+ "",
5500
+ "```",
5501
+ `${errorText}`,
5502
+ "```",
5503
+ "",
5504
+ "Your task:",
5505
+ `1. Search for the error location in the codebase (grep for the error code "${cli.errorCode ?? ""}" or relevant type names)`,
5506
+ "2. Read the source file(s)",
5507
+ "3. Identify the root cause",
5508
+ "4. Fix with strict types \u2014 no `as any` or `@ts-ignore`",
5509
+ "5. Verify with `typecheck` or `tsc --noEmit`"
5510
+ ].join("\n");
5511
+ case "security":
5512
+ return [
5513
+ `## Fix: Security Issue${lang}`,
5514
+ "",
5515
+ "```",
5516
+ `${errorText}`,
5517
+ "```",
5518
+ "",
5519
+ "Your task:",
5520
+ "1. Locate the vulnerable code (grep for hardcoded secrets, eval, innerHTML, SQL concatenation)",
5521
+ "2. Classify severity: critical / high / medium",
5522
+ "3. Apply the fix:",
5523
+ " - Secrets \u2192 rotate + use env vars or a secret manager",
5524
+ " - Injection \u2192 parameterized queries, safe DOM APIs",
5525
+ " - Auth \u2192 fix token handling",
5526
+ '4. Check for similar issues: `grep -r "password" --include="*.ts"` etc.',
5527
+ "5. Run security scan if available"
5528
+ ].join("\n");
5529
+ case "runtime":
5530
+ return [
5531
+ `## Fix: Runtime Error${lang}`,
5532
+ "",
5533
+ "```",
5534
+ `${errorText}`,
5535
+ "```",
5536
+ "",
5537
+ "Your task:",
5538
+ "1. Locate the crash site (grep for error message or stack trace context)",
5539
+ "2. Read the relevant file(s)",
5540
+ "3. Identify root cause: null/undefined access, async race, wrong type, etc.",
5541
+ "4. Fix the error",
5542
+ "5. Verify \u2014 re-run or typecheck"
5543
+ ].join("\n");
5544
+ case "compile":
5545
+ return [
5546
+ `## Fix: Compiler Error${lang}`,
5547
+ "",
5548
+ "```",
5549
+ `${errorText}`,
5550
+ "```",
5551
+ "",
5552
+ "Your task:",
5553
+ "1. Locate the file(s) with compile errors",
5554
+ "2. Read the error output carefully",
5555
+ "3. Fix the compile error",
5556
+ "4. Re-compile to verify"
5557
+ ].join("\n");
5558
+ case "dep":
5559
+ return [
5560
+ `## Fix: Dependency / Import Error${lang}`,
5561
+ "",
5562
+ "```",
5563
+ `${errorText}`,
5564
+ "```",
5565
+ "",
5566
+ "Your task:",
5567
+ "1. Identify the missing module or failed import",
5568
+ "2. Fix: install the package, add to imports, or correct the path",
5569
+ "3. Verify imports resolve"
5570
+ ].join("\n");
5571
+ case "infra":
5572
+ return [
5573
+ `## Fix: Infrastructure / Config Error${lang}`,
5574
+ "",
5575
+ "```",
5576
+ `${errorText}`,
5577
+ "```",
5578
+ "",
5579
+ "Your task:",
5580
+ "1. Locate the config file or infrastructure setup",
5581
+ "2. Identify the misconfiguration",
5582
+ "3. Fix the config",
5583
+ "4. Verify"
5584
+ ].join("\n");
5585
+ case "perf":
5586
+ return [
5587
+ `## Fix: Performance / Memory Issue${lang}`,
5588
+ "",
5589
+ "```",
5590
+ `${errorText}`,
5591
+ "```",
5592
+ "",
5593
+ "Your task:",
5594
+ "1. Profile or locate the bottleneck",
5595
+ "2. Identify root cause",
5596
+ "3. Fix: memoize, batch, lazy-load, remove leak, fix loop",
5597
+ "4. Verify performance improvement"
5598
+ ].join("\n");
5599
+ default:
5600
+ return [
5601
+ `## Fix: Problem Reported${lang}`,
5602
+ "",
5603
+ "```",
5604
+ `${errorText}`,
5605
+ "```",
5606
+ "",
5607
+ "Your task:",
5608
+ "1. Analyze the problem description",
5609
+ "2. Locate relevant files",
5610
+ "3. Identify the root cause",
5611
+ "4. Apply the fix",
5612
+ "5. Verify the fix works"
5613
+ ].join("\n");
5614
+ }
5615
+ }
5616
+ function delegateRoleFor(cli) {
5617
+ switch (cli.category) {
5618
+ case "ts":
5619
+ return "typescript-strict";
5620
+ case "security":
5621
+ return "security-scanner";
5622
+ case "perf":
5623
+ return "refactor-planner";
5624
+ default:
5625
+ return "bug-hunter";
5626
+ }
5627
+ }
5628
+ function skillLabel(skillHints) {
5629
+ return skillHints.map((s) => `\`${s}\``).join(", ");
5630
+ }
5631
+ function categoryLabel(cli) {
5632
+ if (cli.language !== "unknown" && cli.language !== "unknown") {
5633
+ return `${cli.subcategory} (${cli.category}, ${cli.language})`;
5634
+ }
5635
+ return `${cli.subcategory} (${cli.category})`;
5636
+ }
5637
+ function buildFixCommand(opts) {
5638
+ return {
5639
+ name: "fix",
5640
+ description: "Classify a bug/error (any language), activate the right skill, and fix it \u2014 inline or via subagent.",
5641
+ argsHint: "<error message or problem description>",
5642
+ help: `
5643
+ # /fix \u2014 Problem Solver
5644
+
5645
+ Classifies an error, bug, or problem description from **any language/framework**,
5646
+ activates the right skill, and drives a focused fix workflow.
5647
+
5648
+ ## Usage
5649
+
5650
+ \`\`\`
5651
+ /fix <error message or problem description>
5652
+ \`\`\`
5653
+
5654
+ ## Supported languages & frameworks
5655
+
5656
+ TypeScript, Rust, Go, Python, Ruby, Java, Kotlin, Swift, C/C++, C#,
5657
+ PHP, Scala, Perl, Haskell, Elixir, Node.js, React, Next.js, Vue, Angular,
5658
+ Docker, Git, CI/CD, and more.
5659
+
5660
+ ## Classification \u2192 skill mapping
5661
+
5662
+ | Error type | Language(s) | Skill activated |
5663
+ |---------------------|--------------------------|-----------------------|
5664
+ | TypeScript | TypeScript | \`typescript-strict\` |
5665
+ | Runtime / crash | Any | \`bug-hunter\` |
5666
+ | Security / secrets | Any | \`security-scanner\` |
5667
+ | Compiler error | Rust, Go, C/C++, Python | \`bug-hunter\` |
5668
+ | Dependency / import | Any | \`bug-hunter\` |
5669
+ | Performance / leak | Any | \`bug-hunter\` + \`refactor-planner\` |
5670
+ | Infrastructure | Config, Docker, Git, CI | \`bug-hunter\` |
5671
+ | React / Next.js | JavaScript | \`react-modern\` |
5672
+ | Node.js | JavaScript | \`node-modern\` |
5673
+
5674
+ ## Auto-delegation
5675
+
5676
+ When the error confidence is low (< 0.85) or the problem spans multiple files,
5677
+ \`/fix\` automatically delegates to the matching specialist subagent via the
5678
+ \`onFix\` callback. Set \`onFix\` in \`SlashCommandContext\` to enable this.
5679
+
5680
+ ## Examples
5681
+
5682
+ \`\`\`
5683
+ /fix TS2345: Argument of type 'string | null' is not assignable
5684
+ /fix TypeError: Cannot read property 'map' of undefined
5685
+ /fix error[E0503]: expected something but found E0503 in src/lib.rs
5686
+ /fix Segmentation fault (core dumped) at main.rs:42
5687
+ /fix AttributeError: 'NoneType' object has no attribute 'encode' (Python)
5688
+ /fix react-dom.development.js:172 Error: Invalid hook call
5689
+ /fix Security: hardcoded API key in config.ts
5690
+ /fix ERRO1014: SQL injection vulnerability in query builder
5691
+ \`\`\`
5692
+ `,
5693
+ async run(args, _ctx) {
5694
+ const trimmed = args.trim();
5695
+ if (!trimmed) {
5696
+ return {
5697
+ message: [
5698
+ `${color.bold("/fix \u2014 Problem Solver")}`,
5699
+ "",
5700
+ "Classifies an error from any language/framework and activates the right skill.",
5701
+ "",
5702
+ "Usage:",
5703
+ " /fix <error message or problem description>",
5704
+ "",
5705
+ "Examples:",
5706
+ ` /fix ${color.dim('TS2345: Argument of type "string | null" is not assignable')}`,
5707
+ ` /fix ${color.dim("TypeError: Cannot read property 'map' of undefined")}`,
5708
+ ` /fix ${color.dim("error[E0503]: expected something but found E0503 in src/lib.rs")}`,
5709
+ ` /fix ${color.dim("AttributeError: 'NoneType' object has no attribute 'encode'")}`,
5710
+ ` /fix ${color.dim("react-dom.development.js:172 Error: Invalid hook call")}`,
5711
+ ` /fix ${color.dim("Security: hardcoded API key in config.ts")}`,
5712
+ "",
5713
+ "Run `/help fix` for full documentation."
5714
+ ].join("\n")
5715
+ };
5716
+ }
5717
+ const cli = classifyError(trimmed);
5718
+ const delegate = needsSubagent(cli);
5719
+ const delegateRole = delegate ? delegateRoleFor(cli) : void 0;
5720
+ const metadata = {
5721
+ skillHints: cli.skillHints,
5722
+ delegateRequested: delegate,
5723
+ delegateRole
5724
+ };
5725
+ if (isSimpleFix(cli) || !delegate && opts.onFix) {
5726
+ const runText2 = [
5727
+ "",
5728
+ `${color.bold("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550 /fix \u2014 Problem Solver \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")}`,
5729
+ "",
5730
+ `**Classification:** ${categoryLabel(cli)}`,
5731
+ `**Confidence:** ${Math.round(cli.confidence * 100)}%`,
5732
+ `**Error code:** \`${cli.errorCode ?? "n/a"}\``,
5733
+ "",
5734
+ `**Skills activated:** ${skillLabel(cli.skillHints)}`,
5735
+ "",
5736
+ `**Next step:** ${delegate ? "Delegating to `" + delegateRole + "` subagent..." : "Applying inline fix..."}`,
5737
+ ""
5738
+ ].join("\n") + "\n---\n" + buildDirective(cli, trimmed);
5739
+ if (opts.onFix) {
5740
+ const injected = await opts.onFix(trimmed);
5741
+ if (injected?.message) {
5742
+ return {
5743
+ message: injected.message,
5744
+ runText: injected.runText ?? runText2,
5745
+ metadata
5746
+ };
5747
+ }
5748
+ }
5749
+ return { message: `${color.green("\u2713")} [${categoryLabel(cli)}] \u2014 Skills: ${skillLabel(cli.skillHints)}`, runText: runText2, metadata };
5750
+ }
5751
+ if (delegate && delegateRole) {
5752
+ const taskPrompt = [
5753
+ `${color.bold("/fix \u2014 Auto-delegated fix")}`,
5754
+ "",
5755
+ `**Problem classification:** ${categoryLabel(cli)} (confidence: ${Math.round(cli.confidence * 100)}%)`,
5756
+ `**Error code:** \`${cli.errorCode ?? "n/a"}\``,
5757
+ `**Skills activated:** ${skillLabel(cli.skillHints)}`,
5758
+ "",
5759
+ buildDirective(cli, trimmed)
5760
+ ].join("\n");
5761
+ metadata.delegateTask = taskPrompt;
5762
+ const runText2 = [
5763
+ "",
5764
+ `${color.bold("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550 /fix \u2014 Auto-delegated \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")}`,
5765
+ "",
5766
+ `**Delegating to:** \`${delegateRole}\` subagent`,
5767
+ `**Classification:** ${categoryLabel(cli)}`,
5768
+ `**Confidence:** ${Math.round(cli.confidence * 100)}% \u2014 delegation triggered (confidence < 85%)`,
5769
+ `**Skills activated:** ${skillLabel(cli.skillHints)}`,
5770
+ "",
5771
+ "The specialist subagent will now fix the issue. Results will be reported when complete."
5772
+ ].join("\n");
5773
+ return { message: `${color.green("\u2713")} Delegating to \`${delegateRole}\`...`, runText: runText2, metadata };
5774
+ }
5775
+ const runText = [
5776
+ "",
5777
+ `${color.bold("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550 /fix \u2014 Problem Solver \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")}`,
5778
+ "",
5779
+ `**Classification:** ${categoryLabel(cli)} (confidence: ${Math.round(cli.confidence * 100)}%)`,
5780
+ `**Skills activated:** ${skillLabel(cli.skillHints)}`,
5781
+ ""
5782
+ ].join("\n") + "\n---\n" + buildDirective(cli, trimmed);
5783
+ return {
5784
+ message: `${color.green("\u2713")} [${categoryLabel(cli)}] \u2014 Skills: ${skillLabel(cli.skillHints)}`,
5785
+ runText,
5786
+ metadata
5787
+ };
5788
+ }
5789
+ };
5790
+ }
4822
5791
  function makeInstaller(opts, projectRoot, global) {
4823
5792
  const globalRoot = path23.join(os6.homedir(), ".wrongstack");
4824
5793
  return new SkillInstaller({
@@ -5020,6 +5989,7 @@ function buildBuiltinSlashCommands(opts) {
5020
5989
  buildGitcheckCommand(),
5021
5990
  buildPushCommand(),
5022
5991
  buildSecurityCommand(opts),
5992
+ buildFixCommand(opts),
5023
5993
  buildStatuslineCommand({
5024
5994
  cwd: opts.cwd,
5025
5995
  hiddenItems: opts.statuslineHiddenItems ?? [],
@@ -7474,22 +8444,22 @@ function fmtDuration(ms) {
7474
8444
  const remMin = m - h * 60;
7475
8445
  return `${h}h${remMin}m`;
7476
8446
  }
7477
- function fmtTaskResultLine(r, color36) {
8447
+ function fmtTaskResultLine(r, color38) {
7478
8448
  const stats = `${r.iterations}it ${r.toolCalls}tc ${fmtDuration(r.durationMs)}`;
7479
8449
  const errMsg = typeof r.error === "string" ? r.error : r.error?.message;
7480
8450
  const errKind = typeof r.error === "object" ? r.error?.kind : void 0;
7481
8451
  const errTail = errMsg ? ` \u2014 ${errMsg.replace(/\s+/g, " ").slice(0, 80)}${errMsg.length > 80 ? "\u2026" : ""}` : "";
7482
- const errKindChip = errKind ? color36.dim(` [${errKind}]`) : "";
7483
- const errSnip = errMsg || errKind ? `${errKindChip}${color36.dim(errTail)}` : "";
8452
+ const errKindChip = errKind ? color38.dim(` [${errKind}]`) : "";
8453
+ const errSnip = errMsg || errKind ? `${errKindChip}${color38.dim(errTail)}` : "";
7484
8454
  switch (r.status) {
7485
8455
  case "success":
7486
- return { mark: color36.green("\u2713"), stats, tail: "" };
8456
+ return { mark: color38.green("\u2713"), stats, tail: "" };
7487
8457
  case "timeout":
7488
- return { mark: color36.yellow("\u23F1"), stats: `${color36.yellow("timeout")} ${stats}`, tail: errSnip };
8458
+ return { mark: color38.yellow("\u23F1"), stats: `${color38.yellow("timeout")} ${stats}`, tail: errSnip };
7489
8459
  case "stopped":
7490
- return { mark: color36.dim("\u2298"), stats: `${color36.dim("stopped")} ${stats}`, tail: errSnip };
8460
+ return { mark: color38.dim("\u2298"), stats: `${color38.dim("stopped")} ${stats}`, tail: errSnip };
7491
8461
  case "failed":
7492
- return { mark: color36.red("\u2717"), stats: `${color36.red("failed")} ${stats}`, tail: errSnip };
8462
+ return { mark: color38.red("\u2717"), stats: `${color38.red("failed")} ${stats}`, tail: errSnip };
7493
8463
  }
7494
8464
  }
7495
8465
 
@@ -7662,10 +8632,12 @@ async function runRepl(opts) {
7662
8632
  opts.renderer.writeWarning("Exiting.");
7663
8633
  process.exit(130);
7664
8634
  }
7665
- const engine = opts.getEternalEngine?.();
7666
- if (engine && opts.getAutonomy?.() === "eternal") {
7667
- engine.stop();
7668
- opts.renderer.writeWarning("Eternal mode stop requested. Press Ctrl+C again to exit.");
8635
+ if (opts.getAutonomy?.() === "eternal" || opts.getAutonomy?.() === "eternal-parallel") {
8636
+ opts.getEternalEngine?.()?.stop();
8637
+ opts.getParallelEngine?.()?.stop();
8638
+ opts.onAutonomy?.("off");
8639
+ opts.renderer.writeWarning("Engine stop requested. Press Ctrl+C again to exit.");
8640
+ interrupts = 0;
7669
8641
  return;
7670
8642
  }
7671
8643
  if (activeCtrl) {
@@ -7714,6 +8686,39 @@ async function runRepl(opts) {
7714
8686
  await new Promise((resolve4) => setTimeout(resolve4, 250));
7715
8687
  continue;
7716
8688
  }
8689
+ } else if (opts.getAutonomy?.() === "eternal-parallel") {
8690
+ const engine = opts.getParallelEngine?.();
8691
+ if (!engine) {
8692
+ opts.renderer.writeWarning("Parallel mode set but no engine wired \u2014 falling back to off.");
8693
+ } else {
8694
+ const beforeGoal = await loadGoalSafe(opts);
8695
+ const beforeIter = beforeGoal?.iterations ?? 0;
8696
+ opts.renderer.write(
8697
+ color.magenta(`
8698
+ \u21B3 [parallel #${beforeIter + 1}] launching fan-out\u2026
8699
+ `)
8700
+ );
8701
+ interrupts = 0;
8702
+ try {
8703
+ const ok = await engine.runOneIteration();
8704
+ const afterGoal = await loadGoalSafe(opts);
8705
+ const last = afterGoal?.journal[afterGoal.journal.length - 1];
8706
+ if (last) {
8707
+ const mark = last.status === "success" ? color.green("\u2713") : last.status === "failure" ? color.red("\u2717") : color.amber("\u2298");
8708
+ const tail = last.note ? color.dim(` \u2014 ${last.note.slice(0, 80)}`) : "";
8709
+ opts.renderer.write(
8710
+ ` ${mark} ${color.dim(`#${last.iteration}`)} ${color.dim(`[${last.source}]`)} ${last.task}${tail}
8711
+ `
8712
+ );
8713
+ }
8714
+ } catch (err) {
8715
+ opts.renderer.writeError(
8716
+ `[parallel] ${err instanceof Error ? err.message : String(err)}`
8717
+ );
8718
+ }
8719
+ await new Promise((resolve4) => setTimeout(resolve4, 250));
8720
+ continue;
8721
+ }
7717
8722
  }
7718
8723
  let raw;
7719
8724
  try {
@@ -8131,7 +9136,9 @@ async function execute(deps) {
8131
9136
  setStatuslineHiddenItems,
8132
9137
  getYolo,
8133
9138
  getAutonomy,
9139
+ onAutonomy,
8134
9140
  getEternalEngine,
9141
+ getParallelEngine,
8135
9142
  subscribeEternalIteration,
8136
9143
  skillLoader
8137
9144
  } = deps;
@@ -8330,7 +9337,9 @@ async function execute(deps) {
8330
9337
  projectName: path23.basename(projectRoot) || void 0,
8331
9338
  projectRoot,
8332
9339
  getAutonomy,
9340
+ onAutonomy,
8333
9341
  getEternalEngine,
9342
+ getParallelEngine,
8334
9343
  skillLoader
8335
9344
  });
8336
9345
  } finally {
@@ -8349,6 +9358,9 @@ async function execute(deps) {
8349
9358
  effectiveMaxContext,
8350
9359
  projectName: path23.basename(projectRoot) || void 0,
8351
9360
  getAutonomy,
9361
+ onAutonomy,
9362
+ getEternalEngine,
9363
+ getParallelEngine,
8352
9364
  skillLoader
8353
9365
  });
8354
9366
  }
@@ -8559,8 +9571,15 @@ var MultiAgentHost = class {
8559
9571
  outputBytes: e.outputBytes
8560
9572
  });
8561
9573
  });
9574
+ const offSummaryBridge = events.on("subagent.iteration_summary", (e) => {
9575
+ hostEvents.emit("subagent.iteration_summary", {
9576
+ ...e,
9577
+ subagentId: subCfg.id ?? subCfg.name ?? "subagent"
9578
+ });
9579
+ });
8562
9580
  const dispose = async () => {
8563
9581
  offToolBridge();
9582
+ offSummaryBridge();
8564
9583
  try {
8565
9584
  await subSession.close?.();
8566
9585
  } catch {
@@ -9509,6 +10528,7 @@ async function main(argv) {
9509
10528
  modelsRegistry,
9510
10529
  permission: {
9511
10530
  yolo: config.yolo,
10531
+ forceAllYolo: flags["force-all-yolo"] === true,
9512
10532
  promptDelegate: makePromptDelegate(reader)
9513
10533
  },
9514
10534
  compactor: { preserveK: config.context.preserveK, eliseThreshold: config.context.eliseThreshold },
@@ -9746,6 +10766,7 @@ async function main(argv) {
9746
10766
  let director = null;
9747
10767
  let autonomyMode = "off";
9748
10768
  let eternalEngine = null;
10769
+ let parallelEngine = null;
9749
10770
  const eternalListeners = /* @__PURE__ */ new Set();
9750
10771
  const broadcastEternalIteration = (entry) => {
9751
10772
  for (const fn of eternalListeners) {
@@ -10016,6 +11037,48 @@ async function main(argv) {
10016
11037
  }
10017
11038
  return `Unknown fleet action: ${action}`;
10018
11039
  },
11040
+ onFleetStatus: () => {
11041
+ if (!director) return null;
11042
+ return director.status();
11043
+ },
11044
+ onFleetUsage: () => {
11045
+ if (!director) return null;
11046
+ return director.snapshot();
11047
+ },
11048
+ onFleetKill: () => {
11049
+ if (!director) return 0;
11050
+ const s = director.status();
11051
+ let killed = 0;
11052
+ for (const sa of s.subagents) {
11053
+ if (sa.status === "running" || sa.status === "idle") {
11054
+ try {
11055
+ director.terminate(sa.id);
11056
+ killed++;
11057
+ } catch {
11058
+ }
11059
+ }
11060
+ }
11061
+ return killed;
11062
+ },
11063
+ onFleetTerminate: (subagentId) => {
11064
+ if (!director) return false;
11065
+ try {
11066
+ director.terminate(subagentId);
11067
+ return true;
11068
+ } catch {
11069
+ return false;
11070
+ }
11071
+ },
11072
+ onFleetSpawn: async (role) => {
11073
+ if (!director) throw new Error("No director active \u2014 start with --director or use /autonomy parallel.");
11074
+ const cfg = FLEET_ROSTER[role] ?? {
11075
+ id: `manual-${Date.now()}`,
11076
+ name: role,
11077
+ maxIterations: 50,
11078
+ maxToolCalls: 200
11079
+ };
11080
+ return director.spawn(cfg);
11081
+ },
10019
11082
  onFleetLog: async (subagentId, mode) => {
10020
11083
  const subagentsRoot = path23.join(fleetRootForPromotion, "subagents");
10021
11084
  let runDirs;
@@ -10264,25 +11327,35 @@ Restart WrongStack to load or unload plugin code in this session.`;
10264
11327
  }
10265
11328
  return autonomyMode;
10266
11329
  },
10267
- onEternalStart: () => {
10268
- if (!eternalEngine) {
10269
- eternalEngine = new EternalAutonomyEngine({
10270
- agent,
10271
- projectRoot,
10272
- // Wire the same compactor the manual /compact command uses so
10273
- // multi-day eternal loops don't overflow the provider's context.
10274
- // effectiveMaxContext is set up earlier with a model-specific
10275
- // value; pass it through so aggressive-mode compact triggers
10276
- // before the next iteration would actually overflow.
10277
- compactor: container.resolve(TOKENS.Compactor),
10278
- maxContextTokens: effectiveMaxContext > 0 ? effectiveMaxContext : void 0,
10279
- onIteration: broadcastEternalIteration
10280
- });
11330
+ onEternalStart: (mode) => {
11331
+ const effectiveMode = mode ?? "eternal";
11332
+ if (effectiveMode === "eternal-parallel") {
11333
+ if (!parallelEngine) {
11334
+ parallelEngine = new ParallelEternalEngine({
11335
+ agent,
11336
+ projectRoot,
11337
+ compactor: container.resolve(TOKENS.Compactor),
11338
+ maxContextTokens: effectiveMaxContext > 0 ? effectiveMaxContext : void 0,
11339
+ onIteration: broadcastEternalIteration
11340
+ });
11341
+ }
11342
+ void parallelEngine.prime?.();
11343
+ } else {
11344
+ if (!eternalEngine) {
11345
+ eternalEngine = new EternalAutonomyEngine({
11346
+ agent,
11347
+ projectRoot,
11348
+ compactor: container.resolve(TOKENS.Compactor),
11349
+ maxContextTokens: effectiveMaxContext > 0 ? effectiveMaxContext : void 0,
11350
+ onIteration: broadcastEternalIteration
11351
+ });
11352
+ }
11353
+ void eternalEngine.prime();
10281
11354
  }
10282
- void eternalEngine.prime();
10283
11355
  },
10284
11356
  onEternalStop: () => {
10285
11357
  eternalEngine?.stop();
11358
+ parallelEngine?.stop();
10286
11359
  },
10287
11360
  onExit: () => {
10288
11361
  void mcpRegistry.stopAll();
@@ -10402,7 +11475,15 @@ Restart WrongStack to load or unload plugin code in this session.`;
10402
11475
  return policy.getYolo();
10403
11476
  },
10404
11477
  getAutonomy: () => autonomyMode,
11478
+ onAutonomy: (setTo) => {
11479
+ if (setTo !== void 0) {
11480
+ autonomyMode = setTo;
11481
+ return setTo;
11482
+ }
11483
+ return autonomyMode;
11484
+ },
10405
11485
  getEternalEngine: () => eternalEngine,
11486
+ getParallelEngine: () => parallelEngine,
10406
11487
  subscribeEternalIteration: (fn) => {
10407
11488
  eternalListeners.add(fn);
10408
11489
  return () => eternalListeners.delete(fn);