@ordewell/core 0.4.19 → 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
  }
@@ -14402,7 +14589,8 @@ function resolveArgs(manifest, ctx) {
14402
14589
  command: manifest.runner.command,
14403
14590
  args,
14404
14591
  env,
14405
- promptInArgs: manifest.runner.promptInArgs
14592
+ promptInArgs: manifest.runner.promptInArgs,
14593
+ submitPromptKey: manifest.runner.submitPromptKey === true && isInteractive(ctx)
14406
14594
  };
14407
14595
  }
14408
14596
  function parseBlockOpen(raw) {
@@ -14756,7 +14944,8 @@ var HeadlessRunner = class extends AbstractRunner {
14756
14944
  launch: await planDirectLaunch(command, args, this.launchDeps),
14757
14945
  resolvedPath,
14758
14946
  env: invocation.env,
14759
- pty
14947
+ pty,
14948
+ submitPromptKey: invocation.submitPromptKey
14760
14949
  };
14761
14950
  }
14762
14951
  async spawn(opts) {
@@ -14766,6 +14955,7 @@ var HeadlessRunner = class extends AbstractRunner {
14766
14955
  const modeStr = opts.mode === "plan" ? "plan" : "build";
14767
14956
  console.error(`[headless] Starting ${opts.runner} [${modeStr}] (${opts.modelId || "default"}) for task ${opts.taskId.slice(0, 8)}${prepared.pty ? " (PTY)" : ""}`);
14768
14957
  session.start(prepared.launch, opts.cwd, prepared.resolvedPath, prepared.env);
14958
+ if (prepared.submitPromptKey) session.write("\r");
14769
14959
  this.registerSession(id, session);
14770
14960
  return session;
14771
14961
  }
@@ -14776,7 +14966,7 @@ var import_child_process8 = require("child_process");
14776
14966
  var import_util4 = require("util");
14777
14967
  var import_os = require("os");
14778
14968
  var import_path = require("path");
14779
- var import_fs = require("fs");
14969
+ var import_fs2 = require("fs");
14780
14970
 
14781
14971
  // src/utils/tmux.ts
14782
14972
  var import_child_process7 = require("child_process");
@@ -14869,7 +15059,7 @@ var TmuxSession = class extends AbstractTerminalSession {
14869
15059
  * lets the user keep poking at a finished task's terminal.
14870
15060
  */
14871
15061
  async start(command, args, cwd, env) {
14872
- (0, import_fs.writeFileSync)(this.logPath, "");
15062
+ (0, import_fs2.writeFileSync)(this.logPath, "");
14873
15063
  const envAssignments = Object.entries(env ?? {}).map(([k, v]) => `${k}=${posixShellQuote(v)}`).join(" ");
14874
15064
  const inner = [command, ...args].map(posixShellQuote).join(" ");
14875
15065
  const prefix = envAssignments ? `env ${envAssignments} ` : "";
@@ -14883,7 +15073,7 @@ var TmuxSession = class extends AbstractTerminalSession {
14883
15073
  if (this.exited) return;
14884
15074
  let content;
14885
15075
  try {
14886
- 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") : "";
14887
15077
  } catch {
14888
15078
  return;
14889
15079
  }
@@ -14910,7 +15100,7 @@ var TmuxSession = class extends AbstractTerminalSession {
14910
15100
  this.tmux(["pipe-pane", "-t", this.target]).catch(() => {
14911
15101
  });
14912
15102
  try {
14913
- (0, import_fs.unlinkSync)(this.logPath);
15103
+ (0, import_fs2.unlinkSync)(this.logPath);
14914
15104
  } catch {
14915
15105
  }
14916
15106
  this.baseHandleExit(code);
@@ -15067,6 +15257,7 @@ var TmuxRunner = class extends AbstractRunner {
15067
15257
  );
15068
15258
  invocation.env = { ...invocation.env, PATH: await this.resolvePath() };
15069
15259
  await session.start(invocation.command, invocation.args, opts.cwd, invocation.env);
15260
+ if (invocation.submitPromptKey) session.write("\r");
15070
15261
  this.registerSession(id, session);
15071
15262
  return session;
15072
15263
  }
@@ -15074,7 +15265,7 @@ var TmuxRunner = class extends AbstractRunner {
15074
15265
 
15075
15266
  // src/utils/daemonToken.ts
15076
15267
  var import_crypto2 = require("crypto");
15077
- var import_fs2 = require("fs");
15268
+ var import_fs3 = require("fs");
15078
15269
  var import_path2 = require("path");
15079
15270
  var BEARER_PREFIX = "bearer ";
15080
15271
  var DAEMON_TOKEN_SUBPROTOCOL_PREFIX = "ordewell.token.";
@@ -15088,22 +15279,22 @@ function daemonTokenPath(port) {
15088
15279
  function mintDaemonToken(port) {
15089
15280
  const token = (0, import_crypto2.randomBytes)(32).toString("base64url");
15090
15281
  const file = daemonTokenPath(port);
15091
- (0, import_fs2.mkdirSync)(configDir(), { recursive: true });
15282
+ (0, import_fs3.mkdirSync)(configDir(), { recursive: true });
15092
15283
  try {
15093
- (0, import_fs2.unlinkSync)(file);
15284
+ (0, import_fs3.unlinkSync)(file);
15094
15285
  } catch {
15095
15286
  }
15096
- const fd = (0, import_fs2.openSync)(file, "wx", 384);
15287
+ const fd = (0, import_fs3.openSync)(file, "wx", 384);
15097
15288
  try {
15098
- (0, import_fs2.writeSync)(fd, token);
15289
+ (0, import_fs3.writeSync)(fd, token);
15099
15290
  } finally {
15100
- (0, import_fs2.closeSync)(fd);
15291
+ (0, import_fs3.closeSync)(fd);
15101
15292
  }
15102
15293
  return { token, file };
15103
15294
  }
15104
15295
  function readDaemonToken(port) {
15105
15296
  try {
15106
- const token = (0, import_fs2.readFileSync)(daemonTokenPath(port), "utf8").trim();
15297
+ const token = (0, import_fs3.readFileSync)(daemonTokenPath(port), "utf8").trim();
15107
15298
  return token === "" ? void 0 : token;
15108
15299
  } catch {
15109
15300
  return void 0;
@@ -15111,7 +15302,7 @@ function readDaemonToken(port) {
15111
15302
  }
15112
15303
  function clearDaemonToken(port) {
15113
15304
  try {
15114
- (0, import_fs2.unlinkSync)(daemonTokenPath(port));
15305
+ (0, import_fs3.unlinkSync)(daemonTokenPath(port));
15115
15306
  } catch {
15116
15307
  }
15117
15308
  }
@@ -15145,17 +15336,17 @@ function tokensMatch(presented, expected) {
15145
15336
 
15146
15337
  // src/plugins/RunnerRegistry.ts
15147
15338
  var fs9 = __toESM(require("fs"));
15148
- var path17 = __toESM(require("path"));
15149
- var os4 = __toESM(require("os"));
15339
+ var path18 = __toESM(require("path"));
15340
+ var os5 = __toESM(require("os"));
15150
15341
  var import_child_process9 = require("child_process");
15151
15342
  var import_crypto3 = require("crypto");
15152
15343
 
15153
15344
  // src/plugins/FsPluginStore.ts
15154
15345
  var fs8 = __toESM(require("fs"));
15155
- var path16 = __toESM(require("path"));
15346
+ var path17 = __toESM(require("path"));
15156
15347
 
15157
15348
  // src/plugins/pluginNames.ts
15158
- var path15 = __toESM(require("path"));
15349
+ var path16 = __toESM(require("path"));
15159
15350
  var PLUGIN_NAME_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
15160
15351
  var MAX_PLUGIN_NAME_LENGTH = 64;
15161
15352
  function isPlainPluginName(name) {
@@ -15170,10 +15361,10 @@ function assertPlainPluginName(name) {
15170
15361
  }
15171
15362
  function resolvePluginInstallDir(pluginsDir, name) {
15172
15363
  assertPlainPluginName(name);
15173
- const root = path15.resolve(pluginsDir);
15174
- const dest = path15.resolve(root, name);
15175
- const relative3 = path15.relative(root, dest);
15176
- 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)) {
15177
15368
  throw new Error(`Plugin install path escapes the plugins directory: ${JSON.stringify(name)}`);
15178
15369
  }
15179
15370
  return dest;
@@ -15188,10 +15379,10 @@ function isValidManifest(obj) {
15188
15379
 
15189
15380
  // src/plugins/FsPluginStore.ts
15190
15381
  function userPluginsDir() {
15191
- return path16.join(globalDataDir(), "plugins");
15382
+ return path17.join(globalDataDir(), "plugins");
15192
15383
  }
15193
15384
  function loadManifestFromDir(dir) {
15194
- const manifestPath = path16.join(dir, "manifest.json");
15385
+ const manifestPath = path17.join(dir, "manifest.json");
15195
15386
  if (!fs8.existsSync(manifestPath)) return null;
15196
15387
  try {
15197
15388
  const raw = fs8.readFileSync(manifestPath, "utf8");
@@ -15206,8 +15397,8 @@ function copyDirSync3(src, dest) {
15206
15397
  ensureDir(dest);
15207
15398
  const entries = fs8.readdirSync(src, { withFileTypes: true });
15208
15399
  for (const entry of entries) {
15209
- const srcPath = path16.join(src, entry.name);
15210
- const destPath = path16.join(dest, entry.name);
15400
+ const srcPath = path17.join(src, entry.name);
15401
+ const destPath = path17.join(dest, entry.name);
15211
15402
  if (entry.isDirectory()) {
15212
15403
  copyDirSync3(srcPath, destPath);
15213
15404
  } else {
@@ -15219,7 +15410,7 @@ function rmDirSync(dir) {
15219
15410
  if (!fs8.existsSync(dir)) return;
15220
15411
  const entries = fs8.readdirSync(dir, { withFileTypes: true });
15221
15412
  for (const entry of entries) {
15222
- const p = path16.join(dir, entry.name);
15413
+ const p = path17.join(dir, entry.name);
15223
15414
  if (entry.isDirectory()) {
15224
15415
  rmDirSync(p);
15225
15416
  } else {
@@ -15272,11 +15463,11 @@ var FsPluginStore = class {
15272
15463
  return null;
15273
15464
  }
15274
15465
  }
15275
- dirExists(path20) {
15276
- return fs8.existsSync(path20) && fs8.statSync(path20).isDirectory();
15466
+ dirExists(path21) {
15467
+ return fs8.existsSync(path21) && fs8.statSync(path21).isDirectory();
15277
15468
  }
15278
- exists(path20) {
15279
- return fs8.existsSync(path20);
15469
+ exists(path21) {
15470
+ return fs8.existsSync(path21);
15280
15471
  }
15281
15472
  };
15282
15473
 
@@ -15535,7 +15726,12 @@ var OPENCODE_MANIFEST = {
15535
15726
  OPENCODE_CONFIG_CONTENT: "{{if interactiveVariant}}{{opencodeVariantConfig}}{{/if}}"
15536
15727
  },
15537
15728
  promptInArgs: true,
15538
- requiresTty: true
15729
+ requiresTty: true,
15730
+ // `--prompt` only pre-fills the TUI's composer; it does not submit it.
15731
+ // (`opencode run` — the headless subcommand — has no such gap: its
15732
+ // message is a positional arg that runs immediately.) An unattended
15733
+ // surface driving the TUI must press Enter itself.
15734
+ submitPromptKey: true
15539
15735
  },
15540
15736
  features: {
15541
15737
  modelSelection: true,
@@ -15703,7 +15899,7 @@ var RunnerRegistry = class {
15703
15899
  return entry?.source === "builtin";
15704
15900
  }
15705
15901
  installFromPath(sourcePath) {
15706
- const absPath = path17.resolve(sourcePath);
15902
+ const absPath = path18.resolve(sourcePath);
15707
15903
  if (!this.store.dirExists(absPath)) {
15708
15904
  throw new Error(`Plugin source must be a directory: ${absPath}`);
15709
15905
  }
@@ -15715,7 +15911,7 @@ var RunnerRegistry = class {
15715
15911
  }
15716
15912
  installFromGit(url) {
15717
15913
  const validated = assertInstallablePluginUrl(url);
15718
- 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")}`);
15719
15915
  this.store.ensureDir(tmpDir);
15720
15916
  try {
15721
15917
  try {
@@ -15728,7 +15924,7 @@ var RunnerRegistry = class {
15728
15924
  const hasManifest = contents.some((f) => f === "manifest.json");
15729
15925
  let sourceDir = tmpDir;
15730
15926
  if (!hasManifest) {
15731
- 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;
15732
15928
  if (!onlyEntry || !this.store.dirExists(onlyEntry)) {
15733
15929
  throw new Error(`No manifest.json found in repository: ${validated.toString()}`);
15734
15930
  }
@@ -15776,7 +15972,7 @@ var RunnerRegistry = class {
15776
15972
  }
15777
15973
  createSkeleton(name, outputDir) {
15778
15974
  assertPlainPluginName(name);
15779
- const dir = path17.resolve(outputDir, name);
15975
+ const dir = path18.resolve(outputDir, name);
15780
15976
  this.store.ensureDir(dir);
15781
15977
  const manifest = {
15782
15978
  name,
@@ -15808,8 +16004,8 @@ var RunnerRegistry = class {
15808
16004
  ]
15809
16005
  }
15810
16006
  };
15811
- this.store.writeFile(path17.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
15812
- 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");
15813
16009
  const scriptContent = `#!/usr/bin/env bash
15814
16010
  # Custom runner script for ${name}
15815
16011
  # Receives:
@@ -15842,14 +16038,14 @@ function fsChmodSync(fpath, mode) {
15842
16038
 
15843
16039
  // src/utils/stateStore.ts
15844
16040
  var fs10 = __toESM(require("fs"));
15845
- var path18 = __toESM(require("path"));
16041
+ var path19 = __toESM(require("path"));
15846
16042
  var STATE_FILE = "state.json";
15847
16043
  function getStatePath(baseDir) {
15848
- return path18.join(getStateDir(baseDir), STATE_FILE);
16044
+ return path19.join(getStateDir(baseDir), STATE_FILE);
15849
16045
  }
15850
16046
  function saveState(plan, baseDir) {
15851
16047
  const statePath = getStatePath(baseDir ?? process.cwd());
15852
- ensureDir(path18.dirname(statePath));
16048
+ ensureDir(path19.dirname(statePath));
15853
16049
  plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
15854
16050
  fs10.writeFileSync(statePath, JSON.stringify(plan, null, 2));
15855
16051
  }
@@ -15882,7 +16078,7 @@ function stateExists(baseDir) {
15882
16078
 
15883
16079
  // src/services/SettingsService.ts
15884
16080
  var fs11 = __toESM(require("fs"));
15885
- var path19 = __toESM(require("path"));
16081
+ var path20 = __toESM(require("path"));
15886
16082
  var DEFAULTS = {
15887
16083
  tdd: { enabled: true },
15888
16084
  verification: { enabled: false }
@@ -15890,7 +16086,7 @@ var DEFAULTS = {
15890
16086
  function getSettingsPath() {
15891
16087
  const override = process.env.ORDEWELL_SETTINGS_PATH;
15892
16088
  if (override && override.trim()) return override.trim();
15893
- return path19.join(globalDataDir(), "settings.json");
16089
+ return path20.join(globalDataDir(), "settings.json");
15894
16090
  }
15895
16091
  function readPlannerModels(raw) {
15896
16092
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
@@ -16018,7 +16214,7 @@ var SettingsService = class {
16018
16214
  return { ...DEFAULTS, tdd: { ...DEFAULTS.tdd }, verification: { ...DEFAULTS.verification } };
16019
16215
  }
16020
16216
  persist() {
16021
- const dir = path19.dirname(this.filePath);
16217
+ const dir = path20.dirname(this.filePath);
16022
16218
  if (!fs11.existsSync(dir)) {
16023
16219
  fs11.mkdirSync(dir, { recursive: true });
16024
16220
  }