@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.mjs CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  resolveTaskMode,
14
14
  runnerModesFrom,
15
15
  validatePlanModification
16
- } from "./chunk-QJ63PD5K.mjs";
16
+ } from "./chunk-MKUTJDT2.mjs";
17
17
  import {
18
18
  CHECKPOINT_TRUNCATE_LENGTH,
19
19
  UPDATABLE_FIELDS,
@@ -6225,6 +6225,19 @@ function renderTerminalOutput(raw) {
6225
6225
  }
6226
6226
  var MARKER_SCAN_TAIL = 16384;
6227
6227
  var IDLE_TIMEOUT_MS = 6e4;
6228
+ function renderCleanCapture(raw, doneToken) {
6229
+ const rendered = renderTerminalOutput(raw).replace(/[\s─-▟]+$/gm, "");
6230
+ if (!doneToken) return rendered.trim();
6231
+ const lines = rendered.split("\n");
6232
+ const flat = (s) => flattenTerminalOutput(s);
6233
+ for (let i = 0; i < lines.length; i++) {
6234
+ const own = flat(lines[i]).includes(doneToken);
6235
+ if (own) return lines.slice(0, i).join("\n").trim();
6236
+ const window = flat(lines[i]) + (i + 1 < lines.length ? flat(lines[i + 1]) : "");
6237
+ if (window.includes(doneToken)) return lines.slice(0, i + 1).join("\n").trim();
6238
+ }
6239
+ return rendered.trim();
6240
+ }
6228
6241
  var VerdictEngine = class {
6229
6242
  markerSeen = /* @__PURE__ */ new Set();
6230
6243
  buffers = /* @__PURE__ */ new Map();
@@ -6452,6 +6465,167 @@ ${line}
6452
6465
  }
6453
6466
  };
6454
6467
 
6468
+ // src/services/transcriptCapture.ts
6469
+ import { readFileSync, readdirSync, statSync as statSync2, existsSync } from "fs";
6470
+ import * as os2 from "os";
6471
+ import * as path4 from "path";
6472
+ function homeDir() {
6473
+ return process.env.HOME || os2.homedir();
6474
+ }
6475
+ async function readFinalAssistantText(query, maxChars = 4e3) {
6476
+ try {
6477
+ if (query.runner === "claude-code") return claudeFinal(query, maxChars);
6478
+ if (query.runner === "opencode") return await opencodeFinal(query, maxChars);
6479
+ if (query.runner === "codex") return codexFinal(query, maxChars);
6480
+ } catch {
6481
+ }
6482
+ return null;
6483
+ }
6484
+ function claudeFinal(query, maxChars) {
6485
+ const munged = query.cwd.replaceAll("/", "-").replaceAll("_", "-");
6486
+ const dir = path4.join(homeDir(), ".claude", "projects", munged);
6487
+ if (!existsSync(dir)) return null;
6488
+ const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
6489
+ const candidates = readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path4.join(dir, f)).filter((f) => cutoff ? statSync2(f).mtimeMs >= cutoff - 5e3 : true).sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs);
6490
+ for (const file of candidates) {
6491
+ const text = claudeLastAssistant(file);
6492
+ if (text) return clamp(text, maxChars);
6493
+ }
6494
+ return null;
6495
+ }
6496
+ function claudeLastAssistant(file) {
6497
+ let last = null;
6498
+ let buf = "";
6499
+ const fd = statSync2(file);
6500
+ const start = Math.max(0, fd.size - 512 * 1024);
6501
+ buf = readFileSync(file, { encoding: "utf8" }).toString();
6502
+ if (start > 0) buf = buf.slice(buf.indexOf("\n", Math.min(start, buf.length - 1)) + 1);
6503
+ for (const line of buf.split("\n")) {
6504
+ if (!line.trim()) continue;
6505
+ let rec;
6506
+ try {
6507
+ rec = JSON.parse(line);
6508
+ } catch {
6509
+ continue;
6510
+ }
6511
+ if (rec.type !== "assistant" || rec.isSidechain) continue;
6512
+ const content = rec.message?.content;
6513
+ if (!Array.isArray(content)) continue;
6514
+ const texts = content.filter((b) => typeof b === "object" && b !== null && b.type === "text").map((b) => b.text).join("\n").trim();
6515
+ if (texts) last = texts;
6516
+ }
6517
+ return last;
6518
+ }
6519
+ async function opencodeFinal(query, maxChars) {
6520
+ let DatabaseSync;
6521
+ try {
6522
+ ({ DatabaseSync } = await import("sqlite"));
6523
+ } catch {
6524
+ return null;
6525
+ }
6526
+ const dbPath = path4.join(homeDir(), ".local", "share", "opencode", "opencode.db");
6527
+ if (!existsSync(dbPath)) return null;
6528
+ let db;
6529
+ try {
6530
+ db = new DatabaseSync(dbPath, { open: true });
6531
+ } catch {
6532
+ return null;
6533
+ }
6534
+ try {
6535
+ const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
6536
+ const rows = db.prepare(
6537
+ `select s.id, s.time_updated from session s
6538
+ join project p on p.id = s.project_id
6539
+ where s.directory = ?
6540
+ order by s.time_updated desc limit 5`
6541
+ ).all(query.cwd);
6542
+ for (const row of rows) {
6543
+ if (cutoff && row.time_updated < cutoff - 5e3) continue;
6544
+ const parts = db.prepare(
6545
+ `select pt.data from part pt
6546
+ join message m on m.id = pt.message_id
6547
+ where m.session_id = ? and m.data like '%"role":"assistant"%'
6548
+ order by pt.id asc`
6549
+ ).all(row.id);
6550
+ let text = null;
6551
+ for (const p of parts) {
6552
+ try {
6553
+ const d = JSON.parse(p.data);
6554
+ if (d.type === "text" && d.text && d.text.trim()) text = d.text.trim();
6555
+ } catch {
6556
+ continue;
6557
+ }
6558
+ }
6559
+ if (text) return clamp(text, maxChars);
6560
+ }
6561
+ return null;
6562
+ } catch {
6563
+ return null;
6564
+ } finally {
6565
+ try {
6566
+ db.close();
6567
+ } catch {
6568
+ }
6569
+ }
6570
+ }
6571
+ function codexFinal(query, maxChars) {
6572
+ const root = path4.join(homeDir(), ".codex", "sessions");
6573
+ if (!existsSync(root)) return null;
6574
+ const cutoff = query.startedAt ? Date.parse(query.startedAt) : 0;
6575
+ const files = [];
6576
+ const stack = [root];
6577
+ while (stack.length) {
6578
+ const dir = stack.pop();
6579
+ let entries;
6580
+ try {
6581
+ entries = readdirSync(dir);
6582
+ } catch {
6583
+ continue;
6584
+ }
6585
+ for (const e of entries) {
6586
+ const full = path4.join(dir, e);
6587
+ let st;
6588
+ try {
6589
+ st = statSync2(full);
6590
+ } catch {
6591
+ continue;
6592
+ }
6593
+ if (st.isDirectory()) stack.push(full);
6594
+ else if (e.startsWith("rollout-") && e.endsWith(".jsonl") && (!cutoff || st.mtimeMs >= cutoff - 5e3)) files.push(full);
6595
+ }
6596
+ }
6597
+ files.sort((a, b) => statSync2(b).mtimeMs - statSync2(a).mtimeMs);
6598
+ for (const file of files.slice(0, 10)) {
6599
+ const text = codexLastAssistant(file, query.cwd);
6600
+ if (text) return clamp(text, maxChars);
6601
+ }
6602
+ return null;
6603
+ }
6604
+ function codexLastAssistant(file, cwd) {
6605
+ const raw = readFileSync(file, "utf8");
6606
+ const lines = raw.split("\n").filter((l) => l.trim());
6607
+ let sawCwd = false;
6608
+ let last = null;
6609
+ for (const line of lines) {
6610
+ let rec;
6611
+ try {
6612
+ rec = JSON.parse(line);
6613
+ } catch {
6614
+ continue;
6615
+ }
6616
+ if (rec.type === "session_meta" && rec.payload?.cwd === cwd) sawCwd = true;
6617
+ if (rec.type !== "response_item") continue;
6618
+ const p = rec.payload;
6619
+ if (p?.role !== "assistant" || p.type !== "message") continue;
6620
+ const texts = (Array.isArray(p.content) ? p.content : []).map((c) => typeof c === "object" && c !== null && c.text || "").join("\n").trim();
6621
+ if (texts) last = texts;
6622
+ }
6623
+ return sawCwd ? last : null;
6624
+ }
6625
+ function clamp(text, maxChars) {
6626
+ return text.length <= maxChars ? text : text.slice(-maxChars);
6627
+ }
6628
+
6455
6629
  // src/services/PlanStore.ts
