@ordewell/core 0.4.20 → 0.4.21

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