@ordewell/cli 0.10.0 → 0.10.2

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.
Files changed (2) hide show
  1. package/dist/main.js +617 -473
  2. package/package.json +5 -3
package/dist/main.js CHANGED
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/main.ts
27
- var import_core46 = require("@ordewell/core");
27
+ var import_core49 = require("@ordewell/core");
28
28
 
29
29
  // src/utils/env.ts
30
30
  var import_fs = require("fs");
@@ -107,6 +107,23 @@ function moveAutonomyToSettings() {
107
107
  }
108
108
  }
109
109
 
110
+ // src/runnerNames.ts
111
+ var import_core2 = require("@ordewell/core");
112
+ function manifests() {
113
+ return new import_core2.RunnerRegistry().list().map((entry) => entry.manifest);
114
+ }
115
+ function runnerIdList() {
116
+ return manifests().map((m) => m.name).join(", ");
117
+ }
118
+ function runnerIdChoice() {
119
+ return manifests().map((m) => m.name).join("|");
120
+ }
121
+ function runnerNamesOr() {
122
+ const names = manifests().map((m) => m.displayName);
123
+ if (names.length < 2) return names.join("");
124
+ return `${names.slice(0, -1).join(", ")} or ${names[names.length - 1]}`;
125
+ }
126
+
110
127
  // src/help.ts