6456
6630
  var PlanStore = class {
6457
6631
  _planTasks = [];
@@ -6833,6 +7007,11 @@ var TaskOrchestrator = class {
6833
7007
  workspaceRootFn = () => process.cwd();
6834
7008
  observers = [];
6835
7009
  tddEnabled = () => false;
7010
+ /**
7011
+ * Spawn context per active task, for locating the agent's own session
7012
+ * transcript at verdict time (issue #16). Cleared with the session entry.
7013
+ */
7014
+ taskSpawnContext = /* @__PURE__ */ new Map();
6836
7015
  /** Advisory silence timestamp for a task's live runner, or null if not idle. */
6837
7016
  getIdleSince(taskId) {
6838
7017
  return this.verifier.getIdleSince(taskId);
@@ -6995,6 +7174,8 @@ var TaskOrchestrator = class {
6995
7174
  const task = this.store.get(taskId);
6996
7175
  if (!task) return;
6997
7176
  this.activeTaskSessions.delete(taskId);
7177
+ const spawnContext = this.taskSpawnContext.get(taskId);
7178
+ this.taskSpawnContext.delete(taskId);
6998
7179
  console.error(`[TaskOrchestrator] Task #${task.order} "${task.title}" verdict=${verdict.outcome}`);
6999
7180
  console.error(`[TaskOrchestrator] Runner: ${task.assignedRunner}, Model: ${task.assignedModel?.modelId ?? "default"}`);
7000
7181
  console.error(`[TaskOrchestrator] Prompt preview: ${(task.prompt ?? "").slice(0, 200)}`);
@@ -7005,6 +7186,10 @@ ${output.slice(-3e3)}`);
7005
7186
  console.error(`[TaskOrchestrator] Output: (empty \u2014 no stdout/stderr captured)`);
7006
7187
  }
7007
7188
  this.store.setTaskVerdict(taskId, verdict);
7189
+ const doneToken = `<<<ORDEWELL_DONE_${task.completionMarker}>>>`;
7190
+ const transcript = spawnContext ? await readFinalAssistantText(spawnContext) : null;
7191
+ const cleaned = transcript ?? renderCleanCapture(output, doneToken);
7192
+ const effective = cleaned.length > 0 ? cleaned : output;
7008
7193
  if (verdict.outcome === "pass") {
7009
7194
  this.store.markCompleted(taskId);
7010
7195
  this.notifications.info(`Task "${task.title}" completed.`);
@@ -7014,7 +7199,7 @@ ${output.slice(-3e3)}`);
7014
7199
  this.planStatus = "approved";
7015
7200
  this.notifications.error(`Task "${task.title}" failed verification: ${verdict.reason}`);
7016
7201
  }
7017
- this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason, output));
7202
+ this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason, effective));
7018
7203
  this.logAndArchive(task, verdict);
7019
7204
  this.emit("onTaskChanged");
7020
7205
  if (!this.running) {
@@ -7254,6 +7439,8 @@ ${output.slice(-3e3)}`);
7254
7439
  try {
7255
7440
  const cwd = this.workspaceRootFn();
7256
7441
  const runner = this.store.resolveTaskRunner(task);
7442
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
7443
+ this.taskSpawnContext.set(task.id, { runner, cwd, startedAt });
7257
7444
  const finalPrompt = composeAugmentedPrompt(task, this.store.planTasks, {
7258
7445
  planMapEnabled: this.config.planMapEnabled,
7259
7446
  tddEnabled: this.tddEnabled()
@@ -7418,7 +7605,7 @@ ${errors.map((e) => `- ${e}`).join("\n")}`
7418
7605
  };
7419
7606
 
7420
7607
  // src/services/ModelDiscovery.ts
7421
- import * as path7 from "path";
7608
+ import * as path8 from "path";
7422
7609
  import { exec as exec2, spawn } from "child_process";
7423
7610
  import { promisify as promisify2 } from "util";
7424
7611
  import * as fsSync3 from "fs";
@@ -7427,8 +7614,8 @@ import * as osMod from "os";
7427
7614
  // src/utils/shellPath.ts
7428
7615
  import { exec } from "child_process";
7429
7616
  import { promisify } from "util";
7430
- import * as os2 from "os";
7431
- import * as path4 from "path";
7617
+ import * as os3 from "os";
7618
+ import * as path5 from "path";
7432
7619
  var execAsync = promisify(exec);
7433
7620
  var LOGIN_SHELL_TIMEOUT_MS = 5e3;
7434
7621
  var PATH_MARKER = "__ORDEWELL_PATH__";
@@ -7437,42 +7624,42 @@ var defaultExec = async (command, options) => {
7437
7624
  return { stdout: String(stdout) };
7438
7625
  };
7439
7626
  function posixBinDirs() {
7440
- const home = os2.homedir();
7627
+ const home = os3.homedir();
7441
7628
  return [
7442
- path4.join(home, ".local", "bin"),
7443
- path4.join(home, ".opencode", "bin"),
7444
- path4.join(home, ".claude", "bin"),
7445
- path4.join(home, ".bun", "bin"),
7446
- path4.join(home, ".volta", "bin"),
7447
- path4.join(home, ".npm-global", "bin"),
7448
- path4.join(home, "bin"),
7629
+ path5.join(home, ".local", "bin"),
7630
+ path5.join(home, ".opencode", "bin"),
7631
+ path5.join(home, ".claude", "bin"),
7632
+ path5.join(home, ".bun", "bin"),
7633
+ path5.join(home, ".volta", "bin"),
7634
+ path5.join(home, ".npm-global", "bin"),
7635
+ path5.join(home, "bin"),
7449
7636
  "/usr/local/bin",
7450
7637
  "/opt/homebrew/bin"
7451
7638
  ];
7452
7639
  }
