@ordewell/core 0.4.20 → 0.4.22

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
@@ -4340,6 +4340,7 @@ function resolveTaskMode(emittedMode, runnerId, runnerModes, autonomousDefault =
4340
4340
  if (!runnerModes) return rawMode === "plan" ? "plan" : "build";
4341
4341
  const modes = runnerModes[runnerId];
4342
4342
  if (!modes || modes.length === 0) return rawMode;
4343
+ if (!emittedMode) return resolveDefaultMode(modes, autonomousDefault) ?? "build";
4343
4344
  const validIds = new Set(modes.map((m) => m.id));
4344
4345
  if (rawMode === "build" || validIds.has(rawMode)) {
4345
4346
  if (rawMode === "plan" || rawMode === "build") return rawMode;
@@ -6671,9 +6672,9 @@ function summarizeToolCall(tool, argsJson, toolLabel) {
6671
6672
  const scope = args.include ? ` in ${args.include}` : "";
6672
6673
  return `grep ${ellipsize(String(args.pattern), 40)}${scope}${mode}`;
6673
6674
  }
6674
- const path20 = args.filePath || args.file_path || args.path;
6675
- if (path20) {
6676
- const basename = String(path20).split("/").pop() || String(path20);
6675
+ const path21 = args.filePath || args.file_path || args.path;
6676
+ if (path21) {
6677
+ const basename = String(path21).split("/").pop() || String(path21);
6677
6678
  return `${display} ${basename}`;
6678
6679
  }
6679
6680
  if (args.pattern) {
@@ -8058,6 +8059,19 @@ function renderTerminalOutput(raw) {
8058
8059
  }
8059
8060
  var MARKER_SCAN_TAIL = 16384;
8060
8061
  var IDLE_TIMEOUT_MS = 6e4;
8062
+ function renderCleanCapture(raw, doneToken) {
8063
+ const rendered = renderTerminalOutput(raw).replace(/[\s─-▟]+$/gm, "");
8064
+ if (!doneToken) return rendered.trim();
8065
+ const lines = rendered.split("\n");
8066
+ const flat = (s) => flattenTerminalOutput(s);
8067
+ for (let i = 0; i < lines.length; i++) {
8068
+ const own = flat(lines[i]).includes(doneToken);
8069
+ if (own) return lines.slice(0, i).join("\n").trim();
8070
+ const window = flat(lines[i]) + (i + 1 < lines.length ? flat(lines[i + 1]) : "");
8071
+ if (window.includes(doneToken)) return lines.slice(0, i + 1).join("\n").trim();
8072
+ }
8073
+ return rendered.trim();
8074
+ }
8061
8075
  var VerdictEngine = class {
8062
8076
  markerSeen = /* @__PURE__ */ new Set();
8063
8077
  buffers = /* @__PURE__ */ new Map();
@@ -8285,6 +8299,167 @@ ${line}
8285
8299
  }
8286
8300
  };
8287
8301
 
8302
+ // src/services/transcriptCapture.ts
8303
+ var import_fs = require("fs");
8304
+ var os2 = __toESM(require("os"));
8305
+ var path4 = __toESM(require("path"));
8306
+ function homeDir() {
8307
+ return process.env.HOME || os2.homedir();
8308
+ }
8309
+ async function readFinalAssistantText(query, maxChars = 4e3) {
8310
+ try {
8311
+ if (query.runner === "claude-code") return claudeFinal(query, maxChars);
8312
+ if (query.runner === "opencode") return await opencodeFinal(query, maxChars);
8313
+ if (query.runner === "codex") return codexFinal(query, maxChars);
8314
+ } catch {
8315
+ }
8316
+ return null;
8317
+ }
8318
+ function claudeFinal(query, maxChars) {
8319
+ const munged = query.cwd.replaceAll("/", "-").replaceAll("_", "-");
8320
+ const dir = path4.join(homeDir(), ".claude", "projects", munged);
8321
+ if (!(0, import_fs.existsSync)(dir)) return null;
8322
+ const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
8323
+ const candidates = (0, import_fs.readdirSync)(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path4.join(dir, f)).filter((f) => cutoff ? (0, import_fs.statSync)(f).mtimeMs >= cutoff - 5e3 : true).sort((a, b) => (0, import_fs.statSync)(b).mtimeMs - (0, import_fs.statSync)(a).mtimeMs);
8324
+ for (const file of candidates) {
8325
+ const text = claudeLastAssistant(file);
8326
+ if (text) return clamp(text, maxChars);
8327
+ }
8328
+ return null;
8329
+ }
8330
+ function claudeLastAssistant(file) {
8331
+ let last = null;
8332
+ let buf = "";
8333
+ const fd = (0, import_fs.statSync)(file);
8334
+ const start = Math.max(0, fd.size - 512 * 1024);
8335
+ buf = (0, import_fs.readFileSync)(file, { encoding: "utf8" }).toString();
8336
+ if (start > 0) buf = buf.slice(buf.indexOf("\n", Math.min(start, buf.length - 1)) + 1);
8337
+ for (const line of buf.split("\n")) {
8338
+ if (!line.trim()) continue;
8339
+ let rec;
8340
+ try {
8341
+ rec = JSON.parse(line);
8342
+ } catch {
8343
+ continue;
8344
+ }
8345
+ if (rec.type !== "assistant" || rec.isSidechain) continue;
8346
+ const content = rec.message?.content;
8347
+ if (!Array.isArray(content)) continue;
8348
+ const texts = content.filter((b) => typeof b === "object" && b !== null && b.type === "text").map((b) => b.text).join("\n").trim();
8349
+ if (texts) last = texts;
8350
+ }
8351
+ return last;
8352
+ }
8353
+ async function opencodeFinal(query, maxChars) {
8354
+ let DatabaseSync;
8355
+ try {
8356
+ ({ DatabaseSync } = await import("sqlite"));
8357
+ } catch {
8358
+ return null;
8359
+ }
8360
+ const dbPath = path4.join(homeDir(), ".local", "share", "opencode", "opencode.db");
8361
+ if (!(0, import_fs.existsSync)(dbPath)) return null;
8362
+ let db;
8363
+ try {
8364
+ db = new DatabaseSync(dbPath, { open: true });
8365
+ } catch {
8366
+ return null;
8367
+ }
8368
+ try {
8369
+ const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
8370
+ const rows = db.prepare(
8371
+ `select s.id, s.time_updated from session s
8372
+ join project p on p.id = s.project_id
8373
+ where s.directory = ?
8374
+ order by s.time_updated desc limit 5`
8375
+ ).all(query.cwd);
8376
+ for (const row of rows) {
8377
+ if (cutoff && row.time_updated < cutoff - 5e3) continue;
8378
+ const parts = db.prepare(
8379
+ `select pt.data from part pt
8380
+ join message m on m.id = pt.message_id
8381
+ where m.session_id = ? and m.data like '%"role":"assistant"%'
8382
+ order by pt.id asc`
8383
+ ).all(row.id);
8384
+ let text = null;
8385
+ for (const p of parts) {
8386
+ try {
8387
+ const d = JSON.parse(p.data);
8388
+ if (d.type === "text" && d.text && d.text.trim()) text = d.text.trim();
8389
+ } catch {
8390
+ continue;
8391
+ }
8392
+ }
8393
+ if (text) return clamp(text, maxChars);
8394
+ }
8395
+ return null;
8396
+ } catch {
8397
+ return null;
8398
+ } finally {
8399
+ try {
8400
+ db.close();
8401
+ } catch {
8402
+ }
8403
+ }
8404
+ }
8405
+ function codexFinal(query, maxChars) {
8406
+ const root = path4.join(homeDir(), ".codex", "sessions");
8407
+ if (!(0, import_fs.existsSync)(root)) return null;
8408
+ const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
8409
+ const files = [];
8410
+ const stack = [root];
8411
+ while (stack.length) {
8412
+ const dir = stack.pop();
8413
+ let entries;
8414
+ try {
8415
+ entries = (0, import_fs.readdirSync)(dir);
8416
+ } catch {
8417
+ continue;
8418
+ }
8419
+ for (const e of entries) {
8420
+ const full = path4.join(dir, e);
8421
+ let st;
8422
+ try {
8423
+ st = (0, import_fs.statSync)(full);
8424
+ } catch {
8425
+ continue;
8426
+ }
8427
+ if (st.isDirectory()) stack.push(full);
8428
+ else if (e.startsWith("rollout-") && e.endsWith(".jsonl") && (!cutoff || st.mtimeMs >= cutoff - 5e3)) files.push(full);
8429
+ }
8430
+ }
8431
+ files.sort((a, b) => (0, import_fs.statSync)(b).mtimeMs - (0, import_fs.statSync)(a).mtimeMs);
8432
+ for (const file of files.slice(0, 10)) {
8433
+ const text = codexLastAssistant(file, query.cwd);
8434
+ if (text) return clamp(text, maxChars);
8435
+ }
8436
+ return null;
8437
+ }
8438
+ function codexLastAssistant(file, cwd) {
8439
+ const raw = (0, import_fs.readFileSync)(file, "utf8");
8440
+ const lines = raw.split("\n").filter((l) => l.trim());
8441
+ let sawCwd = false;
8442
+ let last = null;
8443
+ for (const line of lines) {
8444
+ let rec;
8445
+ try {
8446
+ rec = JSON.parse(line);
8447
+ } catch {
8448
+ continue;
8449
+ }
8450
+ if (rec.type === "session_meta" && rec.payload?.cwd === cwd) sawCwd = true;
8451
+ if (rec.type !== "response_item") continue;
8452
+ const p = rec.payload;
8453
+ if (p?.role !== "assistant" || p.type !== "message") continue;
8454
+ const texts = (Array.isArray(p.content) ? p.content : []).map((c) => typeof c === "object" && c !== null && c.text || "").join("\n").trim();
8455
+ if (texts) last = texts;
8456
+ }
8457
+ return sawCwd ? last : null;
8458
+ }
8459
+ function clamp(text, maxChars) {
8460
+ return text.length <= maxChars ? text : text.slice(-maxChars);
8461
+ }
8462
+
8288
8463
  // src/services/PlanStore.ts
8289
8464
  var PlanStore = class {
8290
8465
  _planTasks = [];
@@ -8666,6 +8841,11 @@ var TaskOrchestrator = class {
8666
8841
  workspaceRootFn = () => process.cwd();
8667
8842
  observers = [];
8668
8843
  tddEnabled = () => false;
8844
+ /**
8845
+ * Spawn context per active task, for locating the agent's own session
8846
+ * transcript at verdict time (issue #16). Cleared with the session entry.
8847
+ */
8848
+ taskSpawnContext = /* @__PURE__ */ new Map();
8669
8849
  /** Advisory silence timestamp for a task's live runner, or null if not idle. */
8670
8850
  getIdleSince(taskId) {
8671
8851
  return this.verifier.getIdleSince(taskId);
@@ -8828,6 +9008,8 @@ var TaskOrchestrator = class {
8828
9008
  const task = this.store.get(taskId);
8829
9009
  if (!task) return;
8830
9010
  this.activeTaskSessions.delete(taskId);
9011
+ const spawnContext = this.taskSpawnContext.get(taskId);
9012
+ this.taskSpawnContext.delete(taskId);
8831
9013
  console.error(`[TaskOrchestrator] Task #${task.order} "${task.title}" verdict=${verdict.outcome}`);
8832
9014
  console.error(`[TaskOrchestrator] Runner: ${task.assignedRunner}, Model: ${task.assignedModel?.modelId ?? "default"}`);
8833
9015
  console.error(`[TaskOrchestrator] Prompt preview: ${(task.prompt ?? "").slice(0, 200)}`);
@@ -8838,6 +9020,10 @@ ${output.slice(-3e3)}`);
8838
9020
  console.error(`[TaskOrchestrator] Output: (empty \u2014 no stdout/stderr captured)`);
8839
9021
  }
8840
9022
  this.store.setTaskVerdict(taskId, verdict);
9023
+ const doneToken = `<<<ORDEWELL_DONE_${task.completionMarker}>>>`;
9024
+ const transcript = spawnContext ? await readFinalAssistantText(spawnContext) : null;
9025
+ const cleaned = transcript ?? renderCleanCapture(output, doneToken);
9026
+ const effective = cleaned.length > 0 ? cleaned : output;
8841
9027
  if (verdict.outcome === "pass") {
8842
9028
  this.store.markCompleted(taskId);
8843
9029
  this.notifications.info(`Task "${task.title}" completed.`);
@@ -8847,7 +9033,7 @@ ${output.slice(-3e3)}`);
8847
9033
  this.planStatus = "approved";
8848
9034
  this.notifications.error(`Task "${task.title}" failed verification: ${verdict.reason}`);
8849
9035
  }
8850
- this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason, output));
9036
+ this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason, effective));
8851
9037
  this.logAndArchive(task, verdict);
8852
9038
  this.emit("onTaskChanged");
8853
9039
  if (!this.running) {
@@ -9087,6 +9273,8 @@ ${output.slice(-3e3)}`);
9087
9273
  try {
9088
9274
  const cwd = this.workspaceRootFn();
9089
9275
  const runner = this.store.resolveTaskRunner(task);
9276
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
9277
+ this.taskSpawnContext.set(task.id, { runner, cwd, startedAt });
9090
9278
  const finalPrompt = composeAugmentedPrompt(task, this.store.planTasks, {
9091
9279
  planMapEnabled: this.config.planMapEnabled,
9092
9280
  tddEnabled: this.tddEnabled()
@@ -9251,7 +9439,7 @@ ${errors.map((e) => `- ${e}`).join("\n")}`
9251
9439
  };
9252
9440
 
9253
9441
  // src/services/ModelDiscovery.ts
9254
- var path7 = __toESM(require("path"));
9442
+ var path8 = __toESM(require("path"));
9255
9443
  var import_child_process3 = require("child_process");
9256
9444
  var import_util2 = require("util");
9257
9445
  var fsSync3 = __toESM(require("fs"));
@@ -9260,8 +9448,8 @@ var osMod = __toESM(require("os"));
9260
9448
  // src/utils/shellPath.ts
9261
9449
  var import_child_process = require("child_process");
9262
9450
  var import_util = require("util");
9263
- var os2 = __toESM(require("os"));
9264
- var path4 = __toESM(require("path"));
9451
+ var os3 = __toESM(require("os"));
9452
+ var path5 = __toESM(require("path"));
9265
9453
  var execAsync = (0, import_util.promisify)(import_child_process.exec);
9266
9454
  var LOGIN_SHELL_TIMEOUT_MS = 5e3;
9267
9455
  var PATH_MARKER = "__ORDEWELL_PATH__";
@@ -9270,42 +9458,42 @@ var defaultExec = async (command, options) => {
9270
9458
  return { stdout: String(stdout) };
9271
9459
  };
9272
9460
  function posixBinDirs() {
9273
- const home = os2.homedir();
9461
+ const home = os3.homedir();
9274
9462
  return [
9275
- path4.join(home, ".local", "bin"),
9276
- path4.join(home, ".opencode", "bin"),
9277
- path4.join(home, ".claude", "bin"),
9278
- path4.join(home, ".bun", "bin"),
9279
- path4.join(home, ".volta", "bin"),
9280
- path4.join(home, ".npm-global", "bin"),
9281
- path4.join(home, "bin"),
9463
+ path5.join(home, ".local", "bin"),
9464
+ path5.join(home, ".opencode", "bin"),
9465
+ path5.join(home, ".claude", "bin"),
9466
+ path5.join(home, ".bun", "bin"),
9467
+ path5.join(home, ".volta", "bin"),
9468
+ path5.join(home, ".npm-global", "bin"),
9469
+ path5.join(home, "bin"),
9282
9470
  "/usr/local/bin",
9283
9471
  "/opt/homebrew/bin"
9284
9472
  ];
9285
9473
  }
9286
9474
  function windowsBinDirs(env, home) {
9287
- const join19 = (...parts) => path4.win32.join(...parts);
9288
- const under = (base, ...parts) => base ? [join19(base, ...parts)] : [];
9475
+ const join20 = (...parts) => path5.win32.join(...parts);
9476
+ const under = (base, ...parts) => base ? [join20(base, ...parts)] : [];
9289
9477
  const appData = env.APPDATA;
9290
9478
  const localAppData = env.LOCALAPPDATA;
9291
9479
  const programData = env.ProgramData;
9292
9480
  return [
9293
9481
  // Native per-user installers, PowerShell-driven and otherwise.
9294
- join19(home, ".local", "bin"),
9295
- join19(home, ".opencode", "bin"),
9296
- join19(home, ".claude", "bin"),
9297
- join19(home, ".codex", "bin"),
9482
+ join20(home, ".local", "bin"),
9483
+ join20(home, ".opencode", "bin"),
9484
+ join20(home, ".claude", "bin"),
9485
+ join20(home, ".codex", "bin"),
9298
9486
  ...under(localAppData, "Programs", "claude"),
9299
9487
  // Node package managers. npm's global prefix is `%APPDATA%\npm`; the
9300
9488
  // literal spelling is kept as a fallback for a host that does not export
9301
9489
  // APPDATA (a service account, a stripped CI container).
9302
9490
  ...under(appData, "npm"),
9303
- join19(home, "AppData", "Roaming", "npm"),
9491
+ join20(home, "AppData", "Roaming", "npm"),
9304
9492
  ...under(localAppData, "pnpm"),
9305
9493
  ...under(localAppData, "Yarn", "bin"),
9306
- join19(home, ".bun", "bin"),
9494
+ join20(home, ".bun", "bin"),
9307
9495
  // Windows package managers.
9308
- join19(home, "scoop", "shims"),
9496
+ join20(home, "scoop", "shims"),
9309
9497
  ...under(env.SCOOP, "shims"),
9310
9498
  ...under(env.SCOOP_GLOBAL ?? programData, "scoop", "shims"),
9311
9499
  ...under(programData, "chocolatey", "bin"),
@@ -9315,13 +9503,13 @@ function windowsBinDirs(env, home) {
9315
9503
  ...under(localAppData, "Microsoft", "WindowsApps"),
9316
9504
  // Version managers. Volta's Windows home is not the POSIX `~/.volta`.
9317
9505
  ...under(localAppData, "Volta", "bin"),
9318
- join19(home, ".volta", "bin")
9506
+ join20(home, ".volta", "bin")
9319
9507
  ];
9320
9508
  }
9321
9509
  function wellKnownBinDirs(deps = {}) {
9322
9510
  const platform = deps.platform ?? process.platform;
9323
9511
  if (platform !== "win32") return posixBinDirs();
9324
- return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ?? os2.homedir()))];
9512
+ return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ?? os3.homedir()))];
9325
9513
  }
