@wrongstack/cli 0.8.4 → 0.8.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
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import * as path25 from 'path';
3
3
  import { join } from 'path';
4
- import * as fsp2 from 'fs/promises';
4
+ import * as fsp3 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, AutoApprovePermissionPolicy, makeLLMClassifier, resolveWstackPaths, DefaultSecretVault, migratePlaintextSecrets, DefaultConfigLoader, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, atomicWrite, DefaultPluginAPI, makeAgentSubagentRunner, NULL_FLEET_BUS, AutoPhaseRunner, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, resolveContextWindowPolicy, AGENTS_BY_PHASE, dispatchAgent, formatTodosList, emptyPlan, clearPlan, savePlan, formatPlanTemplates, getPlanTemplate, addPlanItem, formatPlan, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, renderProgress, renderTaskGraph, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, pendingBtwCount, setBtwNote, InputBuilder, FsError, ERROR_CODES, PhaseStore, projectHash, WrongStackError, defaultOrchestrator, decryptConfigSecrets, encryptConfigSecrets as encryptConfigSecrets$1, SpecVersioning, ParallelEternalEngine, 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, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, PhaseOrchestrator, makeLLMClassifier, resolveWstackPaths, DefaultSecretVault, migratePlaintextSecrets, DefaultConfigLoader, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, atomicWrite, DefaultPluginAPI, makeAgentSubagentRunner, NULL_FLEET_BUS, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, resolveContextWindowPolicy, AGENTS_BY_PHASE, dispatchAgent, formatTodosList, emptyPlan, clearPlan, savePlan, formatPlanTemplates, getPlanTemplate, addPlanItem, formatPlan, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, renderProgress, renderTaskGraph, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, pendingBtwCount, setBtwNote, InputBuilder, FsError, ERROR_CODES, projectHash, WrongStackError, defaultOrchestrator, decryptConfigSecrets, encryptConfigSecrets as encryptConfigSecrets$1, SpecVersioning, ParallelEternalEngine, allServers as allServers$1 } from '@wrongstack/core';
7
7
  import { createRequire } from 'module';
8
- import * as os7 from 'os';
9
- import os7__default from 'os';
8
+ import * as os6 from 'os';
9
+ import os6__default from 'os';
10
10
  import * as crypto2 from 'crypto';
11
11
  import { randomUUID } from 'crypto';
12
12
  import { DefaultSecretVault as DefaultSecretVault$1, encryptConfigSecrets, isSecretField, decryptConfigSecrets as decryptConfigSecrets$1 } from '@wrongstack/core/security';