7453
7640
  function windowsBinDirs(env, home) {
7454
- const join19 = (...parts) => path4.win32.join(...parts);
7455
- const under = (base, ...parts) => base ? [join19(base, ...parts)] : [];
7641
+ const join20 = (...parts) => path5.win32.join(...parts);
7642
+ const under = (base, ...parts) => base ? [join20(base, ...parts)] : [];
7456
7643
  const appData = env.APPDATA;
7457
7644
  const localAppData = env.LOCALAPPDATA;
7458
7645
  const programData = env.ProgramData;
7459
7646
  return [
7460
7647
  // Native per-user installers, PowerShell-driven and otherwise.
7461
- join19(home, ".local", "bin"),
7462
- join19(home, ".opencode", "bin"),
7463
- join19(home, ".claude", "bin"),
7464
- join19(home, ".codex", "bin"),
7648
+ join20(home, ".local", "bin"),
7649
+ join20(home, ".opencode", "bin"),
7650
+ join20(home, ".claude", "bin"),
7651
+ join20(home, ".codex", "bin"),
7465
7652
  ...under(localAppData, "Programs", "claude"),
7466
7653
  // Node package managers. npm's global prefix is `%APPDATA%\npm`; the
7467
7654
  // literal spelling is kept as a fallback for a host that does not export
7468
7655
  // APPDATA (a service account, a stripped CI container).
7469
7656
  ...under(appData, "npm"),
7470
- join19(home, "AppData", "Roaming", "npm"),
7657
+ join20(home, "AppData", "Roaming", "npm"),
7471
7658
  ...under(localAppData, "pnpm"),
7472
7659
  ...under(localAppData, "Yarn", "bin"),
7473
- join19(home, ".bun", "bin"),
7660
+ join20(home, ".bun", "bin"),
7474
7661
  // Windows package managers.
7475
- join19(home, "scoop", "shims"),
7662
+ join20(home, "scoop", "shims"),
7476
7663
  ...under(env.SCOOP, "shims"),
7477
7664
  ...under(env.SCOOP_GLOBAL ?? programData, "scoop", "shims"),
7478
7665
  ...under(programData, "chocolatey", "bin"),
@@ -7482,13 +7669,13 @@ function windowsBinDirs(env, home) {
7482
7669
  ...under(localAppData, "Microsoft", "WindowsApps"),
7483
7670
  // Version managers. Volta's Windows home is not the POSIX `~/.volta`.
7484
7671
  ...under(localAppData, "Volta", "bin"),
7485
- join19(home, ".volta", "bin")
7672
+ join20(home, ".volta", "bin")
7486
7673
  ];
7487
7674
  }
7488
7675
  function wellKnownBinDirs(deps = {}) {
7489
7676
  const platform = deps.platform ?? process.platform;
7490
7677
  if (platform !== "win32") return posixBinDirs();
7491
- return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ?? os2.homedir()))];
7678
+ return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ?? os3.homedir()))];
7492
7679
  }
7493
7680
  async function loginShellPath(execImpl) {
7494
7681
  if (process.platform === "win32") return null;
@@ -7511,14 +7698,14 @@ function augmentedPath(execImpl = defaultExec) {
7511
7698
  const segments = [];
7512
7699
  const push = (p) => {
7513
7700
  if (!p) return;
7514
- for (const seg of p.split(path4.delimiter)) {
7701
+ for (const seg of p.split(path5.delimiter)) {
7515
7702
  if (seg && !segments.includes(seg)) segments.push(seg);
7516
7703
  }
7517
7704
  };
7518
7705
  push(process.env.PATH);
7519
7706
  push(await loginShellPath(execImpl));
7520
7707
  for (const dir of wellKnownBinDirs()) push(dir);
7521
- return segments.join(path4.delimiter);
7708
+ return segments.join(path5.delimiter);
7522
7709
  })();
7523
7710
  }
7524
7711
  return cachedPath;