9326
9514
  async function loginShellPath(execImpl) {
9327
9515
  if (process.platform === "win32") return null;
@@ -9344,14 +9532,14 @@ function augmentedPath(execImpl = defaultExec) {
9344
9532
  const segments = [];
9345
9533
  const push = (p) => {
9346
9534
  if (!p) return;
9347
- for (const seg of p.split(path4.delimiter)) {
9535
+ for (const seg of p.split(path5.delimiter)) {
9348
9536
  if (seg && !segments.includes(seg)) segments.push(seg);
9349
9537
  }
9350
9538
  };
9351
9539
  push(process.env.PATH);
9352
9540
  push(await loginShellPath(execImpl));
9353
9541
  for (const dir of wellKnownBinDirs()) push(dir);
9354
- return segments.join(path4.delimiter);
9542
+ return segments.join(path5.delimiter);
9355
9543
  })();
9356
9544
  }
9357
9545
  return cachedPath;
@@ -9373,17 +9561,17 @@ function withPath(base, resolvedPath, overrides = {}) {
9373
9561
 
9374
9562
  // src/utils/globalDataDir.ts
9375
9563
  var fs = __toESM(require("fs"));
9376
- var path5 = __toESM(require("path"));
9377
- var os3 = __toESM(require("os"));
9564
+ var path6 = __toESM(require("path"));
9565
+ var os4 = __toESM(require("os"));
9378
9566
  function globalDataDir() {
9379
- return path5.join(os3.homedir(), ".ordewell");
9567
+ return path6.join(os4.homedir(), ".ordewell");
9380
9568
  }
9381
9569
  function copyDirSync(src, dest) {
9382
9570
  fs.mkdirSync(dest, { recursive: true });
9383
9571
  const entries = fs.readdirSync(src, { withFileTypes: true });
9384
9572
  for (const entry of entries) {
9385
- const srcPath = path5.join(src, entry.name);
9386
- const destPath = path5.join(dest, entry.name);
9573
+ const srcPath = path6.join(src, entry.name);
9574
+ const destPath = path6.join(dest, entry.name);
9387
9575
  if (entry.isDirectory()) {
9388
9576
  copyDirSync(srcPath, destPath);
9389
9577
  } else {
@@ -9395,12 +9583,12 @@ var migrated = false;
9395
9583
  function migrateOldConfigDir() {
9396
9584
  if (migrated) return;
9397
9585
  migrated = true;
9398
- const oldDir = path5.join(os3.homedir(), ".config", "ordewell");
9586
+ const oldDir = path6.join(os4.homedir(), ".config", "ordewell");
9399
9587
  if (!fs.existsSync(oldDir)) return;
9400
9588
  const newDir = globalDataDir();
9401
9589
  const liftFile = (name) => {
9402
- const oldFile = path5.join(oldDir, name);
9403
- const newFile = path5.join(newDir, name);
9590
+ const oldFile = path6.join(oldDir, name);
9591
+ const newFile = path6.join(newDir, name);
9404
9592
  if (fs.existsSync(oldFile) && !fs.existsSync(newFile)) {
9405
9593
  fs.mkdirSync(newDir, { recursive: true });
9406
9594
  fs.copyFileSync(oldFile, newFile);
@@ -9408,8 +9596,8 @@ function migrateOldConfigDir() {
9408
9596
  };
9409
9597
  liftFile("settings.json");
9410
9598
  liftFile(".env");
9411
- const oldPlugins = path5.join(oldDir, "plugins");
9412
- const newPlugins = path5.join(newDir, "plugins");
9599
+ const oldPlugins = path6.join(oldDir, "plugins");
9600
+ const newPlugins = path6.join(newDir, "plugins");
9413
9601
  if (fs.existsSync(oldPlugins) && !fs.existsSync(newPlugins)) {
9414
9602
  copyDirSync(oldPlugins, newPlugins);
9415
9603
  }
@@ -9417,7 +9605,7 @@ function migrateOldConfigDir() {
9417
9605
 
9418
9606
  // src/utils/launch.ts
9419
9607
  var fsSync2 = __toESM(require("fs"));
9420
- var path6 = __toESM(require("path"));
9608
+ var path7 = __toESM(require("path"));
9421
9609
 
9422
9610
  // src/utils/shell.ts
9423
9611
  var ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]|\x1b\][^\x07]*\x07|\x1b[()][AB012]|\r/g;
@@ -9446,7 +9634,7 @@ var CMD_EXE_MAX_COMMAND_LINE = 8191;
9446
9634
  var WINDOWS_MAX_COMMAND_LINE = 32767;
9447
9635
  function defaultPowerShell() {
9448
9636
  const root = process.env.SystemRoot || process.env.windir;
9449
- return root ? path6.win32.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : "powershell.exe";
9637
+ return root ? path7.win32.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : "powershell.exe";
9450
9638
  }
9451
9639
  var POWERSHELL_FLAGS = ["-NoLogo", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File"];
9452
9640
  var CommandLineTooLongError = class extends Error {
@@ -9498,7 +9686,7 @@ Searched: ${searchedPath || "(empty PATH)"}`);
9498
9686
  };
9499
9687
  function isResolvableOnPosixPath(command, PATH, exists) {
9500
9688
  if (command.includes("/")) return exists(command);
9501
- return PATH.split(path6.delimiter).map((d) => d.trim()).filter(Boolean).some((dir) => exists(path6.join(dir, command)));
9689
+ return PATH.split(path7.delimiter).map((d) => d.trim()).filter(Boolean).some((dir) => exists(path7.join(dir, command)));
9502
9690
  }
9503
9691
  function isExecutableResolved(command, plan, PATH, deps = {}) {
9504
9692
  if ((deps.platform ?? process.platform) === "win32") return plan.file !== command;
@@ -9538,9 +9726,9 @@ function cmdArgs(line) {
9538
9726
  return ["/d", "/s", "/c", `"${line}"`];
9539
9727
  }
9540
9728
  function candidateExtensions(command, pathExt) {
9541
- const declared = pathExt.split(path6.win32.delimiter).map((e) => e.trim().toLowerCase()).filter(Boolean);
9729
+ const declared = pathExt.split(path7.win32.delimiter).map((e) => e.trim().toLowerCase()).filter(Boolean);
9542
9730
  const known = /* @__PURE__ */ new Set([...DIRECT_EXTENSIONS, ...BATCH_EXTENSIONS, ...POWERSHELL_EXTENSIONS, ...declared]);
9543
- const ext = path6.win32.extname(command).toLowerCase();
9731
+ const ext = path7.win32.extname(command).toLowerCase();
9544
9732
  if (ext && known.has(ext)) {
9545
9733
  const route = BATCH_EXTENSIONS.includes(ext) ? "cmd" : POWERSHELL_EXTENSIONS.includes(ext) ? "powershell" : "direct";
9546
9734
  return { direct: [], cmd: [], powershell: [], [route]: [""] };
@@ -9561,13 +9749,13 @@ async function findWindowsExecutables(command, deps) {
9561
9749
  const exists = deps.exists ?? defaultExists2;
9562
9750
  const pathExt = (deps.pathExt ?? (() => process.env.PATHEXT ?? ""))();
9563
9751
  const byRoute = candidateExtensions(command, pathExt);
9564
- const dirs = path6.win32.basename(command) !== command ? [path6.win32.dirname(path6.win32.resolve(command))] : (await (deps.resolvePath ?? augmentedPath)() || "").split(path6.win32.delimiter).map((d) => d.trim().replace(/^"|"$/g, "")).filter(Boolean);
9565
- const base = path6.win32.basename(command);
9752
+ const dirs = path7.win32.basename(command) !== command ? [path7.win32.dirname(path7.win32.resolve(command))] : (await (deps.resolvePath ?? augmentedPath)() || "").split(path7.win32.delimiter).map((d) => d.trim().replace(/^"|"$/g, "")).filter(Boolean);
9753
+ const base = path7.win32.basename(command);
9566
9754
  const found = [];
9567
9755
  for (const route of ROUTES) {
9568
9756
  outer: for (const ext of byRoute[route]) {
9569
9757
  for (const dir of dirs) {
9570
- const candidate = path6.win32.join(dir, `${base}${ext}`);
9758
+ const candidate = path7.win32.join(dir, `${base}${ext}`);
9571
9759
  if (exists(candidate)) {
9572
9760
  found.push({ file: candidate, route });
9573
9761
  break outer;
@@ -9747,7 +9935,7 @@ function geminiDiscoveryCacheKey(apiKey) {
9747
9935
  return {
9748
9936
  key: `gemini-models:${hash}`,
9749
9937
  dir,
9750
- file: path7.join(dir, `gemini_models_${hash}.json`)
9938
+ file: path8.join(dir, `gemini_models_${hash}.json`)
9751
9939
  };
9752
9940
  }
9753
9941
  function readGeminiCache(apiKey) {
@@ -10271,7 +10459,7 @@ var ModelDiscovery = class {
10271
10459
 
10272
10460
  // src/services/ModelCatalog.ts
10273
10461
  var fs2 = __toESM(require("fs"));
10274
- var path8 = __toESM(require("path"));
10462
+ var path9 = __toESM(require("path"));
10275
10463
  var CACHE_KEY = "model-catalog";
10276
10464
  var CACHE_TTL_MS = 60 * 60 * 1e3;
10277
10465
  function storageKey(baseUrl) {
@@ -10323,7 +10511,7 @@ var ModelCatalog = class {
10323
10511
  const url = (baseUrl || "https://openrouter.ai/api/v1").replace(/\/+$/, "");
10324
10512
  const key = storageKey(url);
10325
10513
  const cacheDir = globalCacheDir();
10326
- const cacheFile = path8.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
10514
+ const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
10327
10515
  if (fs2.existsSync(cacheFile)) fs2.rmSync(cacheFile);
10328
10516
  } catch {
10329
10517
  }
@@ -10331,7 +10519,7 @@ var ModelCatalog = class {
10331
10519
  static readCache(key) {
10332
10520
  try {
10333
10521
  const cacheDir = globalCacheDir();
10334
- const cacheFile = path8.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
10522
+ const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
10335
10523
  if (!fs2.existsSync(cacheFile)) return null;
10336
10524
  const raw = fs2.readFileSync(cacheFile, "utf8");
10337
10525
  const data = JSON.parse(raw);
@@ -10345,7 +10533,7 @@ var ModelCatalog = class {
10345
10533
  try {
10346
10534
  const cacheDir = globalCacheDir();
10347
10535
  fs2.mkdirSync(cacheDir, { recursive: true });
10348
- const cacheFile = path8.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
10536
+ const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
10349
10537
  fs2.writeFileSync(
10350
10538
  cacheFile,
10351
10539
  JSON.stringify({ models, cachedAt: Date.now() }, null, 2)
@@ -10786,7 +10974,7 @@ var import_child_process5 = require("child_process");
10786
10974
 
10787
10975
  // src/utils/workspace.ts
10788
10976
  var fs3 = __toESM(require("fs"));
10789
- var path9 = __toESM(require("path"));
10977
+ var path10 = __toESM(require("path"));
10790
10978
  var WorkspaceNotFoundError = class extends Error {
10791
10979
  constructor(workspace) {
10792
10980
  super(`Workspace "${workspace}" does not exist.`);
@@ -10842,7 +11030,7 @@ function assertWorkspaceIsProject(workspace, deps = {}) {
10842
11030
  throw new WorkspaceNotAProjectError(workspace);
10843
11031
  }
10844
11032
  const hasMarker = [...PROJECT_MARKER_DIRS, ...PROJECT_MARKER_FILES].some(
10845
- (marker2) => exists(path9.join(resolved, marker2))
11033
+ (marker2) => exists(path10.join(resolved, marker2))
10846
11034
  );
10847
11035
  if (!hasMarker) throw new WorkspaceNotAProjectError(workspace);
10848
11036
  }
@@ -11874,14 +12062,14 @@ ${part.text}` : part.text });
11874
12062
  }
11875
12063
  }
11876
12064
  }
11877
- async json(method, path20, body, signal) {
11878
- const response = await this.deps.fetch(`${this.baseUrl}${path20}`, {
12065
+ async json(method, path21, body, signal) {
12066
+ const response = await this.deps.fetch(`${this.baseUrl}${path21}`, {
11879
12067
  method,
11880
12068
  headers: { "content-type": "application/json" },
11881
12069
  ...body === void 0 ? {} : { body: JSON.stringify(body) },
11882
12070
  ...signal ? { signal } : {}
11883
12071
  });
11884
- if (!response.ok) throw new Error(`${method} ${path20} failed: ${response.status} ${response.statusText}`);
12072
+ if (!response.ok) throw new Error(`${method} ${path21} failed: ${response.status} ${response.statusText}`);
11885
12073
  return await response.json().catch(() => null);
11886
12074
  }
11887
12075
  nativeSessionId() {
@@ -12649,7 +12837,7 @@ function runnerAssignment(catalog, current) {
12649
12837
  changes.thinkingEffort = thinkingEffort;
12650
12838
  }
12651
12839
  if (catalog.modes.length > 0) {
12652
- changes.taskMode = catalog.modes.some((m) => m.id === current?.taskMode) ? current.taskMode : catalog.modes[0].id;
12840
+ changes.taskMode = catalog.modes.some((m) => m.id === current?.taskMode) ? current.taskMode : catalog.defaultMode ?? catalog.modes[0].id;
12653
12841
  }
12654
12842
  return changes;
12655
12843
  }
@@ -12661,18 +12849,18 @@ function retargetTaskRunner(task, runner, catalog) {
12661
12849
 
12662
12850
  // src/services/SkillsService.ts
12663
12851
  var fs4 = __toESM(require("fs"));
12664
- var path11 = __toESM(require("path"));
12852
+ var path12 = __toESM(require("path"));
12665
12853
 
12666
12854
  // src/services/builtinSkills.ts
12667
- var path10 = __toESM(require("path"));
12855
+ var path11 = __toESM(require("path"));
12668
12856
  var import_url = require("url");
12669
12857
  var import_meta = {};
12670
12858
  function builtinSkillsDir() {
12671
- const dir = typeof __dirname !== "undefined" && __dirname ? __dirname : path10.dirname((0, import_url.fileURLToPath)(
12859
+ const dir = typeof __dirname !== "undefined" && __dirname ? __dirname : path11.dirname((0, import_url.fileURLToPath)(
12672
12860
  // @ts-expect-error - import.meta is only valid under an ESM module setting
12673
12861
  import_meta.url
12674
12862
  ));
12675
- return path10.join(dir, "..", "skills");
12863
+ return path11.join(dir, "..", "skills");
12676
12864
  }
12677
12865
 
12678
12866
  // src/services/SkillsService.ts
@@ -12711,8 +12899,8 @@ function copyDirSync2(src, dest) {
12711
12899
  fs4.mkdirSync(dest, { recursive: true });
12712
12900
  const entries = fs4.readdirSync(src, { withFileTypes: true });
12713
12901
  for (const entry of entries) {
12714
- const srcPath = path11.join(src, entry.name);
12715
- const destPath = path11.join(dest, entry.name);
12902
+ const srcPath = path12.join(src, entry.name);
12903
+ const destPath = path12.join(dest, entry.name);
12716
12904
  if (entry.isDirectory()) copyDirSync2(srcPath, destPath);
12717
12905
  else fs4.copyFileSync(srcPath, destPath);
12718
12906
  }
@@ -12723,7 +12911,7 @@ function readDir(dir, source) {
12723
12911
  const skills = [];
12724
12912
  for (const entry of entries) {
12725
12913
  if (!entry.isDirectory()) continue;
12726
- const skillFile = path11.join(dir, entry.name, "SKILL.md");
12914
+ const skillFile = path12.join(dir, entry.name, "SKILL.md");
12727
12915
  if (!fs4.existsSync(skillFile)) continue;
12728
12916
  const parsed = parseSkillFile(skillFile, entry.name, source);
12729
12917
  if (parsed) skills.push(parsed);
@@ -12736,17 +12924,17 @@ var SkillsService = class {
12736
12924
  }
12737
12925
  workspaceRoot;
12738
12926
  localDir() {
12739
- return this.workspaceRoot ? path11.join(this.workspaceRoot, ".ordewell", "skills") : void 0;
12927
+ return this.workspaceRoot ? path12.join(this.workspaceRoot, ".ordewell", "skills") : void 0;
12740
12928
  }
12741
12929
  globalDir() {
12742
- return path11.join(globalDataDir(), "skills");
12930
+ return path12.join(globalDataDir(), "skills");
12743
12931
  }
12744
12932
  seed(name) {
12745
- const dest = path11.join(this.globalDir(), name);
12933
+ const dest = path12.join(this.globalDir(), name);
12746
12934
  if (fs4.existsSync(dest)) return false;
12747
12935
  let srcDir;
12748
12936
  try {
12749
- srcDir = path11.join(builtinSkillsDir(), name);
12937
+ srcDir = path12.join(builtinSkillsDir(), name);
12750
12938
  } catch (err) {
12751
12939
  console.warn(`Could not locate built-in skills dir: ${String(err)}`);
12752
12940
  return false;
@@ -12772,7 +12960,7 @@ var SkillsService = class {
12772
12960
  if (entries.length !== 1 || entries[0].name !== "SKILL.md" || !entries[0].isFile()) return false;
12773
12961
  let raw;
12774
12962
  try {
12775
- raw = fs4.readFileSync(path11.join(dir, "SKILL.md"), "utf8");
12963
+ raw = fs4.readFileSync(path12.join(dir, "SKILL.md"), "utf8");
12776
12964
  } catch {
12777
12965
  return false;
12778
12966
  }
@@ -12789,7 +12977,7 @@ var SkillsService = class {
12789
12977
  }
12790
12978
  pruneRetired() {
12791
12979
  for (const name of RETIRED_BUILTIN_SKILL_NAMES) {
12792
- const dest = path11.join(this.globalDir(), name);
12980
+ const dest = path12.join(this.globalDir(), name);
12793
12981
  if (!fs4.existsSync(dest)) continue;
12794
12982
  if (!this.isUnmodifiedRetiredSeed(dest, name)) continue;
12795
12983
  try {
@@ -12804,10 +12992,10 @@ var SkillsService = class {
12804
12992
  if (BUILTIN_SKILL_NAMES.includes(name)) this.seed(name);
12805
12993
  const localDir = this.localDir();
12806
12994
  if (localDir) {
12807
- const localFile = path11.join(localDir, name, "SKILL.md");
12995
+ const localFile = path12.join(localDir, name, "SKILL.md");
12808
12996
  if (fs4.existsSync(localFile)) return parseSkillFile(localFile, name, "local");
12809
12997
  }
12810
- const globalFile = path11.join(this.globalDir(), name, "SKILL.md");
12998
+ const globalFile = path12.join(this.globalDir(), name, "SKILL.md");
12811
12999
  if (fs4.existsSync(globalFile)) return parseSkillFile(globalFile, name, "global");
12812
13000
  return void 0;
12813
13001
  }
@@ -12889,11 +13077,11 @@ function truncateCheckpointSummary(summary) {
12889
13077
 
12890
13078
  // src/utils/sessionStore.ts
12891
13079
  var fs6 = __toESM(require("fs"));
12892
- var path13 = __toESM(require("path"));
13080
+ var path14 = __toESM(require("path"));
12893
13081
 
12894
13082
  // src/utils/fsHelpers.ts
12895
13083
  var fs5 = __toESM(require("fs"));
12896
- var path12 = __toESM(require("path"));
13084
+ var path13 = __toESM(require("path"));
12897
13085
  var STATE_DIR = ".ordewell";
12898
13086
  function ensureDir(dir) {
12899
13087
  if (!fs5.existsSync(dir)) {
@@ -12901,14 +13089,14 @@ function ensureDir(dir) {
12901
13089
  }
12902
13090
  }
12903
13091
  function getStateDir(baseDir) {
12904
- return path12.join(baseDir ?? process.cwd(), STATE_DIR);
13092
+ return path13.join(baseDir ?? process.cwd(), STATE_DIR);
12905
13093
  }
12906
13094
  var IGNORE_FILE = ".gitignore";
12907
13095
  function ensureStateDirIgnored(baseDir) {
12908
13096
  const dir = getStateDir(baseDir);
12909
13097
  ensureDir(dir);
12910
13098
  try {
12911
- fs5.writeFileSync(path12.join(dir, IGNORE_FILE), "*\n", { flag: "wx" });
13099
+ fs5.writeFileSync(path13.join(dir, IGNORE_FILE), "*\n", { flag: "wx" });
12912
13100
  } catch (err) {
12913
13101
  if (err.code !== "EEXIST") throw err;
12914
13102
  }
@@ -12923,7 +13111,7 @@ function mintSessionId() {
12923
13111
  // src/utils/sessionStore.ts
12924
13112
  var SESSIONS_SUBDIR = "sessions";
12925
13113
  function getSessionsDir(baseDir) {
12926
- return path13.join(getStateDir(baseDir), SESSIONS_SUBDIR);
13114
+ return path14.join(getStateDir(baseDir), SESSIONS_SUBDIR);
12927
13115
  }
12928
13116
  var REJECTION_MESSAGE = "This session was created with an older version of Ordewell. Please re-plan.";
12929
13117
  function hasScalarRunner(parsed) {
@@ -12958,7 +13146,7 @@ function saveSession(plan, goal, baseDir, id) {
12958
13146
  plan: JSON.parse(JSON.stringify(plan))
12959
13147
  };
12960
13148
  const filename = sessionFilename(meta);
12961
- const filePath = path13.join(sessionsDir, filename);
13149
+ const filePath = path14.join(sessionsDir, filename);
12962
13150
  fs6.writeFileSync(filePath, JSON.stringify(session, null, 2));
12963
13151
  return meta;
12964
13152
  }
@@ -12968,7 +13156,7 @@ function listSessions(baseDir, logger = defaultLogger) {
12968
13156
  const files = fs6.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
12969
13157
  return files.map((f) => {
12970
13158
  try {
12971
- const raw = fs6.readFileSync(path13.join(sessionsDir, f), "utf-8");
13159
+ const raw = fs6.readFileSync(path14.join(sessionsDir, f), "utf-8");
12972
13160
  const parsed = JSON.parse(raw);
12973
13161
  if (hasScalarRunner(parsed)) {
12974
13162
  logger.warn("sessionStore", `session file ${f}: ${REJECTION_MESSAGE}`);
@@ -12986,7 +13174,7 @@ function findSessionFile(sessionsDir, sessionId, logger) {
12986
13174
  const files = fs6.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
12987
13175
  for (const f of files) {
12988
13176
  try {
12989
- const raw = fs6.readFileSync(path13.join(sessionsDir, f), "utf-8");
13177
+ const raw = fs6.readFileSync(path14.join(sessionsDir, f), "utf-8");
12990
13178
  const session = JSON.parse(raw);
12991
13179
  if (session.meta.id === sessionId) return f;
12992
13180
  } catch (err) {
@@ -13001,7 +13189,7 @@ function loadSession(sessionId, baseDir, logger = defaultLogger) {
13001
13189
  try {
13002
13190
  const file = findSessionFile(sessionsDir, sessionId, logger);
13003
13191
  if (file) {
13004
- const raw = fs6.readFileSync(path13.join(sessionsDir, file), "utf-8");
13192
+ const raw = fs6.readFileSync(path14.join(sessionsDir, file), "utf-8");
13005
13193
  const parsed = JSON.parse(raw);
13006
13194
  if (hasScalarRunner(parsed)) {
13007
13195
  logger.warn("sessionStore", `session file ${file}: ${REJECTION_MESSAGE}`);
@@ -13035,7 +13223,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
13035
13223
  try {
13036
13224
  const file = findSessionFile(sessionsDir, sessionId, logger);
13037
13225
  if (file) {
13038
- fs6.unlinkSync(path13.join(sessionsDir, file));
13226
+ fs6.unlinkSync(path14.join(sessionsDir, file));
13039
13227
  return true;
13040
13228
  }
13041
13229
  } catch (err) {
@@ -13046,7 +13234,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
13046
13234
 
13047
13235
  // src/utils/prdStore.ts
13048
13236
  var fs7 = __toESM(require("fs"));
13049
- var path14 = __toESM(require("path"));
13237
+ var path15 = __toESM(require("path"));
13050
13238
  var PRD_BLOCK_RE = /<!--\s*ORDEWELL_PRD_START\s+slug="([^"]+)"\s*-->\s*([\s\S]*?)\s*<!--\s*ORDEWELL_PRD_END\s*-->/;
13051
13239
  function extractPrdBlock(text) {
13052
13240
  const match = PRD_BLOCK_RE.exec(text);
@@ -13060,9 +13248,9 @@ function sanitizeSlug(raw) {
13060
13248
  return raw.toLowerCase().replace(/[^a-z0-9-_]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
13061
13249
  }
13062
13250
  function savePrdMarkdown(workspace, slug2, markdown) {
13063
- const dir = path14.join(workspace, ".scratch", sanitizeSlug(slug2));
13251
+ const dir = path15.join(workspace, ".scratch", sanitizeSlug(slug2));
13064
13252
  fs7.mkdirSync(dir, { recursive: true });
13065
- const file = path14.join(dir, "PRD.md");
13253
+ const file = path15.join(dir, "PRD.md");
13066
13254
  fs7.writeFileSync(file, markdown.endsWith("\n") ? markdown : markdown + "\n", "utf8");
13067
13255
  return file;
13068
13256
  }
@@ -14089,9 +14277,11 @@ Execution is RUNNING${locked.length ? ` \u2014 these tasks are locked: ${locked.
14089
14277
  }
14090
14278
  /** What a runner offers, as {@link runnerAssignment} needs it. Spawns the runner's CLI to list models. */
14091
14279
  async catalogFor(runner) {
14280
+ const modes = this.runnerModesFor([runner])[runner];
14092
14281
  return {
14093
14282
  models: (await this.modelResolver.modelsForRunners([runner]))[runner] ?? [],
14094
- modes: this.runnerModesFor([runner])[runner]
14283
+ modes,
14284
+ defaultMode: resolveDefaultMode(modes, this.config.autonomousMode)
14095
14285
  };
14096
14286
  }
14097
14287
  /**
@@ -14779,7 +14969,7 @@ var import_child_process8 = require("child_process");
14779
14969
  var import_util4 = require("util");
14780
14970
  var import_os = require("os");
14781
14971
  var import_path = require("path");
14782
- var import_fs = require("fs");
14972
+ var import_fs2 = require("fs");
14783
14973
 
14784
14974
  // src/utils/tmux.ts
14785
14975
  var import_child_process7 = require("child_process");
@@ -14872,7 +15062,7 @@ var TmuxSession = class extends AbstractTerminalSession {
14872
15062
  * lets the user keep poking at a finished task's terminal.
14873
15063
  */
14874
15064
  async start(command, args, cwd, env) {
14875
- (0, import_fs.writeFileSync)(this.logPath, "");
15065
+ (0, import_fs2.writeFileSync)(this.logPath, "");
14876
15066
  const envAssignments = Object.entries(env ?? {}).map(([k, v]) => `${k}=${posixShellQuote(v)}`).join(" ");
14877
15067
  const inner = [command, ...args].map(posixShellQuote).join(" ");
14878
15068
  const prefix = envAssignments ? `env ${envAssignments} ` : "";
@@ -14886,7 +15076,7 @@ var TmuxSession = class extends AbstractTerminalSession {
14886
15076
  if (this.exited) return;
14887
15077
  let content;
14888
15078
  try {
14889
- content = (0, import_fs.existsSync)(this.logPath) ? (0, import_fs.readFileSync)(this.logPath, "utf8") : "";
15079
+ content = (0, import_fs2.existsSync)(this.logPath) ? (0, import_fs2.readFileSync)(this.logPath, "utf8") : "";
14890
15080
  } catch {
14891
15081
  return;
14892
15082
  }
@@ -14913,7 +15103,7 @@ var TmuxSession = class extends AbstractTerminalSession {
14913
15103
  this.tmux(["pipe-pane", "-t", this.target]).catch(() => {
14914
15104
  });
14915
15105
  try {
14916
- (0, import_fs.unlinkSync)(this.logPath);
15106
+ (0, import_fs2.unlinkSync)(this.logPath);
14917
15107
  } catch {
14918
15108
  }
14919
15109
  this.baseHandleExit(code);
@@ -15078,7 +15268,7 @@ var TmuxRunner = class extends AbstractRunner {
15078
15268
 
15079
15269
  // src/utils/daemonToken.ts
15080
15270
  var import_crypto2 = require("crypto");
15081
- var import_fs2 = require("fs");
15271
+ var import_fs3 = require("fs");
15082
15272
  var import_path2 = require("path");
15083
15273
  var BEARER_PREFIX = "bearer ";
15084
15274
  var DAEMON_TOKEN_SUBPROTOCOL_PREFIX = "ordewell.token.";
@@ -15092,22 +15282,22 @@ function daemonTokenPath(port) {
15092
15282
  function mintDaemonToken(port) {
15093
15283
  const token = (0, import_crypto2.randomBytes)(32).toString("base64url");
15094
15284
  const file = daemonTokenPath(port);
15095
- (0, import_fs2.mkdirSync)(configDir(), { recursive: true });
15285
+ (0, import_fs3.mkdirSync)(configDir(), { recursive: true });
15096
15286
  try {
15097
- (0, import_fs2.unlinkSync)(file);
15287
+ (0, import_fs3.unlinkSync)(file);
15098
15288
  } catch {
15099
15289
  }
15100
- const fd = (0, import_fs2.openSync)(file, "wx", 384);
15290
+ const fd = (0, import_fs3.openSync)(file, "wx", 384);
15101
15291
  try {
15102
- (0, import_fs2.writeSync)(fd, token);
15292
+ (0, import_fs3.writeSync)(fd, token);
15103
15293
  } finally {
15104
- (0, import_fs2.closeSync)(fd);
15294
+ (0, import_fs3.closeSync)(fd);
15105
15295
  }
15106
15296
  return { token, file };
15107
15297
  }
15108
15298
  function readDaemonToken(port) {
15109
15299
  try {
15110
- const token = (0, import_fs2.readFileSync)(daemonTokenPath(port), "utf8").trim();
15300
+ const token = (0, import_fs3.readFileSync)(daemonTokenPath(port), "utf8").trim();
15111
15301
  return token === "" ? void 0 : token;
15112
15302
  } catch {
15113
15303
  return void 0;
@@ -15115,7 +15305,7 @@ function readDaemonToken(port) {
15115
15305
  }
15116
15306
  function clearDaemonToken(port) {
15117
15307
  try {
15118
- (0, import_fs2.unlinkSync)(daemonTokenPath(port));
15308
+ (0, import_fs3.unlinkSync)(daemonTokenPath(port));
15119
15309
  } catch {
15120
15310
  }
15121
15311
  }
@@ -15149,17 +15339,17 @@ function tokensMatch(presented, expected) {
15149
15339
 
15150
15340
  // src/plugins/RunnerRegistry.ts
15151
15341
  var fs9 = __toESM(require("fs"));
15152
- var path17 = __toESM(require("path"));
15153
- var os4 = __toESM(require("os"));
15342
+ var path18 = __toESM(require("path"));
15343
+ var os5 = __toESM(require("os"));
15154
15344
  var import_child_process9 = require("child_process");
15155
15345
  var import_crypto3 = require("crypto");
15156
15346
 
15157
15347
  // src/plugins/FsPluginStore.ts
15158
15348
  var fs8 = __toESM(require("fs"));
15159
- var path16 = __toESM(require("path"));
15349
+ var path17 = __toESM(require("path"));
15160
15350
 
15161
15351
  // src/plugins/pluginNames.ts
15162
- var path15 = __toESM(require("path"));
15352
+ var path16 = __toESM(require("path"));
15163
15353
  var PLUGIN_NAME_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
15164
15354
  var MAX_PLUGIN_NAME_LENGTH = 64;
15165
15355
  function isPlainPluginName(name) {
@@ -15174,10 +15364,10 @@ function assertPlainPluginName(name) {
15174
15364
  }
15175
15365
  function resolvePluginInstallDir(pluginsDir, name) {
15176
15366
  assertPlainPluginName(name);
15177
- const root = path15.resolve(pluginsDir);
15178
- const dest = path15.resolve(root, name);
15179
- const relative3 = path15.relative(root, dest);
15180
- if (relative3 !== name || relative3 === "" || path15.isAbsolute(relative3)) {
15367
+ const root = path16.resolve(pluginsDir);
15368
+ const dest = path16.resolve(root, name);
15369
+ const relative3 = path16.relative(root, dest);
15370
+ if (relative3 !== name || relative3 === "" || path16.isAbsolute(relative3)) {
15181
15371
  throw new Error(`Plugin install path escapes the plugins directory: ${JSON.stringify(name)}`);
15182
15372
  }
15183
15373
  return dest;
@@ -15192,10 +15382,10 @@ function isValidManifest(obj) {
15192
15382
 
15193
15383
  // src/plugins/FsPluginStore.ts
15194
15384
  function userPluginsDir() {
15195
- return path16.join(globalDataDir(), "plugins");
15385
+ return path17.join(globalDataDir(), "plugins");
15196
15386
  }
15197
15387
  function loadManifestFromDir(dir) {
15198
- const manifestPath = path16.join(dir, "manifest.json");
15388
+ const manifestPath = path17.join(dir, "manifest.json");
15199
15389
  if (!fs8.existsSync(manifestPath)) return null;
15200
15390
  try {
15201
15391
  const raw = fs8.readFileSync(manifestPath, "utf8");
@@ -15210,8 +15400,8 @@ function copyDirSync3(src, dest) {
15210
15400
  ensureDir(dest);
15211
15401
  const entries = fs8.readdirSync(src, { withFileTypes: true });
15212
15402
  for (const entry of entries) {
15213
- const srcPath = path16.join(src, entry.name);
15214
- const destPath = path16.join(dest, entry.name);
15403
+ const srcPath = path17.join(src, entry.name);
15404
+ const destPath = path17.join(dest, entry.name);
15215
15405
  if (entry.isDirectory()) {
15216
15406
  copyDirSync3(srcPath, destPath);
15217
15407
  } else {
@@ -15223,7 +15413,7 @@ function rmDirSync(dir) {
15223
15413
  if (!fs8.existsSync(dir)) return;
15224
15414
  const entries = fs8.readdirSync(dir, { withFileTypes: true });
15225
15415
  for (const entry of entries) {
15226
- const p = path16.join(dir, entry.name);
15416
+ const p = path17.join(dir, entry.name);
15227
15417
  if (entry.isDirectory()) {
15228
15418
  rmDirSync(p);
15229
15419
  } else {
@@ -15276,11 +15466,11 @@ var FsPluginStore = class {
15276
15466
  return null;
15277
15467
  }
15278
15468
  }
15279
- dirExists(path20) {
15280
- return fs8.existsSync(path20) && fs8.statSync(path20).isDirectory();
15469
+ dirExists(path21) {
15470
+ return fs8.existsSync(path21) && fs8.statSync(path21).isDirectory();
15281
15471
  }
15282
- exists(path20) {
15283
- return fs8.existsSync(path20);
15472
+ exists(path21) {
15473
+ return fs8.existsSync(path21);
15284
15474
  }
15285
15475
  };
15286
15476
 
@@ -15712,7 +15902,7 @@ var RunnerRegistry = class {
15712
15902
  return entry?.source === "builtin";
15713
15903
  }
15714
15904
  installFromPath(sourcePath) {
15715
- const absPath = path17.resolve(sourcePath);
15905
+ const absPath = path18.resolve(sourcePath);
15716
15906
  if (!this.store.dirExists(absPath)) {
15717
15907
  throw new Error(`Plugin source must be a directory: ${absPath}`);
15718
15908
  }
@@ -15724,7 +15914,7 @@ var RunnerRegistry = class {
15724
15914
  }
15725
15915
  installFromGit(url) {
15726
15916
  const validated = assertInstallablePluginUrl(url);
15727
- const tmpDir = path17.join(os4.tmpdir(), `ordewell-plugin-${(0, import_crypto3.randomBytes)(12).toString("hex")}`);
15917
+ const tmpDir = path18.join(os5.tmpdir(), `ordewell-plugin-${(0, import_crypto3.randomBytes)(12).toString("hex")}`);
15728
15918
  this.store.ensureDir(tmpDir);
15729
15919
  try {
15730
15920
  try {
@@ -15737,7 +15927,7 @@ var RunnerRegistry = class {
15737
15927
  const hasManifest = contents.some((f) => f === "manifest.json");
15738
15928
  let sourceDir = tmpDir;
15739
15929
  if (!hasManifest) {
15740
- const onlyEntry = contents.length === 1 ? path17.join(tmpDir, contents[0]) : void 0;
15930
+ const onlyEntry = contents.length === 1 ? path18.join(tmpDir, contents[0]) : void 0;
15741
15931
  if (!onlyEntry || !this.store.dirExists(onlyEntry)) {
15742
15932
  throw new Error(`No manifest.json found in repository: ${validated.toString()}`);
15743
15933
  }
@@ -15785,7 +15975,7 @@ var RunnerRegistry = class {
15785
15975
  }
15786
15976
  createSkeleton(name, outputDir) {
15787
15977
  assertPlainPluginName(name);
15788
- const dir = path17.resolve(outputDir, name);
15978
+ const dir = path18.resolve(outputDir, name);
15789
15979
  this.store.ensureDir(dir);
15790
15980
  const manifest = {
15791
15981
  name,
@@ -15817,8 +16007,8 @@ var RunnerRegistry = class {
15817
16007
  ]
15818
16008
  }
15819
16009
  };
15820
- this.store.writeFile(path17.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
15821
- const runSh = path17.join(dir, "run.sh");
16010
+ this.store.writeFile(path18.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
16011
+ const runSh = path18.join(dir, "run.sh");
15822
16012
  const scriptContent = `#!/usr/bin/env bash
15823
16013
  # Custom runner script for ${name}
15824
16014
  # Receives:
@@ -15851,14 +16041,14 @@ function fsChmodSync(fpath, mode) {
15851
16041
 
15852
16042
  // src/utils/stateStore.ts
15853
16043
  var fs10 = __toESM(require("fs"));
15854
- var path18 = __toESM(require("path"));
16044
+ var path19 = __toESM(require("path"));
15855
16045
  var STATE_FILE = "state.json";
15856
16046
  function getStatePath(baseDir) {
15857
- return path18.join(getStateDir(baseDir), STATE_FILE);
16047
+ return path19.join(getStateDir(baseDir), STATE_FILE);
15858
16048
  }
15859
16049
  function saveState(plan, baseDir) {
15860
16050
  const statePath = getStatePath(baseDir ?? process.cwd());
15861
- ensureDir(path18.dirname(statePath));
16051
+ ensureDir(path19.dirname(statePath));
15862
16052
  plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
15863
16053
  fs10.writeFileSync(statePath, JSON.stringify(plan, null, 2));
15864
16054
  }
@@ -15891,7 +16081,7 @@ function stateExists(baseDir) {
15891
16081
 
15892
16082
  // src/services/SettingsService.ts
15893
16083
  var fs11 = __toESM(require("fs"));
15894
- var path19 = __toESM(require("path"));
16084
+ var path20 = __toESM(require("path"));
15895
16085
  var DEFAULTS = {
15896
16086
  tdd: { enabled: true },
15897
16087
  verification: { enabled: false }
@@ -15899,7 +16089,7 @@ var DEFAULTS = {
15899
16089
  function getSettingsPath() {
15900
16090
  const override = process.env.ORDEWELL_SETTINGS_PATH;
15901
16091
  if (override && override.trim()) return override.trim();
15902
- return path19.join(globalDataDir(), "settings.json");
16092
+ return path20.join(globalDataDir(), "settings.json");
15903
16093
  }
15904
16094
  function readPlannerModels(raw) {
15905
16095
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
@@ -16027,7 +16217,7 @@ var SettingsService = class {
16027
16217
  return { ...DEFAULTS, tdd: { ...DEFAULTS.tdd }, verification: { ...DEFAULTS.verification } };
16028
16218
  }
16029
16219
  persist() {
16030
- const dir = path19.dirname(this.filePath);
16220
+ const dir = path20.dirname(this.filePath);
16031
16221
  if (!fs11.existsSync(dir)) {
16032
16222
  fs11.mkdirSync(dir, { recursive: true });
16033
16223
  }