@@ -403,7 +403,7 @@ function buildSddCommand(opts) {
403
403
  if (!sessionState.getBuilder() && !forceFlag) {
404
404
  const sessionPath = opts.paths.projectSddSession;
405
405
  try {
406
- await fsp2.access(sessionPath);
406
+ await fsp3.access(sessionPath);
407
407
  const projectContext2 = await gatherProjectContext(opts.context?.projectRoot ?? process.cwd());
408
408
  const tempBuilder = new AISpecBuilder({
409
409
  store: specStore,
@@ -1054,16 +1054,16 @@ Start executing the tasks one by one.`
1054
1054
  const sessionPath = opts.paths.projectSddSession;
1055
1055
  let deletedFromDisk = false;
1056
1056
  try {
1057
- await fsp2.unlink(sessionPath);
1057
+ await fsp3.unlink(sessionPath);
1058
1058
  deletedFromDisk = true;
1059
1059
  } catch {
1060
1060
  }
1061
1061
  try {
1062
- await fsp2.rm(opts.paths.projectSpecs, { recursive: true, force: true });
1062
+ await fsp3.rm(opts.paths.projectSpecs, { recursive: true, force: true });
1063
1063
  } catch {
1064
1064
  }
1065
1065
  try {
1066
- await fsp2.rm(opts.paths.projectTaskGraphs, { recursive: true, force: true });
1066
+ await fsp3.rm(opts.paths.projectTaskGraphs, { recursive: true, force: true });
1067
1067
  } catch {
1068
1068
  }
1069
1069
  const cancelBuilder = sddState.getBuilder();
@@ -1399,7 +1399,7 @@ async function gatherProjectContext(projectRoot) {
1399
1399
  const parts = [];
1400
1400
  try {
1401
1401
  const pkgPath = path25.join(projectRoot, "package.json");
1402
- const pkgRaw = await fsp2.readFile(pkgPath, "utf8");
1402
+ const pkgRaw = await fsp3.readFile(pkgPath, "utf8");
1403
1403
  const pkg = JSON.parse(pkgRaw);
1404
1404
  parts.push(`Project: ${String(pkg.name ?? "unknown")}`);
1405
1405
  parts.push(`Description: ${String(pkg.description ?? "none")}`);
@@ -1415,13 +1415,13 @@ async function gatherProjectContext(projectRoot) {
1415
1415
  }
1416
1416
  try {
1417
1417
  const tsconfigPath = path25.join(projectRoot, "tsconfig.json");
1418
- await fsp2.access(tsconfigPath);
1418
+ await fsp3.access(tsconfigPath);
1419
1419
  parts.push("Language: TypeScript");
1420
1420
  } catch {
1421
1421
  }
1422
1422
  try {
1423
1423
  const srcDir = path25.join(projectRoot, "src");
1424
- const entries = await fsp2.readdir(srcDir, { withFileTypes: true });
1424
+ const entries = await fsp3.readdir(srcDir, { withFileTypes: true });
1425
1425
  const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
1426
1426
  if (dirs.length > 0) {
1427
1427
  parts.push(`Source structure: src/${dirs.join(", src/")}`);
@@ -1603,7 +1603,7 @@ function isNewer(a, b) {
1603
1603
  }
1604
1604
  async function readCache(homeFn = defaultHomeDir2) {
1605
1605
  try {
1606
- const raw = await fsp2.readFile(cachePath(homeFn), "utf8");
1606
+ const raw = await fsp3.readFile(cachePath(homeFn), "utf8");
1607
1607
  const entry = JSON.parse(raw);
1608
1608
  if (Date.now() - entry.timestamp > CACHE_TTL_MS) return null;
1609
1609
  return entry;
@@ -1614,8 +1614,8 @@ async function readCache(homeFn = defaultHomeDir2) {
1614
1614
  async function writeCache(entry, homeFn = defaultHomeDir2) {
1615
1615
  try {
1616
1616
  const dir = path25.dirname(cachePath(homeFn));
1617
- await fsp2.mkdir(dir, { recursive: true });
1618
- await fsp2.writeFile(cachePath(homeFn), JSON.stringify(entry, null, 2), "utf8");
1617
+ await fsp3.mkdir(dir, { recursive: true });
1618
+ await fsp3.writeFile(cachePath(homeFn), JSON.stringify(entry, null, 2), "utf8");
1619
1619
  } catch {
1620
1620
  }
1621
1621
  }
@@ -1686,7 +1686,7 @@ async function getUpdateNotification(signal, homeFn) {
1686
1686
  var defaultHomeDir2, CACHE_TTL_MS;
1687
1687
  var init_update_check = __esm({
1688
1688
  "src/update-check.ts"() {
1689
- defaultHomeDir2 = () => os7.homedir();
1689
+ defaultHomeDir2 = () => os6.homedir();
1690
1690
  CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
1691
1691
  }
1692
1692
  });
@@ -1823,10 +1823,27 @@ async function runWebUI(opts) {
1823
1823
  });
1824
1824
  wss.on("connection", (ws, req2) => {
1825
1825
  const isLoopback = (hostname) => hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
1826
+ const tokenMatches = (provided) => {
1827
+ if (!provided) return false;
1828
+ const a = Buffer.from(provided);
1829
+ const b = Buffer.from(authToken);
1830
+ return a.length === b.length && crypto2.timingSafeEqual(a, b);
1831
+ };
1826
1832
  try {
1827
1833
  const url = new URL(req2.url ?? "/", `http://localhost:${port}`);
1828
1834
  const token = url.searchParams.get("token");
1829
- const tokenOk = token === authToken;
1835
+ const tokenOk = tokenMatches(token);
1836
+ const hostHeader = (req2.headers.host ?? "").trim();
1837
+ let hostOk = false;
1838
+ try {
1839
+ hostOk = !!hostHeader && isLoopback(new URL(`http://${hostHeader}`).hostname);
1840
+ } catch {
1841
+ hostOk = false;
1842
+ }
1843
+ if (!hostOk) {
1844
+ ws.close(4003, "Forbidden: non-loopback Host header");
1845
+ return;
1846
+ }
1830
1847
  const origin = req2.headers.origin;
1831
1848
  if (origin) {
1832
1849
  try {
@@ -2206,7 +2223,7 @@ async function runWebUI(opts) {
2206
2223
  if (!opts.globalConfigPath) return {};
2207
2224
  let raw;
2208
2225
  try {
2209
- raw = await fsp2.readFile(opts.globalConfigPath, "utf8");
2226
+ raw = await fsp3.readFile(opts.globalConfigPath, "utf8");
2210
2227
  } catch {
2211
2228
  return {};
2212
2229
  }
@@ -2226,7 +2243,7 @@ async function runWebUI(opts) {
2226
2243
  let raw;
2227
2244
  let fileExists = true;
2228
2245
  try {
2229
- raw = await fsp2.readFile(opts.globalConfigPath, "utf8");
2246
+ raw = await fsp3.readFile(opts.globalConfigPath, "utf8");
2230
2247
  } catch (err) {
2231
2248
  if (err.code !== "ENOENT") {
2232
2249
  throw new Error(
@@ -2459,7 +2476,7 @@ function parseSpawnFlags(input) {
2459
2476
  }
2460
2477
  async function pathExists(file) {
2461
2478
  try {
2462
- await fsp2.access(file);
2479
+ await fsp3.access(file);
2463
2480
  return true;
2464
2481
  } catch {
2465
2482
  return false;
@@ -2494,7 +2511,7 @@ function parseMakeTargets(makefile) {
2494
2511
  async function detectProjectFacts(root) {
2495
2512
  const facts = { hints: [] };
2496
2513
  try {
2497
- const pkg = JSON.parse(await fsp2.readFile(path25.join(root, "package.json"), "utf8"));
2514
+ const pkg = JSON.parse(await fsp3.readFile(path25.join(root, "package.json"), "utf8"));
2498
2515
  const scripts = pkg.scripts ?? {};
2499
2516
  const pm = await detectPackageManager(root, pkg.packageManager);
2500
2517
  if (hasUsableScript(scripts, "build")) facts.build = `${pm} run build`;
@@ -2532,7 +2549,7 @@ async function detectProjectFacts(root) {
2532
2549
  } catch {
2533
2550
  }
2534
2551
  try {
2535
- const makefile = await fsp2.readFile(path25.join(root, "Makefile"), "utf8");
2552
+ const makefile = await fsp3.readFile(path25.join(root, "Makefile"), "utf8");
2536
2553
  const targets = parseMakeTargets(makefile);
2537
2554
  facts.build ??= targets.has("build") ? "make build" : "make";
2538
2555
  if (targets.has("test")) facts.test ??= "make test";
@@ -3428,8 +3445,8 @@ function buildInitCommand(opts) {
3428
3445
  const file = path25.join(dir, "AGENTS.md");
3429
3446
  const detected = await detectProjectFacts(ctx.projectRoot);
3430
3447
  const body = renderAgentsTemplate(detected);
3431
- await fsp2.mkdir(dir, { recursive: true });
3432
- await fsp2.writeFile(file, body, "utf8");
3448
+ await fsp3.mkdir(dir, { recursive: true });
3449
+ await fsp3.writeFile(file, body, "utf8");
3433
3450
  if (detected.hints.length > 0) {
3434
3451
  const msg2 = `Wrote ${file}
3435
3452
  Pre-filled: ${detected.hints.join(", ")}. Edit the file with project context and instructions the system prompt should carry.`;
@@ -3618,7 +3635,7 @@ function stateBadge(state) {
3618
3635
  }
3619
3636
  async function readConfig(path26) {
3620
3637
  try {
3621
- return JSON.parse(await fsp2.readFile(path26, "utf8"));
3638
+ return JSON.parse(await fsp3.readFile(path26, "utf8"));
3622
3639
  } catch {
3623
3640
  return {};
3624
3641
  }
@@ -3626,8 +3643,8 @@ async function readConfig(path26) {
3626
3643
  async function writeConfig(path26, cfg) {
3627
3644
  const raw = JSON.stringify(cfg, null, 2);
3628
3645
  const tmp = path26 + ".tmp";
3629
- await fsp2.writeFile(tmp, raw, "utf8");
3630
- await fsp2.rename(tmp, path26);
3646
+ await fsp3.writeFile(tmp, raw, "utf8");
3647
+ await fsp3.rename(tmp, path26);
3631
3648
  }
3632
3649
 
3633
3650
  // src/slash-commands/mcp.ts
@@ -4899,7 +4916,7 @@ function resolveConfigPath() {
4899
4916
  async function loadStatuslineConfig() {
4900
4917
  const p = resolveConfigPath();
4901
4918
  try {
4902
- const raw = await fsp2.readFile(p, "utf8");
4919
+ const raw = await fsp3.readFile(p, "utf8");
4903
4920
  return { ...DEFAULTS, ...JSON.parse(raw) };
4904
4921
  } catch {
4905
4922
  return { ...DEFAULTS };
@@ -4908,7 +4925,7 @@ async function loadStatuslineConfig() {
4908
4925
  async function saveStatuslineConfig(cfg) {
4909
4926
  const p = resolveConfigPath();
4910
4927
  try {
4911
- await fsp2.mkdir(path25.dirname(p), { recursive: true });
4928
+ await fsp3.mkdir(path25.dirname(p), { recursive: true });
4912
4929
  await atomicWrite(p, JSON.stringify(cfg, null, 2));
4913
4930
  } catch (err) {
4914
4931
  throw new FsError({
@@ -5807,7 +5824,7 @@ When the error confidence is low (< 0.85) or the problem spans multiple files,
5807
5824
  };
5808
5825
  }
5809
5826
  function makeInstaller(opts, projectRoot, global) {
5810
- const globalRoot = path25.join(os7.homedir(), ".wrongstack");
5827
+ const globalRoot = path25.join(os6.homedir(), ".wrongstack");
5811
5828
  return new SkillInstaller({
5812
5829
  manifestPath: path25.join(globalRoot, "installed-skills.json"),
5813
5830
  projectSkillsDir: path25.join(projectRoot, ".wrongstack", "skills"),
@@ -5967,229 +5984,162 @@ function buildSkillUninstallCommand(opts) {
5967
5984
  }
5968
5985
  };
5969
5986
  }
5970
- var currentRunner = null;
5971
- var currentGraph = null;
5972
- var DEFAULT_PHASES = [
5973
- {
5974
- name: "Discovery",
5975
- description: "Requirements gathering and analysis",
5976
- priority: "high",
5977
- estimateHours: 2,
5978
- parallelizable: false
5979
- },
5980
- {
5981
- name: "Design",
5982
- description: "Architecture and design decisions",
5983
- priority: "critical",
5984
- estimateHours: 4,
5985
- parallelizable: false
5986
- },
5987
- {
5988
- name: "Implementation",
5989
- description: "Core feature development",
5990
- priority: "critical",
5991
- estimateHours: 12,
5992
- parallelizable: false
5993
- },
5994
- {
5995
- name: "Testing",
5996
- description: "Unit, integration, and e2e tests",
5997
- priority: "high",
5998
- estimateHours: 6,
5999
- parallelizable: true
6000
- },
6001
- {
6002
- name: "Deployment",
6003
- description: "Deploy to production",
6004
- priority: "medium",
6005
- estimateHours: 2,
6006
- parallelizable: false
6007
- }
6008
- ];
6009
- function getStore() {
6010
- const baseDir = path25.join(os7.homedir(), ".wrongstack", "autophase");
6011
- return new PhaseStore({ baseDir });
5987
+ function getStore(opts) {
5988
+ return new PhaseStore({ baseDir: opts.paths.projectAutophase });
6012
5989
  }
6013
5990
  function formatProgress(p) {
6014
- const bars = "\u2588".repeat(Math.floor(p.percentComplete / 5)) + "\u2591".repeat(20 - Math.floor(p.percentComplete / 5));
5991
+ const filled = Math.floor(p.percentComplete / 5);
5992
+ const bars = "\u2588".repeat(filled) + "\u2591".repeat(20 - filled);
6015
5993
  return [
6016
5994
  `
6017
5995
  \u{1F4CA} Progress: ${bars} ${p.percentComplete}%`,
6018
5996
  ` \u{1F4CB} Phases: ${p.completed}/${p.totalPhases} done, ${p.running} running, ${p.pending} pending`,
6019
5997
  ` \u2705 Tasks: ${p.completedTasks}/${p.totalTasks} completed`,
6020
- ` \u23F1\uFE0F Est: ${p.estimatedHours.toFixed(1)}h | Actual: ${p.actualHours.toFixed(1)}h`
5998
+ ` \u23F1 Est: ${p.estimatedHours.toFixed(1)}h | Actual: ${p.actualHours.toFixed(1)}h`
6021
5999
  ].join("\n");
6022
6000
  }
6001
+ var STATUS_EMOJI = {
6002
+ pending: "\u23F3",
6003
+ ready: "\u{1F51C}",
6004
+ running: "\u{1F504}",
6005
+ paused: "\u23F8",
6006
+ completed: "\u2705",
6007
+ failed: "\u274C",
6008
+ skipped: "\u23ED"
6009
+ };
6023
6010
  function formatPhaseList(graph) {
6024
6011
  const phases = Array.from(graph.phases.values());
6025
- const statusEmoji = {
6026
- pending: "\u23F3",
6027
- ready: "\u{1F51C}",
6028
- running: "\u{1F504}",
6029
- paused: "\u23F8\uFE0F",
6030
- completed: "\u2705",
6031
- failed: "\u274C",
6032
- skipped: "\u23ED\uFE0F"
6033
- };
6034
- return phases.map((p, i) => {
6035
- const emoji = statusEmoji[p.status] ?? "\u26AA";
6036
- const progress = p.taskGraph.nodes.size > 0 ? `${Array.from(p.taskGraph.nodes.values()).filter((t) => t.status === "completed").length}/${p.taskGraph.nodes.size}` : "0/0";
6037
- return ` ${i + 1}. ${emoji} ${p.name} (${p.status}) \u2014 ${progress} tasks`;
6038
- }).join("\n");
6012
+ return [
6013
+ "",
6014
+ "Phases:",
6015
+ ...phases.map((p) => {
6016
+ const total = p.taskGraph.nodes.size;
6017
+ const done = Array.from(p.taskGraph.nodes.values()).filter((t) => t.status === "completed").length;
6018
+ const tasks = total > 0 ? ` (${done}/${total} todos)` : "";
6019
+ return ` ${STATUS_EMOJI[p.status] ?? "?"} ${p.name}: ${p.status}${tasks}`;
6020
+ })
6021
+ ].join("\n");
6039
6022
  }
6040
- var autophaseCommand = {
6041
- name: "autophase",
6042
- description: "Otonom faz tabanl\u0131 i\u015F ak\u0131\u015F\u0131 \u2014 projeyi fazlara b\xF6l ve otonom \xE7al\u0131\u015Ft\u0131r",
6043
- argsHint: "[start|pause|resume|stop|status|list|load|save] [args...]",
6044
- async run(args, _ctx) {
6045
- const parts = args.trim().split(/\s+/).filter(Boolean);
6046
- const sub = parts[0] ?? "status";
6047
- const store = getStore();
6048
- switch (sub) {
6049
- case "start": {
6050
- const title = parts.slice(1).join(" ") || "Untitled Project";
6051
- const runLog = [];
6052
- const log = (line) => runLog.push(line);
6053
- log(`\u{1F680} AutoPhase ba\u015Flat\u0131l\u0131yor: ${title}`);
6054
- currentRunner = new AutoPhaseRunner({
6055
- title,
6056
- phases: DEFAULT_PHASES,
6057
- executeTask: async (task, phaseId) => {
6058
- log(` [${phaseId}] Executing: ${task.title}`);
6059
- await new Promise((r) => setTimeout(r, 500));
6060
- log(` [${phaseId}] \u2705 Completed: ${task.title}`);
6061
- },
6062
- onPhaseComplete: (phase) => {
6063
- log(`\u2705 Phase tamamland\u0131: ${phase.name} (${phase.actualDurationMs ? (phase.actualDurationMs / 6e4).toFixed(1) : 0}m)`);
6064
- },
6065
- onPhaseFail: (phase, error) => {
6066
- log(`\u274C Phase ba\u015Far\u0131s\u0131z: ${phase.name} \u2014 ${error.message}`);
6067
- },
6068
- onProgress: (progress) => {
6069
- if (progress.percentComplete % 10 === 0) {
6070
- log(formatProgress(progress));
6071
- }
6072
- },
6073
- onComplete: (graph) => {
6074
- log(`\u{1F389} T\xFCm fazlar tamamland\u0131! ${graph.title}`);
6075
- },
6076
- onFail: (_graph, phase, error) => {
6077
- log(`\u{1F4A5} AutoPhase durdu: ${phase.name} \u2014 ${error.message}`);
6078
- },
6079
- autonomous: true,
6080
- maxConcurrentPhases: 1,
6081
- maxConcurrentTasks: 2
6082
- });
6083
- currentGraph = await currentRunner.start();
6084
- await store.save(currentGraph);
6085
- return {
6086
- message: [
6087
- `AutoPhase ba\u015Flat\u0131ld\u0131: **${title}**`,
6088
- "",
6089
- formatPhaseList(currentGraph),
6090
- ...runLog.length > 0 ? ["", "---", ...runLog] : []
6091
- ].join("\n")
6092
- };
6093
- }
6094
- case "pause": {
6095
- if (!currentRunner) {
6096
- return { message: "\u274C Aktif AutoPhase yok. \xD6nce `/autophase start` \xE7al\u0131\u015Ft\u0131r\u0131n." };
6023
+ async function gatherProjectContext2(projectRoot) {
6024
+ try {
6025
+ const raw = await fsp3.readFile(path25.join(projectRoot, "package.json"), "utf8");
6026
+ const pkg = JSON.parse(raw);
6027
+ const parts = [
6028
+ `Project: ${String(pkg.name ?? "unknown")}`,
6029
+ pkg.description ? `Description: ${String(pkg.description)}` : ""
6030
+ ].filter(Boolean);
6031
+ return parts.join("\n") || void 0;
6032
+ } catch {
6033
+ return void 0;
6034
+ }
6035
+ }
6036
+ function buildAutoPhaseCommand(opts) {
6037
+ return {
6038
+ name: "autophase",
6039
+ description: "Autonomous phase-based workflow \u2014 plans a project into phases of todos and builds it with the LLM.",
6040
+ help: [
6041
+ "Usage:",
6042
+ " /autophase Show current status",
6043
+ " /autophase start <goal> Plan + start an autonomous phase build",
6044
+ " /autophase pause Pause (in-flight tasks finish, no new ones start)",
6045
+ " /autophase resume Resume a paused run",
6046
+ " /autophase stop Stop and abort in-flight tasks",
6047
+ " /autophase save Persist current graph to disk",
6048
+ " /autophase load [title] Load a persisted graph (display only)",
6049
+ " /autophase list List saved projects",
6050
+ ""
6051
+ ].join("\n"),
6052
+ async run(args) {
6053
+ const parts = args.trim().split(/\s+/).filter(Boolean);
6054
+ const sub = parts[0] ?? "status";
6055
+ const store = getStore(opts);
6056
+ switch (sub) {
6057
+ case "start": {
6058
+ const goal = parts.slice(1).join(" ").trim();
6059
+ if (!goal) {
6060
+ return { message: "Usage: /autophase start <goal> \u2014 describe what to build." };
6061
+ }
6062
+ if (!opts.onAutoPhaseStart) {
6063
+ return { message: "\u274C AutoPhase is not available in this session (no LLM host wired)." };
6064
+ }
6065
+ const projectContext = await gatherProjectContext2(opts.projectRoot);
6066
+ const result = await opts.onAutoPhaseStart({ goal, projectContext });
6067
+ if (!result.ok) {
6068
+ return { message: `\u274C ${result.error}` };
6069
+ }
6070
+ return {
6071
+ message: [
6072
+ `\u{1F680} AutoPhase started: **${result.graph.title}**`,
6073
+ formatPhaseList(result.graph),
6074
+ "",
6075
+ "Building autonomously in the background \u2014 one subagent per todo.",
6076
+ "Use `/autophase` for status, `/autophase pause` to hold, `/autophase stop` to abort."
6077
+ ].join("\n"),
6078
+ metadata: { autoPhaseInit: { title: result.graph.title } }
6079
+ };
6097
6080
  }
6098
- currentRunner.pause();
6099
- return { message: "\u23F8\uFE0F AutoPhase duraklat\u0131ld\u0131. Devam etmek i\xE7in `/autophase resume`" };
6100
- }
6101
- case "resume": {
6102
- if (!currentRunner) {
6103
- return { message: "\u274C Aktif AutoPhase yok. \xD6nce `/autophase start` \xE7al\u0131\u015Ft\u0131r\u0131n." };
6081
+ case "pause": {
6082
+ if (!opts.onAutoPhasePause) return { message: "\u274C AutoPhase host not available." };
6083
+ opts.onAutoPhasePause();
6084
+ return { message: "\u23F8\uFE0F AutoPhase paused \u2014 running tasks will finish; no new ones will start." };
6104
6085
  }
6105
- currentRunner.resume();
6106
- return { message: "\u25B6\uFE0F AutoPhase devam ediyor." };
6107
- }
6108
- case "stop": {
6109
- if (!currentRunner) {
6110
- return { message: "\u274C Aktif AutoPhase yok." };
6086
+ case "resume": {
6087
+ if (!opts.onAutoPhaseResume) return { message: "\u274C AutoPhase host not available." };
6088
+ opts.onAutoPhaseResume();
6089
+ return { message: "\u25B6 AutoPhase resuming." };
6111
6090
  }
6112
- currentRunner.stop();
6113
- currentRunner = null;
6114
- return { message: "\u{1F6D1} AutoPhase durduruldu." };
6115
- }
6116
- case "status": {
6117
- if (!currentRunner || !currentGraph) {
6091
+ case "stop": {
6092
+ if (!opts.onAutoPhaseStop) return { message: "\u274C AutoPhase host not available." };
6093
+ opts.onAutoPhaseStop();
6094
+ return { message: "\u23F9 AutoPhase stopped \u2014 in-flight tasks aborted, progress saved." };
6095
+ }
6096
+ case "save": {
6097
+ const view = opts.getAutoPhaseRunner?.();
6098
+ if (!view) return { message: "\u274C No active AutoPhase to save." };
6099
+ await store.save(view.graph);
6100
+ return { message: `\u{1F4BE} AutoPhase saved: ${view.graph.title}` };
6101
+ }
6102
+ case "load": {
6103
+ const title = parts.slice(1).join(" ").trim();
6118
6104
  const graphs = await store.list();
6119
- if (graphs.length === 0) {
6120
- return { message: "Aktif AutoPhase yok. Ba\u015Flatmak i\xE7in `/autophase start [title]`" };
6121
- }
6122
- const list = graphs.slice(0, 5).map((g) => ` \u2022 ${g.title} (${g.status})`).join("\n");
6123
- return { message: `Kay\u0131tl\u0131 AutoPhase projeleri:
6124
- ${list}` };
6125
- }
6126
- const progress = currentRunner.getProgress();
6127
- const phaseList = formatPhaseList(currentGraph);
6128
- return {
6129
- message: [
6130
- `**${currentGraph.title}**`,
6131
- progress ? formatProgress(progress) : "",
6132
- "",
6133
- "**Fazlar:**",
6134
- phaseList,
6135
- "",
6136
- currentRunner.isPaused() ? "\u23F8\uFE0F Duraklat\u0131ld\u0131" : currentRunner.isRunning() ? "\u{1F504} \xC7al\u0131\u015F\u0131yor" : "\u23F9\uFE0F Durdu"
6137
- ].join("\n")
6138
- };
6139
- }
6140
- case "list": {
6141
- const graphs = await store.list();
6142
- if (graphs.length === 0) {
6143
- return { message: "Kay\u0131tl\u0131 AutoPhase projesi yok." };
6144
- }
6145
- const list = graphs.map((g) => {
6146
- const statusEmoji = g.status === "completed" ? "\u2705" : g.status === "in_progress" ? "\u{1F504}" : "\u23F3";
6147
- return ` ${statusEmoji} ${g.title} (g\xFCncelleme: ${new Date(g.updatedAt).toLocaleDateString("tr-TR")})`;
6148
- }).join("\n");
6149
- return { message: `**Kay\u0131tl\u0131 Projeler:**
6150
- ${list}` };
6151
- }
6152
- case "load": {
6153
- const graphId = parts[1];
6154
- if (!graphId) {
6155
- return { message: "\u274C Graph ID gerekli. Kullan\u0131m: `/autophase load <id>`" };
6105
+ if (graphs.length === 0) return { message: "\u274C No saved projects." };
6106
+ const entry = title ? graphs.find((g) => g.title.toLowerCase().includes(title.toLowerCase())) : graphs[0];
6107
+ if (!entry) return { message: `\u274C No saved project matching "${title}".` };
6108
+ const graph = await store.load(entry.id);
6109
+ if (!graph) return { message: `\u274C Could not load project "${entry.title}".` };
6110
+ return {
6111
+ message: [`\u{1F4C2} Loaded (display only): **${graph.title}**`, formatPhaseList(graph)].join("\n")
6112
+ };
6156
6113
  }
6157
- const graph = await store.load(graphId);
6158
- if (!graph) {
6159
- return { message: `\u274C Graph bulunamad\u0131: ${graphId}` };
6114
+ case "list": {
6115
+ const graphs = await store.list();
6116
+ if (graphs.length === 0) return { message: "No saved projects." };
6117
+ return {
6118
+ message: [
6119
+ "Saved AutoPhase projects:",
6120
+ ...graphs.map((g) => ` \xB7 ${g.title} \u2014 ${g.status} (updated ${new Date(g.updatedAt).toLocaleString()})`)
6121
+ ].join("\n")
6122
+ };
6160
6123
  }
6161
- currentGraph = graph;
6162
- return {
6163
- message: `**${graph.title}** y\xFCklendi.
6164
-
6165
- ${formatPhaseList(graph)}`
6166
- };
6167
- }
6168
- case "save": {
6169
- if (!currentGraph) {
6170
- return { message: "\u274C Kaydedilecek aktif graph yok." };
6124
+ case "default":
6125
+ case "status": {
6126
+ const view = opts.getAutoPhaseRunner?.();
6127
+ if (!view) {
6128
+ return { message: "No active AutoPhase. Run `/autophase start <goal>` to begin." };
6129
+ }
6130
+ const progress = view.getProgress();
6131
+ return {
6132
+ message: [
6133
+ `**${view.graph.title}** ${view.isRunning() ? "\u{1F504} running" : "\u23F8 idle"}`,
6134
+ formatPhaseList(view.graph),
6135
+ ...progress ? [formatProgress(progress)] : []
6136
+ ].join("\n")
6137
+ };
6171
6138
  }
6172
- await store.save(currentGraph);
6173
- return { message: `\u2705 **${currentGraph.title}** kaydedildi.` };
6174
6139
  }
6175
- default:
6176
- return {
6177
- message: [
6178
- "**AutoPhase Komutlar\u0131:**",
6179
- "",
6180
- "`/autophase start [title]` \u2014 Yeni proje ba\u015Flat",
6181
- "`/autophase pause` \u2014 Duraklat",
6182
- "`/autophase resume` \u2014 Devam et",
6183
- "`/autophase stop` \u2014 Durdur",
6184
- "`/autophase status` \u2014 Durum g\xF6ster",
6185
- "`/autophase list` \u2014 Kay\u0131tl\u0131 projeleri listele",
6186
- "`/autophase load <id>` \u2014 Projeyi y\xFCkle",
6187
- "`/autophase save` \u2014 Aktif projeyi kaydet"
6188
- ].join("\n")
6189
- };
6190
6140
  }
6191
- }
6192
- };
6141
+ };
6142
+ }
6193
6143
 
6194
6144
  // src/slash-commands/index.ts
6195
6145
  function buildBuiltinSlashCommands(opts) {
@@ -6232,7 +6182,7 @@ function buildBuiltinSlashCommands(opts) {
6232
6182
  buildPushCommand(),
6233
6183
  buildSecurityCommand(opts),
6234
6184
  buildFixCommand(opts),
6235
- autophaseCommand,
6185
+ buildAutoPhaseCommand(opts),
6236
6186
  buildStatuslineCommand({
6237
6187
  cwd: opts.cwd,
6238
6188
  hiddenItems: opts.statuslineHiddenItems ?? [],
@@ -6260,13 +6210,13 @@ var MANIFESTS = [
6260
6210
  ];
6261
6211
  async function detectProjectKind(projectRoot) {
6262
6212
  try {
6263
- await fsp2.access(path25.join(projectRoot, ".wrongstack", "AGENTS.md"));
6213
+ await fsp3.access(path25.join(projectRoot, ".wrongstack", "AGENTS.md"));
6264
6214
  return "initialized";
6265
6215
  } catch {
6266
6216
  }
6267
6217
  for (const m of MANIFESTS) {
6268
6218
  try {
6269
- await fsp2.access(path25.join(projectRoot, m));
6219
+ await fsp3.access(path25.join(projectRoot, m));
6270
6220
  return "project";
6271
6221
  } catch {
6272
6222
  }
@@ -6278,8 +6228,8 @@ async function scaffoldAgentsMd(projectRoot) {
6278
6228
  const file = path25.join(dir, "AGENTS.md");
6279
6229
  const facts = await detectProjectFacts(projectRoot);
6280
6230
  const body = renderAgentsTemplate(facts);
6281
- await fsp2.mkdir(dir, { recursive: true });
6282
- await fsp2.writeFile(file, body, "utf8");
6231
+ await fsp3.mkdir(dir, { recursive: true });
6232
+ await fsp3.writeFile(file, body, "utf8");
6283
6233
  return file;
6284
6234
  }
6285
6235
  async function runProjectCheck(opts) {
@@ -6322,7 +6272,7 @@ async function runProjectCheck(opts) {
6322
6272
  const gitDir = path25.join(projectRoot, ".git");
6323
6273
  let hasGit = false;
6324
6274
  try {
6325
- await fsp2.access(gitDir);
6275
+ await fsp3.access(gitDir);
6326
6276
  hasGit = true;
6327
6277
  } catch {
6328
6278
  }
@@ -6447,7 +6397,7 @@ async function bootConfig(flags) {
6447
6397
  const cwd = typeof flags["cwd"] === "string" ? path25.resolve(flags["cwd"]) : process.cwd();
6448
6398
  const pathResolver = new DefaultPathResolver(cwd);
6449
6399
  const projectRoot = pathResolver.projectRoot;
6450
- const userHome = os7.homedir();
6400
+ const userHome = os6.homedir();
6451
6401
  const wpaths = resolveWstackPaths({ projectRoot, userHome });
6452
6402
  await ensureProjectMeta(wpaths, projectRoot);
6453
6403
  const vault = new DefaultSecretVault({ keyFile: wpaths.secretsKey });
@@ -6495,13 +6445,13 @@ function flagsToConfigPatch(flags) {
6495
6445
  }
6496
6446
  async function ensureProjectMeta(paths, projectRoot) {
6497
6447
  try {
6498
- await fsp2.mkdir(paths.projectDir, { recursive: true });
6448
+ await fsp3.mkdir(paths.projectDir, { recursive: true });
6499
6449
  const meta = {
6500
6450
  hash: paths.projectHash,
6501
6451
  root: projectRoot,
6502
6452
  lastSeen: (/* @__PURE__ */ new Date()).toISOString()
6503
6453
  };
6504
- await fsp2.writeFile(paths.projectMeta, JSON.stringify(meta, null, 2));
6454
+ await fsp3.writeFile(paths.projectMeta, JSON.stringify(meta, null, 2));
6505
6455
  } catch {
6506
6456
  }
6507
6457
  }
@@ -6511,11 +6461,11 @@ var ReadlineInputReader = class {
6511
6461
  history = [];
6512
6462
  pending = false;
6513
6463
  constructor(opts = {}) {
6514
- this.historyFile = opts.historyFile ?? path25.join(os7.homedir(), ".wrongstack", "history");
6464
+ this.historyFile = opts.historyFile ?? path25.join(os6.homedir(), ".wrongstack", "history");
6515
6465
  }
6516
6466
  async loadHistory() {
6517
6467
  try {
6518
- const raw = await fsp2.readFile(this.historyFile, "utf8");
6468
+ const raw = await fsp3.readFile(this.historyFile, "utf8");
6519
6469
  this.history = raw.split("\n").filter(Boolean).slice(-1e3);
6520
6470
  } catch {
6521
6471
  this.history = [];
@@ -6523,8 +6473,8 @@ var ReadlineInputReader = class {
6523
6473
  }
6524
6474
  async saveHistory() {
6525
6475
  try {
6526
- await fsp2.mkdir(path25.dirname(this.historyFile), { recursive: true });
6527
- await fsp2.writeFile(this.historyFile, this.history.slice(-1e3).join("\n"));
6476
+ await fsp3.mkdir(path25.dirname(this.historyFile), { recursive: true });
6477
+ await fsp3.writeFile(this.historyFile, this.history.slice(-1e3).join("\n"));
6528
6478
  } catch {
6529
6479
  }
6530
6480
  }
@@ -6766,7 +6716,7 @@ async function safeDelete(filePath) {
6766
6716
  const filename = path25.basename(filePath);
6767
6717
  try {
6768
6718
  assertSafeToDelete(filename, dir);
6769
- await fsp2.unlink(filePath);
6719
+ await fsp3.unlink(filePath);
6770
6720
  } catch (err) {
6771
6721
  if (err instanceof Error && err.message.startsWith("Refusing")) {
6772
6722
  process.stderr.write(`[config-history] SAFETY: ${err.message}
@@ -6806,7 +6756,7 @@ function diffSummary(oldCfg, newCfg) {
6806
6756
  }
6807
6757
  return changes.length > 0 ? changes.slice(0, 5).join(", ") : "no changes";
6808
6758
  }
6809
- var defaultHomeDir = () => os7__default.homedir();
6759
+ var defaultHomeDir = () => os6__default.homedir();
6810
6760
  function historyDir(homeFn = defaultHomeDir) {
6811
6761
  return path25.join(homeFn(), ".wrongstack", "config.history", "entries");
6812
6762
  }
@@ -6824,7 +6774,7 @@ function entryId(ts) {
6824
6774
  }
6825
6775
  async function ensureHistoryDir(homeFn = defaultHomeDir) {
6826
6776
  try {
6827
- await fsp2.mkdir(historyDir(homeFn), { recursive: true });
6777
+ await fsp3.mkdir(historyDir(homeFn), { recursive: true });
6828
6778
  } catch (err) {
6829
6779
  throw new FsError({
6830
6780
  message: err instanceof Error ? err.message : String(err),
@@ -6836,7 +6786,7 @@ async function ensureHistoryDir(homeFn = defaultHomeDir) {
6836
6786
  }
6837
6787
  async function readIndex(homeFn = defaultHomeDir) {
6838
6788
  try {
6839
- const raw = await fsp2.readFile(historyIndexPath(homeFn), "utf8");
6789
+ const raw = await fsp3.readFile(historyIndexPath(homeFn), "utf8");
6840
6790
  return JSON.parse(raw);
6841
6791
  } catch {
6842
6792
  return { version: 1, entries: [] };
@@ -6861,7 +6811,7 @@ async function backupCurrent(homeFn = defaultHomeDir) {
6861
6811
  const ts = Date.now();
6862
6812
  let content;
6863
6813
  try {
6864
- content = await fsp2.readFile(cfg, "utf8");
6814
+ content = await fsp3.readFile(cfg, "utf8");
6865
6815
  } catch {
6866
6816
  }
6867
6817
  if (content !== void 0) {
@@ -6879,7 +6829,7 @@ async function backupCurrent(homeFn = defaultHomeDir) {
6879
6829
  }
6880
6830
  try {
6881
6831
  const dir = path25.join(homeFn(), ".wrongstack");
6882
- const files = await fsp2.readdir(dir);
6832
+ const files = await fsp3.readdir(dir);
6883
6833
  const baks = files.filter((f) => f.startsWith("config.json.") && f.endsWith(".bak")).sort().reverse();
6884
6834
  for (const f of baks.slice(10)) {
6885
6835
  await safeDelete(path25.join(dir, f));
@@ -6899,7 +6849,7 @@ async function appendHistory(oldCfg, newCfg, description, homeFn = defaultHomeDi
6899
6849
  diffSummary: diffSummary(oldCfg, newCfg)
6900
6850
  };
6901
6851
  try {
6902
- await fsp2.writeFile(
6852
+ await fsp3.writeFile(
6903
6853
  path25.join(historyDir(homeFn), `${id}.json`),
6904
6854
  JSON.stringify(entry, null, 2),
6905
6855
  "utf8"
@@ -6923,7 +6873,7 @@ async function listHistory(homeFn = defaultHomeDir) {
6923
6873
  }
6924
6874
  async function getHistoryEntry(id, homeFn = defaultHomeDir) {
6925
6875
  try {
6926
- const raw = await fsp2.readFile(path25.join(historyDir(homeFn), `${id}.json`), "utf8");
6876
+ const raw = await fsp3.readFile(path25.join(historyDir(homeFn), `${id}.json`), "utf8");
6927
6877
  return JSON.parse(raw);
6928
6878
  } catch {
6929
6879
  return null;
@@ -6935,7 +6885,7 @@ async function restoreFromHistory(id, homeFn = defaultHomeDir) {
6935
6885
  await backupCurrent(homeFn);
6936
6886
  let oldCfg = {};
6937
6887
  try {
6938
- const raw = await fsp2.readFile(configPath(homeFn), "utf8");
6888
+ const raw = await fsp3.readFile(configPath(homeFn), "utf8");
6939
6889
  oldCfg = JSON.parse(raw);
6940
6890
  } catch {
6941
6891
  }
@@ -6957,13 +6907,13 @@ async function restoreLast(homeFn = defaultHomeDir) {
6957
6907
  const cfg = configPath(homeFn);
6958
6908
  let oldCfg = {};
6959
6909
  try {
6960
- const raw = await fsp2.readFile(cfg, "utf8");
6910
+ const raw = await fsp3.readFile(cfg, "utf8");
6961
6911
  oldCfg = JSON.parse(raw);
6962
6912
  } catch {
6963
6913
  }
6964
6914
  let lastCfg = {};
6965
6915
  try {
6966
- const raw = await fsp2.readFile(last, "utf8");
6916
+ const raw = await fsp3.readFile(last, "utf8");
6967
6917
  lastCfg = JSON.parse(raw);
6968
6918
  } catch {
6969
6919
  return { ok: false, error: "No prior backup found" };
@@ -6994,7 +6944,7 @@ async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => p
6994
6944
  existing.provider = provider;
6995
6945
  existing.model = model;
6996
6946
  await backupCurrent(homeFn);
6997
- await atomicWrite8(configPath2, JSON.stringify(existing, null, 2));
6947
+ await atomicWrite8(configPath2, JSON.stringify(existing, null, 2), { mode: 384 });
6998
6948
  try {
6999
6949
  await appendHistory(
7000
6950
  oldCfg,
@@ -8424,7 +8374,7 @@ async function readKeyInput(deps, intent) {
8424
8374
  async function loadProviders(deps) {
8425
8375
  let raw;
8426
8376
  try {
8427
- raw = await fsp2.readFile(deps.globalConfigPath, "utf8");
8377
+ raw = await fsp3.readFile(deps.globalConfigPath, "utf8");
8428
8378
  } catch (err) {
8429
8379
  if (err.code !== "ENOENT") {
8430
8380
  deps.renderer.writeWarning(
@@ -8449,7 +8399,7 @@ async function mutateProviders(deps, mutator) {
8449
8399
  let raw;
8450
8400
  let fileExists = true;
8451
8401
  try {
8452
- raw = await fsp2.readFile(deps.globalConfigPath, "utf8");
8402
+ raw = await fsp3.readFile(deps.globalConfigPath, "utf8");
8453
8403
  } catch (err) {
8454
8404
  if (err.code !== "ENOENT") {
8455
8405
  throw new Error(
@@ -8595,7 +8545,7 @@ var diagCmd = async (_args, deps) => {
8595
8545
  ` modelsCache: ${deps.paths.modelsCache}`,
8596
8546
  ` cacheAge: ${isFinite(age) ? `${Math.round(age / 60)}m` : "never"}`,
8597
8547
  ` node: ${process.version}`,
8598
- ` os: ${os7.platform()} ${os7.release()}`,
8548
+ ` os: ${os6.platform()} ${os6.release()}`,
8599
8549
  ` provider: ${cfg.provider ?? "<unset>"}`,
8600
8550
  ` model: ${cfg.model ?? "<unset>"}`,
8601
8551
  ` tools: ${deps.toolRegistry?.list().length ?? 0}`,
@@ -8663,7 +8613,7 @@ var doctorCmd = async (_args, deps) => {
8663
8613
  });
8664
8614
  }
8665
8615
  try {
8666
- await fsp2.access(deps.paths.secretsKey);
8616
+ await fsp3.access(deps.paths.secretsKey);
8667
8617
  checks.push({ name: "secret vault", status: "ok", detail: deps.paths.secretsKey });
8668
8618
  } catch {
8669
8619
  checks.push({
@@ -8673,10 +8623,10 @@ var doctorCmd = async (_args, deps) => {
8673
8623
  });
8674
8624
  }
8675
8625
  try {
8676
- await fsp2.mkdir(deps.paths.projectSessions, { recursive: true });
8626
+ await fsp3.mkdir(deps.paths.projectSessions, { recursive: true });
8677
8627
  const probe = path25.join(deps.paths.projectSessions, `.probe-${Date.now()}`);
8678
- await fsp2.writeFile(probe, "");
8679
- await fsp2.unlink(probe);
8628
+ await fsp3.writeFile(probe, "");
8629
+ await fsp3.unlink(probe);
8680
8630
  checks.push({ name: "sessions writable", status: "ok", detail: deps.paths.projectSessions });
8681
8631
  } catch (err) {
8682
8632
  checks.push({
@@ -8777,8 +8727,8 @@ var exportCmd = async (args, deps) => {
8777
8727
  return 1;
8778
8728
  }
8779
8729
  if (output) {
8780
- await fsp2.mkdir(path25.dirname(path25.resolve(deps.cwd, output)), { recursive: true });
8781
- await fsp2.writeFile(path25.resolve(deps.cwd, output), rendered, "utf8");
8730
+ await fsp3.mkdir(path25.dirname(path25.resolve(deps.cwd, output)), { recursive: true });
8731
+ await fsp3.writeFile(path25.resolve(deps.cwd, output), rendered, "utf8");
8782
8732
  deps.renderer.write(`Wrote ${rendered.length} bytes to ${output}
8783
8733
  `);
8784
8734
  } else {
@@ -8845,13 +8795,13 @@ var initCmd = async (_args, deps) => {
8845
8795
  } else {
8846
8796
  deps.renderer.writeInfo(`Found API key in env (${provider.envVars.join(" / ")}).`);
8847
8797
  }
8848
- await fsp2.mkdir(deps.paths.globalRoot, { recursive: true });
8798
+ await fsp3.mkdir(deps.paths.globalRoot, { recursive: true });
8849
8799
  const config = { version: 1, provider: providerId, model: modelId };
8850
8800
  if (apiKey) config.apiKey = apiKey;
8851
8801
  const vault = new DefaultSecretVault$1({ keyFile: deps.paths.secretsKey });
8852
8802
  const encrypted = encryptConfigSecrets(config, vault);
8853
- await atomicWrite(deps.paths.globalConfig, JSON.stringify(encrypted, null, 2));
8854
- await fsp2.mkdir(path25.join(deps.projectRoot, ".wrongstack"), { recursive: true });
8803
+ await atomicWrite(deps.paths.globalConfig, JSON.stringify(encrypted, null, 2), { mode: 384 });
8804
+ await fsp3.mkdir(path25.join(deps.projectRoot, ".wrongstack"), { recursive: true });
8855
8805
  const agentsFile = path25.join(deps.projectRoot, ".wrongstack", "AGENTS.md");
8856
8806
  const projectFacts = await detectProjectFacts(deps.projectRoot);
8857
8807
  await atomicWrite(agentsFile, renderAgentsTemplate(projectFacts));
@@ -8926,7 +8876,7 @@ async function addMcpServer(args, deps) {
8926
8876
  serverCfg.enabled = enable;
8927
8877
  let existing = {};
8928
8878
  try {
8929
- existing = JSON.parse(await fsp2.readFile(deps.paths.globalConfig, "utf8"));
8879
+ existing = JSON.parse(await fsp3.readFile(deps.paths.globalConfig, "utf8"));
8930
8880
  } catch {
8931
8881
  }
8932
8882
  const mcpServers = existing.mcpServers ?? {};
@@ -8935,7 +8885,7 @@ async function addMcpServer(args, deps) {
8935
8885
  `);
8936
8886
  mcpServers[name] = serverCfg;
8937
8887
  existing.mcpServers = mcpServers;
8938
- await atomicWrite(deps.paths.globalConfig, JSON.stringify(existing, null, 2));
8888
+ await atomicWrite(deps.paths.globalConfig, JSON.stringify(existing, null, 2), { mode: 384 });
8939
8889
  const verb = enable ? "Enabled" : "Added (disabled \u2014 set enabled:true to activate)";
8940
8890
  deps.renderer.writeInfo(
8941
8891
  `${verb} "${name}" (${serverCfg.transport}). Config written to ${deps.paths.globalConfig}.
@@ -8946,7 +8896,7 @@ async function addMcpServer(args, deps) {
8946
8896
  async function removeMcpServer(name, deps) {
8947
8897
  let existing = {};
8948
8898
  try {
8949
- existing = JSON.parse(await fsp2.readFile(deps.paths.globalConfig, "utf8"));
8899
+ existing = JSON.parse(await fsp3.readFile(deps.paths.globalConfig, "utf8"));
8950
8900
  } catch {
8951
8901
  deps.renderer.writeError("No config file found.\n");
8952
8902
  return 1;
@@ -8959,7 +8909,7 @@ async function removeMcpServer(name, deps) {
8959
8909
  }
8960
8910
  delete mcpServers[name];
8961
8911
  existing.mcpServers = mcpServers;
8962
- await atomicWrite(deps.paths.globalConfig, JSON.stringify(existing, null, 2));
8912
+ await atomicWrite(deps.paths.globalConfig, JSON.stringify(existing, null, 2), { mode: 384 });
8963
8913
  deps.renderer.writeInfo(`Removed "${name}" from config.
8964
8914
  `);
8965
8915
  return 0;
@@ -9067,7 +9017,7 @@ function renderConfiguredPlugins(config) {
9067
9017
  }
9068
9018
  async function readConfig2(file) {
9069
9019
  try {
9070
- return JSON.parse(await fsp2.readFile(file, "utf8"));
9020
+ return JSON.parse(await fsp3.readFile(file, "utf8"));
9071
9021
  } catch {
9072
9022
  return {};
9073
9023
  }
@@ -9097,7 +9047,7 @@ async function upsertPlugin(spec, opts, deps, verb) {
9097
9047
  };
9098
9048
  existing.plugins = plugins;
9099
9049
  existing.features = features;
9100
- await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2));
9050
+ await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
9101
9051
  return {
9102
9052
  code: 0,
9103
9053
  level: "info",
@@ -9114,7 +9064,7 @@ async function removePlugin(spec, deps) {
9114
9064
  return errorResult(`Plugin "${spec}" not in config.`);
9115
9065
  }
9116
9066
  existing.plugins = next;
9117
- await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2));
9067
+ await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
9118
9068
  return {
9119
9069
  code: 0,
9120
9070
  level: "info",
@@ -9160,7 +9110,7 @@ var usageCmd = async (_args, deps) => {
9160
9110
  var projectsCmd = async (_args, deps) => {
9161
9111
  const projectsRoot = path25.join(deps.paths.globalRoot, "projects");
9162
9112
  try {
9163
- const entries = await fsp2.readdir(projectsRoot);
9113
+ const entries = await fsp3.readdir(projectsRoot);
9164
9114
  if (entries.length === 0) {
9165
9115
  deps.renderer.write("No projects tracked.\n");
9166
9116
  return 0;
@@ -9168,7 +9118,7 @@ var projectsCmd = async (_args, deps) => {
9168
9118
  for (const hash of entries) {
9169
9119
  try {
9170
9120
  const meta = JSON.parse(
9171
- await fsp2.readFile(path25.join(projectsRoot, hash, "meta.json"), "utf8")
9121
+ await fsp3.readFile(path25.join(projectsRoot, hash, "meta.json"), "utf8")
9172
9122
  );
9173
9123
  deps.renderer.write(
9174
9124
  ` ${color.dim(hash)} ${color.dim(meta.lastSeen ?? "")} ${meta.root ?? "?"}
@@ -9319,7 +9269,7 @@ var sessionsFleetCmd = async (args, deps) => {
9319
9269
  async function listFleetRuns(deps) {
9320
9270
  let entries = [];
9321
9271
  try {
9322
- entries = await fsp2.readdir(deps.paths.projectSessions);
9272
+ entries = await fsp3.readdir(deps.paths.projectSessions);
9323
9273
  } catch {
9324
9274
  deps.renderer.writeError(`Cannot read projectSessions: ${deps.paths.projectSessions}
9325
9275
  `);
@@ -9330,7 +9280,7 @@ async function listFleetRuns(deps) {
9330
9280
  const runDir = path25.join(deps.paths.projectSessions, id);
9331
9281
  let stat3;
9332
9282
  try {
9333
- stat3 = await fsp2.stat(runDir);
9283
+ stat3 = await fsp3.stat(runDir);
9334
9284
  } catch {
9335
9285
  continue;
9336
9286
  }
@@ -9340,18 +9290,18 @@ async function listFleetRuns(deps) {
9340
9290
  let subagentCount = 0;
9341
9291
  let subagentsDir;
9342
9292
  try {
9343
- await fsp2.access(path25.join(runDir, "fleet.json"));
9293
+ await fsp3.access(path25.join(runDir, "fleet.json"));
9344
9294
  manifest = true;
9345
9295
  } catch {
9346
9296
  }
9347
9297
  try {
9348
- await fsp2.access(path25.join(runDir, "checkpoint.json"));
9298
+ await fsp3.access(path25.join(runDir, "checkpoint.json"));
9349
9299
  checkpoint = true;
9350
9300
  } catch {
9351
9301
  }
9352
9302
  try {
9353
9303
  subagentsDir = path25.join(runDir, "subagents");
9354
- const files = await fsp2.readdir(subagentsDir);
9304
+ const files = await fsp3.readdir(subagentsDir);
9355
9305
  subagentCount = files.filter((f) => f.endsWith(".jsonl")).length;
9356
9306
  } catch {
9357
9307
  }
@@ -9382,7 +9332,7 @@ async function showFleetRun(runId, deps) {
9382
9332
  const runDir = path25.join(deps.paths.projectSessions, runId);
9383
9333
  let stat3;
9384
9334
  try {
9385
- stat3 = await fsp2.stat(runDir);
9335
+ stat3 = await fsp3.stat(runDir);
9386
9336
  } catch {
9387
9337
  deps.renderer.writeError(`Fleet run not found: ${runId}
9388
9338
  `);
@@ -9399,7 +9349,7 @@ Fleet Run: ${runId}
9399
9349
  const manifestPath = path25.join(runDir, "fleet.json");
9400
9350
  let manifestData = null;
9401
9351
  try {
9402
- manifestData = await fsp2.readFile(manifestPath, "utf8");
9352
+ manifestData = await fsp3.readFile(manifestPath, "utf8");
9403
9353
  const manifest = JSON.parse(manifestData);
9404
9354
  const subagents = manifest.subagents ?? [];
9405
9355
  const tasks = manifest.tasks ?? [];
@@ -9415,12 +9365,12 @@ Fleet Run: ${runId}
9415
9365
  const checkpointPath = path25.join(runDir, "checkpoint.json");
9416
9366
  let checkpointData = null;
9417
9367
  try {
9418
- checkpointData = await fsp2.readFile(checkpointPath, "utf8");
9368
+ checkpointData = await fsp3.readFile(checkpointPath, "utf8");
9419
9369
  const snap = JSON.parse(checkpointData);
9420
9370
  const lockPath = `${checkpointPath}.lock`;
9421
9371
  let lockStatus = color.dim("\u25CB no lock");
9422
9372
  try {
9423
- const lockRaw = await fsp2.readFile(lockPath, "utf8");
9373
+ const lockRaw = await fsp3.readFile(lockPath, "utf8");
9424
9374
  const lock = JSON.parse(lockRaw);
9425
9375
  lockStatus = `${color.yellow("\u25B8")} lock held by pid ${lock.pid} on ${lock.hostname} (started ${lock.startedAt})`;
9426
9376
  } catch {
@@ -9462,7 +9412,7 @@ Fleet Run: ${runId}
9462
9412
  const subagentsDir = path25.join(runDir, "subagents");
9463
9413
  let subagentFiles = [];
9464
9414
  try {
9465
- subagentFiles = await fsp2.readdir(subagentsDir);
9415
+ subagentFiles = await fsp3.readdir(subagentsDir);
9466
9416
  subagentFiles = subagentFiles.filter((f) => f.endsWith(".jsonl"));
9467
9417
  } catch {
9468
9418
  }
@@ -9474,7 +9424,7 @@ Fleet Run: ${runId}
9474
9424
  const filePath = path25.join(subagentsDir, f);
9475
9425
  let size;
9476
9426
  try {
9477
- const s = await fsp2.stat(filePath);
9427
+ const s = await fsp3.stat(filePath);
9478
9428
  size = s.size;
9479
9429
  } catch {
9480
9430
  size = 0;
@@ -9490,7 +9440,7 @@ Fleet Run: ${runId}
9490
9440
  }
9491
9441
  const sharedDir = path25.join(runDir, "shared");
9492
9442
  try {
9493
- const files = await fsp2.readdir(sharedDir);
9443
+ const files = await fsp3.readdir(sharedDir);
9494
9444
  deps.renderer.write(`
9495
9445
  Shared scratchpad: ${files.length} file(s)
9496
9446
  `);
@@ -9787,7 +9737,7 @@ var skillsCmd = async (_args, deps) => {
9787
9737
  };
9788
9738
  var versionCmd = async (_args, deps) => {
9789
9739
  deps.renderer.write(
9790
- `WrongStack ${CLI_VERSION} (apiVersion ${API_VERSION}, node ${process.version}, ${os7.platform()})
9740
+ `WrongStack ${CLI_VERSION} (apiVersion ${API_VERSION}, node ${process.version}, ${os6.platform()})
9791
9741
  `
9792
9742
  );
9793
9743
  return 0;
@@ -10977,6 +10927,36 @@ async function execute(deps) {
10977
10927
  const banneredFamily = savedProviderCfg?.family ?? resolvedProvider?.family;
10978
10928
  const banneredKey = savedProviderCfg?.apiKey ?? config.apiKey ?? (resolvedProvider?.envVars ?? savedProviderCfg?.envVars ?? []).map((v) => process.env[v]).find((v) => !!v);
10979
10929
  const banneredKeyTail = banneredKey && banneredKey.length >= 3 ? banneredKey.slice(-3) : void 0;
10930
+ const autoPhaseHandlers = /* @__PURE__ */ new Map();
10931
+ const subscribeAutoPhase = (handler) => {
10932
+ const registrations = [];
10933
+ const autoPhaseEvents = [
10934
+ "phase.started",
10935
+ "phase.completed",
10936
+ "phase.failed",
10937
+ "phase.statusChange",
10938
+ "phase.taskCompleted",
10939
+ "phase.taskFailed",
10940
+ "phase.taskRetrying",
10941
+ "autonomous.tick",
10942
+ "graph.completed",
10943
+ "graph.failed",
10944
+ "agent.assigned",
10945
+ "agent.released"
10946
+ ];
10947
+ const onUntyped = events.on.bind(events);
10948
+ const offUntyped = events.off.bind(events);
10949
+ for (const ev of autoPhaseEvents) {
10950
+ const h = (p) => handler(ev, p);
10951
+ autoPhaseHandlers.set(ev, h);
10952
+ onUntyped(ev, h);
10953
+ registrations.push(() => offUntyped(ev, h));
10954
+ }
10955
+ return () => {
10956
+ for (const unregister of registrations) unregister();
10957
+ autoPhaseHandlers.clear();
10958
+ };
10959
+ };
10980
10960
  try {
10981
10961
  code = await runTui({
10982
10962
  agent,
@@ -10995,6 +10975,7 @@ async function execute(deps) {
10995
10975
  getEternalEngine,
10996
10976
  subscribeEternalIteration,
10997
10977
  subscribeEternalStage,
10978
+ subscribeAutoPhase,
10998
10979
  appVersion: CLI_VERSION,
10999
10980
  provider: config.provider,
11000
10981
  family: banneredFamily,
@@ -11884,6 +11865,150 @@ function samplePaths(set) {
11884
11865
  if (arr.length <= 2) return arr.join(", ");
11885
11866
  return `${arr[0]}, \u2026 (+${arr.length - 1} more)`;
11886
11867
  }
11868
+ function createAutoPhaseHost(deps) {
11869
+ const store = new PhaseStore({ baseDir: deps.storeDir });
11870
+ let active = null;
11871
+ const log = deps.log ?? (() => {
11872
+ });
11873
+ async function runOnce(prompt, label, signal) {
11874
+ const factory = deps.multiAgentHost.makeSubagentFactory(deps.getConfig());
11875
+ const built = await factory({ name: label });
11876
+ try {
11877
+ const result = await built.agent.run(prompt, { signal });
11878
+ if (result.status !== "done") {
11879
+ throw new Error(result.error?.message ?? `subagent ended with status "${result.status}"`);
11880
+ }
11881
+ return result.finalText ?? "";
11882
+ } finally {
11883
+ await built.dispose?.();
11884
+ }
11885
+ }
11886
+ function buildTaskPrompt(task, phaseName, goal) {
11887
+ return [
11888
+ `You are executing one task inside an autonomous, phase-based build.`,
11889
+ `Overall goal: ${goal}`,
11890
+ `Current phase: ${phaseName}`,
11891
+ "",
11892
+ `TASK: ${task.title}`,
11893
+ task.description ? `Details: ${task.description}` : "",
11894
+ `Type: ${task.type} \xB7 Priority: ${task.priority}`,
11895
+ "",
11896
+ `Do the work now using your tools (read, edit, write, bash, \u2026). Make the`,
11897
+ `change real \u2014 do not just describe it. When finished, end with a one-line`,
11898
+ `summary of what you changed. If the task is impossible or already done,`,
11899
+ `say so explicitly.`
11900
+ ].filter(Boolean).join("\n");
11901
+ }
11902
+ async function persist(graph) {
11903
+ try {
11904
+ await store.save(graph);
11905
+ } catch (err) {
11906
+ log(`\u26A0 AutoPhase save failed: ${err instanceof Error ? err.message : String(err)}`);
11907
+ }
11908
+ }
11909
+ return {
11910
+ async onAutoPhaseStart({ goal, projectContext }) {
11911
+ if (active?.orchestrator.isRunning()) {
11912
+ return { ok: false, error: "An AutoPhase run is already in progress. Use /autophase stop first." };
11913
+ }
11914
+ const abort = new AbortController();
11915
+ log(`\u{1F9E0} Planning phases for: ${goal}`);
11916
+ let phases;
11917
+ try {
11918
+ const planner = new AutoPhasePlanner({
11919
+ goal,
11920
+ projectContext,
11921
+ runOnce: (p) => runOnce(p, "autophase-planner", abort.signal)
11922
+ });
11923
+ const result = await planner.plan();
11924
+ if (result.parseFailed || result.phases.length === 0) {
11925
+ return { ok: false, error: "The planner did not produce a usable phase plan. Try a more specific goal." };
11926
+ }
11927
+ phases = result.phases;
11928
+ } catch (err) {
11929
+ return { ok: false, error: `Planning failed: ${err instanceof Error ? err.message : String(err)}` };
11930
+ }
11931
+ const todoCount = phases.reduce((n, p) => n + (p.taskTemplates?.length ?? 0), 0);
11932
+ log(`\u{1F4CB} Plan ready: ${phases.length} phases, ${todoCount} todos.`);
11933
+ const graph = await new PhaseGraphBuilder({
11934
+ title: goal,
11935
+ phases,
11936
+ autonomous: true
11937
+ }).build();
11938
+ await persist(graph);
11939
+ const orchestrator = new PhaseOrchestrator({
11940
+ graph,
11941
+ ctx: {
11942
+ executeTask: async (task, phaseId) => {
11943
+ const phase = graph.phases.get(phaseId);
11944
+ const phaseName = phase?.name ?? phaseId;
11945
+ return runOnce(
11946
+ buildTaskPrompt(task, phaseName, goal),
11947
+ `autophase-${phaseName}-${task.title}`.slice(0, 48),
11948
+ abort.signal
11949
+ );
11950
+ },
11951
+ onPhaseComplete: (phase) => {
11952
+ log(`\u2705 Phase completed: ${phase.name}`);
11953
+ void persist(graph);
11954
+ },
11955
+ onPhaseFail: (phase, error) => {
11956
+ log(`\u274C Phase failed: ${phase.name} \u2014 ${error.message}`);
11957
+ void persist(graph);
11958
+ }
11959
+ },
11960
+ events: deps.events,
11961
+ autonomous: true,
11962
+ maxConcurrentPhases: 1,
11963
+ // Sequential within a phase: each todo is a full-tool agent editing the
11964
+ // shared working tree, and todos in a phase typically build on one
11965
+ // another. Running two at once risks concurrent writes / lost edits.
11966
+ maxConcurrentTasks: 1
11967
+ });
11968
+ const onUntyped = deps.events.on;
11969
+ const offUntyped = deps.events.off;
11970
+ const onDone = () => {
11971
+ log(`\u{1F389} AutoPhase complete: ${graph.title}`);
11972
+ void persist(graph);
11973
+ };
11974
+ const onFailed = () => void persist(graph);
11975
+ onUntyped("graph.completed", onDone);
11976
+ onUntyped("graph.failed", onFailed);
11977
+ const unsubscribe = () => {
11978
+ offUntyped("graph.completed", onDone);
11979
+ offUntyped("graph.failed", onFailed);
11980
+ };
11981
+ active = { graph, orchestrator, abort, unsubscribe };
11982
+ void orchestrator.start().catch((err) => {
11983
+ log(`\u{1F4A5} AutoPhase aborted: ${err instanceof Error ? err.message : String(err)}`);
11984
+ });
11985
+ return { ok: true, graph };
11986
+ },
11987
+ onAutoPhasePause() {
11988
+ active?.orchestrator.pause();
11989
+ },
11990
+ onAutoPhaseResume() {
11991
+ active?.orchestrator.resume();
11992
+ },
11993
+ onAutoPhaseStop() {
11994
+ if (!active) return;
11995
+ active.abort.abort();
11996
+ active.orchestrator.stop();
11997
+ active.unsubscribe();
11998
+ void persist(active.graph);
11999
+ active = null;
12000
+ },
12001
+ getAutoPhaseRunner() {
12002
+ if (!active) return null;
12003
+ const a = active;
12004
+ return {
12005
+ graph: a.graph,
12006
+ getProgress: () => a.orchestrator.getProgress(),
12007
+ isRunning: () => a.orchestrator.isRunning()
12008
+ };
12009
+ }
12010
+ };
12011
+ }
11887
12012
  var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
11888
12013
  var FILLED2 = "\u2588";
11889
12014
  var EMPTY2 = "\u2591";
@@ -12051,7 +12176,7 @@ function setupMetrics(params) {
12051
12176
  name: "session-store",
12052
12177
  check: async () => {
12053
12178
  try {
12054
- await fsp2.access(wpaths.projectSessions);
12179
+ await fsp3.access(wpaths.projectSessions);
12055
12180
  return { status: "healthy" };
12056
12181
  } catch (e) {
12057
12182
  return { status: "unhealthy", detail: e instanceof Error ? e.message : "access denied" };
@@ -12707,6 +12832,14 @@ async function main(argv) {
12707
12832
  this.visible = visible;
12708
12833
  }
12709
12834
  };
12835
+ const autoPhaseHost = createAutoPhaseHost({
12836
+ multiAgentHost,
12837
+ getConfig: () => config,
12838
+ events,
12839
+ storeDir: wpaths.projectAutophase,
12840
+ log: (line) => renderer.write(`${line}
12841
+ `)
12842
+ });
12710
12843
  const slashCmds = buildBuiltinSlashCommands({
12711
12844
  registry: slashRegistry,
12712
12845
  toolRegistry,
@@ -12716,6 +12849,7 @@ async function main(argv) {
12716
12849
  skillLoader,
12717
12850
  tokenCounter,
12718
12851
  renderer,
12852
+ events,
12719
12853
  memoryStore,
12720
12854
  context,
12721
12855
  cwd,
@@ -12944,7 +13078,7 @@ async function main(argv) {
12944
13078
  const subagentsRoot = path25.join(fleetRootForPromotion, "subagents");
12945
13079
  let runDirs;
12946
13080
  try {
12947
- runDirs = await fsp2.readdir(subagentsRoot);
13081
+ runDirs = await fsp3.readdir(subagentsRoot);
12948
13082
  } catch {
12949
13083
  return "No fleet transcripts on disk \u2014 no subagents have been spawned for this session.";
12950
13084
  }
@@ -12953,7 +13087,7 @@ async function main(argv) {
12953
13087
  const runDir = path25.join(subagentsRoot, runId);
12954
13088
  let files;
12955
13089
  try {
12956
- files = await fsp2.readdir(runDir);
13090
+ files = await fsp3.readdir(runDir);
12957
13091
  } catch {
12958
13092
  continue;
12959
13093
  }
@@ -12961,7 +13095,7 @@ async function main(argv) {
12961
13095
  if (!f.endsWith(".jsonl")) continue;
12962
13096
  const full = path25.join(runDir, f);
12963
13097
  try {
12964
- const stat3 = await fsp2.stat(full);
13098
+ const stat3 = await fsp3.stat(full);
12965
13099
  found.push({
12966
13100
  runId,
12967
13101
  subagentId: f.replace(/\.jsonl$/, ""),
@@ -13000,7 +13134,7 @@ async function main(argv) {
13000
13134
  ].join("\n");
13001
13135
  }
13002
13136
  const t = matches[0];
13003
- const raw = await fsp2.readFile(t.file, "utf8");
13137
+ const raw = await fsp3.readFile(t.file, "utf8");
13004
13138
  if (mode === "raw") return raw;
13005
13139
  const lines = raw.split("\n").filter((l) => l.trim());
13006
13140
  const counts = {};
@@ -13332,7 +13466,12 @@ Restart WrongStack to load or unload plugin code in this session.`;
13332
13466
  onSddParallelStop: () => {
13333
13467
  const run = globalThis.__sddParallelRun;
13334
13468
  run?.stop();
13335
- }
13469
+ },
13470
+ onAutoPhaseStart: autoPhaseHost.onAutoPhaseStart,
13471
+ onAutoPhasePause: autoPhaseHost.onAutoPhasePause,
13472
+ onAutoPhaseResume: autoPhaseHost.onAutoPhaseResume,
13473
+ onAutoPhaseStop: autoPhaseHost.onAutoPhaseStop,
13474
+ getAutoPhaseRunner: autoPhaseHost.getAutoPhaseRunner
13336
13475
  });
13337
13476
  for (const cmd of slashCmds) slashRegistry.register(cmd);
13338
13477
  const eternalFlag = typeof flags["eternal"] === "string" ? flags["eternal"].trim() : "";