@@ -7540,17 +7727,17 @@ function withPath(base, resolvedPath, overrides = {}) {
7540
7727
 
7541
7728
  // src/utils/globalDataDir.ts
7542
7729
  import * as fs from "fs";
7543
- import * as path5 from "path";
7544
- import * as os3 from "os";
7730
+ import * as path6 from "path";
7731
+ import * as os4 from "os";
7545
7732
  function globalDataDir() {
7546
- return path5.join(os3.homedir(), ".ordewell");
7733
+ return path6.join(os4.homedir(), ".ordewell");
7547
7734
  }
7548
7735
  function copyDirSync(src, dest) {
7549
7736
  fs.mkdirSync(dest, { recursive: true });
7550
7737
  const entries = fs.readdirSync(src, { withFileTypes: true });
7551
7738
  for (const entry of entries) {
7552
- const srcPath = path5.join(src, entry.name);
7553
- const destPath = path5.join(dest, entry.name);
7739
+ const srcPath = path6.join(src, entry.name);
7740
+ const destPath = path6.join(dest, entry.name);
7554
7741
  if (entry.isDirectory()) {
7555
7742
  copyDirSync(srcPath, destPath);
7556
7743
  } else {
@@ -7562,12 +7749,12 @@ var migrated = false;
7562
7749
  function migrateOldConfigDir() {
7563
7750
  if (migrated) return;
7564
7751
  migrated = true;
7565
- const oldDir = path5.join(os3.homedir(), ".config", "ordewell");
7752
+ const oldDir = path6.join(os4.homedir(), ".config", "ordewell");
7566
7753
  if (!fs.existsSync(oldDir)) return;
7567
7754
  const newDir = globalDataDir();
7568
7755
  const liftFile = (name) => {
7569
- const oldFile = path5.join(oldDir, name);
7570
- const newFile = path5.join(newDir, name);
7756
+ const oldFile = path6.join(oldDir, name);
7757
+ const newFile = path6.join(newDir, name);
7571
7758
  if (fs.existsSync(oldFile) && !fs.existsSync(newFile)) {
7572
7759
  fs.mkdirSync(newDir, { recursive: true });
7573
7760
  fs.copyFileSync(oldFile, newFile);
@@ -7575,8 +7762,8 @@ function migrateOldConfigDir() {
7575
7762
  };
7576
7763
  liftFile("settings.json");
7577
7764
  liftFile(".env");
7578
- const oldPlugins = path5.join(oldDir, "plugins");
7579
- const newPlugins = path5.join(newDir, "plugins");
7765
+ const oldPlugins = path6.join(oldDir, "plugins");
7766
+ const newPlugins = path6.join(newDir, "plugins");
7580
7767
  if (fs.existsSync(oldPlugins) && !fs.existsSync(newPlugins)) {
7581
7768
  copyDirSync(oldPlugins, newPlugins);
7582
7769
  }
@@ -7584,7 +7771,7 @@ function migrateOldConfigDir() {
7584
7771
 
7585
7772
  // src/utils/launch.ts
7586
7773
  import * as fsSync2 from "fs";
7587
- import * as path6 from "path";
7774
+ import * as path7 from "path";
7588
7775
 
7589
7776
  // src/utils/shell.ts
7590
7777
  var ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]|\x1b\][^\x07]*\x07|\x1b[()][AB012]|\r/g;
@@ -7613,7 +7800,7 @@ var CMD_EXE_MAX_COMMAND_LINE = 8191;
7613
7800
  var WINDOWS_MAX_COMMAND_LINE = 32767;
7614
7801
  function defaultPowerShell() {
7615
7802
  const root = process.env.SystemRoot || process.env.windir;
7616
- return root ? path6.win32.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : "powershell.exe";
7803
+ return root ? path7.win32.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : "powershell.exe";
7617
7804
  }
7618
7805
  var POWERSHELL_FLAGS = ["-NoLogo", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File"];
7619
7806
  var CommandLineTooLongError = class extends Error {
@@ -7665,7 +7852,7 @@ Searched: ${searchedPath || "(empty PATH)"}`);
7665
7852
  };
7666
7853
  function isResolvableOnPosixPath(command, PATH, exists) {
7667
7854
  if (command.includes("/")) return exists(command);
7668
- return PATH.split(path6.delimiter).map((d) => d.trim()).filter(Boolean).some((dir) => exists(path6.join(dir, command)));
7855
+ return PATH.split(path7.delimiter).map((d) => d.trim()).filter(Boolean).some((dir) => exists(path7.join(dir, command)));
7669
7856
  }
7670
7857
  function isExecutableResolved(command, plan, PATH, deps = {}) {
7671
7858
  if ((deps.platform ?? process.platform) === "win32") return plan.file !== command;
@@ -7705,9 +7892,9 @@ function cmdArgs(line) {
7705
7892
  return ["/d", "/s", "/c", `"${line}"`];
7706
7893
  }
7707
7894
  function candidateExtensions(command, pathExt) {
7708
- const declared = pathExt.split(path6.win32.delimiter).map((e) => e.trim().toLowerCase()).filter(Boolean);
7895
+ const declared = pathExt.split(path7.win32.delimiter).map((e) => e.trim().toLowerCase()).filter(Boolean);
7709
7896
  const known = /* @__PURE__ */ new Set([...DIRECT_EXTENSIONS, ...BATCH_EXTENSIONS, ...POWERSHELL_EXTENSIONS, ...declared]);
7710
- const ext = path6.win32.extname(command).toLowerCase();
7897
+ const ext = path7.win32.extname(command).toLowerCase();
7711
7898
  if (ext && known.has(ext)) {
7712
7899
  const route = BATCH_EXTENSIONS.includes(ext) ? "cmd" : POWERSHELL_EXTENSIONS.includes(ext) ? "powershell" : "direct";
7713
7900
  return { direct: [], cmd: [], powershell: [], [route]: [""] };
@@ -7728,13 +7915,13 @@ async function findWindowsExecutables(command, deps) {
7728
7915
  const exists = deps.exists ?? defaultExists2;
7729
7916
  const pathExt = (deps.pathExt ?? (() => process.env.PATHEXT ?? ""))();
7730
7917
  const byRoute = candidateExtensions(command, pathExt);
7731
- 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);
7732
- const base = path6.win32.basename(command);
7918
+ 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);
7919
+ const base = path7.win32.basename(command);
7733
7920
  const found = [];
7734
7921
  for (const route of ROUTES) {
7735
7922
  outer: for (const ext of byRoute[route]) {
7736
7923
  for (const dir of dirs) {
7737
- const candidate = path6.win32.join(dir, `${base}${ext}`);
7924
+ const candidate = path7.win32.join(dir, `${base}${ext}`);
7738
7925
  if (exists(candidate)) {
7739
7926
  found.push({ file: candidate, route });
7740
7927
  break outer;
@@ -7914,7 +8101,7 @@ function geminiDiscoveryCacheKey(apiKey) {
7914
8101
  return {
7915
8102
  key: `gemini-models:${hash}`,
7916
8103
  dir,
7917
- file: path7.join(dir, `gemini_models_${hash}.json`)
8104
+ file: path8.join(dir, `gemini_models_${hash}.json`)
7918
8105
  };
7919
8106
  }
7920
8107
  function readGeminiCache(apiKey) {
@@ -8438,7 +8625,7 @@ var ModelDiscovery = class {
8438
8625
 
8439
8626
  // src/services/ModelCatalog.ts
8440
8627
  import * as fs2 from "fs";
8441
- import * as path8 from "path";
8628
+ import * as path9 from "path";
8442
8629
  var CACHE_KEY = "model-catalog";
8443
8630
  var CACHE_TTL_MS = 60 * 60 * 1e3;
8444
8631
  function storageKey(baseUrl) {
@@ -8490,7 +8677,7 @@ var ModelCatalog = class {
8490
8677
  const url = (baseUrl || "https://openrouter.ai/api/v1").replace(/\/+$/, "");
8491
8678
  const key = storageKey(url);
8492
8679
  const cacheDir = globalCacheDir();
8493
- const cacheFile = path8.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
8680
+ const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
8494
8681
  if (fs2.existsSync(cacheFile)) fs2.rmSync(cacheFile);
8495
8682
  } catch {
8496
8683
  }
@@ -8498,7 +8685,7 @@ var ModelCatalog = class {
8498
8685
  static readCache(key) {
8499
8686
  try {
8500
8687
  const cacheDir = globalCacheDir();
8501
- const cacheFile = path8.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
8688
+ const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
8502
8689
  if (!fs2.existsSync(cacheFile)) return null;
8503
8690
  const raw = fs2.readFileSync(cacheFile, "utf8");
8504
8691
  const data = JSON.parse(raw);
@@ -8512,7 +8699,7 @@ var ModelCatalog = class {
8512
8699
  try {
8513
8700
  const cacheDir = globalCacheDir();
8514
8701
  fs2.mkdirSync(cacheDir, { recursive: true });
8515
- const cacheFile = path8.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
8702
+ const cacheFile = path9.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
8516
8703
  fs2.writeFileSync(
8517
8704
  cacheFile,
8518
8705
  JSON.stringify({ models, cachedAt: Date.now() }, null, 2)
@@ -8953,7 +9140,7 @@ import { spawn as nodeSpawn } from "child_process";
8953
9140
 
8954
9141
  // src/utils/workspace.ts
8955
9142
  import * as fs3 from "fs";
8956
- import * as path9 from "path";
9143
+ import * as path10 from "path";
8957
9144
  var WorkspaceNotFoundError = class extends Error {
8958
9145
  constructor(workspace) {
8959
9146
  super(`Workspace "${workspace}" does not exist.`);
@@ -9009,7 +9196,7 @@ function assertWorkspaceIsProject(workspace, deps = {}) {
9009
9196
  throw new WorkspaceNotAProjectError(workspace);
9010
9197
  }
9011
9198
  const hasMarker = [...PROJECT_MARKER_DIRS, ...PROJECT_MARKER_FILES].some(
9012
- (marker2) => exists(path9.join(resolved, marker2))
9199
+ (marker2) => exists(path10.join(resolved, marker2))
9013
9200
  );
9014
9201
  if (!hasMarker) throw new WorkspaceNotAProjectError(workspace);
9015
9202
  }
@@ -10041,14 +10228,14 @@ ${part.text}` : part.text });
10041
10228
  }
10042
10229
  }
10043
10230
  }
10044
- async json(method, path20, body, signal) {
10045
- const response = await this.deps.fetch(`${this.baseUrl}${path20}`, {
10231
+ async json(method, path21, body, signal) {
10232
+ const response = await this.deps.fetch(`${this.baseUrl}${path21}`, {
10046
10233
  method,
10047
10234
  headers: { "content-type": "application/json" },
10048
10235
  ...body === void 0 ? {} : { body: JSON.stringify(body) },
10049
10236
  ...signal ? { signal } : {}
10050
10237
  });
10051
- if (!response.ok) throw new Error(`${method} ${path20} failed: ${response.status} ${response.statusText}`);
10238
+ if (!response.ok) throw new Error(`${method} ${path21} failed: ${response.status} ${response.statusText}`);
10052
10239
  return await response.json().catch(() => null);
10053
10240
  }
10054
10241
  nativeSessionId() {
@@ -10816,7 +11003,7 @@ function runnerAssignment(catalog, current) {
10816
11003
  changes.thinkingEffort = thinkingEffort;
10817
11004
  }
10818
11005
  if (catalog.modes.length > 0) {
10819
- changes.taskMode = catalog.modes.some((m) => m.id === current?.taskMode) ? current.taskMode : catalog.modes[0].id;
11006
+ changes.taskMode = catalog.modes.some((m) => m.id === current?.taskMode) ? current.taskMode : catalog.defaultMode ?? catalog.modes[0].id;
10820
11007
  }
10821
11008
  return changes;
10822
11009
  }
@@ -10828,17 +11015,17 @@ function retargetTaskRunner(task, runner, catalog) {
10828
11015
 
10829
11016
  // src/services/SkillsService.ts
10830
11017
  import * as fs4 from "fs";
10831
- import * as path11 from "path";
11018
+ import * as path12 from "path";
10832
11019
 
10833
11020
  // src/services/builtinSkills.ts
10834
- import * as path10 from "path";
11021
+ import * as path11 from "path";
10835
11022
  import { fileURLToPath } from "url";
10836
11023
  function builtinSkillsDir() {
10837
- const dir = typeof __dirname !== "undefined" && __dirname ? __dirname : path10.dirname(fileURLToPath(
11024
+ const dir = typeof __dirname !== "undefined" && __dirname ? __dirname : path11.dirname(fileURLToPath(
10838
11025
  // @ts-expect-error - import.meta is only valid under an ESM module setting
10839
11026
  import.meta.url
10840
11027
  ));
10841
- return path10.join(dir, "..", "skills");
11028
+ return path11.join(dir, "..", "skills");
10842
11029
  }
10843
11030
 
10844
11031
  // src/services/SkillsService.ts
@@ -10877,8 +11064,8 @@ function copyDirSync2(src, dest) {
10877
11064
  fs4.mkdirSync(dest, { recursive: true });
10878
11065
  const entries = fs4.readdirSync(src, { withFileTypes: true });
10879
11066
  for (const entry of entries) {
10880
- const srcPath = path11.join(src, entry.name);
10881
- const destPath = path11.join(dest, entry.name);
11067
+ const srcPath = path12.join(src, entry.name);
11068
+ const destPath = path12.join(dest, entry.name);
10882
11069
  if (entry.isDirectory()) copyDirSync2(srcPath, destPath);
10883
11070
  else fs4.copyFileSync(srcPath, destPath);
10884
11071
  }
@@ -10889,7 +11076,7 @@ function readDir(dir, source) {
10889
11076
  const skills = [];
10890
11077
  for (const entry of entries) {
10891
11078
  if (!entry.isDirectory()) continue;
10892
- const skillFile = path11.join(dir, entry.name, "SKILL.md");
11079
+ const skillFile = path12.join(dir, entry.name, "SKILL.md");
10893
11080
  if (!fs4.existsSync(skillFile)) continue;
10894
11081
  const parsed = parseSkillFile(skillFile, entry.name, source);
10895
11082
  if (parsed) skills.push(parsed);
@@ -10902,17 +11089,17 @@ var SkillsService = class {
10902
11089
  }
10903
11090
  workspaceRoot;
10904
11091
  localDir() {
10905
- return this.workspaceRoot ? path11.join(this.workspaceRoot, ".ordewell", "skills") : void 0;
11092
+ return this.workspaceRoot ? path12.join(this.workspaceRoot, ".ordewell", "skills") : void 0;
10906
11093
  }
10907
11094
  globalDir() {
10908
- return path11.join(globalDataDir(), "skills");
11095
+ return path12.join(globalDataDir(), "skills");
10909
11096
  }
10910
11097
  seed(name) {
10911
- const dest = path11.join(this.globalDir(), name);
11098
+ const dest = path12.join(this.globalDir(), name);
10912
11099
  if (fs4.existsSync(dest)) return false;
10913
11100
  let srcDir;
10914
11101
  try {
10915
- srcDir = path11.join(builtinSkillsDir(), name);
11102
+ srcDir = path12.join(builtinSkillsDir(), name);
10916
11103
  } catch (err) {
10917
11104
  console.warn(`Could not locate built-in skills dir: ${String(err)}`);
10918
11105
  return false;
@@ -10938,7 +11125,7 @@ var SkillsService = class {
10938
11125
  if (entries.length !== 1 || entries[0].name !== "SKILL.md" || !entries[0].isFile()) return false;
10939
11126
  let raw;
10940
11127
  try {
10941
- raw = fs4.readFileSync(path11.join(dir, "SKILL.md"), "utf8");
11128
+ raw = fs4.readFileSync(path12.join(dir, "SKILL.md"), "utf8");
10942
11129
  } catch {
10943
11130
  return false;
10944
11131
  }
@@ -10955,7 +11142,7 @@ var SkillsService = class {
10955
11142
  }
10956
11143
  pruneRetired() {
10957
11144
  for (const name of RETIRED_BUILTIN_SKILL_NAMES) {
10958
- const dest = path11.join(this.globalDir(), name);
11145
+ const dest = path12.join(this.globalDir(), name);
10959
11146
  if (!fs4.existsSync(dest)) continue;
10960
11147
  if (!this.isUnmodifiedRetiredSeed(dest, name)) continue;
10961
11148
  try {
@@ -10970,10 +11157,10 @@ var SkillsService = class {
10970
11157
  if (BUILTIN_SKILL_NAMES.includes(name)) this.seed(name);
10971
11158
  const localDir = this.localDir();
10972
11159
  if (localDir) {
10973
- const localFile = path11.join(localDir, name, "SKILL.md");
11160
+ const localFile = path12.join(localDir, name, "SKILL.md");
10974
11161
  if (fs4.existsSync(localFile)) return parseSkillFile(localFile, name, "local");
10975
11162
  }
10976
- const globalFile = path11.join(this.globalDir(), name, "SKILL.md");
11163
+ const globalFile = path12.join(this.globalDir(), name, "SKILL.md");
10977
11164
  if (fs4.existsSync(globalFile)) return parseSkillFile(globalFile, name, "global");
10978
11165
  return void 0;
10979
11166
  }
@@ -11002,11 +11189,11 @@ function createSkillsService(workspaceRoot) {
11002
11189
 
11003
11190
  // src/utils/sessionStore.ts
11004
11191
  import * as fs6 from "fs";
11005
- import * as path13 from "path";
11192
+ import * as path14 from "path";
11006
11193
 
11007
11194
  // src/utils/fsHelpers.ts
11008
11195
  import * as fs5 from "fs";
11009
- import * as path12 from "path";
11196
+ import * as path13 from "path";
11010
11197
  var STATE_DIR = ".ordewell";
11011
11198
  function ensureDir(dir) {
11012
11199
  if (!fs5.existsSync(dir)) {
@@ -11014,14 +11201,14 @@ function ensureDir(dir) {
11014
11201
  }
11015
11202
  }
11016
11203
  function getStateDir(baseDir) {
11017
- return path12.join(baseDir ?? process.cwd(), STATE_DIR);
11204
+ return path13.join(baseDir ?? process.cwd(), STATE_DIR);
11018
11205
  }
11019
11206
  var IGNORE_FILE = ".gitignore";
11020
11207
  function ensureStateDirIgnored(baseDir) {
11021
11208
  const dir = getStateDir(baseDir);
11022
11209
  ensureDir(dir);
11023
11210
  try {
11024
- fs5.writeFileSync(path12.join(dir, IGNORE_FILE), "*\n", { flag: "wx" });
11211
+ fs5.writeFileSync(path13.join(dir, IGNORE_FILE), "*\n", { flag: "wx" });
11025
11212
  } catch (err) {
11026
11213
  if (err.code !== "EEXIST") throw err;
11027
11214
  }
@@ -11036,7 +11223,7 @@ function mintSessionId() {
11036
11223
  // src/utils/sessionStore.ts
11037
11224
  var SESSIONS_SUBDIR = "sessions";
11038
11225
  function getSessionsDir(baseDir) {
11039
- return path13.join(getStateDir(baseDir), SESSIONS_SUBDIR);
11226
+ return path14.join(getStateDir(baseDir), SESSIONS_SUBDIR);
11040
11227
  }
11041
11228
  var REJECTION_MESSAGE = "This session was created with an older version of Ordewell. Please re-plan.";
11042
11229
  function hasScalarRunner(parsed) {
@@ -11071,7 +11258,7 @@ function saveSession(plan, goal, baseDir, id) {
11071
11258
  plan: JSON.parse(JSON.stringify(plan))
11072
11259
  };
11073
11260
  const filename = sessionFilename(meta);
11074
- const filePath = path13.join(sessionsDir, filename);
11261
+ const filePath = path14.join(sessionsDir, filename);
11075
11262
  fs6.writeFileSync(filePath, JSON.stringify(session, null, 2));
11076
11263
  return meta;
11077
11264
  }
@@ -11081,7 +11268,7 @@ function listSessions(baseDir, logger = defaultLogger) {
11081
11268
  const files = fs6.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
11082
11269
  return files.map((f) => {
11083
11270
  try {
11084
- const raw = fs6.readFileSync(path13.join(sessionsDir, f), "utf-8");
11271
+ const raw = fs6.readFileSync(path14.join(sessionsDir, f), "utf-8");
11085
11272
  const parsed = JSON.parse(raw);
11086
11273
  if (hasScalarRunner(parsed)) {
11087
11274
  logger.warn("sessionStore", `session file ${f}: ${REJECTION_MESSAGE}`);
@@ -11099,7 +11286,7 @@ function findSessionFile(sessionsDir, sessionId, logger) {
11099
11286
  const files = fs6.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
11100
11287
  for (const f of files) {
11101
11288
  try {
11102
- const raw = fs6.readFileSync(path13.join(sessionsDir, f), "utf-8");
11289
+ const raw = fs6.readFileSync(path14.join(sessionsDir, f), "utf-8");
11103
11290
  const session = JSON.parse(raw);
11104
11291
  if (session.meta.id === sessionId) return f;
11105
11292
  } catch (err) {
@@ -11114,7 +11301,7 @@ function loadSession(sessionId, baseDir, logger = defaultLogger) {
11114
11301
  try {
11115
11302
  const file = findSessionFile(sessionsDir, sessionId, logger);
11116
11303
  if (file) {
11117
- const raw = fs6.readFileSync(path13.join(sessionsDir, file), "utf-8");
11304
+ const raw = fs6.readFileSync(path14.join(sessionsDir, file), "utf-8");
11118
11305
  const parsed = JSON.parse(raw);
11119
11306
  if (hasScalarRunner(parsed)) {
11120
11307
  logger.warn("sessionStore", `session file ${file}: ${REJECTION_MESSAGE}`);
@@ -11148,7 +11335,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
11148
11335
  try {
11149
11336
  const file = findSessionFile(sessionsDir, sessionId, logger);
11150
11337
  if (file) {
11151
- fs6.unlinkSync(path13.join(sessionsDir, file));
11338
+ fs6.unlinkSync(path14.join(sessionsDir, file));
11152
11339
  return true;
11153
11340
  }
11154
11341
  } catch (err) {
@@ -11159,7 +11346,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
11159
11346
 
11160
11347
  // src/utils/prdStore.ts
11161
11348
  import * as fs7 from "fs";
11162
- import * as path14 from "path";
11349
+ import * as path15 from "path";
11163
11350
  var PRD_BLOCK_RE = /<!--\s*ORDEWELL_PRD_START\s+slug="([^"]+)"\s*-->\s*([\s\S]*?)\s*<!--\s*ORDEWELL_PRD_END\s*-->/;
11164
11351
  function extractPrdBlock(text) {
11165
11352
  const match = PRD_BLOCK_RE.exec(text);
@@ -11173,9 +11360,9 @@ function sanitizeSlug(raw) {
11173
11360
  return raw.toLowerCase().replace(/[^a-z0-9-_]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
11174
11361
  }
11175
11362
  function savePrdMarkdown(workspace, slug2, markdown) {
11176
- const dir = path14.join(workspace, ".scratch", sanitizeSlug(slug2));
11363
+ const dir = path15.join(workspace, ".scratch", sanitizeSlug(slug2));
11177
11364
  fs7.mkdirSync(dir, { recursive: true });
11178
- const file = path14.join(dir, "PRD.md");
11365
+ const file = path15.join(dir, "PRD.md");
11179
11366
  fs7.writeFileSync(file, markdown.endsWith("\n") ? markdown : markdown + "\n", "utf8");
11180
11367
  return file;
11181
11368
  }
@@ -12202,9 +12389,11 @@ Execution is RUNNING${locked.length ? ` \u2014 these tasks are locked: ${locked.
12202
12389
  }
12203
12390
  /** What a runner offers, as {@link runnerAssignment} needs it. Spawns the runner's CLI to list models. */
12204
12391
  async catalogFor(runner) {
12392
+ const modes = this.runnerModesFor([runner])[runner];
12205
12393
  return {
12206
12394
  models: (await this.modelResolver.modelsForRunners([runner]))[runner] ?? [],
12207
- modes: this.runnerModesFor([runner])[runner]
12395
+ modes,
12396
+ defaultMode: resolveDefaultMode(modes, this.config.autonomousMode)
12208
12397
  };
12209
12398
  }
12210
12399
  /**
@@ -12829,8 +13018,8 @@ var HeadlessRunner = class extends AbstractRunner {
12829
13018
  import { execFile as execFile2 } from "child_process";
12830
13019
  import { promisify as promisify4 } from "util";
12831
13020
  import { tmpdir } from "os";
12832
- import { join as join13 } from "path";
12833
- import { existsSync as existsSync8, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
13021
+ import { join as join14 } from "path";
13022
+ import { existsSync as existsSync9, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
12834
13023
 
12835
13024
  // src/utils/tmux.ts
12836
13025
  import { execSync as execSync2 } from "child_process";
@@ -12937,7 +13126,7 @@ var TmuxSession = class extends AbstractTerminalSession {
12937
13126
  if (this.exited) return;
12938
13127
  let content;
12939
13128
  try {
12940
- content = existsSync8(this.logPath) ? readFileSync5(this.logPath, "utf8") : "";
13129
+ content = existsSync9(this.logPath) ? readFileSync6(this.logPath, "utf8") : "";
12941
13130
  } catch {
12942
13131
  return;
12943
13132
  }
@@ -13116,7 +13305,7 @@ var TmuxRunner = class extends AbstractRunner {
13116
13305
  windowName,
13117
13306
  this.execFileImpl,
13118
13307
  this.pollIntervalMs,
13119
- join13(this.logDir, `${id}.log`),
13308
+ join14(this.logDir, `${id}.log`),
13120
13309
  this.socket
13121
13310
  );
13122
13311
  invocation.env = { ...invocation.env, PATH: await this.resolvePath() };
@@ -13129,8 +13318,8 @@ var TmuxRunner = class extends AbstractRunner {
13129
13318
 
13130
13319
  // src/utils/daemonToken.ts
13131
13320
  import { randomBytes as randomBytes2, timingSafeEqual } from "crypto";
13132
- import { closeSync, mkdirSync as mkdirSync7, openSync, readFileSync as readFileSync6, unlinkSync as unlinkSync3, writeSync } from "fs";
13133
- import { join as join14 } from "path";
13321
+ import { closeSync, mkdirSync as mkdirSync7, openSync, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeSync } from "fs";
13322
+ import { join as join15 } from "path";
13134
13323
  var BEARER_PREFIX = "bearer ";
13135
13324
  var DAEMON_TOKEN_SUBPROTOCOL_PREFIX = "ordewell.token.";
13136
13325
  var DAEMON_SUBPROTOCOL = "ordewell.v1";
@@ -13138,7 +13327,7 @@ function configDir() {
13138
13327
  return globalDataDir();
13139
13328
  }
13140
13329
  function daemonTokenPath(port) {
13141
- return join14(configDir(), `server-${port}.token`);
13330
+ return join15(configDir(), `server-${port}.token`);
13142
13331
  }
13143
13332
  function mintDaemonToken(port) {
13144
13333
  const token = randomBytes2(32).toString("base64url");
@@ -13158,7 +13347,7 @@ function mintDaemonToken(port) {
13158
13347
  }
13159
13348
  function readDaemonToken(port) {
13160
13349
  try {
13161
- const token = readFileSync6(daemonTokenPath(port), "utf8").trim();
13350
+ const token = readFileSync7(daemonTokenPath(port), "utf8").trim();
13162
13351
  return token === "" ? void 0 : token;
13163
13352
  } catch {
13164
13353
  return void 0;
@@ -13200,17 +13389,17 @@ function tokensMatch(presented, expected) {
13200
13389
 
13201
13390
  // src/plugins/RunnerRegistry.ts
13202
13391
  import * as fs9 from "fs";
13203
- import * as path17 from "path";
13204
- import * as os4 from "os";
13392
+ import * as path18 from "path";
13393
+ import * as os5 from "os";
13205
13394
  import { execFileSync } from "child_process";
13206
13395
  import { randomBytes as randomBytes3 } from "crypto";
13207
13396
 
13208
13397
  // src/plugins/FsPluginStore.ts
13209
13398
  import * as fs8 from "fs";
13210
- import * as path16 from "path";
13399
+ import * as path17 from "path";
13211
13400
 
13212
13401
  // src/plugins/pluginNames.ts
13213
- import * as path15 from "path";
13402
+ import * as path16 from "path";
13214
13403
  var PLUGIN_NAME_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
13215
13404
  var MAX_PLUGIN_NAME_LENGTH = 64;
13216
13405
  function isPlainPluginName(name) {
@@ -13225,10 +13414,10 @@ function assertPlainPluginName(name) {
13225
13414
  }
13226
13415
  function resolvePluginInstallDir(pluginsDir, name) {
13227
13416
  assertPlainPluginName(name);
13228
- const root = path15.resolve(pluginsDir);
13229
- const dest = path15.resolve(root, name);
13230
- const relative3 = path15.relative(root, dest);
13231
- if (relative3 !== name || relative3 === "" || path15.isAbsolute(relative3)) {
13417
+ const root = path16.resolve(pluginsDir);
13418
+ const dest = path16.resolve(root, name);
13419
+ const relative3 = path16.relative(root, dest);
13420
+ if (relative3 !== name || relative3 === "" || path16.isAbsolute(relative3)) {
13232
13421
  throw new Error(`Plugin install path escapes the plugins directory: ${JSON.stringify(name)}`);
13233
13422
  }
13234
13423
  return dest;
@@ -13243,10 +13432,10 @@ function isValidManifest(obj) {
13243
13432
 
13244
13433
  // src/plugins/FsPluginStore.ts
13245
13434
  function userPluginsDir() {
13246
- return path16.join(globalDataDir(), "plugins");
13435
+ return path17.join(globalDataDir(), "plugins");
13247
13436
  }
13248
13437
  function loadManifestFromDir(dir) {
13249
- const manifestPath = path16.join(dir, "manifest.json");
13438
+ const manifestPath = path17.join(dir, "manifest.json");
13250
13439
  if (!fs8.existsSync(manifestPath)) return null;
13251
13440
  try {
13252
13441
  const raw = fs8.readFileSync(manifestPath, "utf8");
@@ -13261,8 +13450,8 @@ function copyDirSync3(src, dest) {
13261
13450
  ensureDir(dest);
13262
13451
  const entries = fs8.readdirSync(src, { withFileTypes: true });
13263
13452
  for (const entry of entries) {
13264
- const srcPath = path16.join(src, entry.name);
13265
- const destPath = path16.join(dest, entry.name);
13453
+ const srcPath = path17.join(src, entry.name);
13454
+ const destPath = path17.join(dest, entry.name);
13266
13455
  if (entry.isDirectory()) {
13267
13456
  copyDirSync3(srcPath, destPath);
13268
13457
  } else {
@@ -13274,7 +13463,7 @@ function rmDirSync(dir) {
13274
13463
  if (!fs8.existsSync(dir)) return;
13275
13464
  const entries = fs8.readdirSync(dir, { withFileTypes: true });
13276
13465
  for (const entry of entries) {
13277
- const p = path16.join(dir, entry.name);
13466
+ const p = path17.join(dir, entry.name);
13278
13467
  if (entry.isDirectory()) {
13279
13468
  rmDirSync(p);
13280
13469
  } else {
@@ -13327,11 +13516,11 @@ var FsPluginStore = class {
13327
13516
  return null;
13328
13517
  }
13329
13518
  }
13330
- dirExists(path20) {
13331
- return fs8.existsSync(path20) && fs8.statSync(path20).isDirectory();
13519
+ dirExists(path21) {
13520
+ return fs8.existsSync(path21) && fs8.statSync(path21).isDirectory();
13332
13521
  }
13333
- exists(path20) {
13334
- return fs8.existsSync(path20);
13522
+ exists(path21) {
13523
+ return fs8.existsSync(path21);
13335
13524
  }
13336
13525
  };
13337
13526
 
@@ -13763,7 +13952,7 @@ var RunnerRegistry = class {
13763
13952
  return entry?.source === "builtin";
13764
13953
  }
13765
13954
  installFromPath(sourcePath) {
13766
- const absPath = path17.resolve(sourcePath);
13955
+ const absPath = path18.resolve(sourcePath);
13767
13956
  if (!this.store.dirExists(absPath)) {
13768
13957
  throw new Error(`Plugin source must be a directory: ${absPath}`);
13769
13958
  }
@@ -13775,7 +13964,7 @@ var RunnerRegistry = class {
13775
13964
  }
13776
13965
  installFromGit(url) {
13777
13966
  const validated = assertInstallablePluginUrl(url);
13778
- const tmpDir = path17.join(os4.tmpdir(), `ordewell-plugin-${randomBytes3(12).toString("hex")}`);
13967
+ const tmpDir = path18.join(os5.tmpdir(), `ordewell-plugin-${randomBytes3(12).toString("hex")}`);
13779
13968
  this.store.ensureDir(tmpDir);
13780
13969
  try {
13781
13970
  try {
@@ -13788,7 +13977,7 @@ var RunnerRegistry = class {
13788
13977
  const hasManifest = contents.some((f) => f === "manifest.json");
13789
13978
  let sourceDir = tmpDir;
13790
13979
  if (!hasManifest) {
13791
- const onlyEntry = contents.length === 1 ? path17.join(tmpDir, contents[0]) : void 0;
13980
+ const onlyEntry = contents.length === 1 ? path18.join(tmpDir, contents[0]) : void 0;
13792
13981
  if (!onlyEntry || !this.store.dirExists(onlyEntry)) {
13793
13982
  throw new Error(`No manifest.json found in repository: ${validated.toString()}`);
13794
13983
  }
@@ -13836,7 +14025,7 @@ var RunnerRegistry = class {
13836
14025
  }
13837
14026
  createSkeleton(name, outputDir) {
13838
14027
  assertPlainPluginName(name);
13839
- const dir = path17.resolve(outputDir, name);
14028
+ const dir = path18.resolve(outputDir, name);
13840
14029
  this.store.ensureDir(dir);
13841
14030
  const manifest = {
13842
14031
  name,
@@ -13868,8 +14057,8 @@ var RunnerRegistry = class {
13868
14057
  ]
13869
14058
  }
13870
14059
  };
13871
- this.store.writeFile(path17.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
13872
- const runSh = path17.join(dir, "run.sh");
14060
+ this.store.writeFile(path18.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
14061
+ const runSh = path18.join(dir, "run.sh");
13873
14062
  const scriptContent = `#!/usr/bin/env bash
13874
14063
  # Custom runner script for ${name}
13875
14064
  # Receives:
@@ -13902,14 +14091,14 @@ function fsChmodSync(fpath, mode) {
13902
14091
 
13903
14092
  // src/utils/stateStore.ts
13904
14093
  import * as fs10 from "fs";
13905
- import * as path18 from "path";
14094
+ import * as path19 from "path";
13906
14095
  var STATE_FILE = "state.json";
13907
14096
  function getStatePath(baseDir) {
13908
- return path18.join(getStateDir(baseDir), STATE_FILE);
14097
+ return path19.join(getStateDir(baseDir), STATE_FILE);
13909
14098
  }
13910
14099
  function saveState(plan, baseDir) {
13911
14100
  const statePath = getStatePath(baseDir ?? process.cwd());
13912
- ensureDir(path18.dirname(statePath));
14101
+ ensureDir(path19.dirname(statePath));
13913
14102
  plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
13914
14103
  fs10.writeFileSync(statePath, JSON.stringify(plan, null, 2));
13915
14104
  }
@@ -13942,7 +14131,7 @@ function stateExists(baseDir) {
13942
14131
 
13943
14132
  // src/services/SettingsService.ts
13944
14133
  import * as fs11 from "fs";
13945
- import * as path19 from "path";
14134
+ import * as path20 from "path";
13946
14135
  var DEFAULTS = {
13947
14136
  tdd: { enabled: true },
13948
14137
  verification: { enabled: false }
@@ -13950,7 +14139,7 @@ var DEFAULTS = {
13950
14139
  function getSettingsPath() {
13951
14140
  const override = process.env.ORDEWELL_SETTINGS_PATH;
13952
14141
  if (override && override.trim()) return override.trim();
13953
- return path19.join(globalDataDir(), "settings.json");
14142
+ return path20.join(globalDataDir(), "settings.json");
13954
14143
  }
13955
14144
  function readPlannerModels(raw) {
13956
14145
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
@@ -14078,7 +14267,7 @@ var SettingsService = class {
14078
14267
  return { ...DEFAULTS, tdd: { ...DEFAULTS.tdd }, verification: { ...DEFAULTS.verification } };
14079
14268
  }
14080
14269
  persist() {
14081
- const dir = path19.dirname(this.filePath);
14270
+ const dir = path20.dirname(this.filePath);
14082
14271
  if (!fs11.existsSync(dir)) {
14083
14272
  fs11.mkdirSync(dir, { recursive: true });
14084
14273
  }