111
128
  function printHelp() {
112
129
  console.log(`
@@ -157,7 +174,7 @@ Planner, models and runners:
157
174
  ordewell model [set <id>] Show or set the planner model (applies without a restart)
158
175
  ordewell planner-effort [lvl] Thinking effort for a coding-agent planner
159
176
  ordewell key [set <p> <key>] Show which providers have a key, or store one
160
- ordewell runners [<id> on|off] Enable or disable runners (claude-code, opencode, codex)
177
+ ordewell runners [<id> on|off] Enable or disable runners (${runnerIdList()})
161
178
  ordewell allowlist set|clear|show Limit which models a runner may use
162
179
  ordewell auto [full|guarded] Autonomy level for new plans: Full or Guarded
163
180
  ordewell supervisor [off|watch|act] Whether the planner watches or acts on your runs (default watch);
@@ -236,13 +253,13 @@ Quick Start:
236
253
  then run: ordewell plan --goal "Your task description"
237
254
 
238
255
  No API key? Plan with a coding agent you already pay for:
239
- AI_PROVIDER=claude-code ordewell plan --goal "Your task description"
256
+ AI_PROVIDER=<runner> ordewell plan --goal "Your task description"
240
257
 
241
258
  Environment:
242
259
  OPENROUTER_API_KEY OpenRouter API key (recommended)
243
260
  GEMINI_API_KEY Google Gemini API key (alternative)
244
261
  AI_PROVIDER openrouter, google \u2014 auto-detected from keys
245
- claude-code, codex, opencode \u2014 plan with that CLI,
262
+ ${runnerIdList()} \u2014 plan with that CLI,
246
263
  no API key (uses its own subscription)
247
264
  ORDEWELL_PLANNER_EFFORT Thinking effort for a coding-agent planner
248
265
  ORCHESTRATOR_MODEL Default: deepseek/deepseek-v4-flash
@@ -275,9 +292,9 @@ var import_os = require("os");
275
292
  var import_path2 = require("path");
276
293
  var import_http = __toESM(require("http"));
277
294
  var import_net = require("net");
278
- var import_core2 = require("@ordewell/core");
295
+ var import_core3 = require("@ordewell/core");
279
296
  var DEFAULT_PORT = 3742;
280
- var CONFIG_DIR = (0, import_core2.globalDataDir)();
297
+ var CONFIG_DIR = (0, import_core3.globalDataDir)();
281
298
  var LEGACY_PID_FILE = (0, import_path2.join)(CONFIG_DIR, "server.pid");
282
299
  var OLD_CONFIG_DIR = (0, import_path2.join)((0, import_os.homedir)(), ".config", "ordewell");
283
300
  function pidFileFor(port) {
@@ -317,12 +334,12 @@ function getWebServerPath() {
317
334
  );
318
335
  }
319
336
  async function isDaemonRunning(port = DEFAULT_PORT) {
320
- const token = (0, import_core2.readDaemonToken)(port);
337
+ const token = (0, import_core3.readDaemonToken)(port);
321
338
  try {
322
339
  const res = await httpGet(
323
340
  `http://127.0.0.1:${port}/api/workspaces`,
324
341
  2e3,
325
- token ? { Authorization: (0, import_core2.bearerHeaderValue)(token) } : {}
342
+ token ? { Authorization: (0, import_core3.bearerHeaderValue)(token) } : {}
326
343
  );
327
344
  return res.status === 200 || res.status === 401;
328
345
  } catch {
@@ -378,7 +395,7 @@ async function stopDaemon(port = DEFAULT_PORT) {
378
395
  const pid = parseInt(pidStr, 10);
379
396
  if (!pid || isNaN(pid)) {
380
397
  (0, import_fs2.unlinkSync)(pidFile);
381
- (0, import_core2.clearDaemonToken)(port);
398
+ (0, import_core3.clearDaemonToken)(port);
382
399
  return false;
383
400
  }
384
401
  process.kill(pid, "SIGTERM");
@@ -391,7 +408,7 @@ async function stopDaemon(port = DEFAULT_PORT) {
391
408
  (0, import_fs2.unlinkSync)(pidFile);
392
409
  } catch {
393
410
  }
394
- (0, import_core2.clearDaemonToken)(port);
411
+ (0, import_core3.clearDaemonToken)(port);
395
412
  console.log("Server was not running (stale PID removed).");
396
413
  return true;
397
414
  }
@@ -444,7 +461,7 @@ function resolvePort(args = []) {
444
461
  // src/apiClient.ts
445
462
  var import_http2 = __toESM(require("http"));
446
463
  var import_ws = __toESM(require("ws"));
447
- var import_core3 = require("@ordewell/core");
464
+ var import_core4 = require("@ordewell/core");
448
465
  var DEFAULT_HTTP_TIMEOUT_MS = 15 * 60 * 1e3;
449
466
  var DaemonError = class extends Error {
450
467
  constructor(message, status, code) {
@@ -488,7 +505,7 @@ var ApiClient = class _ApiClient {
488
505
  * A missing file is not an error here — the daemon's own 401 names the path.
489
506
  */
490
507
  token() {
491
- return (0, import_core3.readDaemonToken)(this.port);
508
+ return (0, import_core4.readDaemonToken)(this.port);
492
509
  }
493
510
  /**
494
511
  * A daemon holds only the sessions adopted since it started, so after a
@@ -524,7 +541,7 @@ var ApiClient = class _ApiClient {
524
541
  method,
525
542
  headers: {
526
543
  ...body ? { "Content-Type": "application/json" } : {},
527
- ...token ? { Authorization: (0, import_core3.bearerHeaderValue)(token) } : {}
544
+ ...token ? { Authorization: (0, import_core4.bearerHeaderValue)(token) } : {}
528
545
  },
529
546
  // Planner research on a real repository regularly exceeds two minutes.
530
547
  // The benchmark harness uses the same 15-minute default explicitly;
@@ -554,7 +571,7 @@ var ApiClient = class _ApiClient {
554
571
  req.end();
555
572
  });
556
573
  }
557
- async generatePlan(goal, runners2, workspace, sessionId = (0, import_core3.mintSessionId)()) {
574
+ async generatePlan(goal, runners2, workspace, sessionId = (0, import_core4.mintSessionId)()) {
558
575
  const { plan, models, modelsByRunner, notes } = await this.call("POST", `/api/plans/${sessionId}/generate`, "Plan generation failed", {
559
576
  goal,
560
577
  runners: runners2 || void 0,
@@ -789,7 +806,7 @@ var ApiClient = class _ApiClient {
789
806
  const token = this.token();
790
807
  const socket = new import_ws.default(
791
808
  `ws://127.0.0.1:${this.port}/ws/session/${sessionId}`,
792
- token ? (0, import_core3.tokenSubprotocols)(token) : void 0
809
+ token ? (0, import_core4.tokenSubprotocols)(token) : void 0
793
810
  );
794
811
  socket.on("unexpected-response", (_req, res) => {
795
812
  const chunks = [];
@@ -1012,15 +1029,15 @@ function positionals(args) {
1012
1029
  }
1013
1030
 
1014
1031
  // src/utils/tasks.ts
1015
- var import_core4 = require("@ordewell/core");
1032
+ var import_core5 = require("@ordewell/core");
1016
1033
  function allTasksOf(plan) {
1017
1034
  const tasks = plan?.pendingTasks || plan?.tasks || [];
1018
1035
  const executionLog = plan?.executionLog || [];
1019
- return (0, import_core4.rejoinPlanTree)(tasks, executionLog);
1036
+ return (0, import_core5.rejoinPlanTree)(tasks, executionLog);
1020
1037
  }
1021
1038
  function resolveTaskId(plan, identifier) {
1022
1039
  const allTasks = allTasksOf(plan);
1023
- const byRef = (0, import_core4.resolveTaskRef)(allTasks, identifier);
1040
+ const byRef = (0, import_core5.resolveTaskRef)(allTasks, identifier);
1024
1041
  if (byRef) return byRef.id;
1025
1042
  const prefixMatches = allTasks.filter((t) => typeof t.id === "string" && t.id.startsWith(identifier));
1026
1043
  if (prefixMatches.length === 1) return prefixMatches[0].id;
@@ -1030,13 +1047,13 @@ function resolveTaskId(plan, identifier) {
1030
1047
  // src/utils/session.ts
1031
1048
  var import_fs3 = require("fs");
1032
1049
  var import_path3 = require("path");
1033
- var import_core5 = require("@ordewell/core");
1050
+ var import_core6 = require("@ordewell/core");
1034
1051
  var LAST_SESSION_FILENAME = "last-session.json";
1035
1052
  function lastSessionFile(workspace) {
1036
- return (0, import_path3.join)((0, import_core5.getStateDir)(workspace), LAST_SESSION_FILENAME);
1053
+ return (0, import_path3.join)((0, import_core6.getStateDir)(workspace), LAST_SESSION_FILENAME);
1037
1054
  }
1038
1055
  function saveLastSession(sessionId, goal, runners2, workspace) {
1039
- const dir = (0, import_core5.getStateDir)(workspace);
1056
+ const dir = (0, import_core6.getStateDir)(workspace);
1040
1057
  if (!(0, import_fs3.existsSync)(dir)) (0, import_fs3.mkdirSync)(dir, { recursive: true });
1041
1058
  (0, import_fs3.writeFileSync)(
1042
1059
  lastSessionFile(workspace),
@@ -1058,14 +1075,14 @@ function expandSessionId(id, workspace) {
1058
1075
  if (id.startsWith(SESSION_PREFIX)) return id;
1059
1076
  let files;
1060
1077
  try {
1061
- files = (0, import_fs3.readdirSync)((0, import_path3.join)((0, import_core5.getStateDir)(workspace), "sessions")).filter((f) => f.endsWith(".json"));
1078
+ files = (0, import_fs3.readdirSync)((0, import_path3.join)((0, import_core6.getStateDir)(workspace), "sessions")).filter((f) => f.endsWith(".json"));
1062
1079
  } catch {
1063
1080
  return id;
1064
1081
  }
1065
1082
  const matches = /* @__PURE__ */ new Set();
1066
1083
  for (const file of files) {
1067
1084
  try {
1068
- const full = JSON.parse((0, import_fs3.readFileSync)((0, import_path3.join)((0, import_core5.getStateDir)(workspace), "sessions", file), "utf8"))?.meta?.id;
1085
+ const full = JSON.parse((0, import_fs3.readFileSync)((0, import_path3.join)((0, import_core6.getStateDir)(workspace), "sessions", file), "utf8"))?.meta?.id;
1069
1086
  if (typeof full === "string" && (full.endsWith(id) || full.slice(SESSION_PREFIX.length).startsWith(id))) matches.add(full);
1070
1087
  } catch {
1071
1088
  }
@@ -1136,7 +1153,7 @@ ${describeApproval(event)}
1136
1153
  }
1137
1154
 
1138
1155
  // src/commands/researchLog.ts
1139
- var import_core6 = require("@ordewell/core");
1156
+ var import_core7 = require("@ordewell/core");
1140
1157
  var OUTCOME_MARK = {
1141
1158
  success: "\u2713",
1142
1159
  failure: "\u2717",
@@ -1148,7 +1165,7 @@ var RESULT_CHARS = 160;
1148
1165
  var VERBOSE_RESULT_CHARS = 600;
1149
1166
  var THINKING_CHARS = 300;
1150
1167
  function summarize(tool, args, toolLabel) {
1151
- const { name, keyArg } = (0, import_core6.toolHeadline)(tool, args, toolLabel);
1168
+ const { name, keyArg } = (0, import_core7.toolHeadline)(tool, args, toolLabel);
1152
1169
  return `${name}(${keyArg})`;
1153
1170
  }
1154
1171
  function oneLine(text, max) {
@@ -1198,7 +1215,7 @@ function createStepLog(options = {}) {
1198
1215
  }
1199
1216
 
1200
1217
  // src/commands/plan.ts
1201
- var import_core7 = require("@ordewell/core");
1218
+ var import_core8 = require("@ordewell/core");
1202
1219
  function planTasks(plan) {
1203
1220
  return plan ? allTasksOf(plan) : [];
1204
1221
  }
@@ -1282,11 +1299,11 @@ Plan: ${tasks.length} task${tasks.length === 1 ? "" : "s"} (${aiCount} AI, ${man
1282
1299
  for (const t of tasks) {
1283
1300
  const typeIcon = t.type === "user" ? "[MAN]" : t.ops ? "[OPS]" : "[ AI]";
1284
1301
  const deps = t.dependencies?.length ? ` \u2190 ${t.dependencies.join(", ")}` : "";
1285
- console.log(` ${(0, import_core7.taskOrderLabel)(t).padStart(2)}. ${typeIcon} ${t.title}${modelSuffix(t)}${deps}`);
1302
+ console.log(` ${(0, import_core8.taskOrderLabel)(t).padStart(2)}. ${typeIcon} ${t.title}${modelSuffix(t)}${deps}`);
1286
1303
  for (const sub of t.subtasks || []) {
1287
1304
  const subTypeIcon = sub.type === "user" ? "[MAN]" : "[ AI]";
1288
1305
  const subDeps = sub.dependencies?.length ? ` \u2190 ${sub.dependencies.join(", ")}` : "";
1289
- console.log(` ${(0, import_core7.taskOrderLabel)(sub, t)}. ${subTypeIcon} ${sub.title}${modelSuffix(sub)}${subDeps}`);
1306
+ console.log(` ${(0, import_core8.taskOrderLabel)(sub, t)}. ${subTypeIcon} ${sub.title}${modelSuffix(sub)}${subDeps}`);
1290
1307
  }
1291
1308
  }
1292
1309
  if (manCount > 0) {
@@ -1336,7 +1353,7 @@ async function handlePlan(subArgs, deps = {}) {
1336
1353
  runners2 = runnerFlags;
1337
1354
  }
1338
1355
  console.error(`Generating plan for: "${goal}"...`);
1339
- const sessionId = (0, import_core7.mintSessionId)();
1356
+ const sessionId = (0, import_core8.mintSessionId)();
1340
1357
  const isTty = !!process.stderr.isTTY;
1341
1358
  let lastLineLength = 0;
1342
1359
  const stepLog = createStepLog({ verbose });
@@ -1442,7 +1459,7 @@ ${note}`);
1442
1459
  }
1443
1460
 
1444
1461
  // src/isolation.ts
1445
- var import_core8 = require("@ordewell/core");
1462
+ var import_core9 = require("@ordewell/core");
1446
1463
  var STATE_OF = {
1447
1464
  active: "active",
1448
1465
  merged: "integrated",
@@ -1526,9 +1543,9 @@ function repairedLanded(handoff) {
1526
1543
  function repairedNotice(handoff) {
1527
1544
  const repaired = repairedLanded(handoff);
1528
1545
  if (repaired.length === 0) return "";
1529
- const named = repaired.map((t) => `${t.title} (${(0, import_core8.capConflictFiles)(t.repairedFiles)})`);
1530
- const list = named.length === 1 ? named[0] : `${named.slice(0, -1).join(", ")} and ${named[named.length - 1]}`;
1531
- return ` ${list} landed through ${repaired.length === 1 ? "a conflict repair" : "conflict repairs"}.`;
1546
+ const named = repaired.map((t) => `${t.title} (${(0, import_core9.capConflictFiles)(t.repairedFiles)})`);
1547
+ const list2 = named.length === 1 ? named[0] : `${named.slice(0, -1).join(", ")} and ${named[named.length - 1]}`;
1548
+ return ` ${list2} landed through ${repaired.length === 1 ? "a conflict repair" : "conflict repairs"}.`;
1532
1549
  }
1533
1550
  function repoResultLines(handoff) {
1534
1551
  return handoff.repos.map(({ path, landed }) => {
@@ -1541,14 +1558,14 @@ function mergeOutcome(result, branch, group, repaired = []) {
1541
1558
  if (!group && result.outcome === "conflict") {
1542
1559
  return { ok, message: `Merging ${branch} conflicted, so it was aborted \u2014 your tree is as it was. Merge it with git and resolve the conflict there.` };
1543
1560
  }
1544
- const { message } = (0, import_core8.describeMergeResult)(result, branch, group, repaired);
1561
+ const { message } = (0, import_core9.describeMergeResult)(result, branch, group, repaired);
1545
1562
  return { ok, message: ok || !group ? message : `${message} Each repository's ${branch} is a plain branch you can merge by hand.` };
1546
1563
  }
1547
1564
 
1548
1565
  // src/utils/output.ts
1549
- var import_core9 = require("@ordewell/core");
1566
+ var import_core10 = require("@ordewell/core");
1550
1567
  function iconFor(status) {
1551
- switch ((0, import_core9.taskStatusKind)({ status })) {
1568
+ switch ((0, import_core10.taskStatusKind)({ status })) {
1552
1569
  case "done":
1553
1570
  return "\x1B[32m\u2713\x1B[0m";
1554
1571
  case "running":
@@ -1568,7 +1585,7 @@ function iconFor(status) {
1568
1585
  }
1569
1586
 
1570
1587
  // src/commands/run.ts
1571
- var import_core10 = require("@ordewell/core");
1588
+ var import_core11 = require("@ordewell/core");
1572
1589
 
1573
1590
  // src/commands/shared.ts
1574
1591
  var import_readline2 = require("readline");
@@ -1727,11 +1744,11 @@ async function followExecution(api, sessionId, start, onBlocked) {
1727
1744
  });
1728
1745
  const stream = api.streamExecution(sessionId, (event) => {
1729
1746
  if (event.type === "task_started") {
1730
- process.stderr.write(`\xB7 ${(0, import_core10.taskStartedNotice)(event.title, event.runner)}
1747
+ process.stderr.write(`\xB7 ${(0, import_core11.taskStartedNotice)(event.title, event.runner)}
1731
1748
  `);
1732
1749
  }
1733
1750
  if (event.type === "checkpoint") {
1734
- process.stderr.write(`\xB7 Checkpoint \u2014 ${event.taskTitle}: ${(0, import_core10.truncateCheckpointSummary)(event.summary)} \u2014 \`ordewell checkpoint <id> approve|reject [reason]\` answers it
1751
+ process.stderr.write(`\xB7 Checkpoint \u2014 ${event.taskTitle}: ${(0, import_core11.truncateCheckpointSummary)(event.summary)} \u2014 \`ordewell checkpoint <id> approve|reject [reason]\` answers it
1735
1752
  `);
1736
1753
  }
1737
1754
  if (event.type === "status_update" && event.tasks) {
@@ -1812,7 +1829,7 @@ async function handleRun(subArgs, injectedApi) {
1812
1829
  }
1813
1830
 
1814
1831
  // src/tui/blocks.ts
1815
- var import_core11 = require("@ordewell/core");
1832
+ var import_core13 = require("@ordewell/core");
1816
1833
 
1817
1834
  // src/tui/ansi.ts
1818
1835
  var import_string_width = __toESM(require("string-width"));
@@ -2027,94 +2044,191 @@ var style = {
2027
2044
  };
2028
2045
 
2029
2046
  // src/tui/markdown.ts
2047
+ var import_core12 = require("@ordewell/core");
2030
2048
  function renderMarkdown(source, cols) {
2031
- const lines = source.replace(/\r/g, "").replace(/^\n+|\n+$/g, "").split("\n");
2049
+ return blocks((0, import_core12.markdownTokens)(source), { room: Math.max(1, cols), base: [] });
2050
+ }
2051
+ function closeOf(tokens, open) {
2052
+ const { level } = tokens[open];
2053
+ for (let i = open + 1; i < tokens.length; i += 1) {
2054
+ if (tokens[i].nesting === -1 && tokens[i].level === level) return i;
2055
+ }
2056
+ return tokens.length - 1;
2057
+ }
2058
+ function lastLine(tokens) {
2059
+ let last = null;
2060
+ for (const token of tokens) {
2061
+ if (token.nesting === 0 && token.map && (last === null || token.map[1] > last)) last = token.map[1];
2062
+ }
2063
+ return last ?? tokens[0]?.map?.[1] ?? null;
2064
+ }
2065
+ function blocks(tokens, ctx) {
2032
2066
  const out = [];
2033
- let inCodeBlock = false;
2034
- for (let i = 0; i < lines.length; i += 1) {
2035
- const line = lines[i];
2036
- if (/^\s*```/.test(line)) {
2037
- inCodeBlock = !inCodeBlock;
2038
- continue;
2039
- }
2040
- if (inCodeBlock) {
2041
- out.push(...wrap(style.grey(` ${line}`), cols));
2042
- continue;
2043
- }
2044
- const table = tableAt(lines, i);
2045
- if (table) {
2046
- out.push(...renderTable(table.headers, table.rows, cols));
2047
- i = table.end;
2048
- continue;
2049
- }
2050
- const heading = line.match(/^\s{0,3}(#{1,6})\s+(.+?)\s*#*\s*$/);
2051
- if (heading) {
2052
- const paint = heading[1].length <= 2 ? (text) => style.bold(style.brand(text)) : style.bold;
2053
- out.push(...wrap(paint(inline(heading[2])), cols));
2054
- continue;
2055
- }
2056
- if (/^\s{0,3}(?:[-*_]\s*){3,}$/.test(line)) {
2057
- out.push(style.grey("\u2500".repeat(Math.max(1, cols))));
2058
- continue;
2059
- }
2060
- const bullet = line.match(/^(\s*)[-*+]\s+(.+)$/);
2061
- if (bullet) {
2062
- out.push(...wrap(`${bullet[1]}\u2022 ${inline(bullet[2])}`, cols));
2063
- continue;
2064
- }
2065
- const quote = line.match(/^\s*>\s?(.*)$/);
2066
- if (quote) {
2067
- out.push(...wrap(style.grey(`\u2502 ${inline(quote[1])}`), cols));
2068
- continue;
2069
- }
2070
- out.push(...wrap(inline(line), cols));
2067
+ let previousEnd = null;
2068
+ for (let i = 0; i < tokens.length; i += 1) {
2069
+ const token = tokens[i];
2070
+ if (token.nesting === -1) continue;
2071
+ const end = token.nesting === 1 ? closeOf(tokens, i) : i;
2072
+ const children = tokens.slice(i + 1, end);
2073
+ const lines = block(token, children, ctx);
2074
+ const last = lastLine([token, ...children]);
2075
+ i = end;
2076
+ if (lines === null) continue;
2077
+ const start = token.map?.[0] ?? null;
2078
+ if (previousEnd !== null && start !== null && start > previousEnd && out.length > 0) out.push("");
2079
+ previousEnd = last ?? previousEnd;
2080
+ out.push(...lines);
2071
2081
  }
2072
2082
  return out;
2073
2083
  }
2074
- function tableAt(lines, start) {
2075
- if (!lines[start]?.includes("|") || !isTableRule(lines[start + 1] ?? "")) return null;
2076
- const headers = tableCells(lines[start]);
2077
- if (headers.length < 2) return null;
2078
- const rows = [];
2079
- let end = start + 1;
2080
- for (let i = start + 2; i < lines.length && lines[i].includes("|"); i += 1) {
2081
- const cells2 = tableCells(lines[i]);
2082
- if (cells2.length !== headers.length) break;
2083
- rows.push(cells2);
2084
- end = i;
2084
+ function block(token, children, ctx) {
2085
+ switch (token.type) {
2086
+ case "paragraph_open":
2087
+ return wrap(inline(children[0]?.children ?? [], ctx.base, "\n"), ctx.room);
2088
+ case "heading_open": {
2089
+ const level = Number(token.tag.slice(1));
2090
+ const base = level <= 2 ? [style.bold, style.brand] : [style.bold];
2091
+ return wrap(inline(children[0]?.children ?? [], [...ctx.base, ...base], "\n"), ctx.room);
2092
+ }
2093
+ case "fence":
2094
+ case "code_block":
2095
+ return token.content.replace(/\n$/, "").split("\n").flatMap((line) => wrap(` ${line}`, ctx.room)).map(style.grey);
2096
+ case "hr":
2097
+ return [style.grey("\u2500".repeat(ctx.room))];
2098
+ case "blockquote_open": {
2099
+ const inner = blocks(children, { room: Math.max(1, ctx.room - 2), base: [...ctx.base, style.grey] });
2100
+ return inner.map((line) => `${style.grey("\u2502")} ${line}`);
2101
+ }
2102
+ case "bullet_list_open":
2103
+ return list(children, ctx, () => "\u2022");
2104
+ case "ordered_list_open": {
2105
+ const start = Number(token.attrs?.find(([name]) => name === "start")?.[1] ?? 1);
2106
+ let n = start - 1;
2107
+ return list(children, ctx, (item) => {
2108
+ n += 1;
2109
+ return `${item.info || n}${item.markup || "."}`;
2110
+ });
2111
+ }
2112
+ case "table_open":
2113
+ return table(children, ctx);
2114
+ default:
2115
+ return null;
2116
+ }
2117
+ }
2118
+ function list(items, ctx, marker2) {
2119
+ const out = [];
2120
+ let previousEnd = null;
2121
+ for (let i = 0; i < items.length; i += 1) {
2122
+ const item = items[i];
2123
+ if (item.type !== "list_item_open") continue;
2124
+ const end = closeOf(items, i);
2125
+ const mark = marker2(item);
2126
+ const hang = " ".repeat(width(mark) + 1);
2127
+ const content = items.slice(i + 1, end);
2128
+ const inner = blocks(content, { ...ctx, room: Math.max(1, ctx.room - hang.length) });
2129
+ i = end;
2130
+ const start = item.map?.[0] ?? null;
2131
+ if (previousEnd !== null && start !== null && start > previousEnd) out.push("");
2132
+ previousEnd = lastLine(content) ?? previousEnd;
2133
+ (inner.length > 0 ? inner : [""]).forEach((line, row) => out.push(row === 0 ? `${mark} ${line}` : line && `${hang}${line}`));
2085
2134
  }
2086
- return { headers, rows, end };
2135
+ return out;
2087
2136
  }
2088
- function isTableRule(line) {
2089
- const cells2 = tableCells(line);
2090
- return cells2.length >= 2 && cells2.every((cell) => /^:?-{3,}:?$/.test(cell));
2137
+ function inline(tokens, base, lineBreak) {
2138
+ const active = [...base];
2139
+ const paint = (text) => text.split(" ").map((word) => word ? active.reduce((acc, apply) => apply(acc), word) : word).join(" ");
2140
+ let out = "";
2141
+ let href = null;
2142
+ let linkText = "";
2143
+ const emit = (text) => {
2144
+ out += paint(text);
2145
+ if (href !== null) linkText += text;
2146
+ };
2147
+ for (const token of tokens) {
2148
+ switch (token.type) {
2149
+ case "text":
2150
+ case "image":
2151
+ emit(token.content);
2152
+ break;
2153
+ case "code_inline":
2154
+ active.push(style.brand);
2155
+ emit(token.content);
2156
+ active.pop();
2157
+ break;
2158
+ case "softbreak":
2159
+ case "hardbreak":
2160
+ out += lineBreak;
2161
+ break;
2162
+ case "strong_open":
2163
+ active.push(style.bold);
2164
+ break;
2165
+ case "em_open":
2166
+ active.push(style.italic);
2167
+ break;
2168
+ case "s_open":
2169
+ active.push(style.dim);
2170
+ break;
2171
+ case "link_open":
2172
+ href = token.attrs?.find(([name]) => name === "href")?.[1] ?? null;
2173
+ linkText = "";
2174
+ if (href !== null) active.push(style.underline);
2175
+ break;
2176
+ case "link_close":
2177
+ if (href !== null) {
2178
+ active.pop();
2179
+ if (linkText !== href) out += paint(" ") + style.grey(`(${href})`);
2180
+ }
2181
+ href = null;
2182
+ break;
2183
+ case "strong_close":
2184
+ case "em_close":
2185
+ case "s_close":
2186
+ active.pop();
2187
+ break;
2188
+ default:
2189
+ if (token.content) emit(token.content);
2190
+ }
2191
+ }
2192
+ return out;
2091
2193
  }
2092
- function tableCells(line) {
2093
- return line.trim().replace(/^\||\|$/g, "").split("|").map((cell) => cell.trim());
2194
+ function table(tokens, ctx) {
2195
+ const headers = [];
2196
+ const rows = [];
2197
+ let inHead = false;
2198
+ let row = null;
2199
+ for (const token of tokens) {
2200
+ if (token.type === "thead_open") inHead = true;
2201
+ else if (token.type === "thead_close") inHead = false;
2202
+ else if (token.type === "tr_open") row = [];
2203
+ else if (token.type === "tr_close" && row) {
2204
+ if (inHead) headers.push(...row);
2205
+ else rows.push(row);
2206
+ row = null;
2207
+ } else if (token.type === "inline" && row) {
2208
+ row.push(inline(token.children ?? [], inHead ? [style.bold] : [], " "));
2209
+ }
2210
+ }
2211
+ return renderTable(headers, rows, ctx.room);
2094
2212
  }
2095
2213
  function renderTable(headers, rows, cols) {
2096
2214
  const separator = " \u2502 ";
2097
2215
  const separatorWidth = width(separator);
2098
2216
  const available = Math.max(headers.length, cols - separatorWidth * (headers.length - 1));
2099
2217
  const natural = headers.map(
2100
- (header, column) => Math.max(width(inline(header)), ...rows.map((row) => width(inline(row[column] ?? ""))))
2218
+ (header, column) => Math.max(width(header), ...rows.map((row) => width(row[column] ?? "")))
2101
2219
  );
2102
2220
  const columnWidths = fitTableColumns(natural, available);
2103
- if (columnWidths.some((size) => size < 4)) return renderStackedTable(headers, rows, cols);
2104
- const renderRow = (cells2, paint = (text) => text) => {
2105
- const wrapped = cells2.map((cell, index) => wrap(inline(cell), columnWidths[index]));
2221
+ if (columnWidths.some((size, index) => size < Math.min(4, natural[index]))) return renderRecords(headers, rows, cols);
2222
+ const renderRow = (cells2) => {
2223
+ const wrapped = headers.map((_, index) => wrap(cells2[index] ?? "", columnWidths[index]));
2106
2224
  const height = Math.max(...wrapped.map((cell) => cell.length));
2107
2225
  return Array.from(
2108
2226
  { length: height },
2109
- (_, line) => wrapped.map((cell, column) => pad(paint(cell[line] ?? ""), columnWidths[column])).join(separator)
2227
+ (_, line) => wrapped.map((cell, column) => pad(cell[line] ?? "", columnWidths[column])).join(separator)
2110
2228
  );
2111
2229
  };
2112
2230
  const rule = columnWidths.map((size) => style.grey("\u2500".repeat(size))).join(style.grey("\u2500\u253C\u2500"));
2113
- return [
2114
- ...renderRow(headers, style.bold),
2115
- rule,
2116
- ...rows.flatMap((row) => renderRow(row))
2117
- ];
2231
+ return [...renderRow(headers), rule, ...rows.flatMap(renderRow)];
2118
2232
  }
2119
2233
  function fitTableColumns(natural, available) {
2120
2234
  const widths = [...natural];
@@ -2127,15 +2241,12 @@ function fitTableColumns(natural, available) {
2127
2241
  }
2128
2242
  return widths;
2129
2243
  }
2130
- function renderStackedTable(headers, rows, cols) {
2244
+ function renderRecords(headers, rows, cols) {
2131
2245
  return rows.flatMap((row, rowIndex) => [
2132
- ...rowIndex === 0 ? [] : [""],
2133
- ...row.flatMap((cell, column) => wrap(`${style.bold(inline(headers[column]))}: ${inline(cell)}`, cols))
2246
+ ...rowIndex === 0 ? [] : [style.grey("\u2500".repeat(cols))],
2247
+ ...headers.flatMap((header, column) => wrap(`${header}: ${row[column] ?? ""}`, cols))
2134
2248
  ]);
2135
2249
  }
2136
- function inline(text) {
2137
- return text.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/\[([^\]]+)\]\(([^\s)]+)(?:\s+[^)]*)?\)/g, "$1 ($2)").replace(/\*\*([^*]+)\*\*/g, (_, bold) => style.bold(bold)).replace(/__([^_]+)__/g, (_, bold) => style.bold(bold)).replace(/(^|[^\w])\*([^*]+)\*(?![\w*])/g, (_, prefix, italic) => `${prefix}${style.italic(italic)}`).replace(/(^|[^\w])_([^_]+)_(?![\w_])/g, (_, prefix, italic) => `${prefix}${style.italic(italic)}`).replace(/`([^`]+)`/g, (_, code) => style.brand(code));
2138
- }
2139
2250
 
2140
2251
  // src/tui/blocks.ts
2141
2252
  function countOf(n, noun) {
@@ -2168,25 +2279,25 @@ var ROLE_CONTINUATION = {
2168
2279
  error: style.red,
2169
2280
  wake_up: style.yellow
2170
2281
  };
2171
- function messageLines(block, cols) {
2172
- const text = sanitize(block.text);
2282
+ function messageLines(block2, cols) {
2283
+ const text = sanitize(block2.text);
2173
2284
  const room = Math.max(1, cols - 2);
2174
- const wrapped = block.role === "planner" || block.role === "agent" || block.role === "supervisor" ? renderMarkdown(text, room) : block.skills ? skillPaintedLines(text, block.skills, room) : wrap(text, room);
2175
- const rest = ROLE_CONTINUATION[block.role] ?? ((t) => t);
2176
- const rows = wrapped.map((line, i) => i === 0 ? ROLE_PREFIX[block.role](line) : rest(` ${line}`));
2177
- if (block.role === "user" && block.forced) {
2285
+ const wrapped = block2.role === "planner" || block2.role === "agent" || block2.role === "supervisor" ? renderMarkdown(text, room) : block2.skills ? skillPaintedLines(text, block2.skills, room) : wrap(text, room);
2286
+ const rest = ROLE_CONTINUATION[block2.role] ?? ((t) => t);
2287
+ const rows = wrapped.map((line, i) => i === 0 ? ROLE_PREFIX[block2.role](line) : rest(` ${line}`));
2288
+ if (block2.role === "user" && block2.forced) {
2178
2289
  const note = style.grey(" \xB7 sent now");
2179
2290
  if (width(rows[0]) + width(note) <= cols) rows[0] += note;
2180
2291
  else rows.push(` ${note}`);
2181
2292
  }
2182
- return block.role === "user" ? onBand(rows, cols) : rows;
2293
+ return block2.role === "user" ? onBand(rows, cols) : rows;
2183
2294
  }
2184
2295
  function onBand(rows, cols) {
2185
2296
  const band = ["", ...rows, ""];
2186
2297
  return style.enabled ? band.map((row) => style.band(pad(row, cols))) : band;
2187
2298
  }
2188
2299
  function skillPaintedLines(text, skills, room) {
2189
- const tokens = (0, import_core11.loadedSkillTokens)(text, skills);
2300
+ const tokens = (0, import_core13.loadedSkillTokens)(text, skills);
2190
2301
  return wrapLines(text, room).map(({ line, start }) => {
2191
2302
  let painted = "";
2192
2303
  let at = 0;
@@ -2200,19 +2311,19 @@ function skillPaintedLines(text, skills, room) {
2200
2311
  return painted + line.slice(at);
2201
2312
  });
2202
2313
  }
2203
- function skillLoadLine(block, cols) {
2204
- const head = block.attaches ? `\u25CF /${sanitize(block.name)} will be attached to fitting tasks \xB7 ` : block.invokedBy === "planner" ? `\u25CF ${sanitize(block.name)} skill loaded by planner \xB7 ` : `\u25CF /${sanitize(block.name)} skill loaded \xB7 `;
2205
- const line = truncate(`${head}${truncatePath(sanitize(block.path), Math.max(1, cols - width(head)))}`, cols);
2314
+ function skillLoadLine(block2, cols) {
2315
+ const head = block2.attaches ? `\u25CF /${sanitize(block2.name)} will be attached to fitting tasks \xB7 ` : block2.invokedBy === "planner" ? `\u25CF ${sanitize(block2.name)} skill loaded by planner \xB7 ` : `\u25CF /${sanitize(block2.name)} skill loaded \xB7 `;
2316
+ const line = truncate(`${head}${truncatePath(sanitize(block2.path), Math.max(1, cols - width(head)))}`, cols);
2206
2317
  return `${style.green("\u25CF")}${style.grey(line.slice(1))}`;
2207
2318
  }
2208
- function thinkingLines(block, cols, detailAll) {
2209
- const text = sanitize(block.text).trim();
2319
+ function thinkingLines(block2, cols, detailAll) {
2320
+ const text = sanitize(block2.text).trim();
2210
2321
  const head = `\u2234 Thinking (${countOf(text ? text.split(/\s+/).length : 0, "word")})`;
2211
2322
  if (detailAll) {
2212
2323
  const body = text ? wrap(text, Math.max(1, cols - 2)).map((line) => style.grey(` ${line}`)) : [];
2213
2324
  return [style.grey(truncate(head, cols)), ...body];
2214
2325
  }
2215
- const latest = block.streaming ? (text.split("\n").at(-1) ?? "").trim() : "";
2326
+ const latest = block2.streaming ? (text.split("\n").at(-1) ?? "").trim() : "";
2216
2327
  const room = cols - width(`${head} \xB7 `);
2217
2328
  if (!latest || room < 2) return [style.grey(truncate(head, cols))];
2218
2329
  const shown = width(latest) > room ? `\u2026${tailOf(latest, room - 1)}` : latest;
@@ -2224,21 +2335,21 @@ var PREVIEW_LINES = 3;
2224
2335
  function underHeader(lines) {
2225
2336
  return lines.map((line, i) => `${i === 0 ? style.grey(OUTPUT_HEAD) : OUTPUT_INDENT}${line}`);
2226
2337
  }
2227
- function unsettledOutcome(block) {
2228
- switch (block.status) {
2338
+ function unsettledOutcome(block2) {
2339
+ switch (block2.status) {
2229
2340
  case "error":
2230
2341
  return { label: "Error", paint: style.red };
2231
2342
  case "denied":
2232
- return { label: block.outcome === "refused" ? "Refused" : "Denied", paint: style.yellow };
2343
+ return { label: block2.outcome === "refused" ? "Refused" : "Denied", paint: style.yellow };
2233
2344
  case "interrupted":
2234
2345
  return { label: "Interrupted", paint: style.grey };
2235
2346
  default:
2236
2347
  return null;
2237
2348
  }
2238
2349
  }
2239
- function commandMark(block) {
2240
- if (block.status === "pending") return style.grey("\u25CB");
2241
- return (unsettledOutcome(block)?.paint ?? style.green)("\u25CF");
2350
+ function commandMark(block2) {
2351
+ if (block2.status === "pending") return style.grey("\u25CB");
2352
+ return (unsettledOutcome(block2)?.paint ?? style.green)("\u25CF");
2242
2353
  }
2243
2354
  var PATH_LIKE = /^(?![a-z][a-z0-9+.-]*:\/\/)\S*\/\S*$/i;
2244
2355
  function truncatePath(path, max) {
@@ -2251,17 +2362,17 @@ function truncatePath(path, max) {
2251
2362
  const slash = tail.search(/[\\/]/);
2252
2363
  return `\u2026${slash > 0 ? tail.slice(slash) : tail}`;
2253
2364
  }
2254
- function commandHeader(block, cols, detailAll) {
2255
- const name = sanitize(block.headline.name);
2256
- const keyArg = sanitize(block.headline.keyArg);
2365
+ function commandHeader(block2, cols, detailAll) {
2366
+ const name = sanitize(block2.headline.name);
2367
+ const keyArg = sanitize(block2.headline.keyArg);
2257
2368
  if (detailAll) {
2258
- return wrap(`${name}(${keyArg})`, Math.max(1, cols - 2)).map((line, i) => i === 0 ? `${commandMark(block)} ${line}` : ` ${line}`);
2369
+ return wrap(`${name}(${keyArg})`, Math.max(1, cols - 2)).map((line, i) => i === 0 ? `${commandMark(block2)} ${line}` : ` ${line}`);
2259
2370
  }
2260
2371
  const open = `\u25CF ${name}(`;
2261
2372
  const room = cols - width(open) - 1;
2262
2373
  const cut = PATH_LIKE.test(keyArg) ? truncatePath(keyArg, room) : truncate(keyArg, room);
2263
2374
  const text = room > 1 ? `${open}${cut})` : truncate(`${open}${keyArg})`, cols);
2264
- return [`${commandMark(block)}${text.slice(1)}`];
2375
+ return [`${commandMark(block2)}${text.slice(1)}`];
2265
2376
  }
2266
2377
  function argumentLines(args) {
2267
2378
  if (!args.trim()) return [];
@@ -2277,21 +2388,21 @@ function argumentLines(args) {
2277
2388
  return [`${key}: ${first}`, ...rest];
2278
2389
  });
2279
2390
  }
2280
- function resultLines(block, room, detailAll) {
2281
- if (block.status === "pending") return [style.grey("Running\u2026")];
2391
+ function resultLines(block2, room, detailAll) {
2392
+ if (block2.status === "pending") return [style.grey("Running\u2026")];
2282
2393
  const fit2 = (line) => detailAll ? wrap(line, room) : [truncate(line, room)];
2283
- const outcome = unsettledOutcome(block);
2394
+ const outcome = unsettledOutcome(block2);
2284
2395
  if (outcome) {
2285
- const [reason, ...rest] = (0, import_core11.outputLines)(block.output).map(sanitize);
2396
+ const [reason, ...rest] = (0, import_core13.outputLines)(block2.output).map(sanitize);
2286
2397
  const status = fit2(reason ? `${outcome.label}: ${reason}` : outcome.label).map(outcome.paint);
2287
2398
  return detailAll ? [...status, ...rest.flatMap(fit2).map(style.grey)] : status;
2288
2399
  }
2289
2400
  if (detailAll) {
2290
- const lines2 = (0, import_core11.outputLines)(block.output).map(sanitize);
2401
+ const lines2 = (0, import_core13.outputLines)(block2.output).map(sanitize);
2291
2402
  const note = lines2.length > PREVIEW_LINES ? ["\u2026 (ctrl+o to collapse)"] : [];
2292
2403
  return lines2.length > 0 ? [...lines2.flatMap(fit2), ...note].map(style.grey) : [style.grey("(no output)")];
2293
2404
  }
2294
- const { lines, hiddenLineCount } = (0, import_core11.outputPreview)(block.output, PREVIEW_LINES);
2405
+ const { lines, hiddenLineCount } = (0, import_core13.outputPreview)(block2.output, PREVIEW_LINES);
2295
2406
  if (lines.length === 0) return [style.grey("(no output)")];
2296
2407
  const more = hiddenLineCount > 0 ? [`\u2026 +${countOf(hiddenLineCount, "line")} (ctrl+o to expand)`] : [];
2297
2408
  return [...lines.map(sanitize), ...more].map((line) => style.grey(truncate(line, room)));
@@ -2304,8 +2415,8 @@ var DIFF_PAINT = {
2304
2415
  gap: style.grey
2305
2416
  };
2306
2417
  var DIFF_SIGN = { added: "+", removed: "-", context: " ", gap: "" };
2307
- function diffLines(block, diff, room, detailAll) {
2308
- const rows = (0, import_core11.diffRows)(block.output);
2418
+ function diffLines(block2, diff, room, detailAll) {
2419
+ const rows = (0, import_core13.diffRows)(block2.output);
2309
2420
  const gutter = Math.max(0, ...rows.map((row) => String(row.line ?? "").length));
2310
2421
  const draw = (row) => {
2311
2422
  const text = row.kind === "gap" ? `${" ".repeat(gutter)} \u22EE` : `${String(row.line ?? "").padStart(gutter)} ${DIFF_SIGN[row.kind]} ${sanitize(row.text)}`;
@@ -2314,14 +2425,14 @@ function diffLines(block, diff, room, detailAll) {
2314
2425
  const shown = detailAll ? rows : rows.slice(0, DIFF_PREVIEW_ROWS);
2315
2426
  const hidden = rows.length - shown.length;
2316
2427
  const more = hidden > 0 ? [style.grey(`\u2026 +${countOf(hidden, "line")} (ctrl+o to expand)`)] : [];
2317
- return [(0, import_core11.diffSummary)(diff), ...shown.flatMap(draw), ...more];
2428
+ return [(0, import_core13.diffSummary)(diff), ...shown.flatMap(draw), ...more];
2318
2429
  }
2319
- function toolLines(block, cols, detailAll) {
2430
+ function toolLines(block2, cols, detailAll) {
2320
2431
  const room = Math.max(1, cols - OUTPUT_INDENT.length);
2321
- const diff = block.diff && block.status === "ok" ? block.diff : null;
2322
- const args = detailAll && !diff ? argumentLines(block.args).flatMap((line) => wrap(line, room)).map((line) => OUTPUT_INDENT + style.grey(line)) : [];
2323
- const result = diff ? diffLines(block, diff, room, detailAll) : resultLines(block, room, detailAll);
2324
- return [...commandHeader(block, cols, detailAll), ...args, ...underHeader(result)];
2432
+ const diff = block2.diff && block2.status === "ok" ? block2.diff : null;
2433
+ const args = detailAll && !diff ? argumentLines(block2.args).flatMap((line) => wrap(line, room)).map((line) => OUTPUT_INDENT + style.grey(line)) : [];
2434
+ const result = diff ? diffLines(block2, diff, room, detailAll) : resultLines(block2, room, detailAll);
2435
+ return [...commandHeader(block2, cols, detailAll), ...args, ...underHeader(result)];
2325
2436
  }
2326
2437
  var SUBAGENT_PAINT = {
2327
2438
  running: style.yellow,
@@ -2330,24 +2441,24 @@ var SUBAGENT_PAINT = {
2330
2441
  stopped: style.grey
2331
2442
  };
2332
2443
  var CHILD_INDENT = " ";
2333
- function subagentHeader(block, cols) {
2334
- const brief = firstLine(block.brief);
2335
- const steps = block.children.filter((c) => c.type === "tool").length;
2336
- const status = block.status === "running" && steps > 0 ? `running \xB7 ${countOf(steps, "step")}` : block.status;
2444
+ function subagentHeader(block2, cols) {
2445
+ const brief = firstLine(block2.brief);
2446
+ const steps = block2.children.filter((c) => c.type === "tool").length;
2447
+ const status = block2.status === "running" && steps > 0 ? `running \xB7 ${countOf(steps, "step")}` : block2.status;
2337
2448
  const head = brief ? " Agent: " : " Agent";
2338
2449
  const briefRoom = cols - width(`\u25C6${head} ${status}`);
2339
2450
  if (briefRoom < 4) return truncate(`\u25C6${head}${brief} ${status}`, cols);
2340
- const named = `${style.brand("\u25C6")}${head}${truncate(brief, briefRoom)} ${SUBAGENT_PAINT[block.status](status)}`;
2341
- const digest = firstLine(block.digest);
2451
+ const named = `${style.brand("\u25C6")}${head}${truncate(brief, briefRoom)} ${SUBAGENT_PAINT[block2.status](status)}`;
2452
+ const digest = firstLine(block2.digest);
2342
2453
  const digestRoom = cols - width(named) - width(" \xB7 ");
2343
2454
  return digest && digestRoom >= 4 ? `${named}${style.grey(` \xB7 ${truncate(digest, digestRoom)}`)}` : named;
2344
2455
  }
2345
- function subagentLines(block, cols, detailAll) {
2346
- const header = subagentHeader(block, cols);
2456
+ function subagentLines(block2, cols, detailAll) {
2457
+ const header = subagentHeader(block2, cols);
2347
2458
  if (!detailAll) return [header];
2348
2459
  const childCols = Math.max(1, cols - CHILD_INDENT.length);
2349
- const children = block.children.flatMap((child) => blockLines(child, childCols, true).map((line) => CHILD_INDENT + line));
2350
- const digest = sanitize(block.digest).trim();
2460
+ const children = block2.children.flatMap((child) => blockLines(child, childCols, true).map((line) => CHILD_INDENT + line));
2461
+ const digest = sanitize(block2.digest).trim();
2351
2462
  const handedBack = digest ? underHeader(wrap(digest, Math.max(1, cols - OUTPUT_INDENT.length)).map(style.grey)) : [];
2352
2463
  return [header, ...children, ...handedBack];
2353
2464
  }
@@ -2372,24 +2483,39 @@ var DECIDED_BY = {
2372
2483
  budget: "web-read budget",
2373
2484
  unsupported: "not usable on this runner version"
2374
2485
  };
2375
- function approvalLine(block, cols) {
2376
- const policy = block.decidedBy && block.decidedBy !== "asked" ? DECIDED_BY[block.decidedBy] : void 0;
2377
- const [mark, status, paint] = block.status === "pending" ? ["?", "Waiting for you", style.yellow] : block.status === "granted" ? ["\u2713", policy ? `Auto-approved (${policy})` : block.forTask ? "Approved for this task" : "Approved", style.green] : block.status === "withdrawn" ? ["\xB7", "Withdrawn", style.grey] : ["\u2298", policy ? `Auto-denied (${policy})` : "Denied", style.yellow];
2378
- const note = block.note ? ` \u2014 \u201C${firstLine(block.note)}\u201D` : "";
2379
- const line = `${mark} ${status} \xB7 ${APPROVAL_KIND[block.kind]}: ${firstLine(block.subject)}${note}`;
2486
+ function approvalLine(block2, cols) {
2487
+ const policy = block2.decidedBy && block2.decidedBy !== "asked" ? DECIDED_BY[block2.decidedBy] : void 0;
2488
+ const [mark, status, paint] = block2.status === "pending" ? ["?", "Waiting for you", style.yellow] : block2.status === "granted" ? ["\u2713", policy ? `Auto-approved (${policy})` : block2.forTask ? "Approved for this task" : "Approved", style.green] : block2.status === "withdrawn" ? ["\xB7", "Withdrawn", style.grey] : ["\u2298", policy ? `Auto-denied (${policy})` : "Denied", style.yellow];
2489
+ const note = block2.note ? ` \u2014 \u201C${firstLine(block2.note)}\u201D` : "";
2490
+ const line = `${mark} ${status} \xB7 ${APPROVAL_KIND[block2.kind]}: ${firstLine(block2.subject)}${note}`;
2380
2491
  return `${paint(mark)}${truncate(line, cols).slice(mark.length)}`;
2381
2492
  }
2382
- function approvalKeysLine(block, cols) {
2383
- const keys = ["ctrl-y allow", ...block.allowForTask ? ["ctrl-t allow for task"] : [], "ctrl-g deny (composer text is the note)"];
2493
+ function approvalKeysLine(block2, cols) {
2494
+ const keys = ["ctrl-y allow", ...block2.allowForTask ? ["ctrl-t allow for task"] : [], "ctrl-g deny (composer text is the note)"];
2384
2495
  return style.grey(truncate(` ${keys.join(" \xB7 ")}`, cols));
2385
2496
  }
2386
2497
  function checkpointCardLines(order, question, cols, approvalFirst) {
2387
2498
  const room = Math.max(1, cols - 2);
2388
- const keys = approvalFirst ? "answer the tool request above first (ctrl-y / ctrl-g), then ctrl-y approves \xB7 ctrl-g rejects (composer text is the reason)" : "ctrl-y approve \xB7 ctrl-g reject (composer text is the reason)";
2499
+ const first = approvalFirst ? wrap("answer the tool request above first (ctrl-y / ctrl-g), then:", room) : [];
2389
2500
  return [
2390
2501
  truncate(`${style.accent("\u25C6")} ${style.bold(`Task ${order} asks`)}`, cols),
2391
2502
  ...wrap(sanitize(question).trim(), room).map((line) => ` ${line}`),
2392
- ...wrap(keys, room).map((line) => style.grey(` ${line}`))
2503
+ ...first.map((line) => style.grey(` ${line}`)),
2504
+ ...CHECKPOINT_CHOICES.flatMap(([key, text]) => choiceLines(key, text, room))
2505
+ ];
2506
+ }
2507
+ var CHECKPOINT_CHOICES = [
2508
+ ["enter", "reply: the task goes on with what you typed"],
2509
+ ["ctrl-y", "approve as is"],
2510
+ ["ctrl-g", "reject (with nothing typed, a plain no)"]
2511
+ ];
2512
+ var CHOICE_KEY_WIDTH = 6;
2513
+ function choiceLines(key, text, room) {
2514
+ const hang = CHOICE_KEY_WIDTH + 2;
2515
+ const [head = "", ...rest] = wrap(text, Math.max(1, room - hang));
2516
+ return [
2517
+ ` ${style.accent(style.bold(pad(key, CHOICE_KEY_WIDTH)))} ${style.grey(head)}`,
2518
+ ...rest.map((line) => ` ${" ".repeat(hang)}${style.grey(line)}`)
2393
2519
  ];
2394
2520
  }
2395
2521
  var COMMAND_PAINT = {
@@ -2398,22 +2524,22 @@ var COMMAND_PAINT = {
2398
2524
  failed: style.red,
2399
2525
  stopped: style.grey
2400
2526
  };
2401
- function runnerCommandLines(block, cols, detailAll) {
2402
- const typed = sanitize(`/${block.name}${block.args ? ` ${block.args}` : ""}`);
2403
- const status = ` ${block.status}`;
2404
- const head = `${style.accent("\u276F")} ${truncate(typed, Math.max(1, cols - 2 - width(status)))}${COMMAND_PAINT[block.status](status)}`;
2527
+ function runnerCommandLines(block2, cols, detailAll) {
2528
+ const typed = sanitize(`/${block2.name}${block2.args ? ` ${block2.args}` : ""}`);
2529
+ const status = ` ${block2.status}`;
2530
+ const head = `${style.accent("\u276F")} ${truncate(typed, Math.max(1, cols - 2 - width(status)))}${COMMAND_PAINT[block2.status](status)}`;
2405
2531
  const room = Math.max(1, cols - OUTPUT_INDENT.length);
2406
- const printed = (0, import_core11.outputLines)(block.output).map(sanitize);
2532
+ const printed = (0, import_core13.outputLines)(block2.output).map(sanitize);
2407
2533
  const shown = detailAll ? printed.flatMap((line) => wrap(line, room)) : printed.slice(0, PREVIEW_LINES).map((line) => truncate(line, room));
2408
2534
  return [head, ...underHeader(shown.map(style.grey))];
2409
2535
  }
2410
- function compactionLine(block, cols) {
2411
- const sizes = block.preTokens !== void 0 && block.postTokens !== void 0 ? ` \xB7 ${compactCount(block.preTokens)} \u2192 ${compactCount(block.postTokens)} tokens` : "";
2412
- const text = block.trigger === "auto" && !sizes ? "\u2261 Context compacted by the runner on its own" : `\u2261 Context compacted${sizes}`;
2536
+ function compactionLine(block2, cols) {
2537
+ const sizes = block2.preTokens !== void 0 && block2.postTokens !== void 0 ? ` \xB7 ${compactCount(block2.preTokens)} \u2192 ${compactCount(block2.postTokens)} tokens` : "";
2538
+ const text = block2.trigger === "auto" && !sizes ? "\u2261 Context compacted by the runner on its own" : `\u2261 Context compacted${sizes}`;
2413
2539
  return style.grey(truncate(text, cols));
2414
2540
  }
2415
- function runnerLoadedLines(block, cols, detailAll) {
2416
- const of = (kind) => block.commands.filter((c) => c.kind === kind).map((c) => `/${sanitize(c.name)}`);
2541
+ function runnerLoadedLines(block2, cols, detailAll) {
2542
+ const of = (kind) => block2.commands.filter((c) => c.kind === kind).map((c) => `/${sanitize(c.name)}`);
2417
2543
  const skills = of("skill");
2418
2544
  const commands = of("command");
2419
2545
  const builtins = of("builtin");
@@ -2421,66 +2547,66 @@ function runnerLoadedLines(block, cols, detailAll) {
2421
2547
  countOf(skills.length, "skill"),
2422
2548
  countOf(commands.length, "command"),
2423
2549
  countOf(builtins.length, "built-in command"),
2424
- countOf(block.mcpServers.length, "MCP server")
2550
+ countOf(block2.mcpServers.length, "MCP server")
2425
2551
  ];
2426
2552
  const head = truncate(`\u25CF Runner loaded ${counts.join(", ")}`, cols);
2427
2553
  const lines = [`${style.green("\u25CF")}${style.grey(head.slice(1))}`];
2428
2554
  if (!detailAll) return lines;
2429
2555
  const room = Math.max(1, cols - OUTPUT_INDENT.length);
2430
- const list = (label, names) => names.length > 0 ? wrap(`${label}: ${names.join(" ")}`, room) : [];
2431
- const servers = block.mcpServers.map((m) => `${sanitize(m.name)}${m.status ? ` (${sanitize(m.status)})` : ""}`);
2556
+ const list2 = (label, names) => names.length > 0 ? wrap(`${label}: ${names.join(" ")}`, room) : [];
2557
+ const servers = block2.mcpServers.map((m) => `${sanitize(m.name)}${m.status ? ` (${sanitize(m.status)})` : ""}`);
2432
2558
  return [
2433
2559
  ...lines,
2434
- ...[...list("skills", skills), ...list("commands", commands), ...list("built-in", builtins), ...servers.length > 0 ? wrap(`MCP servers: ${servers.join(", ")}`, room) : []].map((line) => OUTPUT_INDENT + style.grey(line))
2560
+ ...[...list2("skills", skills), ...list2("commands", commands), ...list2("built-in", builtins), ...servers.length > 0 ? wrap(`MCP servers: ${servers.join(", ")}`, room) : []].map((line) => OUTPUT_INDENT + style.grey(line))
2435
2561
  ];
2436
2562
  }
2437
- function planLine(block, cols) {
2438
- const count = block.taskCount === void 0 ? "" : ` (${countOf(block.taskCount, "task")})`;
2439
- const text = block.status === "building" ? "Building plan\u2026" : `Plan ${block.status}${count}`;
2563
+ function planLine(block2, cols) {
2564
+ const count = block2.taskCount === void 0 ? "" : ` (${countOf(block2.taskCount, "task")})`;
2565
+ const text = block2.status === "building" ? "Building plan\u2026" : `Plan ${block2.status}${count}`;
2440
2566
  return `${style.brand("\u25C7")}${truncate(`\u25C7 ${text}`, cols).slice(1)}`;
2441
2567
  }
2442
- function blockLines(block, cols, detailAll) {
2443
- switch (block.type) {
2568
+ function blockLines(block2, cols, detailAll) {
2569
+ switch (block2.type) {
2444
2570
  case "message":
2445
- return messageLines(block, cols);
2571
+ return messageLines(block2, cols);
2446
2572
  case "thinking":
2447
- return thinkingLines(block, cols, detailAll);
2573
+ return thinkingLines(block2, cols, detailAll);
2448
2574
  case "tool":
2449
- return toolLines(block, cols, detailAll);
2575
+ return toolLines(block2, cols, detailAll);
2450
2576
  case "subagent":
2451
- return subagentLines(block, cols, detailAll);
2577
+ return subagentLines(block2, cols, detailAll);
2452
2578
  case "approval":
2453
- return [approvalLine(block, cols)];
2579
+ return [approvalLine(block2, cols)];
2454
2580
  case "plan":
2455
- return [planLine(block, cols)];
2581
+ return [planLine(block2, cols)];
2456
2582
  case "skill_load":
2457
- return [skillLoadLine(block, cols)];
2583
+ return [skillLoadLine(block2, cols)];
2458
2584
  case "command":
2459
- return runnerCommandLines(block, cols, detailAll);
2585
+ return runnerCommandLines(block2, cols, detailAll);
2460
2586
  case "compaction":
2461
- return [compactionLine(block, cols)];
2587
+ return [compactionLine(block2, cols)];
2462
2588
  case "runner_loaded":
2463
- return runnerLoadedLines(block, cols, detailAll);
2589
+ return runnerLoadedLines(block2, cols, detailAll);
2464
2590
  // Pinned under the pane rather than drawn in it — see `tokenLine`.
2465
2591
  case "usage":
2466
2592
  return [];
2467
2593
  }
2468
2594
  }
2469
2595
  var drawnBlocks = /* @__PURE__ */ new WeakMap();
2470
- function drawn(block, cols, detailAll) {
2471
- const cached = drawnBlocks.get(block);
2596
+ function drawn(block2, cols, detailAll) {
2597
+ const cached = drawnBlocks.get(block2);
2472
2598
  if (cached && cached.cols === cols && cached.detailAll === detailAll) return cached.lines;
2473
- const lines = blockLines(block, cols, detailAll);
2474
- drawnBlocks.set(block, { cols, detailAll, lines });
2599
+ const lines = blockLines(block2, cols, detailAll);
2600
+ drawnBlocks.set(block2, { cols, detailAll, lines });
2475
2601
  return lines;
2476
2602
  }
2477
- function conversationLines(blocks, cols, detailAll, answering) {
2603
+ function conversationLines(blocks2, cols, detailAll, answering) {
2478
2604
  const lines = [];
2479
- for (const [i, block] of blocks.entries()) {
2480
- if (block.type === "usage") continue;
2481
- lines.push(...drawn(block, cols, detailAll));
2482
- if (block === answering) lines.push(approvalKeysLine(block, cols));
2483
- if (blocks[i + 1]?.type !== "skill_load") lines.push("");
2605
+ for (const [i, block2] of blocks2.entries()) {
2606
+ if (block2.type === "usage") continue;
2607
+ lines.push(...drawn(block2, cols, detailAll));
2608
+ if (block2 === answering) lines.push(approvalKeysLine(block2, cols));
2609
+ if (blocks2[i + 1]?.type !== "skill_load") lines.push("");
2484
2610
  }
2485
2611
  return lines;
2486
2612
  }
@@ -2494,8 +2620,8 @@ function formatCost(currency, amount) {
2494
2620
  const value = `${whole}.${frac.padEnd(2, "0")}`;
2495
2621
  return currency.toLowerCase() === "usd" ? `$${value}` : `${value} ${currency.toUpperCase()}`;
2496
2622
  }
2497
- function tokenLine(blocks, cols) {
2498
- const usage = blocks[blocks.length - 1];
2623
+ function tokenLine(blocks2, cols) {
2624
+ const usage = blocks2[blocks2.length - 1];
2499
2625
  if (usage?.type !== "usage") return null;
2500
2626
  const parts = usageMeasures(usage.totals, false);
2501
2627
  if (usage.model && !usage.contextFill) parts.push("ctx unknown");
@@ -2521,7 +2647,7 @@ function taskUsageText(usage) {
2521
2647
 
2522
2648
  // src/commands/status.ts
2523
2649
  var import_fs4 = require("fs");
2524
- var import_core12 = require("@ordewell/core");
2650
+ var import_core14 = require("@ordewell/core");
2525
2651
  async function handleStatus(subArgs, injectedApi) {
2526
2652
  const sessionId = flag(subArgs, "--session-id");
2527
2653
  const workspace = flag(subArgs, "--workspace") || process.cwd();
@@ -2576,8 +2702,8 @@ function emitJson(payload, outputPath) {
2576
2702
  }
2577
2703
  function printOneSession(sessionId, meta, plan) {
2578
2704
  const allTasks = allTasksOf(plan);
2579
- const everyTask = (0, import_core12.flattenTasks)(allTasks);
2580
- const blocked = (0, import_core12.blockingFailures)(everyTask.map((t) => ({ ...t, subtasks: [], dependencies: t.dependencies ?? [] })));
2705
+ const everyTask = (0, import_core14.flattenTasks)(allTasks);
2706
+ const blocked = (0, import_core14.blockingFailures)(everyTask.map((t) => ({ ...t, subtasks: [], dependencies: t.dependencies ?? [] })));
2581
2707
  const count = (status) => everyTask.filter((t) => t.status === status || status === "blocked" && blocked.has(t.id)).length;
2582
2708
  console.log(`Session: ${sessionId}`);
2583
2709
  console.log(`Goal: ${meta.goal}`);
@@ -2585,25 +2711,25 @@ function printOneSession(sessionId, meta, plan) {
2585
2711
  console.log(`Phase: ${plan?.phase || "unknown"} | Created: ${meta.createdAt}`);
2586
2712
  console.log(`Tasks: ${everyTask.length} total | ${count("completed")} done | ${count("failed")} failed | ${count("in_progress")} running | ${count("blocked")} blocked | ${count("skipped")} skipped
2587
2713
  `);
2588
- const usage = (0, import_core12.planUsage)(allTasks);
2714
+ const usage = (0, import_core14.planUsage)(allTasks);
2589
2715
  if (usage.attempts) console.log(`Tasks total: ${taskUsageText(usage)}`);
2590
2716
  for (const t of allTasks) {
2591
2717
  const icon = iconFor(blocked.has(t.id) ? "blocked" : t.status);
2592
2718
  const model = t.assignedModel ? ` (${t.assignedModel.modelLabel})` : "";
2593
2719
  const shortId = (t.id ?? "").slice(-8);
2594
- console.log(` ${(0, import_core12.taskOrderLabel)(t).padStart(2)}. ${icon} [${shortId}] ${t.title}${model}`);
2595
- const row = (0, import_core12.taskRowView)({ ...t, dependencies: t.dependencies ?? [] }, { tasks: allTasks });
2596
- if (row.blockedBy) console.log(` ${(0, import_core12.blockedByLabel)(row.blockedBy)}`);
2597
- if (row.status === "skipped") console.log(` ${(0, import_core12.skippedLabel)(row.skipReason)}`);
2720
+ console.log(` ${(0, import_core14.taskOrderLabel)(t).padStart(2)}. ${icon} [${shortId}] ${t.title}${model}`);
2721
+ const row = (0, import_core14.taskRowView)({ ...t, dependencies: t.dependencies ?? [] }, { tasks: allTasks });
2722
+ if (row.blockedBy) console.log(` ${(0, import_core14.blockedByLabel)(row.blockedBy)}`);
2723
+ if (row.status === "skipped") console.log(` ${(0, import_core14.skippedLabel)(row.skipReason)}`);
2598
2724
  if (row.usage) console.log(` ${taskUsageText(row.usage)}`);
2599
2725
  for (const sub of t.subtasks || []) {
2600
2726
  const subIcon = iconFor(blocked.has(sub.id) ? "blocked" : sub.status);
2601
2727
  const subModel = sub.assignedModel ? ` (${sub.assignedModel.modelLabel})` : "";
2602
2728
  const subShortId = (sub.id ?? "").slice(-8);
2603
- console.log(` ${(0, import_core12.taskOrderLabel)(sub, t)}. ${subIcon} [${subShortId}] ${sub.title}${subModel}`);
2604
- const subRow = (0, import_core12.taskRowView)({ ...sub, dependencies: sub.dependencies ?? [] }, { parent: t, tasks: allTasks });
2605
- if (subRow.blockedBy) console.log(` ${(0, import_core12.blockedByLabel)(subRow.blockedBy)}`);
2606
- if (subRow.status === "skipped") console.log(` ${(0, import_core12.skippedLabel)(subRow.skipReason)}`);
2729
+ console.log(` ${(0, import_core14.taskOrderLabel)(sub, t)}. ${subIcon} [${subShortId}] ${sub.title}${subModel}`);
2730
+ const subRow = (0, import_core14.taskRowView)({ ...sub, dependencies: sub.dependencies ?? [] }, { parent: t, tasks: allTasks });
2731
+ if (subRow.blockedBy) console.log(` ${(0, import_core14.blockedByLabel)(subRow.blockedBy)}`);
2732
+ if (subRow.status === "skipped") console.log(` ${(0, import_core14.skippedLabel)(subRow.skipReason)}`);
2607
2733
  if (subRow.usage) console.log(` ${taskUsageText(subRow.usage)}`);
2608
2734
  }
2609
2735
  }
@@ -2656,10 +2782,10 @@ async function handleWeb(subArgs) {
2656
2782
  }
2657
2783
 
2658
2784
  // src/commands/models.ts
2659
- var import_core14 = require("@ordewell/core");
2785
+ var import_core16 = require("@ordewell/core");
2660
2786
 
2661
2787
  // src/commands/model.ts
2662
- var import_core13 = require("@ordewell/core");
2788
+ var import_core15 = require("@ordewell/core");
2663
2789
  var USAGE = "Usage: ordewell model [show | set <model-id>]";
2664
2790
  async function handleModel(subArgs, injectedApi) {
2665
2791
  const [action, modelId] = positionals(subArgs);
@@ -2674,7 +2800,7 @@ async function handleModel(subArgs, injectedApi) {
2674
2800
  if (!modelId) fail(USAGE);
2675
2801
  const settings = await api.getSettings();
2676
2802
  const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
2677
- const runner = (0, import_core13.runnerForProvider)(provider);
2803
+ const runner = (0, import_core15.runnerForProvider)(provider);
2678
2804
  if (runner) {
2679
2805
  const known = (await fetchCatalog(api)).models.filter((m) => m.runners?.includes(runner));
2680
2806
  if (known.length > 0 && !known.some((m) => m.id === modelId)) {
@@ -2697,7 +2823,7 @@ async function showModels(api) {
2697
2823
  const [settings, catalog] = await Promise.all([api.getSettings(), fetchCatalog(api)]);
2698
2824
  const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
2699
2825
  const current = typeof settings.orchestratorModel === "string" ? settings.orchestratorModel : "";
2700
- const runner = (0, import_core13.runnerForProvider)(provider);
2826
+ const runner = (0, import_core15.runnerForProvider)(provider);
2701
2827
  const options = runner ? catalog.models.filter((m) => m.runners?.includes(runner)) : catalog.orchestratorModels;
2702
2828
  console.log(`
2703
2829
  Planner model: ${current || "(backend default)"}`);
@@ -2731,8 +2857,8 @@ async function handleModels(subArgs) {
2731
2857
  const rest = subArgs.filter((_, i) => i !== setIdx && i !== setIdx + 1);
2732
2858
  return handleModel(["set", subArgs[setIdx + 1], ...rest]);
2733
2859
  }
2734
- const config = new import_core14.EnvConfig();
2735
- const providers = (0, import_core14.configuredProviders)(config);
2860
+ const config = new import_core16.EnvConfig();
2861
+ const providers = (0, import_core16.configuredProviders)(config);
2736
2862
  if (providers.length === 0) {
2737
2863
  console.error("No providers configured. Set an API key for a provider, e.g.:");
2738
2864
  console.error(" OPENROUTER_API_KEY=... (OpenRouter)");
@@ -2741,19 +2867,19 @@ async function handleModels(subArgs) {
2741
2867
  console.error(" OPENAI_COMPATIBLE_BASE_URL=... (self-hosted / OpenAI-compatible)");
2742
2868
  process.exit(1);
2743
2869
  }
2744
- const { apiKeys, baseUrls } = (0, import_core14.collectProviderCredentials)(config);
2870
+ const { apiKeys, baseUrls } = (0, import_core16.collectProviderCredentials)(config);
2745
2871
  let models;
2746
2872
  let errors;
2747
2873
  try {
2748
- const result = await (0, import_core14.fetchAllProviderModels)({ apiKeys, baseUrls });
2749
- models = (0, import_core14.toOrchestratorOptions)(result.models, import_core14.ORCHESTRATOR_SHORTCUTS);
2874
+ const result = await (0, import_core16.fetchAllProviderModels)({ apiKeys, baseUrls });
2875
+ models = (0, import_core16.toOrchestratorOptions)(result.models, import_core16.ORCHESTRATOR_SHORTCUTS);
2750
2876
  errors = result.errors;
2751
2877
  } catch (err) {
2752
2878
  console.error(`Failed to fetch models: ${err instanceof Error ? err.message : String(err)}`);
2753
2879
  process.exit(1);
2754
2880
  return;
2755
2881
  }
2756
- const providerLabel = (p) => (0, import_core14.getProviderMeta)(p)?.label ?? p;
2882
+ const providerLabel = (p) => (0, import_core16.getProviderMeta)(p)?.label ?? p;
2757
2883
  console.log(
2758
2884
  `
2759
2885
  Available models (${models.length}) across ${providers.length} configured provider(s):`
@@ -2793,7 +2919,7 @@ ${providerLabel(provider)}`);
2793
2919
 
2794
2920
  // src/commands/setup.ts
2795
2921
  var import_fs6 = require("fs");
2796
- var import_core15 = require("@ordewell/core");
2922
+ var import_core17 = require("@ordewell/core");
2797
2923
  function handleSetup(subArgs) {
2798
2924
  const modelIdx = subArgs.indexOf("--model");
2799
2925
  const chosenModel = modelIdx !== -1 ? subArgs[modelIdx + 1] : null;
@@ -2838,7 +2964,7 @@ function handleSetup(subArgs) {
2838
2964
 
2839
2965
  # Or plan with a coding agent you already have installed \u2014 no API key needed,
2840
2966
  # it uses that agent's own subscription. Set the model to one of its own.
2841
- # AI_PROVIDER=claude-code|codex|opencode
2967
+ # AI_PROVIDER=${runnerIdChoice()}
2842
2968
  # ORCHESTRATOR_MODEL=haiku
2843
2969
  # ORDEWELL_PLANNER_EFFORT=low
2844
2970
 
@@ -2865,13 +2991,13 @@ function handleSetup(subArgs) {
2865
2991
  # STEPFUN_API_KEY=...
2866
2992
  # SILICONFLOW_API_KEY=...
2867
2993
  `;
2868
- (0, import_core15.writePrivateFile)(envFile, content);
2994
+ (0, import_core17.writePrivateFile)(envFile, content);
2869
2995
  console.log(`Wrote: ${envFile}`);
2870
2996
  console.log("Review and edit the file, then run: ordewell tui");
2871
2997
  }
2872
2998
 
2873
2999
  // src/commands/skills.ts
2874
- var import_core16 = require("@ordewell/core");
3000
+ var import_core18 = require("@ordewell/core");
2875
3001
  var import_path5 = require("path");
2876
3002
  function invocation(skill) {
2877
3003
  if (skill.userInvocable && skill.modelInvocable) return "both";
@@ -2884,22 +3010,22 @@ function handleSkills(subArgs) {
2884
3010
  fail("Usage: ordewell skills [--workspace /path] [--json]");
2885
3011
  }
2886
3012
  const workspace = (0, import_path5.resolve)(flag(subArgs, "--workspace") || process.cwd());
2887
- const catalog = (0, import_core16.createSkillsService)(workspace, new import_core16.EnvConfig().workspaceRepos).readCatalog();
3013
+ const catalog = (0, import_core18.createSkillsService)(workspace, new import_core18.EnvConfig().workspaceRepos).readCatalog();
2888
3014
  const skills = catalog.skills.map((skill) => ({
2889
3015
  name: skill.name,
2890
3016
  scope: skill.source,
2891
3017
  appliesTo: skill.appliesTo,
2892
3018
  invocation: invocation(skill),
2893
- path: (0, import_core16.abbreviateHome)(skill.path)
3019
+ path: (0, import_core18.abbreviateHome)(skill.path)
2894
3020
  }));
2895
3021
  const shadowed = catalog.shadowed.map(({ skill, shadowedBy }) => ({
2896
3022
  name: skill.name,
2897
- path: (0, import_core16.abbreviateHome)(skill.path),
2898
- shadowedBy: { scope: shadowedBy.source, path: (0, import_core16.abbreviateHome)(shadowedBy.path) }
3023
+ path: (0, import_core18.abbreviateHome)(skill.path),
3024
+ shadowedBy: { scope: shadowedBy.source, path: (0, import_core18.abbreviateHome)(shadowedBy.path) }
2899
3025
  }));
2900
3026
  const invalid = catalog.invalid.map((skill) => ({
2901
3027
  name: skill.name,
2902
- path: (0, import_core16.abbreviateHome)(skill.path),
3028
+ path: (0, import_core18.abbreviateHome)(skill.path),
2903
3029
  reason: skill.reason
2904
3030
  }));
2905
3031
  if (hasFlag(subArgs, "--json")) {
@@ -3014,7 +3140,7 @@ async function handleShow(args, api) {
3014
3140
  }
3015
3141
 
3016
3142
  // src/commands/task-control.ts
3017
- var import_core17 = require("@ordewell/core");
3143
+ var import_core19 = require("@ordewell/core");
3018
3144
  var PAST_TENSE = {
3019
3145
  run: "Task started.",
3020
3146
  "force-start": "Task force-started.",
@@ -3057,7 +3183,7 @@ async function confirmPastGate(subArgs, api, sessionId, taskId, confirm2) {
3057
3183
  if (hasFlag(subArgs, "--yes")) return;
3058
3184
  const unmerged = await api.getMergeGate(sessionId, taskId).catch(() => []);
3059
3185
  if (unmerged.length === 0) return;
3060
- const question = `${(0, import_core17.pastGateConfirmation)(unmerged.map((d) => (0, import_core17.titledTaskRef)(d)))} Start it anyway?`;
3186
+ const question = `${(0, import_core19.pastGateConfirmation)(unmerged.map((d) => (0, import_core19.titledTaskRef)(d)))} Start it anyway?`;
3061
3187
  if (!await confirm2(question)) fail("Not started \u2014 nothing was changed. Pass --yes to start it without a prompt.");
3062
3188
  }
3063
3189
  function makeHandler(action, command = action) {
@@ -3370,24 +3496,24 @@ async function handleRewind(subArgs, injectedApi) {
3370
3496
  }
3371
3497
 
3372
3498
  // src/tui/transcript.ts
3373
- var import_core18 = require("@ordewell/core");
3499
+ var import_core20 = require("@ordewell/core");
3374
3500
  function show(state, { view: conversation, gate: turnGate }) {
3375
3501
  const gated = turnGate === state.turnGate ? state : { ...state, turnGate };
3376
3502
  if (conversation === state.conversation) return gated;
3377
3503
  return { ...gated, conversation };
3378
3504
  }
3379
3505
  function fold(state, input) {
3380
- return show(state, { view: (0, import_core18.reduceConversation)(state.conversation, input), gate: state.turnGate });
3506
+ return show(state, { view: (0, import_core20.reduceConversation)(state.conversation, input), gate: state.turnGate });
3381
3507
  }
3382
3508
  function say(state, role, text) {
3383
3509
  const said = fold(state, { type: "local_entry", role, text });
3384
3510
  return said.conversation.nextId > state.conversation.nextId ? { ...said, scroll: 0 } : said;
3385
3511
  }
3386
3512
  function hear(state, message) {
3387
- return show(state, (0, import_core18.followTurn)(state.conversation, state.turnGate, message));
3513
+ return show(state, (0, import_core20.followTurn)(state.conversation, state.turnGate, message));
3388
3514
  }
3389
3515
  function cutTurn(state) {
3390
- return show(state, (0, import_core18.stopTurn)(state.conversation, state.turnGate));
3516
+ return show(state, (0, import_core20.stopTurn)(state.conversation, state.turnGate));
3391
3517
  }
3392
3518
  function wiped(view) {
3393
3519
  return { ...view, blocks: view.blocks.filter((b) => b.type === "usage") };
@@ -3636,7 +3762,7 @@ async function handleHandoff(subArgs, injectedApi, confirm2 = askYesNo) {
3636
3762
  }
3637
3763
 
3638
3764
  // src/commands/planner.ts
3639
- var import_core19 = require("@ordewell/core");
3765
+ var import_core21 = require("@ordewell/core");
3640
3766
 
3641
3767
  // src/plannerModelSwitch.ts
3642
3768
  function plannerSwitchRecall(settings) {
@@ -3646,7 +3772,6 @@ function plannerSwitchRecall(settings) {
3646
3772
  }
3647
3773
 
3648
3774
  // src/commands/planner.ts
3649
- var isAiProvider = (id) => Object.hasOwn(import_core19.ALL_PROVIDERS, id);
3650
3775
  async function handlePlanner(subArgs, injectedApi) {
3651
3776
  const api = await connect(subArgs, injectedApi);
3652
3777
  const [wanted] = positionals(subArgs);
@@ -3655,19 +3780,19 @@ async function handlePlanner(subArgs, injectedApi) {
3655
3780
  return;
3656
3781
  }
3657
3782
  const provider = wanted.toLowerCase();
3658
- if (!isAiProvider(provider)) {
3783
+ const meta = (0, import_core21.getProviderMeta)(provider);
3784
+ if (!meta) {
3659
3785
  fail(`Unknown planner: ${provider}`, "Run `ordewell planner` with no arguments to see the list.");
3660
3786
  }
3661
3787
  const settings = await persistEnv(api, { AI_PROVIDER: provider });
3662
3788
  const recall2 = plannerSwitchRecall(settings);
3663
3789
  writeEnv({ ORCHESTRATOR_MODEL: recall2.model, ORDEWELL_PLANNER_EFFORT: recall2.effort });
3664
- const meta = import_core19.ALL_PROVIDERS[provider];
3665
3790
  const catalog = await fetchCatalog(api);
3666
3791
  console.log(
3667
- (0, import_core19.isCliProvider)(provider) ? `Planning with ${meta.label} \u2014 no API key needed, it uses that agent's own subscription.` : `Planner set to ${meta.label}.`
3792
+ (0, import_core21.isCliProvider)(provider) ? `Planning with ${meta.label} \u2014 no API key needed, it uses that agent's own subscription.` : `Planner set to ${meta.label}.`
3668
3793
  );
3669
3794
  console.log(plannerModelLine(recall2));
3670
- if (!(0, import_core19.isCliProvider)(provider) && !catalog.providers.includes(provider)) {
3795
+ if ((0, import_core21.isApiProvider)(provider) && !catalog.providers.includes(provider)) {
3671
3796
  console.log(` No ${meta.apiKeyEnvVar} configured yet \u2014 set one with \`ordewell key set ${provider} <key>\`.`);
3672
3797
  }
3673
3798
  }
@@ -3685,15 +3810,15 @@ async function showPlanners(api) {
3685
3810
  const [settings, catalog] = await Promise.all([api.getSettings(), fetchCatalog(api)]);
3686
3811
  const current = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
3687
3812
  console.log("\nCoding agents (no API key \u2014 they use their own subscription)");
3688
- for (const id of import_core19.CLI_PROVIDERS) {
3689
- const runner = (0, import_core19.runnerForProvider)(id);
3813
+ for (const id of import_core21.CLI_PROVIDERS) {
3814
+ const runner = (0, import_core21.runnerForProvider)(id);
3690
3815
  const discovered = runner ? catalog.models.some((m) => m.runners?.includes(runner)) : false;
3691
- console.log(` ${marker(id === current)} ${id.padEnd(14)} ${import_core19.ALL_PROVIDERS[id].label}${discovered ? "" : " (not detected)"}`);
3816
+ console.log(` ${marker(id === current)} ${id.padEnd(14)} ${(0, import_core21.getProviderMeta)(id)?.label ?? id}${discovered ? "" : " (not detected)"}`);
3692
3817
  }
3693
3818
  console.log("\nAPI providers");
3694
- for (const id of import_core19.PROVIDER_PRIORITY) {
3819
+ for (const id of import_core21.PROVIDER_PRIORITY) {
3695
3820
  const configured = catalog.providers.includes(id);
3696
- const meta = import_core19.ALL_PROVIDERS[id];
3821
+ const meta = (0, import_core21.getProviderMeta)(id);
3697
3822
  console.log(` ${marker(id === current)} ${id.padEnd(14)} ${meta.label}${configured ? "" : ` (no ${meta.apiKeyEnvVar})`}`);
3698
3823
  }
3699
3824
  console.log(`
@@ -3710,11 +3835,11 @@ async function handlePlannerEffort(subArgs, injectedApi) {
3710
3835
  const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
3711
3836
  const modelId = typeof settings.orchestratorModel === "string" ? settings.orchestratorModel : "";
3712
3837
  const currentEffort = typeof settings.plannerThinkingEffort === "string" ? settings.plannerThinkingEffort : "";
3713
- const runner = isAiProvider(provider) ? (0, import_core19.runnerForProvider)(provider) : null;
3838
+ const runner = (0, import_core21.runnerForProvider)(provider);
3714
3839
  if (!runner) {
3715
3840
  fail(
3716
3841
  "Thinking effort applies to a coding-agent planner.",
3717
- "Switch with: ordewell planner claude-code|codex|opencode"
3842
+ `Switch with: ordewell planner ${runnerIdChoice()}`
3718
3843
  );
3719
3844
  }
3720
3845
  const model = catalog.models.find((m) => m.id === modelId && m.runners?.includes(runner));
@@ -3750,7 +3875,7 @@ async function handlePlannerEffort(subArgs, injectedApi) {
3750
3875
  }
3751
3876
 
3752
3877
  // src/commands/parallel.ts
3753
- var import_core20 = require("@ordewell/core");
3878
+ var import_core22 = require("@ordewell/core");
3754
3879
  var USAGE5 = "Usage: ordewell parallel [<number of tasks, 1 or more>]";
3755
3880
  async function handleParallel(subArgs, injectedApi) {
3756
3881
  const [wanted] = positionals(subArgs);
@@ -3760,14 +3885,14 @@ async function handleParallel(subArgs, injectedApi) {
3760
3885
  console.log(`Up to ${String(settings.maxParallel ?? "?")} AI tasks run at once. Change with: ordewell parallel <n>`);
3761
3886
  return;
3762
3887
  }
3763
- const limit = (0, import_core20.parseMaxParallel)(wanted);
3888
+ const limit = (0, import_core22.parseMaxParallel)(wanted);
3764
3889
  if (limit === null) fail(`"${wanted}" is not a number of tasks (1 or more).`, USAGE5);
3765
3890
  await persistEnv(api, { ORDEWELL_MAX_PARALLEL: String(limit) });
3766
3891
  console.log(`Up to ${limit} AI task${limit === 1 ? "" : "s"} now run at once.`);
3767
3892
  }
3768
3893
 
3769
3894
  // src/commands/runSettings.ts
3770
- var import_core21 = require("@ordewell/core");
3895
+ var import_core23 = require("@ordewell/core");
3771
3896
  var SUPERVISOR_USAGE = "Usage: ordewell supervisor [off|watch|act] \xB7 ordewell supervisor retries <n> \xB7 ordewell supervisor reads <n>";
3772
3897
  var AUTOMERGE_USAGE = "Usage: ordewell automerge [on|off]";
3773
3898
  var AUTORUN_USAGE = "Usage: ordewell autorun [on|off]";
@@ -3778,28 +3903,28 @@ async function handleSupervisor(subArgs, injectedApi) {
3778
3903
  const [arg, value] = positionals(subArgs);
3779
3904
  let changes = null;
3780
3905
  if (arg === "off" || arg === "watch" || arg === "act") changes = { supervisorLevel: arg };
3781
- else if (arg === "retries") changes = maybe((0, import_core21.parseCount)(value, 0), (n) => ({ supervisorRetryLimit: n }));
3782
- else if (arg === "reads") changes = maybe((0, import_core21.parseCount)(value, 1), (n) => ({ wakeUpReadBudget: n }));
3906
+ else if (arg === "retries") changes = maybe((0, import_core23.parseCount)(value, 0), (n) => ({ supervisorRetryLimit: n }));
3907
+ else if (arg === "reads") changes = maybe((0, import_core23.parseCount)(value, 1), (n) => ({ wakeUpReadBudget: n }));
3783
3908
  if (arg !== void 0 && changes === null) fail(SUPERVISOR_USAGE);
3784
3909
  const api = await connect(subArgs, injectedApi);
3785
3910
  if (!changes) {
3786
- console.log((0, import_core21.supervisorSummary)((await api.getSettings()).run));
3911
+ console.log((0, import_core23.supervisorSummary)((await api.getSettings()).run));
3787
3912
  console.log(` ${SUPERVISOR_USAGE}`);
3788
3913
  return;
3789
3914
  }
3790
3915
  await save(api, changes);
3791
- if (changes.supervisorLevel) console.log(`Supervisor: ${import_core21.SUPERVISOR_LEVEL_LABEL[changes.supervisorLevel]}, from each session's next run.`);
3792
- if (changes.supervisorLevel === "act") console.log(import_core21.ACT_RISK);
3916
+ if (changes.supervisorLevel) console.log(`Supervisor: ${import_core23.SUPERVISOR_LEVEL_LABEL[changes.supervisorLevel]}, from each session's next run.`);
3917
+ if (changes.supervisorLevel === "act") console.log(import_core23.ACT_RISK);
3793
3918
  if (changes.supervisorRetryLimit !== void 0) console.log(`Supervisor retry limit: ${changes.supervisorRetryLimit} per task.`);
3794
3919
  if (changes.wakeUpReadBudget !== void 0) console.log(`Wake-up read budget: ${changes.wakeUpReadBudget} reads.`);
3795
3920
  }
3796
3921
  async function handleAutomerge(subArgs, injectedApi) {
3797
3922
  const [arg] = positionals(subArgs);
3798
- const enabled = arg === void 0 ? null : (0, import_core21.parseSwitch)(arg);
3923
+ const enabled = arg === void 0 ? null : (0, import_core23.parseSwitch)(arg);
3799
3924
  if (arg !== void 0 && enabled === null) fail(AUTOMERGE_USAGE);
3800
3925
  const api = await connect(subArgs, injectedApi);
3801
3926
  if (enabled === null) {
3802
- console.log((0, import_core21.automergeSummary)((await api.getSettings()).run));
3927
+ console.log((0, import_core23.automergeSummary)((await api.getSettings()).run));
3803
3928
  console.log(` ${AUTOMERGE_USAGE}`);
3804
3929
  return;
3805
3930
  }
@@ -3808,24 +3933,24 @@ async function handleAutomerge(subArgs, injectedApi) {
3808
3933
  }
3809
3934
  async function handleAutorun(subArgs, injectedApi) {
3810
3935
  const [arg] = positionals(subArgs);
3811
- const enabled = arg === void 0 ? null : (0, import_core21.parseSwitch)(arg);
3936
+ const enabled = arg === void 0 ? null : (0, import_core23.parseSwitch)(arg);
3812
3937
  if (arg !== void 0 && enabled === null) fail(AUTORUN_USAGE);
3813
3938
  const api = await connect(subArgs, injectedApi);
3814
3939
  if (enabled === null) {
3815
- console.log((0, import_core21.autorunSummary)((await api.getSettings()).run));
3940
+ console.log((0, import_core23.autorunSummary)((await api.getSettings()).run));
3816
3941
  console.log(` ${AUTORUN_USAGE}`);
3817
3942
  return;
3818
3943
  }
3819
3944
  await save(api, { autorun: enabled });
3820
3945
  console.log(`Autorun: ${enabled ? "on \u2014 each plan the planner submits starts at once" : "off \u2014 plans wait for your review"}.`);
3821
- if (enabled) console.log(import_core21.AUTORUN_RISK);
3946
+ if (enabled) console.log(import_core23.AUTORUN_RISK);
3822
3947
  }
3823
3948
  function maybe(n, wrap2) {
3824
3949
  return n === null ? null : wrap2(n);
3825
3950
  }
3826
3951
 
3827
3952
  // src/commands/key.ts
3828
- var import_core22 = require("@ordewell/core");
3953
+ var import_core24 = require("@ordewell/core");
3829
3954
  var USAGE6 = "Usage: ordewell key [list | set <provider> <key>]";
3830
3955
  async function handleKey(subArgs, injectedApi) {
3831
3956
  const [action, provider, ...keyParts] = positionals(subArgs);
@@ -3836,8 +3961,8 @@ async function handleKey(subArgs, injectedApi) {
3836
3961
  if (action !== "set") {
3837
3962
  const catalog = await fetchCatalog(api);
3838
3963
  console.log("\nAPI provider keys\n");
3839
- for (const id2 of import_core22.PROVIDER_PRIORITY) {
3840
- const meta2 = import_core22.ALL_PROVIDERS[id2];
3964
+ for (const id2 of import_core24.PROVIDER_PRIORITY) {
3965
+ const meta2 = (0, import_core24.getProviderMeta)(id2);
3841
3966
  const configured = catalog.providers.includes(id2);
3842
3967
  console.log(` ${configured ? "\u2713" : " "} ${id2.padEnd(14)} ${meta2.apiKeyEnvVar.padEnd(28)} ${meta2.label}`);
3843
3968
  }
@@ -3847,10 +3972,10 @@ async function handleKey(subArgs, injectedApi) {
3847
3972
  }
3848
3973
  if (!provider) fail(USAGE6);
3849
3974
  const id = provider.toLowerCase();
3850
- const meta = import_core22.ALL_PROVIDERS[id];
3851
- if (!meta) {
3975
+ if (!(0, import_core24.isApiProvider)(id)) {
3852
3976
  fail(`Unknown provider: ${provider}`, "Run `ordewell key` to see the list.");
3853
3977
  }
3978
+ const meta = (0, import_core24.getProviderMeta)(id);
3854
3979
  const key = keyParts.join(" ").trim();
3855
3980
  if (!key) fail(`Usage: ordewell key set ${id} <key>`);
3856
3981
  await persistEnv(api, { [meta.apiKeyEnvVar]: key });
@@ -3858,7 +3983,7 @@ async function handleKey(subArgs, injectedApi) {
3858
3983
  }
3859
3984
 
3860
3985
  // src/commands/runners.ts
3861
- var import_core23 = require("@ordewell/core");
3986
+ var import_core25 = require("@ordewell/core");
3862
3987
  var USAGE7 = "Usage: ordewell runners [<runner-id> on|off]";
3863
3988
  async function handleRunners(subArgs, injectedApi) {
3864
3989
  const [runner, toggle] = positionals(subArgs);
@@ -3869,7 +3994,7 @@ async function handleRunners(subArgs, injectedApi) {
3869
3994
  for (const r of state2.runners) {
3870
3995
  console.log(` ${r.enabled ? "\u2713" : " "} ${r.id.padEnd(14)} ${r.name}${r.enabled ? "" : " (disabled)"}`);
3871
3996
  }
3872
- const notice = (0, import_core23.codexSandboxNotice)((await fetchCatalog(api).catch(() => null))?.modesByRunner);
3997
+ const notice = (0, import_core25.codexSandboxNotice)((await fetchCatalog(api).catch(() => null))?.modesByRunner);
3873
3998
  if (notice) console.log(`
3874
3999
  ${notice.line}
3875
4000
  ${notice.docs}`);
@@ -3890,17 +4015,17 @@ async function handleRunners(subArgs, injectedApi) {
3890
4015
  var AUTO_USAGE = "Usage: ordewell auto [full|guarded]";
3891
4016
  function handleAuto(subArgs) {
3892
4017
  const [arg] = positionals(subArgs);
3893
- const settings = new import_core23.SettingsService();
4018
+ const settings = new import_core25.SettingsService();
3894
4019
  const current = settings.autonomousMode();
3895
4020
  if (!arg) {
3896
- console.log(`Autonomy level: ${(0, import_core23.autonomyLevelLabel)(current)}`);
4021
+ console.log(`Autonomy level: ${(0, import_core25.autonomyLevelLabel)(current)}`);
3897
4022
  console.log(` ${AUTO_USAGE}`);
3898
4023
  return;
3899
4024
  }
3900
- const enabled = (0, import_core23.parseAutonomyLevel)(arg);
4025
+ const enabled = (0, import_core25.parseAutonomyLevel)(arg);
3901
4026
  if (enabled === null) fail(AUTO_USAGE);
3902
4027
  settings.setAutonomousMode(enabled);
3903
- console.log(settings.autonomousModeOverridden() ? `${(0, import_core23.autonomyLevelLabel)(enabled)} is saved, but ORDEWELL_AUTONOMOUS_MODE in the environment decides the level until it is unset.` : `Autonomy level: ${(0, import_core23.autonomyLevelLabel)(enabled)} for new plans.`);
4028
+ console.log(settings.autonomousModeOverridden() ? `${(0, import_core25.autonomyLevelLabel)(enabled)} is saved, but ORDEWELL_AUTONOMOUS_MODE in the environment decides the level until it is unset.` : `Autonomy level: ${(0, import_core25.autonomyLevelLabel)(enabled)} for new plans.`);
3904
4029
  }
3905
4030
  async function handleRefresh(subArgs, injectedApi) {
3906
4031
  const api = await connect(subArgs, injectedApi);
@@ -3930,7 +4055,7 @@ async function handleApprove(subArgs, injectedApi) {
3930
4055
  }
3931
4056
 
3932
4057
  // src/commands/task-assign.ts
3933
- var import_core25 = require("@ordewell/core");
4058
+ var import_core27 = require("@ordewell/core");
3934
4059
  var import_plan_utils = require("@ordewell/core/plan-utils");
3935
4060
 
3936
4061
  // src/tui/taskAssignment.ts
@@ -3970,7 +4095,7 @@ function modesForTask(modesByRunner, task) {
3970
4095
  }
3971
4096
 
3972
4097
  // src/tui/state.ts
3973
- var import_core24 = require("@ordewell/core");
4098
+ var import_core26 = require("@ordewell/core");
3974
4099
 
3975
4100
  // src/tui/editor.ts
3976
4101
  function emptyEditor() {
@@ -4128,7 +4253,7 @@ function queuedTarget(tv) {
4128
4253
  for (let i = queued.length - 1; i >= 0; i--) if (!queued[i].forced) return i;
4129
4254
  return -1;
4130
4255
  }
4131
- var anyTaskRunning = (state) => state.tasks.some(import_core24.isTaskRunning);
4256
+ var anyTaskRunning = (state) => state.tasks.some(import_core26.isTaskRunning);
4132
4257
  var plannerInFlight = (state) => state.planner !== "idle";
4133
4258
  var planPaneOpen = (state) => state.focus === "plan" && !state.overlay && (!!state.taskEditor || !!state.expandedTaskId);
4134
4259
  function planRows(state) {
@@ -4148,8 +4273,8 @@ function selectedPlanRow(state) {
4148
4273
  }
4149
4274
  function runnerCommands(tv) {
4150
4275
  for (let i = tv.view.blocks.length - 1; i >= 0; i--) {
4151
- const block = tv.view.blocks[i];
4152
- if (block.type === "runner_loaded") return block.commands;
4276
+ const block2 = tv.view.blocks[i];
4277
+ if (block2.type === "runner_loaded") return block2.commands;
4153
4278
  }
4154
4279
  return [];
4155
4280
  }
@@ -4174,10 +4299,10 @@ function findTask(tasks, id) {
4174
4299
  return void 0;
4175
4300
  }
4176
4301
  function refFor(state, task) {
4177
- return (0, import_core24.taskRefOf)(state.tasks, task.id) ?? (0, import_core24.taskRef)(task);
4302
+ return (0, import_core26.taskRefOf)(state.tasks, task.id) ?? (0, import_core26.taskRef)(task);
4178
4303
  }
4179
4304
  function titledRefFor(state, task) {
4180
- return (0, import_core24.titledTaskRefOf)(state.tasks, task.id) ?? (0, import_core24.titledTaskRef)(task);
4305
+ return (0, import_core26.titledTaskRefOf)(state.tasks, task.id) ?? (0, import_core26.titledTaskRef)(task);
4181
4306
  }
4182
4307
  function asRunTasks(tasks) {
4183
4308
  return tasks.map((task) => ({ ...task, subtasks: asRunTasks(task.subtasks ?? []) }));
@@ -4185,7 +4310,7 @@ function asRunTasks(tasks) {
4185
4310
  function seedRun(overrides) {
4186
4311
  if (overrides.run) return overrides.run;
4187
4312
  return {
4188
- ...import_core24.EMPTY_RUN,
4313
+ ...import_core26.EMPTY_RUN,
4189
4314
  tasks: asRunTasks(overrides.tasks ?? []),
4190
4315
  handoff: overrides.handoff ?? null,
4191
4316
  runMerge: overrides.runMerge ? { waitingAtGate: overrides.runMerge.waitingAtGate, paused: overrides.runMerge.paused, repos: overrides.runMerge.handoff.repos, landed: overrides.runMerge.handoff.landed } : null
@@ -4194,9 +4319,9 @@ function seedRun(overrides) {
4194
4319
  function initialState(overrides = {}) {
4195
4320
  return {
4196
4321
  editor: emptyEditor(),
4197
- conversation: import_core24.EMPTY_CONVERSATION,
4322
+ conversation: import_core26.EMPTY_CONVERSATION,
4198
4323
  taskView: null,
4199
- turnGate: import_core24.NO_TURN,
4324
+ turnGate: import_core26.NO_TURN,
4200
4325
  detailAll: false,
4201
4326
  status: "idle",
4202
4327
  planner: "idle",
@@ -4222,11 +4347,11 @@ function initialState(overrides = {}) {
4222
4347
  plannerProvider: "",
4223
4348
  plannerEffort: "",
4224
4349
  plannerModels: {},
4225
- maxParallel: import_core24.DEFAULT_MAX_PARALLEL,
4350
+ maxParallel: import_core26.DEFAULT_MAX_PARALLEL,
4226
4351
  configuredProviders: [],
4227
4352
  allowlist: {},
4228
4353
  autonomous: true,
4229
- runSettings: { ...import_core24.RUN_SETTINGS_DEFAULTS },
4354
+ runSettings: { ...import_core26.RUN_SETTINGS_DEFAULTS },
4230
4355
  runAutoMerge: null,
4231
4356
  runSupervisor: null,
4232
4357
  mouseCapture: true,
@@ -4236,7 +4361,7 @@ function initialState(overrides = {}) {
4236
4361
  runMerge: null,
4237
4362
  overlay: null,
4238
4363
  pendingApprovals: [],
4239
- queuedPrompts: import_core24.EMPTY_HOLD,
4364
+ queuedPrompts: import_core26.EMPTY_HOLD,
4240
4365
  stopArmed: false,
4241
4366
  stopArmToken: 0,
4242
4367
  stopRequested: false,
@@ -4370,7 +4495,7 @@ Mode \xB7 ${namedOf(tasks, task)}${task.assignedRunner ? ` (${task.assignedRunne
4370
4495
  for (const m of modes) {
4371
4496
  console.log(` ${m.id === task.taskMode ? "*" : " "} ${m.id.padEnd(14)} ${m.label}${m.unavailable ? " \u2014 unavailable on this host" : m.description ? ` \u2014 ${m.description}` : ""}`);
4372
4497
  }
4373
- const notice = (0, import_core25.codexSandboxNotice)(catalog.modesByRunner);
4498
+ const notice = (0, import_core27.codexSandboxNotice)(catalog.modesByRunner);
4374
4499
  if (notice) console.log(`
4375
4500
  ${notice.line}
4376
4501
  ${notice.docs}`);
@@ -4419,7 +4544,7 @@ var SKILLS_USAGE = "Usage: ordewell task-skills <task-id-or-order> [<name> [<nam
4419
4544
  async function handleTaskSkills(subArgs, injectedApi) {
4420
4545
  await withTask(subArgs, SKILLS_USAGE, injectedApi, async (api, sessionId, task, tasks, value) => {
4421
4546
  if (task.type !== "ai") fail("Manual tasks do not run an executor, so they take no skills.");
4422
- const catalog = (0, import_core25.createSkillsService)(flag(subArgs, "--workspace") || process.cwd(), new import_core25.EnvConfig().workspaceRepos).listSkills().filter((s) => s.appliesTo === "task");
4547
+ const catalog = (0, import_core27.createSkillsService)(flag(subArgs, "--workspace") || process.cwd(), new import_core27.EnvConfig().workspaceRepos).listSkills().filter((s) => s.appliesTo === "task");
4423
4548
  if (!value) {
4424
4549
  console.log(`
4425
4550
  Skills \xB7 ${namedOf(tasks, task)}
@@ -4464,10 +4589,10 @@ ${namedOf(tasks, task)} is ${task.ops ? "an ops task: it runs in your checkout o
4464
4589
  }
4465
4590
 
4466
4591
  // src/tui/index.ts
4467
- var import_core45 = require("@ordewell/core");
4592
+ var import_core48 = require("@ordewell/core");
4468
4593
 
4469
4594
  // src/tui/slash.ts
4470
- var import_core26 = require("@ordewell/core");
4595
+ var import_core28 = require("@ordewell/core");
4471
4596
  var SLASH_COMMANDS = [
4472
4597
  // Planning. There is deliberately no `/plan`: typing the goal *is* the way to
4473
4598
  // start planning, and an alias for it only shadowed `/planner` on completion.
@@ -4485,6 +4610,7 @@ var SLASH_COMMANDS = [
4485
4610
  { name: "cancel", usage: "/cancel <id>", description: "Kill a running task", category: "tasks" },
4486
4611
  { name: "force-start", usage: "/force-start <id>", description: "Start a task now, ignoring dependencies", category: "tasks" },
4487
4612
  { name: "continue", usage: "/continue <id> <message>", description: "Continue a finished task in its saved runner session, with your message", category: "tasks" },
4613
+ { name: "open", usage: "/open <id>", description: "Open a task's view: its log, and the keys that answer its checkpoint or tool request", category: "tasks" },
4488
4614
  { name: "checkpoint", usage: "/checkpoint <id> approve|reject [reason]", description: "Answer the checkpoint a task waits at: approve lets it go on, reject tells it why not", category: "tasks" },
4489
4615
  { name: "task-runner", usage: "/task-runner <id> [runner]", description: "Choose or set a task's executor (re-picks its model and mode)", category: "tasks" },
4490
4616
  { name: "task-model", usage: "/task-model <id> [model]", description: "Choose or set a task's executor model", category: "tasks" },
@@ -4499,7 +4625,7 @@ var SLASH_COMMANDS = [
4499
4625
  { name: "planner-effort", usage: "/planner-effort [<level>]", description: "Thinking effort for a coding-agent planner", category: "models" },
4500
4626
  { name: "key", usage: "/key [set <provider> <key>]", description: "Configure API provider keys", category: "models" },
4501
4627
  { name: "allowlist", usage: "/allowlist [set <runner> <ids> | clear <runner>]", description: "Limit which models a runner may use", category: "models" },
4502
- { name: "runners", usage: "/runners [<id> on|off]", description: "Enable or disable runners (claude-code, opencode, codex)", category: "models" },
4628
+ { name: "runners", usage: "/runners [<id> on|off]", description: `Enable or disable runners (${runnerIdList()})`, category: "models" },
4503
4629
  { name: "auto", usage: "/auto [full|guarded]", description: "Autonomy level for new plans: Full or Guarded", category: "models" },
4504
4630
  { name: "supervisor", usage: "/supervisor [off|watch|act] \xB7 retries <n> \xB7 reads <n>", description: "Whether the planner watches or acts on your runs, now and from then on", category: "models" },
4505
4631
  { name: "automerge", usage: "/automerge [on|off]", description: "Merge into your branch by itself at merge gates and at the end of a run", category: "models" },
@@ -4585,7 +4711,7 @@ function parseRunnerCommand(text) {
4585
4711
  return match ? { name: match[1], args: (match[2] ?? "").trim() } : null;
4586
4712
  }
4587
4713
  function runnerCommandFor(commands, name) {
4588
- return (0, import_core26.findRunnerCommand)(commands, name) ?? (0, import_core26.findRunnerCommand)(commands, name.toLowerCase());
4714
+ return (0, import_core28.findRunnerCommand)(commands, name) ?? (0, import_core28.findRunnerCommand)(commands, name.toLowerCase());
4589
4715
  }
4590
4716
  function composerCompletions(token, runner) {
4591
4717
  if (runner) return token.start === 0 ? runner.filter((c) => c.name.toLowerCase().startsWith(token.name)).map((c) => c.name) : [];
@@ -4632,10 +4758,10 @@ function chatEditorRoomFor(state, active) {
4632
4758
  }
4633
4759
 
4634
4760
  // src/tui/layout.ts
4635
- var import_core29 = require("@ordewell/core");
4761
+ var import_core31 = require("@ordewell/core");
4636
4762
 
4637
4763
  // src/tui/reducers/pickers.ts
4638
- var import_core27 = require("@ordewell/core");
4764
+ var import_core29 = require("@ordewell/core");
4639
4765
  var import_plan_utils2 = require("@ordewell/core/plan-utils");
4640
4766
  var DEFAULT_EFFORT = "__runner_default__";
4641
4767
  function picker(title, items, action, extra = {}) {
@@ -4654,11 +4780,11 @@ function modelDetail(m) {
4654
4780
  function providerErrorHint(state) {
4655
4781
  const failed = Object.keys(state.providerErrors ?? {});
4656
4782
  if (failed.length === 0) return void 0;
4657
- const names = failed.map((p) => import_core27.ALL_PROVIDERS[p]?.label ?? p);
4783
+ const names = failed.map((p) => (0, import_core29.getProviderMeta)(p)?.label ?? p);
4658
4784
  return `\u26A0 Unavailable (key or fetch failed): ${names.join(", ")} \u2014 showing working providers only.`;
4659
4785
  }
4660
4786
  function plannerModelItems(state, provider, selectedId) {
4661
- const runner = (0, import_core27.runnerForProvider)(provider);
4787
+ const runner = (0, import_core29.runnerForProvider)(provider);
4662
4788
  if (!runner) {
4663
4789
  return state.orchestratorModels.map((m) => ({ id: m.id, label: m.label, detail: modelDetail(m), selected: m.id === selectedId }));
4664
4790
  }
@@ -4674,11 +4800,11 @@ function plannerModelItems(state, provider, selectedId) {
4674
4800
  return items.length > 0 ? items : [{ id: "", label: `No ${runner} models discovered yet`, detail: "run /refresh", disabled: true }];
4675
4801
  }
4676
4802
  function plannerHarnessModel(state, provider, modelId) {
4677
- const runner = (0, import_core27.runnerForProvider)(provider);
4803
+ const runner = (0, import_core29.runnerForProvider)(provider);
4678
4804
  return runner ? state.models.find((m) => m.id === modelId && m.runners?.includes(runner)) : void 0;
4679
4805
  }
4680
4806
  function plannerEffortItems(state, provider, modelId, selectedEffort) {
4681
- if (!(0, import_core27.runnerForProvider)(provider)) {
4807
+ if (!(0, import_core29.runnerForProvider)(provider)) {
4682
4808
  return [{ id: "", label: "Thinking effort applies to a coding-agent planner", detail: "switch with /planner", disabled: true }];
4683
4809
  }
4684
4810
  const model = plannerHarnessModel(state, provider, modelId);
@@ -4796,11 +4922,11 @@ function pickerItemsFor(state, action) {
4796
4922
  function plannerItems(state) {
4797
4923
  const installed = new Set(state.runners.map((r) => r.id));
4798
4924
  const usability = {};
4799
- for (const id of import_core27.CLI_PROVIDERS) {
4800
- const runner = (0, import_core27.runnerForProvider)(id);
4925
+ for (const id of import_core29.CLI_PROVIDERS) {
4926
+ const runner = (0, import_core29.runnerForProvider)(id);
4801
4927
  usability[runner] = installed.has(runner) ? { usable: true } : { usable: false, reason: "CLI not installed or not on PATH" };
4802
4928
  }
4803
- const entries = (0, import_core27.plannerBackendEntries)(usability, state.configuredProviders);
4929
+ const entries = (0, import_core29.plannerBackendEntries)(usability, state.configuredProviders);
4804
4930
  const items = entries.map((entry) => ({
4805
4931
  id: entry.id,
4806
4932
  label: entry.label,
@@ -4825,12 +4951,17 @@ function cliVersion() {
4825
4951
  }
4826
4952
 
4827
4953
  // src/tui/planKeys.ts
4828
- var import_core28 = require("@ordewell/core");
4954
+ var import_core30 = require("@ordewell/core");
4829
4955
  var PLAN_KEYS = {
4830
4956
  move: { keys: "up / down", meaning: "move between tasks", group: "Navigation" },
4831
4957
  scroll: { keys: "pgup / pgdn", meaning: "scroll the plan", group: "Navigation" },
4832
4958
  expand: { keys: "\u2192", meaning: "reveal a task's subtasks, then edit its prompt", group: "Navigation", hint: "\u2192 expand" },
4833
- log: { keys: "enter", meaning: "open the task's log and message its runner", group: "Navigation", hint: "enter log" },
4959
+ log: {
4960
+ keys: "enter",
4961
+ meaning: "open the task's log and message its runner \u2014 or, at a checkpoint, answer it",
4962
+ group: "Navigation",
4963
+ hint: (task) => task?.status === "awaiting_user" && task.awaitingReason === "checkpoint" ? "enter answer" : "enter log"
4964
+ },
4834
4965
  back: { keys: "esc", meaning: "collapse the task, or leave a task's log for the plan", group: "Navigation" },
4835
4966
  runner: { keys: "R", meaning: "pick the task's runner", group: "Assign" },
4836
4967
  model: { keys: "o", meaning: "pick the task's model", group: "Assign", hint: "o model" },
@@ -4847,7 +4978,7 @@ var PLAN_KEYS = {
4847
4978
  meaning: "cancel the task's runner, or keep a task paused on a usage limit from resuming on its own",
4848
4979
  group: "Run",
4849
4980
  // `c` cancels the resume while the task has one; it has no runner to cancel then.
4850
- hint: (task) => task && (0, import_core28.resumeLabel)(task) ? "c don't resume" : "c cancel"
4981
+ hint: (task) => task && (0, import_core30.resumeLabel)(task) ? "c don't resume" : "c cancel"
4851
4982
  },
4852
4983
  resume: { keys: "r", meaning: "resume a task paused on a usage limit now, once the limit has reset", group: "Run", hint: "r resume now" },
4853
4984
  resolve: { keys: "x", meaning: "resolve a merge conflict", group: "Run", hint: "x resolve conflict" },
@@ -4857,7 +4988,7 @@ var PLAN_KEYS = {
4857
4988
  meaning: "mark the task done, or take it back",
4858
4989
  group: "Status",
4859
4990
  // `m` toggles, so the hint names the direction it will go for this task.
4860
- hint: (task) => task && (0, import_core28.markAction)(task) === "uncomplete" ? "m undone" : "m done"
4991
+ hint: (task) => task && (0, import_core30.markAction)(task) === "uncomplete" ? "m undone" : "m done"
4861
4992
  },
4862
4993
  skip: { keys: "s", meaning: "skip the task: none of its work lands, and what depends on it goes ahead", group: "Status", hint: "s skip" },
4863
4994
  remove: { keys: "d", meaning: "remove the task", group: "Status" },
@@ -4884,7 +5015,7 @@ function hintOf(id, task) {
4884
5015
  }
4885
5016
  function taskKeyIds(task, runActive) {
4886
5017
  if (!task) return ["add"];
4887
- const row = (0, import_core28.taskRowView)(task);
5018
+ const row = (0, import_core30.taskRowView)(task);
4888
5019
  if (row.conflict) return ["resolve", "log"];
4889
5020
  if (row.actions.includes("resume-now") || row.resumes) {
4890
5021
  return [...row.actions.includes("resume-now") ? ["resume"] : [], ...row.resumes ? ["cancel"] : [], "skip", "log"];
@@ -4912,7 +5043,7 @@ function planFooterHints(task, runActive) {
4912
5043
  }
4913
5044
 
4914
5045
  // src/tui/layout.ts
4915
- var import_core30 = require("@ordewell/core");
5046
+ var import_core32 = require("@ordewell/core");
4916
5047
  var CHROME_ROWS = 1;
4917
5048
  function chatInputWrap(state) {
4918
5049
  const active = state.focus === "chat" && !state.overlay;
@@ -4931,15 +5062,17 @@ function footerHints(state) {
4931
5062
  const taskSends = !!tv && tv.view.working && !!state.editor.text.trim() && !continuesTask(findTask(state.tasks, tv.taskId));
4932
5063
  const sendNowHint = planning || taskSends ? "ctrl-s send now" : null;
4933
5064
  const stopRunnerHint = runnerStoppable(state) ? "ctrl-x stop runner" : null;
5065
+ const checkpointHints = tv && waitingCheckpoint(findTask(state.tasks, tv.taskId)) && !waitingApproval(tv) ? ["enter reply", "ctrl-y approve", "ctrl-g reject"] : [];
4934
5066
  if (state.focus === "plan") {
4935
5067
  if (state.taskEditor) {
4936
5068
  return ["type to edit prompt", "pgup/pgdn scroll", "alt-enter newline", "enter save", "esc cancel"];
4937
5069
  }
4938
5070
  return [...escHint ? [escHint] : [], ...planFooterHints(selected, state.status === "executing")];
4939
5071
  }
4940
- const detailHint = (0, import_core30.hasHiddenDetail)(state.taskView ? state.taskView.view.blocks : state.conversation.blocks) ? [state.detailAll ? "ctrl-o collapse all" : "ctrl-o expand all"] : [];
5072
+ const detailHint = (0, import_core32.hasHiddenDetail)(state.taskView ? state.taskView.view.blocks : state.conversation.blocks) ? [state.detailAll ? "ctrl-o collapse all" : "ctrl-o expand all"] : [];
4941
5073
  return [
4942
5074
  "/help",
5075
+ ...checkpointHints,
4943
5076
  ...stopRunnerHint ? [stopRunnerHint] : [],
4944
5077
  "tab plan",
4945
5078
  ...detailHint,
@@ -4995,12 +5128,12 @@ function queuedTaskBubble(message, target, sends, cols) {
4995
5128
  }
4996
5129
  function taskActivity(task, working) {
4997
5130
  if (task?.status === "completed" || task?.status === "failed") return task.status;
4998
- const approvals = (0, import_core30.approvalLabel)(task?.awaitingApproval);
5131
+ const approvals = (0, import_core32.approvalLabel)(task?.awaitingApproval);
4999
5132
  if (approvals) return inRow(approvals);
5000
5133
  if (working) return "working";
5001
5134
  if (task?.status === "awaiting_user") {
5002
- const resumes = (0, import_core30.resumeLabel)(task);
5003
- return [inRow((0, import_core30.awaitingLabel)(task) ?? "Waiting for your input"), resumes ? inRow(resumes) : ""].filter(Boolean).join(" \xB7 ");
5135
+ const resumes = (0, import_core32.resumeLabel)(task);
5136
+ return [inRow((0, import_core32.awaitingLabel)(task) ?? "Waiting for your input"), resumes ? inRow(resumes) : ""].filter(Boolean).join(" \xB7 ");
5004
5137
  }
5005
5138
  return task?.status ?? "";
5006
5139
  }
@@ -5013,7 +5146,7 @@ function taskHeaderLines(state, tv, cols) {
5013
5146
  taskActivity(task, tv.view.working)
5014
5147
  ].filter(Boolean);
5015
5148
  const approval = waitingApproval(tv);
5016
- const hint = approval ? ["ctrl-y allow", ...approval.allowForTask ? ["ctrl-t allow for task"] : [], "ctrl-g deny (composer text is the note)"] : waitingCheckpoint(task) ? ["ctrl-y approve", "ctrl-g reject (composer text is the reason)", "ctrl-x stop runner"] : task && (0, import_core30.resumeLabel)(task) ? ["ctrl-x don't resume"] : [...runnerStoppable(state) ? ["ctrl-x stop runner"] : [], "ctrl-r remove queued", "ctrl-s send now"];
5149
+ const hint = approval ? ["ctrl-y allow", ...approval.allowForTask ? ["ctrl-t allow for task"] : [], "ctrl-g deny (composer text is the note)"] : waitingCheckpoint(task) ? ["enter reply", "ctrl-y approve", "ctrl-g reject", "ctrl-x stop runner"] : task && (0, import_core32.resumeLabel)(task) ? ["ctrl-x don't resume"] : [...runnerStoppable(state) ? ["ctrl-x stop runner"] : [], "ctrl-r remove queued", "ctrl-s send now"];
5017
5150
  if (approval && waitingCheckpoint(task)) hint.push("then the checkpoint");
5018
5151
  const index = tv.attempts.indexOf(tv.attempt);
5019
5152
  if (tv.attempts.length > 1) hint.push(`alt\u2190/\u2192 attempt ${index >= 0 ? index + 1 : 1}/${tv.attempts.length}`);
@@ -5043,9 +5176,9 @@ function chatActivity(state) {
5043
5176
  const own = findTask(state.tasks, tv.taskId);
5044
5177
  const task = state.tasks.find((t) => t.subtasks?.some((s) => s.id === tv.taskId)) ?? own;
5045
5178
  if (!task) return null;
5046
- if ((0, import_core24.isTaskRunning)(task) || own && (0, import_core24.isTaskRunning)(own)) return { label: "Working\u2026", busy: true };
5179
+ if ((0, import_core26.isTaskRunning)(task) || own && (0, import_core26.isTaskRunning)(own)) return { label: "Working\u2026", busy: true };
5047
5180
  const at = task.status === "awaiting_user" && task.awaitingReason === "usage-limit" && task.resumeAt ? new Date(task.resumeAt) : null;
5048
- if (at && !Number.isNaN(at.getTime())) return { label: `paused \xB7 resumes ${(0, import_core30.resumeTime)(at)}`, busy: false };
5181
+ if (at && !Number.isNaN(at.getTime())) return { label: `paused \xB7 resumes ${(0, import_core32.resumeTime)(at)}`, busy: false };
5049
5182
  return null;
5050
5183
  }
5051
5184
  function runHints(state) {
@@ -5074,41 +5207,41 @@ function bodyRows(state) {
5074
5207
  return Math.max(0, state.rows - CHROME_ROWS - composerRows(state) - footer);
5075
5208
  }
5076
5209
  var chatBodyMemo = null;
5077
- function chatBodyLines(blocks, cols, detailAll, answering) {
5210
+ function chatBodyLines(blocks2, cols, detailAll, answering) {
5078
5211
  const memo = chatBodyMemo;
5079
- if (memo && memo.blocks === blocks && memo.cols === cols && memo.detailAll === detailAll) return memo.lines;
5080
- const lines = conversationLines(blocks, cols, detailAll, answering);
5081
- chatBodyMemo = { blocks, cols, detailAll, lines };
5212
+ if (memo && memo.blocks === blocks2 && memo.cols === cols && memo.detailAll === detailAll) return memo.lines;
5213
+ const lines = conversationLines(blocks2, cols, detailAll, answering);
5214
+ chatBodyMemo = { blocks: blocks2, cols, detailAll, lines };
5082
5215
  return lines;
5083
5216
  }
5084
5217
  function chatLayout(state, rows, cols) {
5085
5218
  const tv = state.taskView;
5086
- const blocks = tv ? tv.view.blocks : state.conversation.blocks;
5219
+ const blocks2 = tv ? tv.view.blocks : state.conversation.blocks;
5087
5220
  const welcome = !tv && state.tasks.length === 0;
5088
5221
  const checkpoint = tv ? waitingCheckpoint(findTask(state.tasks, tv.taskId)) : void 0;
5089
5222
  const card = tv && checkpoint ? checkpointCardLines(findTask(state.tasks, tv.taskId)?.order ?? 0, checkpoint, cols, waitingApproval(tv) !== void 0) : [];
5090
- const answering = chatBodyLines(blocks, cols, state.detailAll, tv ? waitingApproval(tv) : void 0);
5223
+ const answering = chatBodyLines(blocks2, cols, state.detailAll, tv ? waitingApproval(tv) : void 0);
5091
5224
  const body = card.length > 0 ? [...answering, ...card] : answering;
5092
5225
  const transcript = !welcome ? body : body.length === 0 ? welcomeLines(state, rows, cols) : [...welcomeLines(state, rows, cols), "", ...body];
5093
5226
  const bubbles = tv ? taskQueuedRows(state, cols) : queuedPromptRows(state, cols);
5094
5227
  const content = [...transcript, ...bubbles.length > 0 ? ["", ...bubbles] : []];
5095
5228
  const taskHeader = tv ? taskHeaderLines(state, tv, cols) : [];
5096
- const usage = rows <= 1 ? [] : tv ? taskUsageFooter(state, tv, blocks, cols) : tokenRow(blocks, cols);
5229
+ const usage = rows <= 1 ? [] : tv ? taskUsageFooter(state, tv, blocks2, cols) : tokenRow(blocks2, cols);
5097
5230
  const footer = usage.slice(0, Math.max(1, rows - taskHeader.length - 1));
5098
5231
  const space = Math.max(0, rows - taskHeader.length - footer.length);
5099
5232
  return { lines: content, header: taskHeader, footer, anchor: content.length > space ? "bottom" : "top", maxScroll: Math.max(0, content.length - space) };
5100
5233
  }
5101
- var tokenRow = (blocks, cols) => {
5102
- const line = tokenLine(blocks, cols);
5234
+ var tokenRow = (blocks2, cols) => {
5235
+ const line = tokenLine(blocks2, cols);
5103
5236
  return line ? [line] : [];
5104
5237
  };
5105
- function taskUsageFooter(state, tv, blocks, cols) {
5238
+ function taskUsageFooter(state, tv, blocks2, cols) {
5106
5239
  const task = findTask(state.tasks, tv.taskId);
5107
5240
  const reported = task?.attemptUsage ?? [];
5108
5241
  const onScreen = tv.attempt > 0 ? reported.find((a) => a.attempt === tv.attempt) : reported.at(-1);
5109
- if (!task || !onScreen) return tokenRow(blocks, cols);
5110
- const usage = (0, import_core30.taskRowView)({ ...task, attemptUsage: [onScreen] }).usage;
5111
- if (!usage) return tokenRow(blocks, cols);
5242
+ if (!task || !onScreen) return tokenRow(blocks2, cols);
5243
+ const usage = (0, import_core32.taskRowView)({ ...task, attemptUsage: [onScreen] }).usage;
5244
+ if (!usage) return tokenRow(blocks2, cols);
5112
5245
  const models = usage.byModel ?? [];
5113
5246
  return [
5114
5247
  style.grey(truncate(taskUsageText(usage), cols)),
@@ -5120,17 +5253,17 @@ function chatScrollMax(state) {
5120
5253
  }
5121
5254
  function plannerSetup(state) {
5122
5255
  const provider = state.plannerProvider;
5123
- const registration = import_core30.ALL_PROVIDERS[provider];
5256
+ const registration = (0, import_core32.getProviderMeta)(provider);
5124
5257
  if (!registration) return { label: "not set", ready: false };
5125
- const runner = (0, import_core30.runnerForProvider)(provider);
5126
- const ready = runner ? state.runners.some((r) => r.id === runner) : state.configuredProviders.includes(provider);
5258
+ const runner = (0, import_core32.runnerForProvider)(provider);
5259
+ const ready = runner ? state.runners.some((r) => r.id === runner) : (0, import_core32.isApiProvider)(provider) && state.configuredProviders.includes(provider);
5127
5260
  return { label: registration.label, ready };
5128
5261
  }
5129
5262
  var SETUP_KEY_COLS = 10;
5130
5263
  var SETUP_VALUE_COLS = 32;
5131
5264
  function runSettingsValue(state) {
5132
5265
  const { supervisorLevel, mergeAtGatesAutomatically, autorun } = state.runSettings;
5133
- const level = `supervisor ${import_core29.SUPERVISOR_LEVEL_LABEL[supervisorLevel]}`;
5266
+ const level = `supervisor ${import_core31.SUPERVISOR_LEVEL_LABEL[supervisorLevel]}`;
5134
5267
  return [
5135
5268
  supervisorLevel === "act" ? style.yellow(level) : level,
5136
5269
  `auto-merge ${mergeAtGatesAutomatically ? "on" : "off"}`,
@@ -5231,7 +5364,7 @@ function welcomeLines(state, rows, cols) {
5231
5364
  ];
5232
5365
  const notice = canPlan ? [] : [
5233
5366
  ...wrap(
5234
- style.yellow("Ordewell needs one coding agent installed (Claude Code, Codex, OpenCode) \u2014 or an API key from a provider such as OpenRouter, added with /key."),
5367
+ style.yellow(`Ordewell needs one coding agent installed (${runnerNamesOr()}) \u2014 or an API key from a provider such as OpenRouter, added with /key.`),
5235
5368
  Math.max(1, cols - 1)
5236
5369
  ),
5237
5370
  ""
@@ -5265,7 +5398,7 @@ var STATUS_ICON = {
5265
5398
  var inRow = (label) => label.charAt(0).toLowerCase() + label.slice(1);
5266
5399
  function planLayout(state, rows, cols) {
5267
5400
  const done = state.tasks.filter((t) => t.status === "completed").length;
5268
- const totalUsage = (0, import_core30.planUsage)(state.tasks);
5401
+ const totalUsage = (0, import_core32.planUsage)(state.tasks);
5269
5402
  const unmerged = state.runMerge?.handoff.landed.length ?? 0;
5270
5403
  const count = `${done}/${state.tasks.length}`;
5271
5404
  const hints = runHints(state);
@@ -5343,7 +5476,7 @@ function planScrollExtent(state) {
5343
5476
  }
5344
5477
  function taskLines(state, planRow, index, cols) {
5345
5478
  const { task, parent } = planRow;
5346
- const row = (0, import_core30.taskRowView)(task, { parent, tasks: state.tasks, modes: modesForTask(state.modesByRunner, task) });
5479
+ const row = (0, import_core32.taskRowView)(task, { parent, tasks: state.tasks, modes: modesForTask(state.modesByRunner, task) });
5347
5480
  const selected = state.focus === "plan" && index === state.selectedTask;
5348
5481
  const expanded = state.expandedTaskId === task.id;
5349
5482
  const rawIcon = row.status === "running" ? SPINNER[state.spinnerFrame % SPINNER.length] : STATUS_ICON[row.status];
@@ -5394,10 +5527,10 @@ function taskLines(state, planRow, index, cols) {
5394
5527
  lines.push(style.yellow(truncate(`${bodyPad}\u23F8 waits for Merge all \u2014 ${row.mergeGate.join(", ")} not merged into your branch yet`, cols)));
5395
5528
  }
5396
5529
  if (row.blockedBy) {
5397
- lines.push(style.red(truncate(`${bodyPad}\u2298 ${inRow((0, import_core30.blockedByLabel)(row.blockedBy))} \u2014 runs once ${row.blockedBy.length === 1 ? "it is retried and passes" : "they are retried and pass"}`, cols)));
5530
+ lines.push(style.red(truncate(`${bodyPad}\u2298 ${inRow((0, import_core32.blockedByLabel)(row.blockedBy))} \u2014 runs once ${row.blockedBy.length === 1 ? "it is retried and passes" : "they are retried and pass"}`, cols)));
5398
5531
  }
5399
5532
  if (row.status === "skipped") {
5400
- lines.push(style.grey(truncate(`${bodyPad}\xBB ${inRow((0, import_core30.skippedLabel)(row.skipReason))} \u2014 nothing of it landed; m done lands its kept work`, cols)));
5533
+ lines.push(style.grey(truncate(`${bodyPad}\xBB ${inRow((0, import_core32.skippedLabel)(row.skipReason))} \u2014 nothing of it landed; m done lands its kept work`, cols)));
5401
5534
  }
5402
5535
  const resumable = row.actions.includes("resume-now");
5403
5536
  if (row.resumes) {
@@ -5515,7 +5648,7 @@ function commandSheetBody(cols) {
5515
5648
  style.grey(" ctrl-n/ctrl-p pick a pending message (the newest until you do) \xB7 ctrl-r removes a queued one"),
5516
5649
  style.grey(" ctrl-x stops the runner's running turn, and it then waits for your next message \u2014 on a task paused on a usage limit, it keeps it from resuming"),
5517
5650
  style.grey(" ctrl-y allows a tool request (its keys sit under it) \xB7 ctrl-t allows it for the task \xB7 ctrl-g denies it, with the composer text as the note"),
5518
- style.grey(" at a checkpoint, ctrl-y approves and ctrl-g rejects, with the composer text as the reason \xB7 /checkpoint <id> approve|reject [reason] from anywhere"),
5651
+ style.grey(" at a checkpoint, enter replies with what you typed, ctrl-y approves, ctrl-g rejects (the text is its reason) \xB7 /checkpoint <id> approve|reject [reason] from anywhere"),
5519
5652
  style.grey(" alt\u2190/\u2192 changes attempt \xB7 esc returns")
5520
5653
  );
5521
5654
  return body;
@@ -5532,8 +5665,8 @@ function helpScrollMax(state) {
5532
5665
  }
5533
5666
 
5534
5667
  // src/tui/render.ts
5535
- var import_core31 = require("@ordewell/core");
5536
- var import_core32 = require("@ordewell/core");
5668
+ var import_core33 = require("@ordewell/core");
5669
+ var import_core34 = require("@ordewell/core");
5537
5670
  function render(state) {
5538
5671
  const { rows, cols } = state;
5539
5672
  const rowsForBody = bodyRows(state);
@@ -5632,8 +5765,8 @@ function runSettingsBadge(state) {
5632
5765
  const { supervisorLevel, mergeAtGatesAutomatically, autorun } = state.runSettings;
5633
5766
  const paint = (text, warn) => warn ? style.yellow(text) : style.grey(text);
5634
5767
  const run = state.status === "executing" ? state.runSupervisor : null;
5635
- const actual = run?.unsupervised ? "unsupervised" : run && run.level !== supervisorLevel ? import_core32.SUPERVISOR_LEVEL_LABEL[run.level] : null;
5636
- const level = `supervisor ${import_core32.SUPERVISOR_LEVEL_LABEL[supervisorLevel]}${actual ? ` \u2192 ${actual}` : ""}`;
5768
+ const actual = run?.unsupervised ? "unsupervised" : run && run.level !== supervisorLevel ? import_core34.SUPERVISOR_LEVEL_LABEL[run.level] : null;
5769
+ const level = `supervisor ${import_core34.SUPERVISOR_LEVEL_LABEL[supervisorLevel]}${actual ? ` \u2192 ${actual}` : ""}`;
5637
5770
  return [
5638
5771
  paint(level, supervisorLevel === "act"),
5639
5772
  ...mergeAtGatesAutomatically ? [style.grey("auto-merge")] : [],
@@ -5830,8 +5963,8 @@ function renderHandoff(state, overlay, rows, cols) {
5830
5963
  return frame(`Diff \u2014 ${handoffBranch(handoff)}`, [...shown, "", style.grey(`${more}enter or esc goes back`)], rows, cols);
5831
5964
  }
5832
5965
  const landed = handoff.landed.length === 0 ? [style.grey("Nothing landed on it.")] : handoff.landed.map((task) => {
5833
- const repaired = task.repairedFiles?.length ? style.yellow(` \u2014 repaired (${(0, import_core31.capConflictFiles)(task.repairedFiles)})`) : "";
5834
- return ` ${style.green("\u2713")} ${(0, import_core31.titledTaskRefOf)(state.tasks, task.taskId) ?? (0, import_core31.titledTaskRef)(task)}${repaired}`;
5966
+ const repaired = task.repairedFiles?.length ? style.yellow(` \u2014 repaired (${(0, import_core33.capConflictFiles)(task.repairedFiles)})`) : "";
5967
+ return ` ${style.green("\u2713")} ${(0, import_core33.titledTaskRefOf)(state.tasks, task.taskId) ?? (0, import_core33.titledTaskRef)(task)}${repaired}`;
5835
5968
  });
5836
5969
  const actions = handoffActions(handoff).map((action, index) => {
5837
5970
  const active = index === overlay.index;
@@ -5879,8 +6012,8 @@ function renderPicker(picker2, rows, cols) {
5879
6012
  ...picker2.filterable ? [["type", "to filter"]] : []
5880
6013
  ]);
5881
6014
  const room = Math.max(1, rows - head.length - 3);
5882
- const list = items.length === 0 ? [style.grey(picker2.filter ? "Nothing matches that filter." : "Nothing to show yet\u2026")] : pickerRows({ items, index: picker2.index, numbered: !picker2.filterable, chosen: picker2.multi ? picker2.chosen : void 0 }, room, inner);
5883
- return frame(picker2.title, [...head, ...list, "", footer], rows, cols);
6015
+ const list2 = items.length === 0 ? [style.grey(picker2.filter ? "Nothing matches that filter." : "Nothing to show yet\u2026")] : pickerRows({ items, index: picker2.index, numbered: !picker2.filterable, chosen: picker2.multi ? picker2.chosen : void 0 }, room, inner);
6016
+ return frame(picker2.title, [...head, ...list2, "", footer], rows, cols);
5884
6017
  }
5885
6018
  function renderStepper(stepper, rows, cols) {
5886
6019
  const { definition, trail } = stepper;
@@ -5911,13 +6044,13 @@ function renderStepper(stepper, rows, cols) {
5911
6044
  cancel
5912
6045
  ]);
5913
6046
  const room = Math.max(1, rows - head.length - 3);
5914
- const list = items.length === 0 ? [style.grey(stepper.filter ? "Nothing matches that filter." : "Nothing to show yet\u2026")] : pickerRows({ items, index: stepper.index, numbered: !active.filterable }, room, inner);
5915
- return frame(definition.title, [...head, ...list, "", footer], rows, cols);
6047
+ const list2 = items.length === 0 ? [style.grey(stepper.filter ? "Nothing matches that filter." : "Nothing to show yet\u2026")] : pickerRows({ items, index: stepper.index, numbered: !active.filterable }, room, inner);
6048
+ return frame(definition.title, [...head, ...list2, "", footer], rows, cols);
5916
6049
  }
5917
6050
  var DETAIL_GAP = 2;
5918
- function pickerRows(list, room, inner) {
5919
- const { items, numbered, chosen } = list;
5920
- const index = Math.max(0, Math.min(list.index, items.length - 1));
6051
+ function pickerRows(list2, room, inner) {
6052
+ const { items, numbered, chosen } = list2;
6053
+ const index = Math.max(0, Math.min(list2.index, items.length - 1));
5921
6054
  const digits = String(items.length).length;
5922
6055
  const prefixWidth = 2 + (numbered ? digits + 2 : 0) + (chosen ? 4 : 0);
5923
6056
  const rowWidth = Math.max(1, inner - prefixWidth);
@@ -5926,7 +6059,7 @@ function pickerRows(list, room, inner) {
5926
6059
  const labelWidth = items.some((item) => item.detail) ? Math.min(widest, Math.max(8, rowWidth - DETAIL_GAP - Math.max(16, Math.floor(rowWidth / 3)))) : Math.min(widest, rowWidth);
5927
6060
  const detailWidth = Math.max(1, rowWidth - labelWidth - DETAIL_GAP);
5928
6061
  const detailIndent = " ".repeat(prefixWidth + labelWidth + DETAIL_GAP);
5929
- const block = (item, i) => {
6062
+ const block2 = (item, i) => {
5930
6063
  const active = i === index;
5931
6064
  const current = isCurrent(item);
5932
6065
  const number = numbered ? `${String(i + 1).padStart(digits)}. ` : "";
@@ -5943,29 +6076,29 @@ function pickerRows(list, room, inner) {
5943
6076
  ];
5944
6077
  return active ? lines.map((line) => style.highlight(pad(line, inner))) : lines;
5945
6078
  };
5946
- const blocks = items.map(block);
5947
- if (blocks.reduce((n, b) => n + b.length, 0) <= room) return blocks.flat();
6079
+ const blocks2 = items.map(block2);
6080
+ if (blocks2.reduce((n, b) => n + b.length, 0) <= room) return blocks2.flat();
5948
6081
  const fit2 = Math.max(1, room - 2);
5949
6082
  let lo = index;
5950
6083
  let hi = index;
5951
- let used = blocks[index].length;
6084
+ let used = blocks2[index].length;
5952
6085
  for (let grew = true; grew; ) {
5953
6086
  grew = false;
5954
- if (hi + 1 < blocks.length && used + blocks[hi + 1].length <= fit2) {
6087
+ if (hi + 1 < blocks2.length && used + blocks2[hi + 1].length <= fit2) {
5955
6088
  hi += 1;
5956
- used += blocks[hi].length;
6089
+ used += blocks2[hi].length;
5957
6090
  grew = true;
5958
6091
  }
5959
- if (lo > 0 && used + blocks[lo - 1].length <= fit2) {
6092
+ if (lo > 0 && used + blocks2[lo - 1].length <= fit2) {
5960
6093
  lo -= 1;
5961
- used += blocks[lo].length;
6094
+ used += blocks2[lo].length;
5962
6095
  grew = true;
5963
6096
  }
5964
6097
  }
5965
6098
  return [
5966
6099
  ...lo > 0 ? [style.grey(` \u2191 \u2026 +${lo} more`)] : [],
5967
- ...blocks.slice(lo, hi + 1).flat().slice(0, fit2),
5968
- ...hi < blocks.length - 1 ? [style.grey(` \u2193 \u2026 +${blocks.length - 1 - hi} more`)] : []
6100
+ ...blocks2.slice(lo, hi + 1).flat().slice(0, fit2),
6101
+ ...hi < blocks2.length - 1 ? [style.grey(` \u2193 \u2026 +${blocks2.length - 1 - hi} more`)] : []
5969
6102
  ];
5970
6103
  }
5971
6104
  function keyHints(hints) {
@@ -6005,7 +6138,10 @@ function frame(title, body, rows, cols) {
6005
6138
  }
6006
6139
 
6007
6140
  // src/tui/reducer.ts
6008
- var import_core43 = require("@ordewell/core");
6141
+ var import_core46 = require("@ordewell/core");
6142
+
6143
+ // src/tui/reducers/overlays.ts
6144
+ var import_core45 = require("@ordewell/core");
6009
6145
 
6010
6146
  // src/tui/reducers/shared.ts
6011
6147
  function step(state, effects = []) {
@@ -6064,10 +6200,10 @@ function handleApprovalKey(state, overlay, key) {
6064
6200
  }
6065
6201
 
6066
6202
  // src/tui/reducers/commands.ts
6067
- var import_core42 = require("@ordewell/core");
6203
+ var import_core44 = require("@ordewell/core");
6068
6204
 
6069
6205
  // src/tui/reducers/plannerStepper.ts
6070
- var import_core33 = require("@ordewell/core");
6206
+ var import_core35 = require("@ordewell/core");
6071
6207
  var offered = (items) => new Set(items.filter((i) => !i.disabled).map((i) => i.id));
6072
6208
  function preferredModel(state, provider) {
6073
6209
  const listed = offered(plannerModelItems(state, provider, ""));
@@ -6115,7 +6251,7 @@ var plannerStepper = {
6115
6251
  const model = plannerModelItems(state, provider, "").find((m) => m.id === modelId);
6116
6252
  const level = plannerEffortItems(state, provider, modelId, "").find((e) => e.id === effort);
6117
6253
  const parts = [
6118
- import_core33.ALL_PROVIDERS[provider]?.label ?? provider,
6254
+ (0, import_core35.getProviderMeta)(provider)?.label ?? provider,
6119
6255
  model?.label ?? modelId,
6120
6256
  ...effort ? [effortLabel(level?.label ?? effort)] : []
6121
6257
  ];
@@ -6130,10 +6266,10 @@ var plannerStepper = {
6130
6266
  };
6131
6267
 
6132
6268
  // src/tui/reducers/stepper.ts
6133
- var import_core34 = require("@ordewell/core");
6269
+ var import_core36 = require("@ordewell/core");
6134
6270
  function openStepper(state, definition) {
6135
6271
  const { choices, lists } = settle(state, definition, {});
6136
- const first = lists.findIndex((list) => list !== null);
6272
+ const first = lists.findIndex((list2) => list2 !== null);
6137
6273
  if (first === -1) return definition.save(state, choices);
6138
6274
  return step({ ...state, overlay: { kind: "stepper", stepper: show2(state, definition, choices, first) } });
6139
6275
  }
@@ -6153,11 +6289,11 @@ function handleStepperKey(state, stepper, key) {
6153
6289
  const reopen = (next) => step({ ...state, overlay: { kind: "stepper", stepper: next } });
6154
6290
  const { definition, current, entry, choices } = stepper;
6155
6291
  const def = definition.steps[current];
6156
- const typed = def.number && entry ? (0, import_core34.parseCount)(entry.text, def.number.min) : null;
6292
+ const typed = def.number && entry ? (0, import_core36.parseCount)(entry.text, def.number.min) : null;
6157
6293
  const { lists } = settle(state, definition, choices);
6158
6294
  const items = matchingItems(stepper.items, stepper.filter);
6159
6295
  const before = lastIndexBefore(lists, current);
6160
- const after = lists.findIndex((list, i) => i > current && list !== null);
6296
+ const after = lists.findIndex((list2, i) => i > current && list2 !== null);
6161
6297
  if (key.name === "escape") return step({ ...state, overlay: null });
6162
6298
  if (key.name === "tab" || key.name === "right") return after === -1 ? reopen(stepper) : reopen(show2(state, definition, choices, after));
6163
6299
  if (key.name === "shift-tab" || key.name === "left") return before === -1 ? reopen(stepper) : reopen(show2(state, definition, choices, before));
@@ -6203,14 +6339,14 @@ function choose(state, stepper, value) {
6203
6339
  const saved = definition.save(open, choices);
6204
6340
  if (saved.state.overlay !== open.overlay) return saved;
6205
6341
  const { lists } = settle(saved.state, definition, choices);
6206
- const next = !definition.advanceOnEnter ? current : lists.findIndex((list, i) => i > current && list !== null);
6342
+ const next = !definition.advanceOnEnter ? current : lists.findIndex((list2, i) => i > current && list2 !== null);
6207
6343
  if (next === -1 || lists[next] === null) return { ...saved, state: { ...saved.state, overlay: null } };
6208
6344
  return { ...saved, state: { ...saved.state, overlay: { kind: "stepper", stepper: show2(saved.state, definition, choices, next) } } };
6209
6345
  }
6210
6346
  function reopenStepper(state, stepper) {
6211
6347
  const { definition, current } = stepper;
6212
6348
  const { lists } = settle(state, definition, {});
6213
- const at = lists[current] !== null ? current : lists.findIndex((list) => list !== null);
6349
+ const at = lists[current] !== null ? current : lists.findIndex((list2) => list2 !== null);
6214
6350
  if (at === -1) return { ...state, overlay: null };
6215
6351
  return { ...state, overlay: { kind: "stepper", stepper: show2(state, definition, {}, at) } };
6216
6352
  }
@@ -6219,7 +6355,7 @@ function settle(state, definition, wanted) {
6219
6355
  const lists = definition.steps.map((def) => {
6220
6356
  if (def.skip?.(state, { ...choices })) return null;
6221
6357
  if (def.number) {
6222
- choices[def.id] = String((0, import_core34.parseCount)(wanted[def.id], def.number.min) ?? def.number.current(state, { ...choices }));
6358
+ choices[def.id] = String((0, import_core36.parseCount)(wanted[def.id], def.number.min) ?? def.number.current(state, { ...choices }));
6223
6359
  return [];
6224
6360
  }
6225
6361
  const items = def.items(state, { ...choices });
@@ -6233,10 +6369,10 @@ function settle(state, definition, wanted) {
6233
6369
  function show2(state, definition, wanted, current) {
6234
6370
  const { choices, lists } = settle(state, definition, wanted);
6235
6371
  const items = lists[current] ?? [];
6236
- const trail = lists.flatMap((list, i) => {
6237
- if (list === null) return [];
6372
+ const trail = lists.flatMap((list2, i) => {
6373
+ if (list2 === null) return [];
6238
6374
  const def2 = definition.steps[i];
6239
- const value = i >= current ? void 0 : def2.number ? choices[def2.id] : list.find((item) => item.id === choices[def2.id])?.label;
6375
+ const value = i >= current ? void 0 : def2.number ? choices[def2.id] : list2.find((item) => item.id === choices[def2.id])?.label;
6240
6376
  return [{ label: def2.label, active: i === current, ...value !== void 0 ? { value } : {} }];
6241
6377
  });
6242
6378
  const def = definition.steps[current];
@@ -6258,7 +6394,7 @@ function lastIndexBefore(lists, index) {
6258
6394
  }
6259
6395
 
6260
6396
  // src/tui/reducers/planPane.ts
6261
- var import_core37 = require("@ordewell/core");
6397
+ var import_core39 = require("@ordewell/core");
6262
6398
 
6263
6399
  // src/tui/reducers/pointer.ts
6264
6400
  var WHEEL_NOTCH = 3;
@@ -6336,13 +6472,13 @@ function handleMouseSelect(state, key) {
6336
6472
  }
6337
6473
 
6338
6474
  // src/tui/reducers/taskView.ts
6339
- var import_core35 = require("@ordewell/core");
6475
+ var import_core37 = require("@ordewell/core");
6340
6476
  function openTaskView(state, sessionId, taskId) {
6341
6477
  const task = findTask(state.tasks, taskId);
6342
6478
  if (!task) return step(say(state, "system", `No task ${taskId} in this plan.`));
6343
6479
  const taskView = {
6344
6480
  taskId,
6345
- view: import_core35.EMPTY_TASK_LOG,
6481
+ view: import_core37.EMPTY_TASK_LOG,
6346
6482
  attempts: [],
6347
6483
  attempt: 0,
6348
6484
  pending: [],
@@ -6372,13 +6508,13 @@ function applyLive(tv, attempt, events) {
6372
6508
  }
6373
6509
  next = {
6374
6510
  ...next,
6375
- view: import_core35.EMPTY_TASK_LOG,
6511
+ view: import_core37.EMPTY_TASK_LOG,
6376
6512
  attempt,
6377
6513
  attempts: next.attempts.includes(attempt) ? next.attempts : [...next.attempts, attempt]
6378
6514
  };
6379
6515
  }
6380
6516
  if (attempt < next.attempt) return next;
6381
- return clampQueueIndex({ ...next, view: events.reduce(import_core35.reduceTaskLog, next.view) });
6517
+ return clampQueueIndex({ ...next, view: events.reduce(import_core37.reduceTaskLog, next.view) });
6382
6518
  }
6383
6519
  function taskLogAbandoned(state) {
6384
6520
  const tv = state.taskView;
@@ -6398,14 +6534,15 @@ function taskLogArrived(state, action) {
6398
6534
  function announceApprovals(state, action) {
6399
6535
  if (state.taskView?.taskId === action.taskId) return state;
6400
6536
  const task = findTask(state.tasks, action.taskId);
6401
- const spoken = action.events.reduce((s, event) => event.type === "approval_requested" && !event.decided ? say(s, "system", `Task ${task?.order ?? "?"} waits for approval: ${(0, import_core35.runnerToolSubject)(event.tool, event.args)} \u2014 enter on it, then ctrl-y to allow or ctrl-g to deny`) : s, state);
6537
+ const way = task ? `tab to the plan, select task ${task.order} and press enter (or /open ${task.order})` : "tab to the plan, select it and press enter";
6538
+ const spoken = action.events.reduce((s, event) => event.type === "approval_requested" && !event.decided ? say(s, "system", `Task ${task?.order ?? "?"} waits for approval: ${(0, import_core37.runnerToolSubject)(event.tool, event.args)} \u2014 ${way}, then ctrl-y allows or ctrl-g denies`) : s, state);
6402
6539
  return spoken !== state ? { ...spoken, scroll: state.scroll } : spoken;
6403
6540
  }
6404
6541
  function announceCheckpoint(state, action) {
6405
6542
  const task = findTask(state.tasks, action.taskId) ?? state.tasks.find((t) => t.title === action.title);
6406
6543
  const label = task ? `Task ${task.order}` : action.title;
6407
- const where = "enter on it to answer";
6408
- const spoken = say(state, "system", `${label} asks: ${(0, import_core35.truncateCheckpointSummary)(action.summary)} \u2014 ${where}`);
6544
+ const where = task ? `tab to the plan, select task ${task.order} and press enter (or /open ${task.order}) to answer` : "tab to the plan, select it and press enter to answer";
6545
+ const spoken = say(state, "system", `${label} asks: ${(0, import_core37.truncateCheckpointSummary)(action.summary)} \u2014 ${where}`);
6409
6546
  return { ...spoken, scroll: state.scroll };
6410
6547
  }
6411
6548
  function taskLogLoaded(state, action) {
@@ -6413,7 +6550,7 @@ function taskLogLoaded(state, action) {
6413
6550
  if (!tv || tv.taskId !== action.taskId) return state;
6414
6551
  const loaded = action.attempt >= 1 ? {
6415
6552
  ...tv,
6416
- view: (0, import_core35.replayTaskLog)(action.events),
6553
+ view: (0, import_core37.replayTaskLog)(action.events),
6417
6554
  attempts: action.attempts ?? tv.attempts,
6418
6555
  attempt: action.attempt
6419
6556
  } : { ...tv, attempts: action.attempts ?? tv.attempts };
@@ -6487,7 +6624,7 @@ function handleTaskViewKey(state, key) {
6487
6624
  if (key.name === "ctrl-s") return sendNow(state, tv, state.sessionId);
6488
6625
  if (key.name === "ctrl-x") {
6489
6626
  const task = findTask(state.tasks, tv.taskId);
6490
- if (task && (0, import_core35.resumeLabel)(task)) return step(state, [{ type: "taskAction", sessionId: state.sessionId, taskId: tv.taskId, action: "cancel-resume" }]);
6627
+ if (task && (0, import_core37.resumeLabel)(task)) return step(state, [{ type: "taskAction", sessionId: state.sessionId, taskId: tv.taskId, action: "cancel-resume" }]);
6491
6628
  return step(state, [{ type: "interruptTask", sessionId: state.sessionId, taskId: tv.taskId }]);
6492
6629
  }
6493
6630
  if (key.name === "ctrl-y") return answerWaiting(state, tv, state.sessionId, "allow");
@@ -6505,7 +6642,7 @@ function handleTaskViewKey(state, key) {
6505
6642
  }
6506
6643
 
6507
6644
  // src/tui/reducers/taskEdits.ts
6508
- var import_core36 = require("@ordewell/core");
6645
+ var import_core38 = require("@ordewell/core");
6509
6646
  var import_plan_utils3 = require("@ordewell/core/plan-utils");
6510
6647
  function openTaskRunnerPicker(state, task) {
6511
6648
  if (task.type !== "ai") return fail3(state, "Manual tasks do not run on an executor, so they have no runner.");
@@ -6616,7 +6753,7 @@ function openTaskModePicker(state, task) {
6616
6753
  overlay: {
6617
6754
  kind: "picker",
6618
6755
  picker: picker(`Mode \xB7 ${refFor(state, task)}`, pickerItemsFor(state, action), action, {
6619
- hint: [`Modes declared by ${task.assignedRunner}.`, (0, import_core36.codexSandboxNotice)(state.modesByRunner)?.line].filter(Boolean).join(" ")
6756
+ hint: [`Modes declared by ${task.assignedRunner}.`, (0, import_core38.codexSandboxNotice)(state.modesByRunner)?.line].filter(Boolean).join(" ")
6620
6757
  })
6621
6758
  }
6622
6759
  }
@@ -6844,11 +6981,11 @@ function handlePlanKey(state, key) {
6844
6981
  if (!state.sessionId || key.name !== "char") return step(state);
6845
6982
  if (key.char === "E") return step(state, [{ type: "execute", sessionId: state.sessionId }]);
6846
6983
  if (key.char === "S") return step(state, [{ type: "stopExecution", sessionId: state.sessionId }]);
6847
- const shortcut = key.char === "c" && (0, import_core37.resumeLabel)(task) ? "cancel-resume" : PLAN_SHORTCUTS[key.char ?? ""];
6984
+ const shortcut = key.char === "c" && (0, import_core39.resumeLabel)(task) ? "cancel-resume" : PLAN_SHORTCUTS[key.char ?? ""];
6848
6985
  if (key.char === "r") {
6849
- return (0, import_core37.taskRowActions)(task).includes("resume-now") ? step(state, [taskActionEffect(state, state.sessionId, task.id, "resume-now")]) : step(state);
6986
+ return (0, import_core39.taskRowActions)(task).includes("resume-now") ? step(state, [taskActionEffect(state, state.sessionId, task.id, "resume-now")]) : step(state);
6850
6987
  }
6851
- const action = key.char === "m" ? (0, import_core37.markAction)(task) : shortcut;
6988
+ const action = key.char === "m" ? (0, import_core39.markAction)(task) : shortcut;
6852
6989
  if (action === "force-start" && task.mergeGate?.length) return confirmForceStartPastGate(state, task);
6853
6990
  if (action) {
6854
6991
  return step(state, [taskActionEffect(state, state.sessionId, task.id, action)]);
@@ -6888,9 +7025,9 @@ function commitTaskEdit(state, task, editor) {
6888
7025
  }
6889
7026
 
6890
7027
  // src/tui/reducers/turnQueue.ts
6891
- var import_core38 = require("@ordewell/core");
7028
+ var import_core40 = require("@ordewell/core");
6892
7029
  function drainQueue(state, settled) {
6893
- const next = (0, import_core38.drainNext)(state.queuedPrompts);
7030
+ const next = (0, import_core40.drainNext)(state.queuedPrompts);
6894
7031
  const ended = disarmStop({ ...settled, stopRequested: false, forceSendPending: null });
6895
7032
  if (!next) return step(ended);
6896
7033
  const spoken = say(ended, "user", next.text);
@@ -6905,7 +7042,7 @@ function restoreForced(state) {
6905
7042
  if (!forced) return state;
6906
7043
  const cleared = { ...state, forceSendPending: null };
6907
7044
  if (forced.queueIndex === void 0) {
6908
- const text = (0, import_core38.aheadOfDraft)(forced.text, state.editor.text);
7045
+ const text = (0, import_core40.aheadOfDraft)(forced.text, state.editor.text);
6909
7046
  return { ...cleared, editor: { ...state.editor, text, cursor: text.length } };
6910
7047
  }
6911
7048
  const queued = [...state.queuedPrompts];
@@ -6921,14 +7058,14 @@ function stopPlanning(state, sessionId) {
6921
7058
  return step(queueToEditor(cutTurn({ ...dismissed, stopArmed: false, stopRequested: true, forceSendPending: null })), [{ type: "cancelPlanning", sessionId }]);
6922
7059
  }
6923
7060
  function queueToEditor(state) {
6924
- const all = (0, import_core38.unsendAll)(state.queuedPrompts);
7061
+ const all = (0, import_core40.unsendAll)(state.queuedPrompts);
6925
7062
  if (!all) return state;
6926
7063
  return { ...state, queuedPrompts: all.rest, editor: { ...state.editor, text: all.text, cursor: all.text.length } };
6927
7064
  }
6928
7065
  function unsendLatest(state) {
6929
- const latest = (0, import_core38.unsendLatest)(state.queuedPrompts);
7066
+ const latest = (0, import_core40.unsendLatest)(state.queuedPrompts);
6930
7067
  if (!latest) return step(state);
6931
- const text = (0, import_core38.aheadOfDraft)(latest.text, state.editor.text);
7068
+ const text = (0, import_core40.aheadOfDraft)(latest.text, state.editor.text);
6932
7069
  return step({
6933
7070
  ...state,
6934
7071
  queuedPrompts: latest.rest,
@@ -6944,7 +7081,7 @@ function forceSendPlanner(state) {
6944
7081
  { type: "forceSendPlannerMessage", sessionId: state.sessionId, message: text }
6945
7082
  ]);
6946
7083
  }
6947
- const latest = (0, import_core38.unsendLatest)(state.queuedPrompts);
7084
+ const latest = (0, import_core40.unsendLatest)(state.queuedPrompts);
6948
7085
  if (!latest) return step(say(state, "system", "Nothing to send now: type a message, or queue one with enter."));
6949
7086
  const forced = { text: latest.text, queueIndex: latest.rest.length };
6950
7087
  return step({ ...state, queuedPrompts: latest.rest, stopRequested: false, forceSendPending: forced }, [
@@ -6960,7 +7097,7 @@ function plannerEscape(state) {
6960
7097
  }
6961
7098
 
6962
7099
  // src/tui/reducers/incoming.ts
6963
- var import_core39 = require("@ordewell/core");
7100
+ var import_core41 = require("@ordewell/core");
6964
7101
  var planText = (value, fallback = "") => sanitize(String(value ?? fallback));
6965
7102
  var planLabel = (value, fallback = "") => planText(value, fallback).replace(/\n+/g, " ");
6966
7103
  var asRecord = (value) => typeof value === "object" && value !== null ? value : {};
@@ -6999,7 +7136,7 @@ function runTaskToView(t) {
6999
7136
  ...Array.isArray(model.availableVariants) ? { availableVariants: model.availableVariants.map((variant) => planLabel(variant)) } : {}
7000
7137
  } : void 0,
7001
7138
  isolation: t.isolation,
7002
- awaitingReason: t.status === "awaiting_user" && (0, import_core39.isAwaitingReason)(t.awaitingReason) ? t.awaitingReason : void 0,
7139
+ awaitingReason: t.status === "awaiting_user" && (0, import_core41.isAwaitingReason)(t.awaitingReason) ? t.awaitingReason : void 0,
7003
7140
  ...t.status === "awaiting_user" && t.awaitingReason === "usage-limit" && typeof t.resumeAt === "string" ? { resumeAt: t.resumeAt } : {},
7004
7141
  ...t.status === "skipped" && typeof t.skipReason === "string" ? { skipReason: sanitize(t.skipReason) } : {},
7005
7142
  checkpoint: typeof t.checkpoint === "string" ? sanitize(t.checkpoint) : void 0,
@@ -7018,7 +7155,7 @@ function supervisorOfRun(runSettings) {
7018
7155
  const unsupervised = typeof runSettings.unsupervised === "string" ? runSettings.unsupervised : void 0;
7019
7156
  return {
7020
7157
  runSupervisor: {
7021
- level: (0, import_core39.isSupervisorLevel)(runSettings.supervisorLevel) ? runSettings.supervisorLevel : "off",
7158
+ level: (0, import_core41.isSupervisorLevel)(runSettings.supervisorLevel) ? runSettings.supervisorLevel : "off",
7022
7159
  ...unsupervised ? { unsupervised } : {}
7023
7160
  }
7024
7161
  };
@@ -7035,7 +7172,7 @@ function withRun(state, run) {
7035
7172
  };
7036
7173
  }
7037
7174
  function foldRun(state, input) {
7038
- const run = (0, import_core39.reduceRun)(state.run, input);
7175
+ const run = (0, import_core41.reduceRun)(state.run, input);
7039
7176
  return run === state.run ? state : withRun(state, run);
7040
7177
  }
7041
7178
  function mapRunTasks(tasks, map) {
@@ -7083,21 +7220,21 @@ function followSession(state, message) {
7083
7220
  }
7084
7221
 
7085
7222
  // src/tui/reducers/runSettings.ts
7086
- var import_core40 = require("@ordewell/core");
7223
+ var import_core42 = require("@ordewell/core");
7087
7224
  function runSettingsEffect(state, changes) {
7088
7225
  return { type: "setRunSettings", changes, ...state.sessionId ? { sessionId: state.sessionId } : {} };
7089
7226
  }
7090
7227
  function supervisorCommand(state, args) {
7091
7228
  const [arg, value] = args;
7092
7229
  if (arg === void 0) {
7093
- return step(say(state, "system", `${(0, import_core40.supervisorSummary)(state.runSettings)} \u2014 /supervisor off|watch|act, /supervisor retries <n>, /supervisor reads <n>.`));
7230
+ return step(say(state, "system", `${(0, import_core42.supervisorSummary)(state.runSettings)} \u2014 /supervisor off|watch|act, /supervisor retries <n>, /supervisor reads <n>.`));
7094
7231
  }
7095
7232
  if (arg === "retries") {
7096
- const n = (0, import_core40.parseCount)(value, 0);
7233
+ const n = (0, import_core42.parseCount)(value, 0);
7097
7234
  return n === null ? fail3(state, "Usage: /supervisor retries <whole number, 0 or more>") : step(state, [runSettingsEffect(state, { supervisorRetryLimit: n })]);
7098
7235
  }
7099
7236
  if (arg === "reads") {
7100
- const n = (0, import_core40.parseCount)(value, 1);
7237
+ const n = (0, import_core42.parseCount)(value, 1);
7101
7238
  return n === null ? fail3(state, "Usage: /supervisor reads <whole number, 1 or more>") : step(state, [runSettingsEffect(state, { wakeUpReadBudget: n })]);
7102
7239
  }
7103
7240
  if (arg === "act") return confirmSupervisorAct(state);
@@ -7106,17 +7243,17 @@ function supervisorCommand(state, args) {
7106
7243
  }
7107
7244
  function automergeCommand(state, arg) {
7108
7245
  if (arg === void 0) {
7109
- return step(say(state, "system", `${(0, import_core40.automergeSummary)(state.runSettings)} \u2014 /automerge on|off.`));
7246
+ return step(say(state, "system", `${(0, import_core42.automergeSummary)(state.runSettings)} \u2014 /automerge on|off.`));
7110
7247
  }
7111
- const enabled = (0, import_core40.parseSwitch)(arg);
7248
+ const enabled = (0, import_core42.parseSwitch)(arg);
7112
7249
  if (enabled === null) return fail3(state, "Usage: /automerge [on|off]");
7113
7250
  return step(state, [runSettingsEffect(state, { mergeAtGatesAutomatically: enabled })]);
7114
7251
  }
7115
7252
  function autorunCommand(state, arg) {
7116
7253
  if (arg === void 0) {
7117
- return step(say(state, "system", `${(0, import_core40.autorunSummary)(state.runSettings)} \u2014 /autorun on starts each plan the planner submits, without review.`));
7254
+ return step(say(state, "system", `${(0, import_core42.autorunSummary)(state.runSettings)} \u2014 /autorun on starts each plan the planner submits, without review.`));
7118
7255
  }
7119
- const enabled = (0, import_core40.parseSwitch)(arg);
7256
+ const enabled = (0, import_core42.parseSwitch)(arg);
7120
7257
  if (enabled === null) return fail3(state, "Usage: /autorun [on|off]");
7121
7258
  if (enabled) return confirmAutorun(state);
7122
7259
  return step(state, [runSettingsEffect(state, { autorun: false })]);
@@ -7128,7 +7265,7 @@ function confirmSupervisorAct(state) {
7128
7265
  kind: "confirm",
7129
7266
  title: "Let the supervisor act?",
7130
7267
  message: "At Act the supervisor runs, stops and retries tasks, answers their requests (never allowing), edits the plan and merges, without asking you.",
7131
- note: `${import_core40.ACT_RISK}
7268
+ note: `${import_core42.ACT_RISK}
7132
7269
  It applies to this session's run now, and to every later run.`,
7133
7270
  action: { kind: "supervisor-act" }
7134
7271
  }
@@ -7141,14 +7278,14 @@ function confirmAutorun(state) {
7141
7278
  kind: "confirm",
7142
7279
  title: "Start plans without review?",
7143
7280
  message: "With autorun on, each plan the planner submits starts at once, as if you had pressed Execute. The planner still asks when something is unclear.",
7144
- note: import_core40.AUTORUN_RISK,
7281
+ note: import_core42.AUTORUN_RISK,
7145
7282
  action: { kind: "autorun-on" }
7146
7283
  }
7147
7284
  });
7148
7285
  }
7149
7286
 
7150
7287
  // src/tui/reducers/settings.ts
7151
- var import_core41 = require("@ordewell/core");
7288
+ var import_core43 = require("@ordewell/core");
7152
7289
  var SUPERVISOR_DETAIL = {
7153
7290
  off: "The planner speaks only when you write",
7154
7291
  watch: "The planner follows your runs and suggests what to do",
@@ -7173,7 +7310,7 @@ var SETTINGS = {
7173
7310
  {
7174
7311
  id: "guarded",
7175
7312
  label: "Guarded",
7176
- detail: [`New plans run tasks in each runner's safer mode`, (0, import_core41.codexSandboxNotice)(state.modesByRunner)?.line].filter(Boolean).join(" \xB7 "),
7313
+ detail: [`New plans run tasks in each runner's safer mode`, (0, import_core43.codexSandboxNotice)(state.modesByRunner)?.line].filter(Boolean).join(" \xB7 "),
7177
7314
  selected: !state.autonomous
7178
7315
  }
7179
7316
  ]
@@ -7183,7 +7320,7 @@ var SETTINGS = {
7183
7320
  label: "Supervisor",
7184
7321
  items: (state) => ["off", "watch", "act"].map((level) => ({
7185
7322
  id: level,
7186
- label: import_core41.SUPERVISOR_LEVEL_LABEL[level],
7323
+ label: import_core43.SUPERVISOR_LEVEL_LABEL[level],
7187
7324
  detail: SUPERVISOR_DETAIL[level],
7188
7325
  selected: state.runSettings.supervisorLevel === level
7189
7326
  }))
@@ -7237,12 +7374,12 @@ function saveChoices(state, choices) {
7237
7374
  const autonomous = choices.autonomy === "full";
7238
7375
  if (autonomous !== state.autonomous) {
7239
7376
  save2.autonomous = autonomous;
7240
- changed.push(`Autonomy ${(0, import_core41.autonomyLevelLabel)(autonomous)}`);
7377
+ changed.push(`Autonomy ${(0, import_core43.autonomyLevelLabel)(autonomous)}`);
7241
7378
  }
7242
7379
  const level = choices.supervisor;
7243
7380
  if (level !== state.runSettings.supervisorLevel) {
7244
7381
  run.supervisorLevel = level;
7245
- changed.push(`Supervisor ${import_core41.SUPERVISOR_LEVEL_LABEL[level]}`);
7382
+ changed.push(`Supervisor ${import_core43.SUPERVISOR_LEVEL_LABEL[level]}`);
7246
7383
  }
7247
7384
  if (choices.retries !== void 0 && Number(choices.retries) !== state.runSettings.supervisorRetryLimit) {
7248
7385
  run.supervisorRetryLimit = Number(choices.retries);
@@ -7269,7 +7406,7 @@ function saveChoices(state, choices) {
7269
7406
  }
7270
7407
  if (changed.length === 0) return step(state);
7271
7408
  const effect = { ...save2, message: `Settings: ${changed.join(" \xB7 ")}` };
7272
- const risks = [...run.supervisorLevel === "act" ? [import_core41.ACT_RISK] : [], ...run.autorun ? [import_core41.AUTORUN_RISK] : []];
7409
+ const risks = [...run.supervisorLevel === "act" ? [import_core43.ACT_RISK] : [], ...run.autorun ? [import_core43.AUTORUN_RISK] : []];
7273
7410
  if (risks.length === 0) return saveSettings(state, effect);
7274
7411
  return step({
7275
7412
  ...state,
@@ -7298,7 +7435,6 @@ function saveSettings(state, effect) {
7298
7435
  }
7299
7436
 
7300
7437
  // src/tui/reducers/commands.ts
7301
- var KNOWN_PROVIDERS = Object.keys(import_core42.ALL_PROVIDERS);
7302
7438
  var unknownCommand = (state, name) => fail3(state, `Unknown command: /${name} \u2014 type /help to see what's available.`);
7303
7439
  function runCommand(state, { name, args }) {
7304
7440
  if (!findCommand(name)) return unknownCommand(state, name);
@@ -7385,6 +7521,8 @@ function runCommand(state, { name, args }) {
7385
7521
  if (!text) return fail3(state, "Usage: /continue <id> <message>");
7386
7522
  return continueTaskStep(state, sessionId, taskId, text);
7387
7523
  });
7524
+ case "open":
7525
+ return taskCommand(state, args[0], (sessionId, taskId) => openTaskView(state, sessionId, taskId));
7388
7526
  case "checkpoint":
7389
7527
  return taskCommand(state, args[0], (sessionId, taskId) => {
7390
7528
  const answer = args[1]?.toLowerCase();
@@ -7459,8 +7597,8 @@ function newSession(state) {
7459
7597
  goal: "",
7460
7598
  taskView: null,
7461
7599
  planApproved: false,
7462
- conversation: import_core42.EMPTY_CONVERSATION,
7463
- turnGate: import_core42.NO_TURN,
7600
+ conversation: import_core44.EMPTY_CONVERSATION,
7601
+ turnGate: import_core44.NO_TURN,
7464
7602
  selectedTask: 0,
7465
7603
  expandedTaskId: null,
7466
7604
  taskEditor: null,
@@ -7471,15 +7609,15 @@ function newSession(state) {
7471
7609
  // Prompts belong to the session that raised them; the old planner is gone
7472
7610
  // and its pending requests deny on their own timeout.
7473
7611
  pendingApprovals: [],
7474
- queuedPrompts: import_core42.EMPTY_HOLD,
7612
+ queuedPrompts: import_core44.EMPTY_HOLD,
7475
7613
  stopArmed: false,
7476
7614
  forceSendPending: null,
7477
7615
  overlay: state.overlay?.kind === "approval" ? null : state.overlay
7478
- }, import_core42.EMPTY_RUN), closeEffects);
7616
+ }, import_core44.EMPTY_RUN), closeEffects);
7479
7617
  }
7480
7618
  function setModel(state, args) {
7481
7619
  if (args[0] === "set" && args[1]) {
7482
- const runner = (0, import_core42.runnerForProvider)(state.plannerProvider);
7620
+ const runner = (0, import_core44.runnerForProvider)(state.plannerProvider);
7483
7621
  const known = runner ? modelsForRunner(state.models, runner) : [];
7484
7622
  if (runner && known.length > 0 && !known.some((m) => m.id === args[1])) {
7485
7623
  return fail3(state, `${args[1]} was not discovered for ${runner}.`);
@@ -7502,7 +7640,7 @@ function setModel(state, args) {
7502
7640
  function setPlanner(state, args) {
7503
7641
  if (args[0]) {
7504
7642
  const id = args[0].toLowerCase();
7505
- if (!KNOWN_PROVIDERS.includes(id)) {
7643
+ if (!(0, import_core44.isPlannerBackend)(id)) {
7506
7644
  return fail3(state, `Unknown planner: ${id}. Run /planner with no arguments to see the list.`);
7507
7645
  }
7508
7646
  return step(state, [{ type: "setPlanner", provider: id }]);
@@ -7534,7 +7672,7 @@ function setPlannerEffort(state, args) {
7534
7672
  function setKey(state, args) {
7535
7673
  if (args[0] === "set" && args[1]) {
7536
7674
  const provider = args[1].toLowerCase();
7537
- if (!KNOWN_PROVIDERS.includes(provider)) {
7675
+ if (!(0, import_core44.isApiProvider)(provider)) {
7538
7676
  return fail3(state, `Unknown provider: ${provider}. Run /key with no arguments to see the list.`);
7539
7677
  }
7540
7678
  if (!args[2]) {
@@ -7545,16 +7683,16 @@ function setKey(state, args) {
7545
7683
  }
7546
7684
  return step(state, [{ type: "setApiKey", provider, key: args.slice(2).join(" ") }]);
7547
7685
  }
7548
- const items = import_core42.PROVIDER_PRIORITY.map((id) => ({
7686
+ const items = import_core44.PROVIDER_PRIORITY.map((id) => ({
7549
7687
  id,
7550
- label: import_core42.ALL_PROVIDERS[id].label,
7551
- detail: import_core42.ALL_PROVIDERS[id].apiKeyEnvVar,
7688
+ label: (0, import_core44.getProviderMeta)(id).label,
7689
+ detail: (0, import_core44.getProviderMeta)(id).apiKeyEnvVar,
7552
7690
  selected: state.configuredProviders.includes(id)
7553
7691
  }));
7554
7692
  return step({ ...state, overlay: { kind: "picker", picker: picker("API provider key", items, { kind: "set-key" }) } });
7555
7693
  }
7556
7694
  function keyPrompt(provider) {
7557
- const meta = import_core42.ALL_PROVIDERS[provider];
7695
+ const meta = (0, import_core44.getProviderMeta)(provider);
7558
7696
  return {
7559
7697
  kind: "prompt",
7560
7698
  title: `${meta.label} API key`,
@@ -7631,13 +7769,13 @@ function runners(state, args) {
7631
7769
  }
7632
7770
  function setMaxParallel(state, arg) {
7633
7771
  if (!arg) return step(say(state, "system", `Up to ${state.maxParallel} AI task${state.maxParallel === 1 ? "" : "s"} run at once \u2014 /parallel <n> changes it.`));
7634
- const limit = (0, import_core42.parseMaxParallel)(arg);
7772
+ const limit = (0, import_core44.parseMaxParallel)(arg);
7635
7773
  if (limit === null) return fail3(state, "Usage: /parallel [<number of tasks, 1 or more>]");
7636
7774
  return step({ ...state, maxParallel: limit }, [{ type: "setMaxParallel", limit }]);
7637
7775
  }
7638
7776
  function setAutonomous(state, arg) {
7639
- if (arg === void 0) return step(say(state, "system", `Autonomy level: ${(0, import_core42.autonomyLevelLabel)(state.autonomous)} \u2014 /auto full or /auto guarded changes it for new plans.`));
7640
- const enabled = (0, import_core42.parseAutonomyLevel)(arg);
7777
+ if (arg === void 0) return step(say(state, "system", `Autonomy level: ${(0, import_core44.autonomyLevelLabel)(state.autonomous)} \u2014 /auto full or /auto guarded changes it for new plans.`));
7778
+ const enabled = (0, import_core44.parseAutonomyLevel)(arg);
7641
7779
  if (enabled === null) return fail3(state, "Usage: /auto [full|guarded]");
7642
7780
  return step({ ...state, autonomous: enabled }, [{ type: "setAutonomous", enabled }]);
7643
7781
  }
@@ -7846,7 +7984,7 @@ function choose2(state, picker2, item) {
7846
7984
  case "delete-session":
7847
7985
  return step(closed, [{ type: "deleteSession", sessionId: item.id }]);
7848
7986
  case "set-key":
7849
- return step({ ...state, overlay: keyPrompt(item.id) });
7987
+ return (0, import_core45.isApiProvider)(item.id) ? step({ ...state, overlay: keyPrompt(item.id) }) : step(closed);
7850
7988
  case "choose-allowlist-runner": {
7851
7989
  const action = { kind: "set-allowlist", runner: item.id };
7852
7990
  const items = pickerItemsFor(state, action);
@@ -7922,7 +8060,7 @@ function reduceAction(state, action) {
7922
8060
  // (`task-1`), so nothing of the last one's — a merge gate, a checkpoint, its
7923
8061
  // tasks — may carry over into this.
7924
8062
  case "sessionStarted":
7925
- return step(withRun({ ...state, sessionId: action.sessionId, goal: action.goal, taskView: null }, import_core43.EMPTY_RUN));
8063
+ return step(withRun({ ...state, sessionId: action.sessionId, goal: action.goal, taskView: null }, import_core46.EMPTY_RUN));
7926
8064
  // The daemon registers a session only once planning succeeds; when it does
7927
8065
  // not, holding on to the id would send every next message to a session the
7928
8066
  // server never had.
@@ -7933,18 +8071,18 @@ function reduceAction(state, action) {
7933
8071
  goal: "",
7934
8072
  taskView: null,
7935
8073
  pendingApprovals: [],
7936
- queuedPrompts: import_core43.EMPTY_HOLD,
8074
+ queuedPrompts: import_core46.EMPTY_HOLD,
7937
8075
  stopArmed: false,
7938
8076
  forceSendPending: null,
7939
8077
  overlay: state.overlay?.kind === "approval" ? null : state.overlay
7940
- }, import_core43.EMPTY_RUN));
8078
+ }, import_core46.EMPTY_RUN));
7941
8079
  // Deleting the session on screen stops it in the daemon; a view left on it
7942
8080
  // would answer every next message with a session-not-found.
7943
8081
  case "sessionDeleted":
7944
8082
  return action.sessionId === state.sessionId ? newSession(state) : step(state);
7945
8083
  case "chatRestored":
7946
8084
  if (stale(state, action.sessionId)) return step(state);
7947
- return step({ ...state, conversation: (0, import_core43.fromTranscript)(action.history, action.researchLog, action.plannerUsage, action.pendingTurns), scroll: 0 });
8085
+ return step({ ...state, conversation: (0, import_core46.fromTranscript)(action.history, action.researchLog, action.plannerUsage, action.pendingTurns), scroll: 0 });
7948
8086
  case "planUpdated": {
7949
8087
  if (stale(state, action.sessionId)) return step(state);
7950
8088
  const settled = { ...showPlan(state, action.plan), planner: "idle" };
@@ -7984,15 +8122,15 @@ function reduceAction(state, action) {
7984
8122
  case "taskStarted": {
7985
8123
  if (stale(state, action.sessionId)) return step(state);
7986
8124
  const existing = findTask(state.tasks, action.taskId);
7987
- if (existing && (0, import_core24.isTaskRunning)(existing)) return step(state);
8125
+ if (existing && (0, import_core26.isTaskRunning)(existing)) return step(state);
7988
8126
  const folded = foldRun(state, {
7989
8127
  type: "task_started",
7990
8128
  taskId: action.taskId,
7991
8129
  order: action.order ?? 0,
7992
8130
  title: action.title,
7993
- runner: action.runner ?? "claude-code"
8131
+ runner: action.runner ?? import_core46.DEFAULT_RUNNERS[0]
7994
8132
  });
7995
- const spoken = say(folded, "system", (0, import_core43.taskStartedNotice)(action.title, action.runner));
8133
+ const spoken = say(folded, "system", (0, import_core46.taskStartedNotice)(action.title, action.runner));
7996
8134
  return step({ ...spoken, status: "executing" });
7997
8135
  }
7998
8136
  case "taskCheckpoint":
@@ -8038,7 +8176,7 @@ function reduceAction(state, action) {
8038
8176
  completed: state.tasks.filter((t) => t.status === "completed").length,
8039
8177
  total: state.tasks.length,
8040
8178
  failed: state.tasks.filter((t) => t.status === "failed").length,
8041
- blocked: (0, import_core43.blockingFailures)(state.tasks).size,
8179
+ blocked: (0, import_core46.blockingFailures)(state.tasks).size,
8042
8180
  skipped: state.tasks.filter((t) => t.status === "skipped").length
8043
8181
  };
8044
8182
  const failures = `${failed > 0 ? ` \xB7 ${failed} failed` : ""}${blocked ? ` \xB7 ${blocked} blocked` : ""}${skipped ? ` \xB7 ${skipped} skipped` : ""}`;
@@ -8102,11 +8240,11 @@ function reduceAction(state, action) {
8102
8240
  planner: "idle",
8103
8241
  planApproved: false,
8104
8242
  pendingApprovals: [],
8105
- queuedPrompts: import_core43.EMPTY_HOLD,
8243
+ queuedPrompts: import_core46.EMPTY_HOLD,
8106
8244
  stopArmed: false,
8107
8245
  forceSendPending: null,
8108
8246
  overlay: state.overlay?.kind === "approval" ? null : state.overlay
8109
- }, import_core43.EMPTY_RUN));
8247
+ }, import_core46.EMPTY_RUN));
8110
8248
  // The rewound message comes back as a draft to edit and resend, so it lands
8111
8249
  // as if just typed: history is not being browsed, and nothing is parked.
8112
8250
  case "inputPrefilled":
@@ -8178,7 +8316,7 @@ function showPlan(state, plan) {
8178
8316
  });
8179
8317
  }
8180
8318
  function runStatus(state, tasks) {
8181
- if (tasks.some(import_core24.isTaskRunning)) return "executing";
8319
+ if (tasks.some(import_core26.isTaskRunning)) return "executing";
8182
8320
  if (tasks.some((t) => t.status === "awaiting_user") || state.runMerge?.paused) return "executing";
8183
8321
  return "idle";
8184
8322
  }
@@ -8257,6 +8395,12 @@ function submit(state) {
8257
8395
  return step({ ...cleared, taskView: { ...state.taskView, notice } });
8258
8396
  }
8259
8397
  if (state.taskView.notice) cleared.taskView = { ...state.taskView, notice: void 0 };
8398
+ if (!command && waitingCheckpoint(task)) {
8399
+ if (waitingApproval(state.taskView)) {
8400
+ return step(say(state, "system", "A tool request is waiting ahead of the checkpoint \u2014 answer it first (ctrl-y to allow, ctrl-g to deny), then enter replies to the checkpoint."));
8401
+ }
8402
+ return answerCheckpoint(cleared, state.sessionId, taskId, "reject", text);
8403
+ }
8260
8404
  if (continuesTask(task)) return continueTaskStep(cleared, state.sessionId, taskId, text);
8261
8405
  if (command && offered2.length > 0) return step(cleared, [{ type: "invokeTaskCommand", sessionId: state.sessionId, taskId, ...command }]);
8262
8406
  return step(cleared, [{ type: "sendTaskMessage", sessionId: state.sessionId, taskId, text }]);
@@ -8264,7 +8408,7 @@ function submit(state) {
8264
8408
  const builtIn = builtInCommand(text);
8265
8409
  if (builtIn) return runCommand(cleared, builtIn);
8266
8410
  if (plannerInFlight(state)) {
8267
- return step({ ...cleared, queuedPrompts: (0, import_core43.holdPrompt)(state.queuedPrompts, text) });
8411
+ return step({ ...cleared, queuedPrompts: (0, import_core46.holdPrompt)(state.queuedPrompts, text) });
8268
8412
  }
8269
8413
  const spoken = say(cleared, "user", text);
8270
8414
  const effect = state.sessionId ? { type: "sendMessage", sessionId: state.sessionId, message: text } : { type: "startConversation", goal: text };
@@ -8339,7 +8483,7 @@ function createApp(deps) {
8339
8483
 
8340
8484
  // src/tui/effects.ts
8341
8485
  var import_child_process3 = require("child_process");
8342
- var import_core44 = require("@ordewell/core");
8486
+ var import_core47 = require("@ordewell/core");
8343
8487
 
8344
8488
  // src/tui/inbound.ts
8345
8489
  var CONVERSATION_TYPES = /* @__PURE__ */ new Set([
@@ -8748,13 +8892,13 @@ async function perform(effect, deps) {
8748
8892
  await refreshPlan(deps, sessionId);
8749
8893
  return;
8750
8894
  }
8751
- const request = action === "cancel" || action === "retry" || action === "force-start" ? () => api.taskControl(sessionId, taskId, action) : action === "resume-now" ? () => api.resumeNow(sessionId, taskId) : action === "skip" ? () => api.skipTask(sessionId, taskId) : (0, import_core44.markRequestFor)(action) === "uncomplete" ? () => api.markTaskIncomplete(sessionId, taskId) : () => api.markTaskComplete(sessionId, taskId);
8895
+ const request = action === "cancel" || action === "retry" || action === "force-start" ? () => api.taskControl(sessionId, taskId, action) : action === "resume-now" ? () => api.resumeNow(sessionId, taskId) : action === "skip" ? () => api.skipTask(sessionId, taskId) : (0, import_core47.markRequestFor)(action) === "uncomplete" ? () => api.markTaskIncomplete(sessionId, taskId) : () => api.markTaskComplete(sessionId, taskId);
8752
8896
  await (effect.watch ? withExecutionStream(deps, sessionId, request) : request());
8753
8897
  await refreshPlan(deps, sessionId);
8754
8898
  return;
8755
8899
  }
8756
8900
  case "addTask": {
8757
- const fields = (0, import_core44.newTaskFields)(effect.title);
8901
+ const fields = (0, import_core47.newTaskFields)(effect.title);
8758
8902
  if (!fields) return;
8759
8903
  await api.addTask(effect.sessionId, { ...fields });
8760
8904
  await refreshPlan(deps, effect.sessionId);
@@ -8862,7 +9006,7 @@ async function perform(effect, deps) {
8862
9006
  return;
8863
9007
  }
8864
9008
  case "setPlanner": {
8865
- const meta = import_core44.ALL_PROVIDERS[effect.provider];
9009
+ const meta = (0, import_core47.getProviderMeta)(effect.provider);
8866
9010
  if (!meta) throw new Error(`Unknown planner: ${effect.provider}`);
8867
9011
  const env = { AI_PROVIDER: effect.provider };
8868
9012
  const settings = await api.updateSettings({ env });
@@ -8874,7 +9018,7 @@ async function perform(effect, deps) {
8874
9018
  });
8875
9019
  dispatch({
8876
9020
  type: "notice",
8877
- message: `${(0, import_core44.isCliProvider)(effect.provider) ? `Planning with ${meta.label} \u2014 no API key needed.` : `Planner set to ${meta.label}.`} ${plannerModelNotice(recall2)}`
9021
+ message: `${(0, import_core47.isCliProvider)(effect.provider) ? `Planning with ${meta.label} \u2014 no API key needed.` : `Planner set to ${meta.label}.`} ${plannerModelNotice(recall2)}`
8878
9022
  });
8879
9023
  await loadModels(deps);
8880
9024
  return;
@@ -8902,7 +9046,7 @@ async function perform(effect, deps) {
8902
9046
  dispatch({ type: "notice", message: `Planner effort set to ${effect.effort || "the runner default"}.` });
8903
9047
  return;
8904
9048
  case "setApiKey": {
8905
- const meta = import_core44.ALL_PROVIDERS[effect.provider];
9049
+ const meta = (0, import_core47.isApiProvider)(effect.provider) ? (0, import_core47.getProviderMeta)(effect.provider) : void 0;
8906
9050
  if (!meta) throw new Error(`Unknown provider: ${effect.provider}`);
8907
9051
  await api.updateSettings({ env: { [meta.apiKeyEnvVar]: effect.key } });
8908
9052
  deps.setEnvVar(meta.apiKeyEnvVar, effect.key);
@@ -8950,7 +9094,7 @@ async function perform(effect, deps) {
8950
9094
  }
8951
9095
  case "setAutonomous": {
8952
9096
  const { overridden } = deps.saveAutonomy(effect.enabled);
8953
- const level = (0, import_core44.autonomyLevelLabel)(effect.enabled);
9097
+ const level = (0, import_core47.autonomyLevelLabel)(effect.enabled);
8954
9098
  dispatch({ type: "notice", message: overridden ? `${level} is saved, but ORDEWELL_AUTONOMOUS_MODE in the environment decides the level until it is unset.` : `Autonomy level: ${level} for new plans.` });
8955
9099
  return;
8956
9100
  }
@@ -9114,7 +9258,7 @@ async function saveMaxParallel(deps, limit) {
9114
9258
  function copySelection(deps, text) {
9115
9259
  if (!text) return;
9116
9260
  const lines = text.split("\n").length;
9117
- const command = (0, import_core44.clipboardCopyCommand)(deps.hasBin);
9261
+ const command = (0, import_core47.clipboardCopyCommand)(deps.hasBin);
9118
9262
  if (command) {
9119
9263
  try {
9120
9264
  (deps.pipeToClipboard ?? pipeToClipboardDefault)(command, text);
@@ -9219,7 +9363,7 @@ function lastAssistantMessage(plan) {
9219
9363
  const history = plan?.conversationHistory ?? [];
9220
9364
  for (let i = history.length - 1; i >= 0; i--) {
9221
9365
  const entry = history[i];
9222
- if ((0, import_core44.isUserMessage)(entry)) return null;
9366
+ if ((0, import_core47.isUserMessage)(entry)) return null;
9223
9367
  if (entry.role === "assistant" && entry.kind === void 0) {
9224
9368
  const { content, timestamp } = entry;
9225
9369
  return { content, ...timestamp ? { timestamp } : {} };
@@ -9241,14 +9385,14 @@ async function loadModels(deps) {
9241
9385
  }
9242
9386
  async function loadSessions(deps) {
9243
9387
  const sessions = await deps.api.getSessions(deps.workspace);
9244
- const list = sessions.map((s) => ({
9388
+ const list2 = sessions.map((s) => ({
9245
9389
  id: String(s.id),
9246
9390
  goal: String(s.goal ?? ""),
9247
9391
  taskCount: Number(s.taskCount ?? 0),
9248
9392
  status: String(s.status ?? ""),
9249
9393
  createdAt: String(s.createdAt ?? "")
9250
9394
  }));
9251
- deps.dispatch({ type: "sessionsLoaded", sessions: list });
9395
+ deps.dispatch({ type: "sessionsLoaded", sessions: list2 });
9252
9396
  }
9253
9397
  async function loadRunners(deps) {
9254
9398
  const state = await deps.api.getRunners();
@@ -9574,7 +9718,7 @@ async function handleTui(subArgs) {
9574
9718
  }
9575
9719
  const workspace = flag(subArgs, "--workspace") || process.cwd();
9576
9720
  try {
9577
- (0, import_core45.assertWorkspaceExists)(workspace);
9721
+ (0, import_core48.assertWorkspaceExists)(workspace);
9578
9722
  } catch {
9579
9723
  console.error(
9580
9724
  `Workspace "${workspace}" does not exist.
@@ -9583,7 +9727,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
9583
9727
  );
9584
9728
  process.exit(1);
9585
9729
  }
9586
- const discoveredSkills = (0, import_core45.createSkillsService)(workspace, new import_core45.EnvConfig().workspaceRepos).listSkills();
9730
+ const discoveredSkills = (0, import_core48.createSkillsService)(workspace, new import_core48.EnvConfig().workspaceRepos).listSkills();
9587
9731
  registerSkillCommands(discoveredSkills);
9588
9732
  const taskSkills = discoveredSkills.filter((s) => s.appliesTo === "task").map((s) => ({ name: s.name, description: s.description }));
9589
9733
  const explicitPort = flag(subArgs, "--port") || process.env.ORDEWELL_PORT;
@@ -9595,20 +9739,20 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
9595
9739
  const mouseCapture = process.env.ORDEWELL_TUI_MOUSE !== "false" && process.env.ORDEWELL_TUI_MOUSE !== "0";
9596
9740
  const app = createApp({
9597
9741
  // The level the daemon plans with: the saved one, unless the environment overrides it (ADR-0030).
9598
- initial: { workspace, autonomous: new import_core45.SettingsService().autonomousMode(), mouseCapture, taskSkills },
9742
+ initial: { workspace, autonomous: new import_core48.SettingsService().autonomousMode(), mouseCapture, taskSkills },
9599
9743
  draw: (frame2) => terminal?.draw(frame2),
9600
9744
  perform: (effect) => runEffect(effect, {
9601
9745
  api,
9602
9746
  workspace,
9603
9747
  port,
9604
9748
  dispatch: (action) => app.dispatch(action),
9605
- newSessionId: () => (0, import_core45.mintSessionId)(),
9749
+ newSessionId: () => (0, import_core48.mintSessionId)(),
9606
9750
  setEnvVar: (key, value) => {
9607
9751
  writeEnvVar(findEnvFile(), key, value);
9608
9752
  process.env[key] = value;
9609
9753
  },
9610
9754
  saveAutonomy: (enabled) => {
9611
- const settings = new import_core45.SettingsService();
9755
+ const settings = new import_core48.SettingsService();
9612
9756
  settings.setAutonomousMode(enabled);
9613
9757
  return { overridden: settings.autonomousModeOverridden() };
9614
9758
  },
@@ -9722,7 +9866,7 @@ var COMMANDS = {
9722
9866
  // src/main.ts
9723
9867
  var TUI_FLAGS = /* @__PURE__ */ new Set(["--workspace", "--port"]);
9724
9868
  async function main() {
9725
- (0, import_core46.migrateOldConfigDir)();
9869
+ (0, import_core49.migrateOldConfigDir)();
9726
9870
  moveAutonomyToSettings();
9727
9871
  loadEnvFile();
9728
9872
  const argv = process.argv.slice(2);