@ordewell/cli 0.5.6 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/main.js +128 -105
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -12,8 +12,10 @@ npm install -g @ordewell/cli # or: npm install -g ordewell
|
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
**Requirements:** Node.js 20 or newer, at least one of Claude Code, Codex or
|
|
15
|
-
OpenCode, git for task isolation
|
|
16
|
-
|
|
15
|
+
OpenCode, and git for task isolation. tmux is optional: only the terminal
|
|
16
|
+
transport (`/transport terminal`) uses it, to give each task a terminal window
|
|
17
|
+
you can open. Linux, macOS and Windows are supported; on Windows, run the
|
|
18
|
+
terminal UI under WSL.
|
|
17
19
|
|
|
18
20
|
## Usage
|
|
19
21
|
|
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
|
|
27
|
+
var import_core34 = require("@ordewell/core");
|
|
28
28
|
|
|
29
29
|
// src/utils/env.ts
|
|
30
30
|
var import_fs = require("fs");
|
|
@@ -138,8 +138,8 @@ Planner, models and runners:
|
|
|
138
138
|
ordewell key [set <p> <key>] Show which providers have a key, or store one
|
|
139
139
|
ordewell runners [<id> on|off] Enable or disable runners (claude-code, opencode, codex)
|
|
140
140
|
ordewell allowlist set|clear|show Limit which models a runner may use
|
|
141
|
-
ordewell auto [
|
|
142
|
-
ordewell transport [terminal|structured]
|
|
141
|
+
ordewell auto [full|auto] Autonomy level for new sessions: Full auto or Auto
|
|
142
|
+
ordewell transport [terminal|structured] Structured (default) or terminal task transport, from the next run
|
|
143
143
|
ordewell parallel [<n>] How many AI tasks run at once (default 3; applies to a live run)
|
|
144
144
|
ordewell refresh Re-discover runners and model catalogs
|
|
145
145
|
ordewell models List every provider's catalog (works without a server)
|
|
@@ -212,7 +212,7 @@ Environment:
|
|
|
212
212
|
ORDEWELL_PLANNER_EFFORT Thinking effort for a coding-agent planner
|
|
213
213
|
ORCHESTRATOR_MODEL Default: deepseek/deepseek-v4-flash
|
|
214
214
|
OPENROUTER_BASE_URL Default: https://openrouter.ai/api/v1
|
|
215
|
-
ORDEWELL_AUTONOMOUS_MODE
|
|
215
|
+
ORDEWELL_AUTONOMOUS_MODE true: Full auto, false: Auto, for new sessions (see "ordewell auto")
|
|
216
216
|
ORDEWELL_PORT Daemon port CLI commands target (default: 3742)
|
|
217
217
|
ORDEWELL_DIRENV false: agents skip the project's direnv .envrc
|
|
218
218
|
ORDEWELL_RESEARCH_ENABLED true (default) or false
|
|
@@ -2277,7 +2277,7 @@ async function handleVerify(subArgs, api) {
|
|
|
2277
2277
|
}
|
|
2278
2278
|
|
|
2279
2279
|
// src/commands/transport.ts
|
|
2280
|
-
var describe = (transport) => `Runner transport
|
|
2280
|
+
var describe = (transport) => `Runner transport: ${transport === "terminal" ? "terminal" : "structured"} \u2014 applies from the next run`;
|
|
2281
2281
|
async function handleTransport(subArgs, api) {
|
|
2282
2282
|
const action = subArgs[0];
|
|
2283
2283
|
const port = api ? void 0 : await ensureDaemon(resolvePort(subArgs));
|
|
@@ -2621,14 +2621,14 @@ var import_core15 = require("@ordewell/core");
|
|
|
2621
2621
|
function show(state, { view: conversation, gate: turnGate }) {
|
|
2622
2622
|
const gated = turnGate === state.turnGate ? state : { ...state, turnGate };
|
|
2623
2623
|
if (conversation === state.conversation) return gated;
|
|
2624
|
-
|
|
2625
|
-
return { ...gated, conversation, scroll };
|
|
2624
|
+
return { ...gated, conversation };
|
|
2626
2625
|
}
|
|
2627
2626
|
function fold(state, input) {
|
|
2628
2627
|
return show(state, { view: (0, import_core15.reduceConversation)(state.conversation, input), gate: state.turnGate });
|
|
2629
2628
|
}
|
|
2630
2629
|
function say(state, role, text) {
|
|
2631
|
-
|
|
2630
|
+
const said = fold(state, { type: "local_entry", role, text });
|
|
2631
|
+
return said.conversation.nextId > state.conversation.nextId ? { ...said, scroll: 0 } : said;
|
|
2632
2632
|
}
|
|
2633
2633
|
function hear(state, message) {
|
|
2634
2634
|
return show(state, (0, import_core15.followTurn)(state.conversation, state.turnGate, message));
|
|
@@ -3208,6 +3208,7 @@ async function handleKey(subArgs, injectedApi) {
|
|
|
3208
3208
|
}
|
|
3209
3209
|
|
|
3210
3210
|
// src/commands/runners.ts
|
|
3211
|
+
var import_core19 = require("@ordewell/core");
|
|
3211
3212
|
var USAGE7 = "Usage: ordewell runners [<runner-id> on|off]";
|
|
3212
3213
|
async function handleRunners(subArgs, injectedApi) {
|
|
3213
3214
|
const [runner, toggle] = positionals(subArgs);
|
|
@@ -3232,21 +3233,21 @@ async function handleRunners(subArgs, injectedApi) {
|
|
|
3232
3233
|
await api.setRunnerEnabled(runner, enabled);
|
|
3233
3234
|
console.log(`${runner} ${enabled ? "enabled" : "disabled"}.`);
|
|
3234
3235
|
}
|
|
3235
|
-
var AUTO_USAGE = "Usage: ordewell auto [
|
|
3236
|
+
var AUTO_USAGE = "Usage: ordewell auto [full|auto]";
|
|
3236
3237
|
function handleAuto(subArgs) {
|
|
3237
3238
|
const [arg] = positionals(subArgs);
|
|
3238
3239
|
const currentRaw = process.env.ORDEWELL_AUTONOMOUS_MODE;
|
|
3239
3240
|
const current = currentRaw !== "false" && currentRaw !== "0";
|
|
3240
3241
|
if (!arg) {
|
|
3241
|
-
console.log(`
|
|
3242
|
+
console.log(`Autonomy level: ${(0, import_core19.autonomyLevelLabel)(current)}`);
|
|
3242
3243
|
console.log(` ${AUTO_USAGE}`);
|
|
3243
3244
|
return;
|
|
3244
3245
|
}
|
|
3245
|
-
const enabled =
|
|
3246
|
+
const enabled = (0, import_core19.parseAutonomyLevel)(arg);
|
|
3246
3247
|
if (enabled === null) fail(AUTO_USAGE);
|
|
3247
3248
|
writeEnvVar(findEnvFile(), "ORDEWELL_AUTONOMOUS_MODE", String(enabled));
|
|
3248
3249
|
process.env.ORDEWELL_AUTONOMOUS_MODE = String(enabled);
|
|
3249
|
-
console.log(`
|
|
3250
|
+
console.log(`Autonomy level: ${(0, import_core19.autonomyLevelLabel)(enabled)} for new sessions.`);
|
|
3250
3251
|
}
|
|
3251
3252
|
async function handleRefresh(subArgs, injectedApi) {
|
|
3252
3253
|
const api = await connect(subArgs, injectedApi);
|
|
@@ -3278,7 +3279,7 @@ async function handleApprove(subArgs, injectedApi) {
|
|
|
3278
3279
|
// src/tui/terminalLauncher.ts
|
|
3279
3280
|
var import_child_process3 = require("child_process");
|
|
3280
3281
|
var import_util = require("util");
|
|
3281
|
-
var
|
|
3282
|
+
var import_core20 = require("@ordewell/core");
|
|
3282
3283
|
var execFileAsync = (0, import_util.promisify)(import_child_process3.execFile);
|
|
3283
3284
|
var defaultExecFile = async (command, args) => {
|
|
3284
3285
|
const { stdout, stderr } = await execFileAsync(command, args);
|
|
@@ -3298,16 +3299,16 @@ var defaultWhich = (bin) => {
|
|
|
3298
3299
|
async function openTaskTerminal(port, planSessionId, taskId, deps = {}) {
|
|
3299
3300
|
const platform = deps.platform ?? process.platform;
|
|
3300
3301
|
const env = deps.env ?? process.env;
|
|
3301
|
-
const hasTmuxImpl = deps.hasTmuxImpl ??
|
|
3302
|
+
const hasTmuxImpl = deps.hasTmuxImpl ?? import_core20.hasTmux;
|
|
3302
3303
|
const execFileImpl = deps.execFileImpl ?? defaultExecFile;
|
|
3303
3304
|
const spawnImpl = deps.spawnImpl ?? defaultSpawn;
|
|
3304
3305
|
const which = deps.which ?? defaultWhich;
|
|
3305
3306
|
if (!hasTmuxImpl()) {
|
|
3306
|
-
return { ok: false, message: "tmux is not installed
|
|
3307
|
+
return { ok: false, message: "No terminal window for this task: tmux is not installed. Install tmux to get one for terminal-transport tasks; a structured task has its log view instead." };
|
|
3307
3308
|
}
|
|
3308
|
-
const session = (0,
|
|
3309
|
-
const socket = (0,
|
|
3310
|
-
const base = (0,
|
|
3309
|
+
const session = (0, import_core20.tmuxSessionName)(port);
|
|
3310
|
+
const socket = (0, import_core20.tmuxSocketName)(port);
|
|
3311
|
+
const base = (0, import_core20.tmuxWindowName)(taskId, planSessionId);
|
|
3311
3312
|
let windows;
|
|
3312
3313
|
try {
|
|
3313
3314
|
const { stdout } = await execFileImpl("tmux", ["-L", socket, "list-windows", "-t", session, "-F", "#{window_name}"]);
|
|
@@ -3317,7 +3318,7 @@ async function openTaskTerminal(port, planSessionId, taskId, deps = {}) {
|
|
|
3317
3318
|
}
|
|
3318
3319
|
const window = latestAttempt(windows, base);
|
|
3319
3320
|
if (!window) {
|
|
3320
|
-
return { ok: false, message: "This task
|
|
3321
|
+
return { ok: false, message: "This task has no live terminal and no saved log \u2014 it may still be pending." };
|
|
3321
3322
|
}
|
|
3322
3323
|
const manualHint = `tmux -L ${socket} attach -t ${session}:${window}`;
|
|
3323
3324
|
const viewer = `${session}-view-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -3601,7 +3602,7 @@ Dependencies \xB7 #${task.order} ${task.title}
|
|
|
3601
3602
|
}
|
|
3602
3603
|
|
|
3603
3604
|
// src/tui/index.ts
|
|
3604
|
-
var
|
|
3605
|
+
var import_core33 = require("@ordewell/core");
|
|
3605
3606
|
|
|
3606
3607
|
// src/tui/editor.ts
|
|
3607
3608
|
function emptyEditor() {
|
|
@@ -3763,8 +3764,8 @@ var SLASH_COMMANDS = [
|
|
|
3763
3764
|
{ name: "key", usage: "/key [set <provider> <key>]", description: "Configure API provider keys", category: "models" },
|
|
3764
3765
|
{ name: "allowlist", usage: "/allowlist [set <runner> <ids> | clear <runner>]", description: "Limit which models a runner may use", category: "models" },
|
|
3765
3766
|
{ name: "runners", usage: "/runners [<id> on|off]", description: "Enable or disable runners (claude-code, opencode, codex)", category: "models" },
|
|
3766
|
-
{ name: "auto", usage: "/auto [
|
|
3767
|
-
{ name: "transport", usage: "/transport [terminal|structured]", description: "
|
|
3767
|
+
{ name: "auto", usage: "/auto [full|auto]", description: "Autonomy level for new plans: Full auto or Auto", category: "models" },
|
|
3768
|
+
{ name: "transport", usage: "/transport [terminal|structured]", description: "Drive tasks through each runner's protocol (structured) or a terminal, from the next run", category: "models" },
|
|
3768
3769
|
{ name: "parallel", usage: "/parallel [<n>]", description: "How many AI tasks run at once (applies to a live run)", category: "models" },
|
|
3769
3770
|
{ name: "refresh", usage: "/refresh", description: "Re-discover runners and model catalogs", category: "models" },
|
|
3770
3771
|
// Skills
|
|
@@ -3849,7 +3850,7 @@ function tokenCompletions(token) {
|
|
|
3849
3850
|
}
|
|
3850
3851
|
|
|
3851
3852
|
// src/tui/blocks.ts
|
|
3852
|
-
var
|
|
3853
|
+
var import_core21 = require("@ordewell/core");
|
|
3853
3854
|
|
|
3854
3855
|
// src/tui/markdown.ts
|
|
3855
3856
|
function renderMarkdown(source, cols) {
|
|
@@ -4057,16 +4058,16 @@ function resultLines(block, room, detailAll) {
|
|
|
4057
4058
|
const fit2 = (line) => detailAll ? wrap(line, room) : [truncate(line, room)];
|
|
4058
4059
|
const outcome = unsettledOutcome(block);
|
|
4059
4060
|
if (outcome) {
|
|
4060
|
-
const [reason, ...rest] = (0,
|
|
4061
|
+
const [reason, ...rest] = (0, import_core21.outputLines)(block.output).map(sanitize);
|
|
4061
4062
|
const status = fit2(reason ? `${outcome.label}: ${reason}` : outcome.label).map(outcome.paint);
|
|
4062
4063
|
return detailAll ? [...status, ...rest.flatMap(fit2).map(style.grey)] : status;
|
|
4063
4064
|
}
|
|
4064
4065
|
if (detailAll) {
|
|
4065
|
-
const lines2 = (0,
|
|
4066
|
+
const lines2 = (0, import_core21.outputLines)(block.output).map(sanitize);
|
|
4066
4067
|
const note = lines2.length > PREVIEW_LINES ? ["\u2026 (ctrl+o to collapse)"] : [];
|
|
4067
4068
|
return lines2.length > 0 ? [...lines2.flatMap(fit2), ...note].map(style.grey) : [style.grey("(no output)")];
|
|
4068
4069
|
}
|
|
4069
|
-
const { lines, hiddenLineCount } = (0,
|
|
4070
|
+
const { lines, hiddenLineCount } = (0, import_core21.outputPreview)(block.output, PREVIEW_LINES);
|
|
4070
4071
|
if (lines.length === 0) return [style.grey("(no output)")];
|
|
4071
4072
|
const more = hiddenLineCount > 0 ? [`\u2026 +${countOf(hiddenLineCount, "line")} (ctrl+o to expand)`] : [];
|
|
4072
4073
|
return [...lines.map(sanitize), ...more].map((line) => style.grey(truncate(line, room)));
|
|
@@ -4187,7 +4188,7 @@ function tokenLine(blocks, cols) {
|
|
|
4187
4188
|
}
|
|
4188
4189
|
|
|
4189
4190
|
// src/tui/state.ts
|
|
4190
|
-
var
|
|
4191
|
+
var import_core22 = require("@ordewell/core");
|
|
4191
4192
|
var SKILL_IDS = ["tdd", "verify"];
|
|
4192
4193
|
function noSkills() {
|
|
4193
4194
|
return { tdd: false, verify: false };
|
|
@@ -4234,9 +4235,9 @@ function findTask(tasks, id) {
|
|
|
4234
4235
|
function initialState(overrides = {}) {
|
|
4235
4236
|
return {
|
|
4236
4237
|
editor: emptyEditor(),
|
|
4237
|
-
conversation:
|
|
4238
|
+
conversation: import_core22.EMPTY_CONVERSATION,
|
|
4238
4239
|
taskView: null,
|
|
4239
|
-
turnGate:
|
|
4240
|
+
turnGate: import_core22.NO_TURN,
|
|
4240
4241
|
detailAll: false,
|
|
4241
4242
|
status: "idle",
|
|
4242
4243
|
busyLabel: "",
|
|
@@ -4261,18 +4262,18 @@ function initialState(overrides = {}) {
|
|
|
4261
4262
|
orchestratorModel: "",
|
|
4262
4263
|
plannerProvider: "",
|
|
4263
4264
|
plannerEffort: "",
|
|
4264
|
-
maxParallel:
|
|
4265
|
+
maxParallel: import_core22.DEFAULT_MAX_PARALLEL,
|
|
4265
4266
|
configuredProviders: [],
|
|
4266
4267
|
allowlist: {},
|
|
4267
4268
|
autonomous: true,
|
|
4268
|
-
runnerTransport: "
|
|
4269
|
+
runnerTransport: "structured",
|
|
4269
4270
|
mouseCapture: true,
|
|
4270
4271
|
selection: null,
|
|
4271
4272
|
workspace: process.cwd(),
|
|
4272
4273
|
handoff: null,
|
|
4273
4274
|
overlay: null,
|
|
4274
4275
|
pendingApprovals: [],
|
|
4275
|
-
queuedPrompts:
|
|
4276
|
+
queuedPrompts: import_core22.EMPTY_HOLD,
|
|
4276
4277
|
stopArmed: false,
|
|
4277
4278
|
stopArmToken: 0,
|
|
4278
4279
|
stopRequested: false,
|
|
@@ -4320,7 +4321,7 @@ function chatEditorRoomFor(state, active) {
|
|
|
4320
4321
|
}
|
|
4321
4322
|
|
|
4322
4323
|
// src/tui/layout.ts
|
|
4323
|
-
var
|
|
4324
|
+
var import_core23 = require("@ordewell/core");
|
|
4324
4325
|
var CHROME_ROWS = 4;
|
|
4325
4326
|
function chatInputWrap(state) {
|
|
4326
4327
|
const active = state.focus === "chat" && !state.overlay;
|
|
@@ -4359,7 +4360,7 @@ function footerHints(state) {
|
|
|
4359
4360
|
"tab chat"
|
|
4360
4361
|
];
|
|
4361
4362
|
}
|
|
4362
|
-
const detailHint = (0,
|
|
4363
|
+
const detailHint = (0, import_core23.hasHiddenDetail)(state.taskView ? state.taskView.view.blocks : state.conversation.blocks) ? [state.detailAll ? "ctrl-o collapse all" : "ctrl-o expand all"] : [];
|
|
4363
4364
|
return [
|
|
4364
4365
|
"/help",
|
|
4365
4366
|
"tab plan",
|
|
@@ -4464,9 +4465,9 @@ function chatScrollMax(state) {
|
|
|
4464
4465
|
}
|
|
4465
4466
|
function plannerSetup(state) {
|
|
4466
4467
|
const provider = state.plannerProvider;
|
|
4467
|
-
const registration =
|
|
4468
|
+
const registration = import_core23.ALL_PROVIDERS[provider];
|
|
4468
4469
|
if (!registration) return { label: "not set", ready: false };
|
|
4469
|
-
const runner = (0,
|
|
4470
|
+
const runner = (0, import_core23.runnerForProvider)(provider);
|
|
4470
4471
|
const ready = runner ? state.runners.some((r) => r.id === runner) : state.configuredProviders.includes(provider);
|
|
4471
4472
|
return { label: registration.label, ready };
|
|
4472
4473
|
}
|
|
@@ -4657,7 +4658,7 @@ function taskLines(state, row, index, cols) {
|
|
|
4657
4658
|
const icon = paint(rawIcon);
|
|
4658
4659
|
const kind = running ? style.yellow("RUN") : task.type === "user" ? style.yellow("MAN") : style.grey(" AI");
|
|
4659
4660
|
const caret = selected ? style.cyan("\u276F") : " ";
|
|
4660
|
-
const orderLabel = parent ? (0,
|
|
4661
|
+
const orderLabel = parent ? (0, import_core23.taskOrderLabel)(task, parent) : String(task.order).padStart(2);
|
|
4661
4662
|
const indent = parent ? " " : "";
|
|
4662
4663
|
const head = `${indent}${caret} ${icon} ${orderLabel} ${kind} `;
|
|
4663
4664
|
const titleRoom = Math.max(1, cols - width(head));
|
|
@@ -4687,16 +4688,16 @@ function taskLines(state, row, index, cols) {
|
|
|
4687
4688
|
if (effort || mode) lines.push(style.grey(truncate(`${bodyPad}${[effort, mode].filter(Boolean).join(" \xB7 ")}`, cols)));
|
|
4688
4689
|
if (task.isolation?.state === "conflict") {
|
|
4689
4690
|
const where = task.isolation.conflictRepo && task.isolation.conflictRepo !== "." ? ` in ${task.isolation.conflictRepo}` : "";
|
|
4690
|
-
const files = task.isolation.conflictFiles?.length ? ` (${(0,
|
|
4691
|
+
const files = task.isolation.conflictFiles?.length ? ` (${(0, import_core23.capConflictFiles)(task.isolation.conflictFiles)})` : "";
|
|
4691
4692
|
lines.push(style.red(truncate(`${bodyPad}\u26A0 merge conflict${where}${files} \u2014 its work is kept on its own branch`, cols)));
|
|
4692
4693
|
}
|
|
4693
4694
|
if (task.isolation?.state === "repairing") {
|
|
4694
|
-
const files = task.isolation.conflictFiles?.length ? ` in ${(0,
|
|
4695
|
+
const files = task.isolation.conflictFiles?.length ? ` in ${(0, import_core23.capConflictFiles)(task.isolation.conflictFiles)}` : "";
|
|
4695
4696
|
const attempt = task.isolation.repair ? ` (attempt ${task.isolation.repair.attempt}/${task.isolation.repair.limit})` : "";
|
|
4696
4697
|
lines.push(style.yellow(truncate(`${bodyPad}\u21BB repairing conflict${files}${attempt}`, cols)));
|
|
4697
4698
|
}
|
|
4698
4699
|
if (task.isolation?.state === "integrated" && task.isolation.repairedFiles?.length) {
|
|
4699
|
-
lines.push(style.grey(truncate(`${bodyPad}\u21BB landed after repairing conflict in ${(0,
|
|
4700
|
+
lines.push(style.grey(truncate(`${bodyPad}\u21BB landed after repairing conflict in ${(0, import_core23.capConflictFiles)(task.isolation.repairedFiles)}`, cols)));
|
|
4700
4701
|
}
|
|
4701
4702
|
let editorLine;
|
|
4702
4703
|
if (expanded) {
|
|
@@ -4710,7 +4711,7 @@ function taskLines(state, row, index, cols) {
|
|
|
4710
4711
|
}
|
|
4711
4712
|
}
|
|
4712
4713
|
if (modeInfo?.autonomous) {
|
|
4713
|
-
lines.push(...taskText("Autonomy", "Runs without permission prompts.
|
|
4714
|
+
lines.push(...taskText("Autonomy", "Runs without permission prompts (Full auto). Change the level with /auto.", cols, bodyPad));
|
|
4714
4715
|
}
|
|
4715
4716
|
const editableSeed = task.prompt ?? task.description ?? task.title;
|
|
4716
4717
|
if (task.description && task.description !== task.title && task.description !== editableSeed) {
|
|
@@ -4784,7 +4785,7 @@ function helpScrollMax(state) {
|
|
|
4784
4785
|
}
|
|
4785
4786
|
|
|
4786
4787
|
// src/tui/render.ts
|
|
4787
|
-
var
|
|
4788
|
+
var import_core24 = require("@ordewell/core");
|
|
4788
4789
|
function render(state) {
|
|
4789
4790
|
const { rows, cols } = state;
|
|
4790
4791
|
const rowsForBody = bodyRows(state);
|
|
@@ -4879,9 +4880,9 @@ function renderSkills(state, cols) {
|
|
|
4879
4880
|
const badges = SKILL_IDS.map(
|
|
4880
4881
|
(id) => state.skills[id] ? style.green(`\u25CF ${id}`) : style.grey(`\u25CB ${id}`)
|
|
4881
4882
|
);
|
|
4882
|
-
const auto = state.autonomous ? style.yellow("\u25CF auto") : style.
|
|
4883
|
-
const
|
|
4884
|
-
return truncate([...badges, auto, ...
|
|
4883
|
+
const auto = state.autonomous ? style.yellow("\u25CF Full auto") : style.green("\u25CF Auto");
|
|
4884
|
+
const terminal = state.runnerTransport === "terminal" ? [style.yellow("\u25CF terminal")] : [];
|
|
4885
|
+
return truncate([...badges, auto, ...terminal].join(" "), cols);
|
|
4885
4886
|
}
|
|
4886
4887
|
function scrolledBackMark(state) {
|
|
4887
4888
|
return state.focus !== "plan" && state.scroll > 0 ? "\u2191 scrolled back \xB7 pgdn for live" : "";
|
|
@@ -5049,7 +5050,7 @@ function renderHandoff(state, overlay, rows, cols) {
|
|
|
5049
5050
|
return frame(`Diff \u2014 ${handoffBranch(handoff)}`, [...shown, "", style.grey(`${more}enter or esc goes back`)], rows, cols);
|
|
5050
5051
|
}
|
|
5051
5052
|
const landed = handoff.landed.length === 0 ? [style.grey("Nothing landed on it.")] : handoff.landed.map((task) => {
|
|
5052
|
-
const repaired = task.repairedFiles?.length ? style.yellow(` \u2014 repaired (${(0,
|
|
5053
|
+
const repaired = task.repairedFiles?.length ? style.yellow(` \u2014 repaired (${(0, import_core24.capConflictFiles)(task.repairedFiles)})`) : "";
|
|
5053
5054
|
return ` ${style.green("\u2713")} #${task.order} ${task.title}${repaired}`;
|
|
5054
5055
|
});
|
|
5055
5056
|
const actions = handoffActions(handoff).map((action, index) => {
|
|
@@ -5139,7 +5140,7 @@ function frame(title, body, rows, cols) {
|
|
|
5139
5140
|
}
|
|
5140
5141
|
|
|
5141
5142
|
// src/tui/reducer.ts
|
|
5142
|
-
var
|
|
5143
|
+
var import_core30 = require("@ordewell/core");
|
|
5143
5144
|
|
|
5144
5145
|
// src/tui/reducers/shared.ts
|
|
5145
5146
|
function step(state, effects = []) {
|
|
@@ -5188,10 +5189,10 @@ function handleApprovalKey(state, overlay, key) {
|
|
|
5188
5189
|
}
|
|
5189
5190
|
|
|
5190
5191
|
// src/tui/reducers/commands.ts
|
|
5191
|
-
var
|
|
5192
|
+
var import_core28 = require("@ordewell/core");
|
|
5192
5193
|
|
|
5193
5194
|
// src/tui/reducers/pickers.ts
|
|
5194
|
-
var
|
|
5195
|
+
var import_core25 = require("@ordewell/core");
|
|
5195
5196
|
var import_plan_utils2 = require("@ordewell/core/plan-utils");
|
|
5196
5197
|
var DEFAULT_EFFORT = "__runner_default__";
|
|
5197
5198
|
function picker(title, items, action, extra = {}) {
|
|
@@ -5210,11 +5211,11 @@ function modelDetail(m) {
|
|
|
5210
5211
|
function providerErrorHint(state) {
|
|
5211
5212
|
const failed = Object.keys(state.providerErrors ?? {});
|
|
5212
5213
|
if (failed.length === 0) return void 0;
|
|
5213
|
-
const names = failed.map((p) =>
|
|
5214
|
+
const names = failed.map((p) => import_core25.ALL_PROVIDERS[p]?.label ?? p);
|
|
5214
5215
|
return `\u26A0 Unavailable (key or fetch failed): ${names.join(", ")} \u2014 showing working providers only.`;
|
|
5215
5216
|
}
|
|
5216
5217
|
function plannerModelItems(state) {
|
|
5217
|
-
const runner = (0,
|
|
5218
|
+
const runner = (0, import_core25.runnerForProvider)(state.plannerProvider);
|
|
5218
5219
|
if (!runner) return state.orchestratorModels.map((m) => ({ id: m.id, label: m.label, detail: modelDetail(m) }));
|
|
5219
5220
|
const items = state.models.filter((m) => m.runners?.includes(runner)).map((m) => ({
|
|
5220
5221
|
id: m.id,
|
|
@@ -5228,7 +5229,7 @@ function plannerModelItems(state) {
|
|
|
5228
5229
|
return items.length > 0 ? items : [{ id: "", label: `No ${runner} models discovered yet`, detail: "run /refresh", disabled: true }];
|
|
5229
5230
|
}
|
|
5230
5231
|
function plannerEffortItems(state) {
|
|
5231
|
-
const runner = (0,
|
|
5232
|
+
const runner = (0, import_core25.runnerForProvider)(state.plannerProvider);
|
|
5232
5233
|
if (!runner) {
|
|
5233
5234
|
return [{ id: "", label: "Thinking effort applies to a coding-agent planner", detail: "switch with /planner", disabled: true }];
|
|
5234
5235
|
}
|
|
@@ -5337,21 +5338,21 @@ function pickerItemsFor(state, action) {
|
|
|
5337
5338
|
}
|
|
5338
5339
|
function plannerItems(state) {
|
|
5339
5340
|
const installed = new Set(state.runners.map((r) => r.id));
|
|
5340
|
-
const agents =
|
|
5341
|
-
const runner = (0,
|
|
5341
|
+
const agents = import_core25.CLI_PROVIDERS.map((id) => {
|
|
5342
|
+
const runner = (0, import_core25.runnerForProvider)(id);
|
|
5342
5343
|
const ready = installed.has(runner);
|
|
5343
5344
|
return {
|
|
5344
5345
|
id,
|
|
5345
|
-
label:
|
|
5346
|
+
label: import_core25.ALL_PROVIDERS[id].label,
|
|
5346
5347
|
detail: ready ? "coding agent \xB7 no API key needed" : "CLI not installed or not on PATH",
|
|
5347
5348
|
selected: state.plannerProvider === id,
|
|
5348
5349
|
disabled: !ready
|
|
5349
5350
|
};
|
|
5350
5351
|
});
|
|
5351
|
-
const vendors =
|
|
5352
|
+
const vendors = import_core25.PROVIDER_PRIORITY.filter((id) => state.configuredProviders.includes(id)).map((id) => ({
|
|
5352
5353
|
id,
|
|
5353
|
-
label:
|
|
5354
|
-
detail:
|
|
5354
|
+
label: import_core25.ALL_PROVIDERS[id].label,
|
|
5355
|
+
detail: import_core25.ALL_PROVIDERS[id].apiKeyEnvVar,
|
|
5355
5356
|
selected: state.plannerProvider === id
|
|
5356
5357
|
}));
|
|
5357
5358
|
return vendors.length > 0 ? [...agents, ...vendors] : [...agents, { id: "", label: "No API providers configured", detail: "add a key with /key", disabled: true }];
|
|
@@ -5433,13 +5434,13 @@ function handleMouseSelect(state, key) {
|
|
|
5433
5434
|
}
|
|
5434
5435
|
|
|
5435
5436
|
// src/tui/reducers/taskView.ts
|
|
5436
|
-
var
|
|
5437
|
+
var import_core26 = require("@ordewell/core");
|
|
5437
5438
|
function openTaskView(state, sessionId, taskId) {
|
|
5438
5439
|
const task = findTask(state.tasks, taskId);
|
|
5439
5440
|
if (!task) return step(say(state, "system", `No task ${taskId} in this plan.`));
|
|
5440
5441
|
const taskView = {
|
|
5441
5442
|
taskId,
|
|
5442
|
-
view:
|
|
5443
|
+
view: import_core26.EMPTY_TASK_LOG,
|
|
5443
5444
|
attempts: [],
|
|
5444
5445
|
attempt: 0,
|
|
5445
5446
|
pending: [],
|
|
@@ -5472,13 +5473,13 @@ function applyLive(tv, attempt, events) {
|
|
|
5472
5473
|
}
|
|
5473
5474
|
next = {
|
|
5474
5475
|
...next,
|
|
5475
|
-
view:
|
|
5476
|
+
view: import_core26.EMPTY_TASK_LOG,
|
|
5476
5477
|
attempt,
|
|
5477
5478
|
attempts: next.attempts.includes(attempt) ? next.attempts : [...next.attempts, attempt]
|
|
5478
5479
|
};
|
|
5479
5480
|
}
|
|
5480
5481
|
if (attempt < next.attempt) return next;
|
|
5481
|
-
return clampQueueIndex({ ...next, view: events.reduce(
|
|
5482
|
+
return clampQueueIndex({ ...next, view: events.reduce(import_core26.reduceTaskLog, next.view) });
|
|
5482
5483
|
}
|
|
5483
5484
|
function taskLogAbandoned(state) {
|
|
5484
5485
|
const tv = state.taskView;
|
|
@@ -5498,15 +5499,15 @@ function taskLogArrived(state, action) {
|
|
|
5498
5499
|
function announceApprovals(state, action) {
|
|
5499
5500
|
if (state.taskView?.taskId === action.taskId) return state;
|
|
5500
5501
|
const task = findTask(state.tasks, action.taskId);
|
|
5501
|
-
const spoken = action.events.reduce((s, event) => event.type === "approval_requested" ? say(s, "system", `\xB7 Task ${task?.order ?? "?"} waits for approval: ${(0,
|
|
5502
|
-
return
|
|
5502
|
+
const spoken = action.events.reduce((s, event) => event.type === "approval_requested" ? say(s, "system", `\xB7 Task ${task?.order ?? "?"} waits for approval: ${(0, import_core26.runnerToolSubject)(event.tool, event.args)} \u2014 t on it to answer`) : s, state);
|
|
5503
|
+
return spoken !== state ? { ...spoken, scroll: state.scroll } : spoken;
|
|
5503
5504
|
}
|
|
5504
5505
|
function taskLogLoaded(state, action) {
|
|
5505
5506
|
const tv = state.taskView;
|
|
5506
5507
|
if (!tv || tv.taskId !== action.taskId) return state;
|
|
5507
5508
|
const loaded = action.attempt >= 1 ? {
|
|
5508
5509
|
...tv,
|
|
5509
|
-
view: (0,
|
|
5510
|
+
view: (0, import_core26.replayTaskLog)(action.events),
|
|
5510
5511
|
attempts: action.attempts ?? tv.attempts,
|
|
5511
5512
|
attempt: action.attempt
|
|
5512
5513
|
} : { ...tv, attempts: action.attempts ?? tv.attempts };
|
|
@@ -5868,9 +5869,9 @@ function commitTaskEdit(state, task, editor) {
|
|
|
5868
5869
|
}
|
|
5869
5870
|
|
|
5870
5871
|
// src/tui/reducers/turnQueue.ts
|
|
5871
|
-
var
|
|
5872
|
+
var import_core27 = require("@ordewell/core");
|
|
5872
5873
|
function drainQueue(state, settled) {
|
|
5873
|
-
const next = (0,
|
|
5874
|
+
const next = (0, import_core27.drainNext)(state.queuedPrompts);
|
|
5874
5875
|
const ended = disarmStop({ ...settled, stopRequested: false });
|
|
5875
5876
|
if (!next) return step(ended);
|
|
5876
5877
|
const spoken = say(ended, "user", next.text);
|
|
@@ -5889,14 +5890,14 @@ function stopPlanning(state, sessionId) {
|
|
|
5889
5890
|
return step(queueToEditor(cutTurn({ ...dismissed, stopArmed: false, stopRequested: true })), [{ type: "cancelPlanning", sessionId }]);
|
|
5890
5891
|
}
|
|
5891
5892
|
function queueToEditor(state) {
|
|
5892
|
-
const all = (0,
|
|
5893
|
+
const all = (0, import_core27.unsendAll)(state.queuedPrompts);
|
|
5893
5894
|
if (!all) return state;
|
|
5894
5895
|
return { ...state, queuedPrompts: all.rest, editor: { ...state.editor, text: all.text, cursor: all.text.length } };
|
|
5895
5896
|
}
|
|
5896
5897
|
function unsendLatest(state) {
|
|
5897
|
-
const latest = (0,
|
|
5898
|
+
const latest = (0, import_core27.unsendLatest)(state.queuedPrompts);
|
|
5898
5899
|
if (!latest) return step(state);
|
|
5899
|
-
const text = (0,
|
|
5900
|
+
const text = (0, import_core27.aheadOfDraft)(latest.text, state.editor.text);
|
|
5900
5901
|
return step({
|
|
5901
5902
|
...state,
|
|
5902
5903
|
queuedPrompts: latest.rest,
|
|
@@ -5913,7 +5914,7 @@ function plannerEscape(state) {
|
|
|
5913
5914
|
}
|
|
5914
5915
|
|
|
5915
5916
|
// src/tui/reducers/commands.ts
|
|
5916
|
-
var KNOWN_PROVIDERS2 = Object.keys(
|
|
5917
|
+
var KNOWN_PROVIDERS2 = Object.keys(import_core28.ALL_PROVIDERS);
|
|
5917
5918
|
function runCommand(state, { name, args }) {
|
|
5918
5919
|
if (!findCommand(name)) {
|
|
5919
5920
|
return fail3(state, `Unknown command: /${name} \u2014 type /help to see what's available.`);
|
|
@@ -6069,8 +6070,8 @@ function newSession(state) {
|
|
|
6069
6070
|
taskView: null,
|
|
6070
6071
|
tasks: [],
|
|
6071
6072
|
planApproved: false,
|
|
6072
|
-
conversation:
|
|
6073
|
-
turnGate:
|
|
6073
|
+
conversation: import_core28.EMPTY_CONVERSATION,
|
|
6074
|
+
turnGate: import_core28.NO_TURN,
|
|
6074
6075
|
selectedTask: 0,
|
|
6075
6076
|
expandedTaskId: null,
|
|
6076
6077
|
taskEditor: null,
|
|
@@ -6081,14 +6082,14 @@ function newSession(state) {
|
|
|
6081
6082
|
// Prompts belong to the session that raised them; the old planner is gone
|
|
6082
6083
|
// and its pending requests deny on their own timeout.
|
|
6083
6084
|
pendingApprovals: [],
|
|
6084
|
-
queuedPrompts:
|
|
6085
|
+
queuedPrompts: import_core28.EMPTY_HOLD,
|
|
6085
6086
|
stopArmed: false,
|
|
6086
6087
|
overlay: state.overlay?.kind === "approval" ? null : state.overlay
|
|
6087
6088
|
}, closeEffects);
|
|
6088
6089
|
}
|
|
6089
6090
|
function setModel(state, args) {
|
|
6090
6091
|
if (args[0] === "set" && args[1]) {
|
|
6091
|
-
const runner = (0,
|
|
6092
|
+
const runner = (0, import_core28.runnerForProvider)(state.plannerProvider);
|
|
6092
6093
|
const known = runner ? modelsForRunner(state.models, runner) : [];
|
|
6093
6094
|
if (runner && known.length > 0 && !known.some((m) => m.id === args[1])) {
|
|
6094
6095
|
return fail3(state, `${args[1]} was not discovered for ${runner}.`);
|
|
@@ -6161,16 +6162,16 @@ function setKey(state, args) {
|
|
|
6161
6162
|
}
|
|
6162
6163
|
return step(state, [{ type: "setApiKey", provider, key: args.slice(2).join(" ") }]);
|
|
6163
6164
|
}
|
|
6164
|
-
const items =
|
|
6165
|
+
const items = import_core28.PROVIDER_PRIORITY.map((id) => ({
|
|
6165
6166
|
id,
|
|
6166
|
-
label:
|
|
6167
|
-
detail:
|
|
6167
|
+
label: import_core28.ALL_PROVIDERS[id].label,
|
|
6168
|
+
detail: import_core28.ALL_PROVIDERS[id].apiKeyEnvVar,
|
|
6168
6169
|
selected: state.configuredProviders.includes(id)
|
|
6169
6170
|
}));
|
|
6170
6171
|
return step({ ...state, overlay: { kind: "picker", picker: picker("API provider key", items, { kind: "set-key" }) } });
|
|
6171
6172
|
}
|
|
6172
6173
|
function keyPrompt(provider) {
|
|
6173
|
-
const meta =
|
|
6174
|
+
const meta = import_core28.ALL_PROVIDERS[provider];
|
|
6174
6175
|
return {
|
|
6175
6176
|
kind: "prompt",
|
|
6176
6177
|
title: `${meta.label} API key`,
|
|
@@ -6247,18 +6248,19 @@ function runners(state, args) {
|
|
|
6247
6248
|
}
|
|
6248
6249
|
function setMaxParallel(state, arg) {
|
|
6249
6250
|
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.`));
|
|
6250
|
-
const limit = (0,
|
|
6251
|
+
const limit = (0, import_core28.parseMaxParallel)(arg);
|
|
6251
6252
|
if (limit === null) return fail3(state, "Usage: /parallel [<number of tasks, 1 or more>]");
|
|
6252
6253
|
return step({ ...state, maxParallel: limit }, [{ type: "setMaxParallel", limit }]);
|
|
6253
6254
|
}
|
|
6254
6255
|
function setAutonomous(state, arg) {
|
|
6255
|
-
|
|
6256
|
-
|
|
6256
|
+
if (arg === void 0) return step(say(state, "system", `Autonomy level: ${(0, import_core28.autonomyLevelLabel)(state.autonomous)} \u2014 /auto full or /auto auto changes it for new plans.`));
|
|
6257
|
+
const enabled = (0, import_core28.parseAutonomyLevel)(arg);
|
|
6258
|
+
if (enabled === null) return fail3(state, "Usage: /auto [full|auto]");
|
|
6257
6259
|
return step({ ...state, autonomous: enabled }, [{ type: "setAutonomous", enabled }]);
|
|
6258
6260
|
}
|
|
6259
6261
|
function setTransport(state, arg) {
|
|
6260
6262
|
const value = arg?.toLowerCase() ?? (state.runnerTransport === "structured" ? "terminal" : "structured");
|
|
6261
|
-
if (!(0,
|
|
6263
|
+
if (!(0, import_core28.isRunnerTransport)(value)) return fail3(state, "Usage: /transport [terminal|structured]");
|
|
6262
6264
|
return step(state, [{ type: "setTransport", transport: value }]);
|
|
6263
6265
|
}
|
|
6264
6266
|
function setMouseCapture(state, arg) {
|
|
@@ -6508,7 +6510,7 @@ function choose(state, picker2, item) {
|
|
|
6508
6510
|
}
|
|
6509
6511
|
|
|
6510
6512
|
// src/tui/reducers/incoming.ts
|
|
6511
|
-
var
|
|
6513
|
+
var import_core29 = require("@ordewell/core");
|
|
6512
6514
|
var planText = (value, fallback = "") => sanitize(String(value ?? fallback));
|
|
6513
6515
|
var planLabel = (value, fallback = "") => planText(value, fallback).replace(/\n+/g, " ");
|
|
6514
6516
|
var asRecord = (value) => typeof value === "object" && value !== null ? value : {};
|
|
@@ -6539,7 +6541,7 @@ function toTaskView2(t, index) {
|
|
|
6539
6541
|
prompt: typeof t.prompt === "string" ? sanitize(t.prompt) : void 0,
|
|
6540
6542
|
type: t.type === "user" ? "user" : "ai",
|
|
6541
6543
|
status: planLabel(t.status, "pending"),
|
|
6542
|
-
awaitingReason: t.status === "awaiting_user" && (0,
|
|
6544
|
+
awaitingReason: t.status === "awaiting_user" && (0, import_core29.isAwaitingReason)(t.awaitingReason) ? t.awaitingReason : void 0,
|
|
6543
6545
|
dependencies: Array.isArray(t.dependencies) ? t.dependencies.map((id) => planLabel(id)) : [],
|
|
6544
6546
|
assignedRunner: typeof t.assignedRunner === "string" ? planLabel(t.assignedRunner) : void 0,
|
|
6545
6547
|
taskMode: typeof t.taskMode === "string" ? planLabel(t.taskMode) : void 0,
|
|
@@ -6570,7 +6572,7 @@ function applySettings(state, settings) {
|
|
|
6570
6572
|
plannerProvider: typeof settings.aiProvider === "string" ? settings.aiProvider : state.plannerProvider,
|
|
6571
6573
|
plannerEffort: typeof settings.plannerThinkingEffort === "string" ? settings.plannerThinkingEffort : state.plannerEffort,
|
|
6572
6574
|
maxParallel: typeof settings.maxParallel === "number" ? settings.maxParallel : state.maxParallel,
|
|
6573
|
-
runnerTransport: (0,
|
|
6575
|
+
runnerTransport: (0, import_core29.isRunnerTransport)(settings.runnerTransport) ? settings.runnerTransport : state.runnerTransport,
|
|
6574
6576
|
allowlist: settings.modelAllowlist && typeof settings.modelAllowlist === "object" ? settings.modelAllowlist : state.allowlist
|
|
6575
6577
|
};
|
|
6576
6578
|
}
|
|
@@ -6612,7 +6614,18 @@ function followSession(state, message) {
|
|
|
6612
6614
|
}
|
|
6613
6615
|
|
|
6614
6616
|
// src/tui/reducer.ts
|
|
6617
|
+
function holdReadingPlace(before, after) {
|
|
6618
|
+
if (before.scroll <= 0 || after.scroll !== before.scroll) return after;
|
|
6619
|
+
if (before.taskView?.taskId !== after.taskView?.taskId) return after;
|
|
6620
|
+
const grown = chatScrollMax(after) - chatScrollMax(before);
|
|
6621
|
+
return grown > 0 ? { ...after, scroll: clamp(after.scroll + grown, chatScrollMax(after)) } : after;
|
|
6622
|
+
}
|
|
6615
6623
|
function reduce(state, action) {
|
|
6624
|
+
const result = reduceAction(state, action);
|
|
6625
|
+
if (action.type !== "sessionMessage" && action.type !== "taskLog") return result;
|
|
6626
|
+
return { ...result, state: holdReadingPlace(state, result.state) };
|
|
6627
|
+
}
|
|
6628
|
+
function reduceAction(state, action) {
|
|
6616
6629
|
switch (action.type) {
|
|
6617
6630
|
case "key":
|
|
6618
6631
|
return handleKey2(state, action.key);
|
|
@@ -6630,13 +6643,13 @@ function reduce(state, action) {
|
|
|
6630
6643
|
goal: "",
|
|
6631
6644
|
taskView: null,
|
|
6632
6645
|
pendingApprovals: [],
|
|
6633
|
-
queuedPrompts:
|
|
6646
|
+
queuedPrompts: import_core30.EMPTY_HOLD,
|
|
6634
6647
|
stopArmed: false,
|
|
6635
6648
|
overlay: state.overlay?.kind === "approval" ? null : state.overlay
|
|
6636
6649
|
});
|
|
6637
6650
|
case "chatRestored":
|
|
6638
6651
|
if (stale(state, action.sessionId)) return step(state);
|
|
6639
|
-
return step({ ...state, conversation: (0,
|
|
6652
|
+
return step({ ...state, conversation: (0, import_core30.fromTranscript)(action.history, action.researchLog, action.plannerUsage), scroll: 0 });
|
|
6640
6653
|
case "planUpdated": {
|
|
6641
6654
|
if (stale(state, action.sessionId)) return step(state);
|
|
6642
6655
|
const isolation = isolationOfPlan(action.plan);
|
|
@@ -6671,6 +6684,9 @@ function reduce(state, action) {
|
|
|
6671
6684
|
case "taskLog":
|
|
6672
6685
|
if (stale(state, action.sessionId)) return step(state);
|
|
6673
6686
|
return step(announceApprovals(taskLogArrived(state, action), action));
|
|
6687
|
+
case "taskViewRequested":
|
|
6688
|
+
if (stale(state, action.sessionId)) return step(state);
|
|
6689
|
+
return openTaskView(state, action.sessionId, action.taskId);
|
|
6674
6690
|
case "taskLogLoaded":
|
|
6675
6691
|
if (stale(state, action.sessionId)) return step(state);
|
|
6676
6692
|
return step(taskLogLoaded(state, action));
|
|
@@ -6682,7 +6698,7 @@ function reduce(state, action) {
|
|
|
6682
6698
|
const existing = findTask(state.tasks, action.taskId);
|
|
6683
6699
|
if (existing && isTaskRunning(existing)) return step(state);
|
|
6684
6700
|
const tasks = state.tasks.map((t) => t.id === action.taskId && !isTaskRunning(t) ? { ...t, status: "in_progress" } : t);
|
|
6685
|
-
const spoken = say(state, "system", (0,
|
|
6701
|
+
const spoken = say(state, "system", (0, import_core30.taskStartedNotice)(action.title, action.runner));
|
|
6686
6702
|
return step({ ...spoken, tasks, status: "executing", busyLabel: runLabel(tasks) });
|
|
6687
6703
|
}
|
|
6688
6704
|
case "taskStatus": {
|
|
@@ -6786,7 +6802,7 @@ function reduce(state, action) {
|
|
|
6786
6802
|
busyLabel: "",
|
|
6787
6803
|
planApproved: false,
|
|
6788
6804
|
pendingApprovals: [],
|
|
6789
|
-
queuedPrompts:
|
|
6805
|
+
queuedPrompts: import_core30.EMPTY_HOLD,
|
|
6790
6806
|
stopArmed: false,
|
|
6791
6807
|
overlay: state.overlay?.kind === "approval" ? null : state.overlay
|
|
6792
6808
|
});
|
|
@@ -6915,7 +6931,7 @@ function submit(state) {
|
|
|
6915
6931
|
return step(cleared, [{ type: "sendTaskMessage", sessionId: state.sessionId, taskId, text }]);
|
|
6916
6932
|
}
|
|
6917
6933
|
if (plannerInFlight(state)) {
|
|
6918
|
-
return step({ ...cleared, queuedPrompts: (0,
|
|
6934
|
+
return step({ ...cleared, queuedPrompts: (0, import_core30.holdPrompt)(state.queuedPrompts, text) });
|
|
6919
6935
|
}
|
|
6920
6936
|
const spoken = say(cleared, "user", text);
|
|
6921
6937
|
const effect = state.sessionId ? { type: "sendMessage", sessionId: state.sessionId, message: text } : { type: "startConversation", goal: text };
|
|
@@ -6975,10 +6991,10 @@ function createApp(deps) {
|
|
|
6975
6991
|
|
|
6976
6992
|
// src/tui/effects.ts
|
|
6977
6993
|
var import_child_process4 = require("child_process");
|
|
6978
|
-
var
|
|
6994
|
+
var import_core32 = require("@ordewell/core");
|
|
6979
6995
|
|
|
6980
6996
|
// src/tui/inbound.ts
|
|
6981
|
-
var
|
|
6997
|
+
var import_core31 = require("@ordewell/core");
|
|
6982
6998
|
var CONVERSATION_TYPES = /* @__PURE__ */ new Set([
|
|
6983
6999
|
"planner_message",
|
|
6984
7000
|
"planner_turn_started",
|
|
@@ -7193,7 +7209,7 @@ function dispatchLifecycle(dispatch, event, sessionId) {
|
|
|
7193
7209
|
idleSince: task.idleSince ?? null,
|
|
7194
7210
|
isolation: task.isolation,
|
|
7195
7211
|
transport: task.transport,
|
|
7196
|
-
awaitingReason: (0,
|
|
7212
|
+
awaitingReason: (0, import_core31.isAwaitingReason)(task.awaitingReason) ? task.awaitingReason : void 0,
|
|
7197
7213
|
...task.continuable ? { continuable: true } : {},
|
|
7198
7214
|
awaitingApproval: typeof task.awaitingApproval === "number" && task.awaitingApproval > 0 ? task.awaitingApproval : void 0
|
|
7199
7215
|
};
|
|
@@ -7207,7 +7223,7 @@ function dispatchLifecycle(dispatch, event, sessionId) {
|
|
|
7207
7223
|
// The extension shows these in its checkpoint panel; here they are
|
|
7208
7224
|
// transcript lines, which is the TUI's equivalent surface.
|
|
7209
7225
|
case "checkpoint":
|
|
7210
|
-
dispatch({ type: "notice", message: `\xB7 Checkpoint \u2014 ${event.taskTitle}: ${(0,
|
|
7226
|
+
dispatch({ type: "notice", message: `\xB7 Checkpoint \u2014 ${event.taskTitle}: ${(0, import_core31.truncateCheckpointSummary)(event.summary)}` });
|
|
7211
7227
|
return;
|
|
7212
7228
|
case "review_needed":
|
|
7213
7229
|
dispatch({ type: "notice", message: "Plan needs your sign-off \u2014 /approve to continue." });
|
|
@@ -7405,7 +7421,14 @@ async function perform(effect, deps) {
|
|
|
7405
7421
|
}
|
|
7406
7422
|
return;
|
|
7407
7423
|
}
|
|
7424
|
+
// A task with a saved log ran structured, whatever its `transport` says
|
|
7425
|
+
// after a reload; it has no tmux window, so open the log rather than fail.
|
|
7408
7426
|
case "openTaskTerminal": {
|
|
7427
|
+
const saved = await api.getTaskLogAttempts(effect.sessionId, effect.taskId, workspace).catch(() => []);
|
|
7428
|
+
if (saved.length > 0) {
|
|
7429
|
+
dispatch({ type: "taskViewRequested", sessionId: effect.sessionId, taskId: effect.taskId });
|
|
7430
|
+
return;
|
|
7431
|
+
}
|
|
7409
7432
|
const result = await deps.openTerminal(effect.sessionId, effect.taskId);
|
|
7410
7433
|
dispatch(result.ok ? { type: "notice", message: result.message } : { type: "failed", message: result.message });
|
|
7411
7434
|
return;
|
|
@@ -7460,7 +7483,7 @@ async function perform(effect, deps) {
|
|
|
7460
7483
|
case "setTransport": {
|
|
7461
7484
|
const result = await api.sendCommand("transport", { action: effect.transport });
|
|
7462
7485
|
if (result.settings) dispatch({ type: "settingsLoaded", settings: result.settings });
|
|
7463
|
-
dispatch({ type: "notice", message: `Runner transport is ${effect.transport}
|
|
7486
|
+
dispatch({ type: "notice", message: `Runner transport is ${effect.transport} \u2014 it applies from the next run.` });
|
|
7464
7487
|
return;
|
|
7465
7488
|
}
|
|
7466
7489
|
case "setModel":
|
|
@@ -7470,7 +7493,7 @@ async function perform(effect, deps) {
|
|
|
7470
7493
|
dispatch({ type: "notice", message: `Orchestrator model set to ${effect.modelId}.` });
|
|
7471
7494
|
return;
|
|
7472
7495
|
case "setPlanner": {
|
|
7473
|
-
const meta =
|
|
7496
|
+
const meta = import_core32.ALL_PROVIDERS[effect.provider];
|
|
7474
7497
|
if (!meta) throw new Error(`Unknown planner: ${effect.provider}`);
|
|
7475
7498
|
const env = { AI_PROVIDER: effect.provider };
|
|
7476
7499
|
const settings = await api.updateSettings({ env });
|
|
@@ -7482,7 +7505,7 @@ async function perform(effect, deps) {
|
|
|
7482
7505
|
});
|
|
7483
7506
|
dispatch({
|
|
7484
7507
|
type: "notice",
|
|
7485
|
-
message: `${(0,
|
|
7508
|
+
message: `${(0, import_core32.isCliProvider)(effect.provider) ? `Planning with ${meta.label} \u2014 no API key needed.` : `Planner set to ${meta.label}.`} ${plannerModelNotice(recall2)}`
|
|
7486
7509
|
});
|
|
7487
7510
|
await loadModels(deps);
|
|
7488
7511
|
return;
|
|
@@ -7494,7 +7517,7 @@ async function perform(effect, deps) {
|
|
|
7494
7517
|
dispatch({ type: "notice", message: `Planner effort set to ${effect.effort || "the runner default"}.` });
|
|
7495
7518
|
return;
|
|
7496
7519
|
case "setApiKey": {
|
|
7497
|
-
const meta =
|
|
7520
|
+
const meta = import_core32.ALL_PROVIDERS[effect.provider];
|
|
7498
7521
|
if (!meta) throw new Error(`Unknown provider: ${effect.provider}`);
|
|
7499
7522
|
await api.updateSettings({ env: { [meta.apiKeyEnvVar]: effect.key } });
|
|
7500
7523
|
deps.setEnvVar(meta.apiKeyEnvVar, effect.key);
|
|
@@ -7532,7 +7555,7 @@ async function perform(effect, deps) {
|
|
|
7532
7555
|
return;
|
|
7533
7556
|
case "setAutonomous":
|
|
7534
7557
|
deps.setEnvVar("ORDEWELL_AUTONOMOUS_MODE", String(effect.enabled));
|
|
7535
|
-
dispatch({ type: "notice", message: `
|
|
7558
|
+
dispatch({ type: "notice", message: `Autonomy level: ${(0, import_core32.autonomyLevelLabel)(effect.enabled)} for new plans.` });
|
|
7536
7559
|
return;
|
|
7537
7560
|
case "setMouseCapture":
|
|
7538
7561
|
deps.setMouseCapture(effect.enabled);
|
|
@@ -7665,7 +7688,7 @@ function osc52(text) {
|
|
|
7665
7688
|
function copySelection(deps, text) {
|
|
7666
7689
|
if (!text) return;
|
|
7667
7690
|
const lines = text.split("\n").length;
|
|
7668
|
-
const command = (0,
|
|
7691
|
+
const command = (0, import_core32.clipboardCopyCommand)(deps.hasBin);
|
|
7669
7692
|
if (command) {
|
|
7670
7693
|
try {
|
|
7671
7694
|
(deps.pipeToClipboard ?? pipeToClipboardDefault)(command, text);
|
|
@@ -8055,7 +8078,7 @@ async function handleTui(subArgs) {
|
|
|
8055
8078
|
}
|
|
8056
8079
|
const workspace = flag(subArgs, "--workspace") || process.cwd();
|
|
8057
8080
|
try {
|
|
8058
|
-
(0,
|
|
8081
|
+
(0, import_core33.assertWorkspaceExists)(workspace);
|
|
8059
8082
|
} catch {
|
|
8060
8083
|
console.error(
|
|
8061
8084
|
`Workspace "${workspace}" does not exist.
|
|
@@ -8064,7 +8087,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
|
|
|
8064
8087
|
);
|
|
8065
8088
|
process.exit(1);
|
|
8066
8089
|
}
|
|
8067
|
-
registerSkillCommands((0,
|
|
8090
|
+
registerSkillCommands((0, import_core33.createSkillsService)(workspace).listSkills());
|
|
8068
8091
|
const explicitPort = flag(subArgs, "--port") || process.env.ORDEWELL_PORT;
|
|
8069
8092
|
const targetPort = explicitPort ? resolvePort(subArgs) : await findFreePort();
|
|
8070
8093
|
const { port, owned: ownedAtLaunch } = await ensureDaemonOwned(targetPort, { detached: false });
|
|
@@ -8081,7 +8104,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
|
|
|
8081
8104
|
workspace,
|
|
8082
8105
|
port,
|
|
8083
8106
|
dispatch: (action) => app.dispatch(action),
|
|
8084
|
-
newSessionId: () => (0,
|
|
8107
|
+
newSessionId: () => (0, import_core33.mintSessionId)(),
|
|
8085
8108
|
setEnvVar: (key, value) => {
|
|
8086
8109
|
writeEnvVar(findEnvFile(), key, value);
|
|
8087
8110
|
process.env[key] = value;
|
|
@@ -8204,7 +8227,7 @@ function cliVersion() {
|
|
|
8204
8227
|
// src/main.ts
|
|
8205
8228
|
var TUI_FLAGS = /* @__PURE__ */ new Set(["--workspace", "--port"]);
|
|
8206
8229
|
async function main() {
|
|
8207
|
-
(0,
|
|
8230
|
+
(0, import_core34.migrateOldConfigDir)();
|
|
8208
8231
|
loadEnvFile();
|
|
8209
8232
|
const argv = process.argv.slice(2);
|
|
8210
8233
|
if (TUI_FLAGS.has(argv[0] ?? "")) argv.unshift("tui");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ordewell/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"typecheck": "tsc --noEmit"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@ordewell/core": "^0.
|
|
53
|
-
"@ordewell/web": "^0.
|
|
52
|
+
"@ordewell/core": "^0.6.0",
|
|
53
|
+
"@ordewell/web": "^0.6.0",
|
|
54
54
|
"string-width": "^7.2.0",
|
|
55
55
|
"ws": "^8.18.0"
|
|
56
56
|
},
|