@ordewell/cli 0.4.11 → 0.4.12

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 +92 -72
  2. package/package.json +1 -1
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_core18 = require("@ordewell/core");
27
+ var import_core19 = require("@ordewell/core");
28
28
 
29
29
  // src/utils/env.ts
30
30
  var import_fs = require("fs");
@@ -1181,6 +1181,7 @@ function iconFor(status) {
1181
1181
  }
1182
1182
 
1183
1183
  // src/commands/run.ts
1184
+ var import_core7 = require("@ordewell/core");
1184
1185
  function resolveSessionId(subArgs) {
1185
1186
  const explicit = flag(subArgs, "--session-id");
1186
1187
  if (explicit) return explicit;
@@ -1221,6 +1222,10 @@ async function followExecution(api, sessionId) {
1221
1222
  await api.streamExecution(sessionId, (event) => {
1222
1223
  if (event.type === "task_started") {
1223
1224
  process.stderr.write(`[${event.order}/${event.title}] Started: ${event.runner} / ${event.modelId}
1225
+ `);
1226
+ }
1227
+ if (event.type === "checkpoint") {
1228
+ process.stderr.write(`\xB7 Checkpoint \u2014 ${event.taskTitle}: ${(0, import_core7.truncateCheckpointSummary)(event.summary)}
1224
1229
  `);
1225
1230
  }
1226
1231
  if (event.type === "status_update" && event.tasks) {
@@ -1261,7 +1266,7 @@ async function handleRun(subArgs) {
1261
1266
 
1262
1267
  // src/commands/status.ts
1263
1268
  var import_fs4 = require("fs");
1264
- var import_core7 = require("@ordewell/core");
1269
+ var import_core8 = require("@ordewell/core");
1265
1270
  async function handleStatus(subArgs, injectedApi) {
1266
1271
  const sessionId = flag(subArgs, "--session-id");
1267
1272
  const workspace = flag(subArgs, "--workspace") || process.cwd();
@@ -1332,12 +1337,12 @@ function printOneSession(sessionId, meta, plan) {
1332
1337
  const icon = iconFor(t.status);
1333
1338
  const model = t.assignedModel ? ` (${t.assignedModel.modelLabel})` : "";
1334
1339
  const shortId = (t.id ?? "").slice(-8);
1335
- console.log(` ${(0, import_core7.taskOrderLabel)(t).padStart(2)}. ${icon} [${shortId}] ${t.title}${model}`);
1340
+ console.log(` ${(0, import_core8.taskOrderLabel)(t).padStart(2)}. ${icon} [${shortId}] ${t.title}${model}`);
1336
1341
  for (const sub of t.subtasks || []) {
1337
1342
  const subIcon = iconFor(sub.status);
1338
1343
  const subModel = sub.assignedModel ? ` (${sub.assignedModel.modelLabel})` : "";
1339
1344
  const subShortId = (sub.id ?? "").slice(-8);
1340
- console.log(` ${(0, import_core7.taskOrderLabel)(sub, t)}. ${subIcon} [${subShortId}] ${sub.title}${subModel}`);
1345
+ console.log(` ${(0, import_core8.taskOrderLabel)(sub, t)}. ${subIcon} [${subShortId}] ${sub.title}${subModel}`);
1341
1346
  }
1342
1347
  }
1343
1348
  }
@@ -1389,10 +1394,10 @@ async function handleWeb(subArgs) {
1389
1394
  }
1390
1395
 
1391
1396
  // src/commands/models.ts
1392
- var import_core9 = require("@ordewell/core");
1397
+ var import_core10 = require("@ordewell/core");
1393
1398
 
1394
1399
  // src/commands/model.ts
1395
- var import_core8 = require("@ordewell/core");
1400
+ var import_core9 = require("@ordewell/core");
1396
1401
 
1397
1402
  // src/catalog.ts
1398
1403
  function normalizeCatalog(result) {
@@ -1498,7 +1503,7 @@ async function handleModel(subArgs, injectedApi) {
1498
1503
  if (!modelId) fail(USAGE);
1499
1504
  const settings = await api.getSettings();
1500
1505
  const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
1501
- const runner = (0, import_core8.runnerForProvider)(provider);
1506
+ const runner = (0, import_core9.runnerForProvider)(provider);
1502
1507
  if (runner) {
1503
1508
  const known = (await fetchCatalog(api)).models.filter((m) => m.runners?.includes(runner));
1504
1509
  if (known.length > 0 && !known.some((m) => m.id === modelId)) {
@@ -1517,7 +1522,7 @@ async function showModels(api) {
1517
1522
  const [settings, catalog] = await Promise.all([api.getSettings(), fetchCatalog(api)]);
1518
1523
  const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
1519
1524
  const current = typeof settings.orchestratorModel === "string" ? settings.orchestratorModel : "";
1520
- const runner = (0, import_core8.runnerForProvider)(provider);
1525
+ const runner = (0, import_core9.runnerForProvider)(provider);
1521
1526
  const options = runner ? catalog.models.filter((m) => m.runners?.includes(runner)) : catalog.orchestratorModels;
1522
1527
  console.log(`
1523
1528
  Planner model: ${current || "(backend default)"}`);
@@ -1551,8 +1556,8 @@ async function handleModels(subArgs) {
1551
1556
  const rest = subArgs.filter((_, i) => i !== setIdx && i !== setIdx + 1);
1552
1557
  return handleModel(["set", subArgs[setIdx + 1], ...rest]);
1553
1558
  }
1554
- const config = new import_core9.EnvConfig();
1555
- const providers = (0, import_core9.configuredProviders)(config);
1559
+ const config = new import_core10.EnvConfig();
1560
+ const providers = (0, import_core10.configuredProviders)(config);
1556
1561
  if (providers.length === 0) {
1557
1562
  console.error("No providers configured. Set an API key for a provider, e.g.:");
1558
1563
  console.error(" OPENROUTER_API_KEY=... (OpenRouter)");
@@ -1561,19 +1566,19 @@ async function handleModels(subArgs) {
1561
1566
  console.error(" OPENAI_COMPATIBLE_BASE_URL=... (self-hosted / OpenAI-compatible)");
1562
1567
  process.exit(1);
1563
1568
  }
1564
- const { apiKeys, baseUrls } = (0, import_core9.collectProviderCredentials)(config);
1569
+ const { apiKeys, baseUrls } = (0, import_core10.collectProviderCredentials)(config);
1565
1570
  let models;
1566
1571
  let errors;
1567
1572
  try {
1568
- const result = await (0, import_core9.fetchAllProviderModels)({ apiKeys, baseUrls });
1569
- models = (0, import_core9.toOrchestratorOptions)(result.models, import_core9.ORCHESTRATOR_SHORTCUTS);
1573
+ const result = await (0, import_core10.fetchAllProviderModels)({ apiKeys, baseUrls });
1574
+ models = (0, import_core10.toOrchestratorOptions)(result.models, import_core10.ORCHESTRATOR_SHORTCUTS);
1570
1575
  errors = result.errors;
1571
1576
  } catch (err) {
1572
1577
  console.error(`Failed to fetch models: ${err instanceof Error ? err.message : String(err)}`);
1573
1578
  process.exit(1);
1574
1579
  return;
1575
1580
  }
1576
- const providerLabel = (p) => (0, import_core9.getProviderMeta)(p)?.label ?? p;
1581
+ const providerLabel = (p) => (0, import_core10.getProviderMeta)(p)?.label ?? p;
1577
1582
  console.log(
1578
1583
  `
1579
1584
  Available models (${models.length}) across ${providers.length} configured provider(s):`
@@ -1690,9 +1695,9 @@ function handleSetup(subArgs) {
1690
1695
  }
1691
1696
 
1692
1697
  // src/commands/plugins.ts
1693
- var import_core10 = require("@ordewell/core");
1698
+ var import_core11 = require("@ordewell/core");
1694
1699
  function handlePlugins(subArgs) {
1695
- const registry = new import_core10.RunnerRegistry();
1700
+ const registry = new import_core11.RunnerRegistry();
1696
1701
  registry.loadUserPlugins();
1697
1702
  const sub = subArgs[0];
1698
1703
  if (sub === "list" || !sub) {
@@ -1728,7 +1733,7 @@ ${plugins.length} plugin(s):
1728
1733
  process.exit(1);
1729
1734
  }
1730
1735
  try {
1731
- const resolved = (0, import_core10.classifyPluginSource)(source);
1736
+ const resolved = (0, import_core11.classifyPluginSource)(source);
1732
1737
  const manifest = resolved.kind === "git" ? registry.installFromGit(resolved.url) : registry.installFromPath(resolved.path);
1733
1738
  console.log(`Installed plugin: ${manifest.name} v${manifest.version}`);
1734
1739
  } catch (err) {
@@ -2123,7 +2128,7 @@ async function handleSessions(subArgs, injectedApi) {
2123
2128
  }
2124
2129
 
2125
2130
  // src/commands/planner.ts
2126
- var import_core11 = require("@ordewell/core");
2131
+ var import_core12 = require("@ordewell/core");
2127
2132
 
2128
2133
  // src/plannerModelSwitch.ts
2129
2134
  function describePlannerSwitch(settings, provider) {
@@ -2142,7 +2147,7 @@ function rememberedModelFor(settings, provider) {
2142
2147
  }
2143
2148
 
2144
2149
  // src/commands/planner.ts
2145
- var KNOWN_PROVIDERS = Object.keys(import_core11.ALL_PROVIDERS);
2150
+ var KNOWN_PROVIDERS = Object.keys(import_core12.ALL_PROVIDERS);
2146
2151
  async function handlePlanner(subArgs, injectedApi) {
2147
2152
  const api = await connect(subArgs, injectedApi);
2148
2153
  const [wanted] = positionals(subArgs);
@@ -2157,13 +2162,13 @@ async function handlePlanner(subArgs, injectedApi) {
2157
2162
  const settings = await persistEnv(api, { AI_PROVIDER: provider });
2158
2163
  const recall2 = describePlannerSwitch(settings, provider);
2159
2164
  writeEnv({ ORCHESTRATOR_MODEL: recall2.model, ORDEWELL_PLANNER_EFFORT: recall2.effort });
2160
- const meta = import_core11.ALL_PROVIDERS[provider];
2165
+ const meta = import_core12.ALL_PROVIDERS[provider];
2161
2166
  const catalog = await fetchCatalog(api);
2162
2167
  console.log(
2163
- (0, import_core11.isCliProvider)(provider) ? `Planning with ${meta.label} \u2014 no API key needed, it uses that agent's own subscription.` : `Planner set to ${meta.label}.`
2168
+ (0, import_core12.isCliProvider)(provider) ? `Planning with ${meta.label} \u2014 no API key needed, it uses that agent's own subscription.` : `Planner set to ${meta.label}.`
2164
2169
  );
2165
2170
  console.log(plannerModelLine(recall2));
2166
- if (!(0, import_core11.isCliProvider)(provider) && !catalog.providers.includes(provider)) {
2171
+ if (!(0, import_core12.isCliProvider)(provider) && !catalog.providers.includes(provider)) {
2167
2172
  console.log(` No ${meta.apiKeyEnvVar} configured yet \u2014 set one with \`ordewell key set ${provider} <key>\`.`);
2168
2173
  }
2169
2174
  }
@@ -2181,15 +2186,15 @@ async function showPlanners(api) {
2181
2186
  const [settings, catalog] = await Promise.all([api.getSettings(), fetchCatalog(api)]);
2182
2187
  const current = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
2183
2188
  console.log("\nCoding agents (no API key \u2014 they use their own subscription)");
2184
- for (const id of import_core11.CLI_PROVIDERS) {
2185
- const runner = (0, import_core11.runnerForProvider)(id);
2189
+ for (const id of import_core12.CLI_PROVIDERS) {
2190
+ const runner = (0, import_core12.runnerForProvider)(id);
2186
2191
  const discovered = runner ? catalog.models.some((m) => m.runners?.includes(runner)) : false;
2187
- console.log(` ${marker(id === current)} ${id.padEnd(14)} ${import_core11.ALL_PROVIDERS[id].label}${discovered ? "" : " (not detected)"}`);
2192
+ console.log(` ${marker(id === current)} ${id.padEnd(14)} ${import_core12.ALL_PROVIDERS[id].label}${discovered ? "" : " (not detected)"}`);
2188
2193
  }
2189
2194
  console.log("\nAPI providers");
2190
- for (const id of import_core11.PROVIDER_PRIORITY) {
2195
+ for (const id of import_core12.PROVIDER_PRIORITY) {
2191
2196
  const configured = catalog.providers.includes(id);
2192
- const meta = import_core11.ALL_PROVIDERS[id];
2197
+ const meta = import_core12.ALL_PROVIDERS[id];
2193
2198
  console.log(` ${marker(id === current)} ${id.padEnd(14)} ${meta.label}${configured ? "" : ` (no ${meta.apiKeyEnvVar})`}`);
2194
2199
  }
2195
2200
  console.log(`
@@ -2206,7 +2211,7 @@ async function handlePlannerEffort(subArgs, injectedApi) {
2206
2211
  const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
2207
2212
  const modelId = typeof settings.orchestratorModel === "string" ? settings.orchestratorModel : "";
2208
2213
  const currentEffort = typeof settings.plannerThinkingEffort === "string" ? settings.plannerThinkingEffort : "";
2209
- const runner = (0, import_core11.runnerForProvider)(provider);
2214
+ const runner = (0, import_core12.runnerForProvider)(provider);
2210
2215
  if (!runner) {
2211
2216
  fail(
2212
2217
  "Thinking effort applies to a coding-agent planner.",
@@ -2246,7 +2251,7 @@ async function handlePlannerEffort(subArgs, injectedApi) {
2246
2251
  }
2247
2252
 
2248
2253
  // src/commands/key.ts
2249
- var import_core12 = require("@ordewell/core");
2254
+ var import_core13 = require("@ordewell/core");
2250
2255
  var USAGE4 = "Usage: ordewell key [list | set <provider> <key>]";
2251
2256
  async function handleKey(subArgs, injectedApi) {
2252
2257
  const [action, provider, ...keyParts] = positionals(subArgs);
@@ -2257,8 +2262,8 @@ async function handleKey(subArgs, injectedApi) {
2257
2262
  if (action !== "set") {
2258
2263
  const catalog = await fetchCatalog(api);
2259
2264
  console.log("\nAPI provider keys\n");
2260
- for (const id2 of import_core12.PROVIDER_PRIORITY) {
2261
- const meta2 = import_core12.ALL_PROVIDERS[id2];
2265
+ for (const id2 of import_core13.PROVIDER_PRIORITY) {
2266
+ const meta2 = import_core13.ALL_PROVIDERS[id2];
2262
2267
  const configured = catalog.providers.includes(id2);
2263
2268
  console.log(` ${configured ? "\u2713" : " "} ${id2.padEnd(14)} ${meta2.apiKeyEnvVar.padEnd(28)} ${meta2.label}`);
2264
2269
  }
@@ -2268,7 +2273,7 @@ async function handleKey(subArgs, injectedApi) {
2268
2273
  }
2269
2274
  if (!provider) fail(USAGE4);
2270
2275
  const id = provider.toLowerCase();
2271
- const meta = import_core12.ALL_PROVIDERS[id];
2276
+ const meta = import_core13.ALL_PROVIDERS[id];
2272
2277
  if (!meta) {
2273
2278
  fail(`Unknown provider: ${provider}`, "Run `ordewell key` to see the list.");
2274
2279
  }
@@ -2348,7 +2353,7 @@ async function handleApprove(subArgs, injectedApi) {
2348
2353
  // src/tui/terminalLauncher.ts
2349
2354
  var import_child_process3 = require("child_process");
2350
2355
  var import_util = require("util");
2351
- var import_core13 = require("@ordewell/core");
2356
+ var import_core14 = require("@ordewell/core");
2352
2357
  var execFileAsync = (0, import_util.promisify)(import_child_process3.execFile);
2353
2358
  var defaultExecFile = async (command, args) => {
2354
2359
  const { stdout, stderr } = await execFileAsync(command, args);
@@ -2368,16 +2373,16 @@ var defaultWhich = (bin) => {
2368
2373
  async function openTaskTerminal(port, planSessionId, taskId, deps = {}) {
2369
2374
  const platform = deps.platform ?? process.platform;
2370
2375
  const env = deps.env ?? process.env;
2371
- const hasTmuxImpl = deps.hasTmuxImpl ?? import_core13.hasTmux;
2376
+ const hasTmuxImpl = deps.hasTmuxImpl ?? import_core14.hasTmux;
2372
2377
  const execFileImpl = deps.execFileImpl ?? defaultExecFile;
2373
2378
  const spawnImpl = deps.spawnImpl ?? defaultSpawn;
2374
2379
  const which = deps.which ?? defaultWhich;
2375
2380
  if (!hasTmuxImpl()) {
2376
2381
  return { ok: false, message: "tmux is not installed \u2014 install it to get a real terminal per task." };
2377
2382
  }
2378
- const session = (0, import_core13.tmuxSessionName)(port);
2379
- const socket = (0, import_core13.tmuxSocketName)(port);
2380
- const base = (0, import_core13.tmuxWindowName)(taskId, planSessionId);
2383
+ const session = (0, import_core14.tmuxSessionName)(port);
2384
+ const socket = (0, import_core14.tmuxSocketName)(port);
2385
+ const base = (0, import_core14.tmuxWindowName)(taskId, planSessionId);
2381
2386
  let windows;
2382
2387
  try {
2383
2388
  const { stdout } = await execFileImpl("tmux", ["-L", socket, "list-windows", "-t", session, "-F", "#{window_name}"]);
@@ -2671,7 +2676,7 @@ Dependencies \xB7 #${task.order} ${task.title}
2671
2676
  }
2672
2677
 
2673
2678
  // src/tui/index.ts
2674
- var import_core17 = require("@ordewell/core");
2679
+ var import_core18 = require("@ordewell/core");
2675
2680
 
2676
2681
  // src/tui/ansi.ts
2677
2682
  var import_string_width = __toESM(require("string-width"));
@@ -3196,6 +3201,14 @@ function planRows(state) {
3196
3201
  function selectedPlanRow(state) {
3197
3202
  return planRows(state)[state.selectedTask] ?? null;
3198
3203
  }
3204
+ function findTask(tasks, id) {
3205
+ for (const task of tasks) {
3206
+ if (task.id === id) return task;
3207
+ const found = findTask(task.subtasks ?? [], id);
3208
+ if (found) return found;
3209
+ }
3210
+ return void 0;
3211
+ }
3199
3212
  function initialState(overrides = {}) {
3200
3213
  return {
3201
3214
  editor: emptyEditor(),
@@ -3241,7 +3254,7 @@ function initialState(overrides = {}) {
3241
3254
  }
3242
3255
 
3243
3256
  // src/tui/layout.ts
3244
- var import_core14 = require("@ordewell/core");
3257
+ var import_core15 = require("@ordewell/core");
3245
3258
  var CHROME_ROWS = 4;
3246
3259
  function chatInputWrap(state) {
3247
3260
  const active = state.focus === "chat" && !state.overlay;
@@ -3253,7 +3266,7 @@ function footerHints(state) {
3253
3266
  const planning = state.status === "planning" || state.status === "researching";
3254
3267
  const escHint = planning ? "esc stop planning" : null;
3255
3268
  if (state.focus === "plan") {
3256
- if (state.expandedTaskId) {
3269
+ if (state.taskEditor) {
3257
3270
  return ["type to edit prompt", "pgup/pgdn scroll", "alt-enter newline", "enter save", "esc cancel"];
3258
3271
  }
3259
3272
  return [
@@ -3377,9 +3390,9 @@ function chatScrollMax(state) {
3377
3390
  }
3378
3391
  function plannerSetup(state) {
3379
3392
  const provider = state.plannerProvider;
3380
- const registration = import_core14.ALL_PROVIDERS[provider];
3393
+ const registration = import_core15.ALL_PROVIDERS[provider];
3381
3394
  if (!registration) return { label: "not set", ready: false };
3382
- const runner = (0, import_core14.runnerForProvider)(provider);
3395
+ const runner = (0, import_core15.runnerForProvider)(provider);
3383
3396
  const ready = runner ? state.runners.some((r) => r.id === runner) : state.configuredProviders.includes(provider);
3384
3397
  return { label: registration.label, ready };
3385
3398
  }
@@ -3526,7 +3539,7 @@ function taskLines(state, row, index, cols) {
3526
3539
  const icon = paint(rawIcon);
3527
3540
  const kind = running ? style.yellow("RUN") : task.type === "user" ? style.yellow("MAN") : style.grey(" AI");
3528
3541
  const caret = selected ? style.cyan("\u276F") : " ";
3529
- const orderLabel = parent ? (0, import_core14.taskOrderLabel)(task, parent) : String(task.order).padStart(2);
3542
+ const orderLabel = parent ? (0, import_core15.taskOrderLabel)(task, parent) : String(task.order).padStart(2);
3530
3543
  const indent = parent ? " " : "";
3531
3544
  const head = `${indent}${caret} ${icon} ${orderLabel} ${kind} `;
3532
3545
  const titleRoom = Math.max(1, cols - width(head));
@@ -3904,9 +3917,9 @@ function frame(title, body, rows, cols) {
3904
3917
  }
3905
3918
 
3906
3919
  // src/tui/reducer.ts
3907
- var import_core15 = require("@ordewell/core");
3920
+ var import_core16 = require("@ordewell/core");
3908
3921
  var import_plan_utils3 = require("@ordewell/core/plan-utils");
3909
- var KNOWN_PROVIDERS2 = Object.keys(import_core15.ALL_PROVIDERS);
3922
+ var KNOWN_PROVIDERS2 = Object.keys(import_core16.ALL_PROVIDERS);
3910
3923
  var DEFAULT_EFFORT = "__runner_default__";
3911
3924
  function step(state, effects = []) {
3912
3925
  return { state, effects };
@@ -3988,7 +4001,7 @@ function reduce(state, action) {
3988
4001
  case "planUpdated": {
3989
4002
  if (stale(state, action.sessionId)) return step(state);
3990
4003
  const tasks = normalizeTasks(action.plan);
3991
- const expandedTaskId = tasks.some((task) => task.id === state.expandedTaskId) ? state.expandedTaskId : null;
4004
+ const expandedTaskId = state.expandedTaskId && findTask(tasks, state.expandedTaskId) ? state.expandedTaskId : null;
3992
4005
  const next = {
3993
4006
  ...state,
3994
4007
  tasks,
@@ -4203,11 +4216,11 @@ function modelDetail(m) {
4203
4216
  function providerErrorHint(state) {
4204
4217
  const failed = Object.keys(state.providerErrors ?? {});
4205
4218
  if (failed.length === 0) return void 0;
4206
- const names = failed.map((p) => import_core15.ALL_PROVIDERS[p]?.label ?? p);
4219
+ const names = failed.map((p) => import_core16.ALL_PROVIDERS[p]?.label ?? p);
4207
4220
  return `\u26A0 Unavailable (key or fetch failed): ${names.join(", ")} \u2014 showing working providers only.`;
4208
4221
  }
4209
4222
  function plannerModelItems(state) {
4210
- const runner = (0, import_core15.runnerForProvider)(state.plannerProvider);
4223
+ const runner = (0, import_core16.runnerForProvider)(state.plannerProvider);
4211
4224
  if (!runner) return state.orchestratorModels.map((m) => ({ id: m.id, label: m.label, detail: modelDetail(m) }));
4212
4225
  const items = state.models.filter((m) => m.runners?.includes(runner)).map((m) => ({
4213
4226
  id: m.id,
@@ -4218,7 +4231,7 @@ function plannerModelItems(state) {
4218
4231
  return items.length > 0 ? items : [{ id: "", label: `No ${runner} models discovered yet`, detail: "run /refresh", disabled: true }];
4219
4232
  }
4220
4233
  function plannerEffortItems(state) {
4221
- const runner = (0, import_core15.runnerForProvider)(state.plannerProvider);
4234
+ const runner = (0, import_core16.runnerForProvider)(state.plannerProvider);
4222
4235
  if (!runner) {
4223
4236
  return [{ id: "", label: "Thinking effort applies to a coding-agent planner", detail: "switch with /planner", disabled: true }];
4224
4237
  }
@@ -4427,9 +4440,12 @@ function markAction(task) {
4427
4440
  return task.status === "completed" ? "uncomplete" : "complete";
4428
4441
  }
4429
4442
  function handlePlanKey(state, key) {
4430
- const editingTask = state.expandedTaskId ? state.tasks.find((t) => t.id === state.expandedTaskId) : void 0;
4443
+ const editingTask = state.expandedTaskId ? findTask(state.tasks, state.expandedTaskId) : void 0;
4431
4444
  if (editingTask && state.taskEditor) return handleTaskEditKey(state, editingTask, state.taskEditor, key);
4432
- if (key.name === "escape") return step({ ...state, focus: "chat" });
4445
+ if (key.name === "escape") {
4446
+ if (state.expandedTaskId) return step({ ...state, expandedTaskId: null, planScroll: null });
4447
+ return step({ ...state, focus: "chat" });
4448
+ }
4433
4449
  if (key.name === "up") {
4434
4450
  return step({ ...state, selectedTask: Math.max(0, state.selectedTask - 1), planScroll: null });
4435
4451
  }
@@ -4446,6 +4462,10 @@ function handlePlanKey(state, key) {
4446
4462
  if (!row) return step(state);
4447
4463
  const task = row.task;
4448
4464
  if (key.name === "enter" || key.name === "right") {
4465
+ const hasSubtasks = (task.subtasks?.length ?? 0) > 0;
4466
+ if (hasSubtasks && state.expandedTaskId !== task.id) {
4467
+ return step({ ...state, expandedTaskId: task.id, taskEditor: null, planScroll: null });
4468
+ }
4449
4469
  const text = task.prompt ?? task.description ?? task.title;
4450
4470
  return step({
4451
4471
  ...state,
@@ -4856,7 +4876,7 @@ function newSession(state) {
4856
4876
  }
4857
4877
  function setModel(state, args) {
4858
4878
  if (args[0] === "set" && args[1]) {
4859
- const runner = (0, import_core15.runnerForProvider)(state.plannerProvider);
4879
+ const runner = (0, import_core16.runnerForProvider)(state.plannerProvider);
4860
4880
  const known = runner ? modelsForRunner(state.models, runner) : [];
4861
4881
  if (runner && known.length > 0 && !known.some((m) => m.id === args[1])) {
4862
4882
  return fail2(state, `${args[1]} was not discovered for ${runner}.`);
@@ -4878,21 +4898,21 @@ function setModel(state, args) {
4878
4898
  }
4879
4899
  function plannerItems(state) {
4880
4900
  const installed = new Set(state.runners.map((r) => r.id));
4881
- const agents = import_core15.CLI_PROVIDERS.map((id) => {
4882
- const runner = (0, import_core15.runnerForProvider)(id);
4901
+ const agents = import_core16.CLI_PROVIDERS.map((id) => {
4902
+ const runner = (0, import_core16.runnerForProvider)(id);
4883
4903
  const ready = installed.has(runner);
4884
4904
  return {
4885
4905
  id,
4886
- label: import_core15.ALL_PROVIDERS[id].label,
4906
+ label: import_core16.ALL_PROVIDERS[id].label,
4887
4907
  detail: ready ? "coding agent \xB7 no API key needed" : "CLI not installed or not on PATH",
4888
4908
  selected: state.plannerProvider === id,
4889
4909
  disabled: !ready
4890
4910
  };
4891
4911
  });
4892
- const vendors = import_core15.PROVIDER_PRIORITY.filter((id) => state.configuredProviders.includes(id)).map((id) => ({
4912
+ const vendors = import_core16.PROVIDER_PRIORITY.filter((id) => state.configuredProviders.includes(id)).map((id) => ({
4893
4913
  id,
4894
- label: import_core15.ALL_PROVIDERS[id].label,
4895
- detail: import_core15.ALL_PROVIDERS[id].apiKeyEnvVar,
4914
+ label: import_core16.ALL_PROVIDERS[id].label,
4915
+ detail: import_core16.ALL_PROVIDERS[id].apiKeyEnvVar,
4896
4916
  selected: state.plannerProvider === id
4897
4917
  }));
4898
4918
  return vendors.length > 0 ? [...agents, ...vendors] : [...agents, { id: "", label: "No API providers configured", detail: "add a key with /key", disabled: true }];
@@ -4950,16 +4970,16 @@ function setKey(state, args) {
4950
4970
  }
4951
4971
  return step(state, [{ type: "setApiKey", provider, key: args.slice(2).join(" ") }]);
4952
4972
  }
4953
- const items = import_core15.PROVIDER_PRIORITY.map((id) => ({
4973
+ const items = import_core16.PROVIDER_PRIORITY.map((id) => ({
4954
4974
  id,
4955
- label: import_core15.ALL_PROVIDERS[id].label,
4956
- detail: import_core15.ALL_PROVIDERS[id].apiKeyEnvVar,
4975
+ label: import_core16.ALL_PROVIDERS[id].label,
4976
+ detail: import_core16.ALL_PROVIDERS[id].apiKeyEnvVar,
4957
4977
  selected: state.configuredProviders.includes(id)
4958
4978
  }));
4959
4979
  return step({ ...state, overlay: { kind: "picker", picker: picker("API provider key", items, { kind: "set-key" }) } });
4960
4980
  }
4961
4981
  function keyPrompt(provider) {
4962
- const meta = import_core15.ALL_PROVIDERS[provider];
4982
+ const meta = import_core16.ALL_PROVIDERS[provider];
4963
4983
  return {
4964
4984
  kind: "prompt",
4965
4985
  title: `${meta.label} API key`,
@@ -5317,7 +5337,7 @@ function createApp(deps) {
5317
5337
 
5318
5338
  // src/tui/effects.ts
5319
5339
  var import_child_process4 = require("child_process");
5320
- var import_core16 = require("@ordewell/core");
5340
+ var import_core17 = require("@ordewell/core");
5321
5341
  var import_plan_utils4 = require("@ordewell/core/plan-utils");
5322
5342
  var ConversationQueue = class {
5323
5343
  tail = Promise.resolve();
@@ -5484,7 +5504,7 @@ async function perform(effect, deps) {
5484
5504
  dispatch({ type: "notice", message: `Orchestrator model set to ${effect.modelId}.` });
5485
5505
  return;
5486
5506
  case "setPlanner": {
5487
- const meta = import_core16.ALL_PROVIDERS[effect.provider];
5507
+ const meta = import_core17.ALL_PROVIDERS[effect.provider];
5488
5508
  if (!meta) throw new Error(`Unknown planner: ${effect.provider}`);
5489
5509
  const env = { AI_PROVIDER: effect.provider };
5490
5510
  const settings = await api.updateSettings({ env });
@@ -5496,7 +5516,7 @@ async function perform(effect, deps) {
5496
5516
  });
5497
5517
  dispatch({
5498
5518
  type: "notice",
5499
- message: `${(0, import_core16.isCliProvider)(effect.provider) ? `Planning with ${meta.label} \u2014 no API key needed.` : `Planner set to ${meta.label}.`} ${plannerModelNotice(recall2)}`
5519
+ message: `${(0, import_core17.isCliProvider)(effect.provider) ? `Planning with ${meta.label} \u2014 no API key needed.` : `Planner set to ${meta.label}.`} ${plannerModelNotice(recall2)}`
5500
5520
  });
5501
5521
  await loadModels(deps);
5502
5522
  return;
@@ -5508,7 +5528,7 @@ async function perform(effect, deps) {
5508
5528
  dispatch({ type: "notice", message: `Planner effort set to ${effect.effort || "the runner default"}.` });
5509
5529
  return;
5510
5530
  case "setApiKey": {
5511
- const meta = import_core16.ALL_PROVIDERS[effect.provider];
5531
+ const meta = import_core17.ALL_PROVIDERS[effect.provider];
5512
5532
  if (!meta) throw new Error(`Unknown provider: ${effect.provider}`);
5513
5533
  await api.updateSettings({ env: { [meta.apiKeyEnvVar]: effect.key } });
5514
5534
  deps.setEnvVar(meta.apiKeyEnvVar, effect.key);
@@ -5596,7 +5616,7 @@ function osc52(text) {
5596
5616
  function copySelection(deps, text) {
5597
5617
  if (!text) return;
5598
5618
  const lines = text.split("\n").length;
5599
- const command = (0, import_core16.clipboardCopyCommand)(deps.hasBin);
5619
+ const command = (0, import_core17.clipboardCopyCommand)(deps.hasBin);
5600
5620
  if (command) {
5601
5621
  try {
5602
5622
  (deps.pipeToClipboard ?? pipeToClipboardDefault)(command, text);
@@ -5738,7 +5758,7 @@ function onExecutionEvent(dispatch, event, sessionId) {
5738
5758
  // The extension shows these in its checkpoint panel; here they are
5739
5759
  // transcript lines, which is the TUI's equivalent surface.
5740
5760
  case "checkpoint":
5741
- dispatch({ type: "notice", message: `Checkpoint \u2014 ${event.taskTitle}: ${event.summary}` });
5761
+ dispatch({ type: "notice", message: `\xB7 Checkpoint \u2014 ${event.taskTitle}: ${(0, import_core17.truncateCheckpointSummary)(event.summary)}` });
5742
5762
  return;
5743
5763
  case "approval_decided":
5744
5764
  dispatch({ type: "notice", message: describeApprovalDecision2(event) });
@@ -6091,7 +6111,7 @@ async function handleTui(subArgs) {
6091
6111
  }
6092
6112
  const workspace = flag(subArgs, "--workspace") || process.cwd();
6093
6113
  try {
6094
- (0, import_core17.assertWorkspaceExists)(workspace);
6114
+ (0, import_core18.assertWorkspaceExists)(workspace);
6095
6115
  } catch {
6096
6116
  console.error(
6097
6117
  `Workspace "${workspace}" does not exist.
@@ -6100,7 +6120,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
6100
6120
  );
6101
6121
  process.exit(1);
6102
6122
  }
6103
- registerSkillCommands((0, import_core17.createSkillsService)(workspace).listSkills());
6123
+ registerSkillCommands((0, import_core18.createSkillsService)(workspace).listSkills());
6104
6124
  const explicitPort = flag(subArgs, "--port") || process.env.ORDEWELL_PORT;
6105
6125
  const targetPort = explicitPort ? resolvePort(subArgs) : await findFreePort();
6106
6126
  const { port, owned: ownedAtLaunch } = await ensureDaemonOwned(targetPort, { detached: false });
@@ -6119,7 +6139,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
6119
6139
  conversationQueue,
6120
6140
  port,
6121
6141
  dispatch: (action) => app.dispatch(action),
6122
- newSessionId: () => (0, import_core17.mintSessionId)(),
6142
+ newSessionId: () => (0, import_core18.mintSessionId)(),
6123
6143
  setEnvVar: (key, value) => {
6124
6144
  writeEnvVar(findEnvFile(), key, value);
6125
6145
  process.env[key] = value;
@@ -6225,7 +6245,7 @@ function cliVersion() {
6225
6245
 
6226
6246
  // src/main.ts
6227
6247
  async function main() {
6228
- (0, import_core18.migrateOldConfigDir)();
6248
+ (0, import_core19.migrateOldConfigDir)();
6229
6249
  loadEnvFile();
6230
6250
  const argv = process.argv.slice(2);
6231
6251
  const command = argv[0] ?? (process.stdin.isTTY ? "tui" : "--help");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordewell/cli",
3
- "version": "0.4.11",
3
+ "version": "0.4.12",
4
4
  "description": "Ordewell CLI and TUI — plan, run and verify coding-agent tasks from the terminal.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Alessandro Costanzo Ciano",