@ordewell/cli 0.10.9 → 0.10.11
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 +11 -7
- package/dist/main.js +99 -305
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -19,17 +19,21 @@ on Windows, run the terminal UI under WSL.
|
|
|
19
19
|
|
|
20
20
|
Run `ordewell` in your project to open the terminal UI: the conversation on the
|
|
21
21
|
left, the live plan on the right. The first run lets you pick a planner and runners
|
|
22
|
-
with `/planner` (Harness › Model › Effort, saved
|
|
22
|
+
with `/planner` (Harness › Model › Effort, each step saved as you go) and `/runners`, and no API key is needed if you plan with a coding
|
|
23
23
|
agent you already use.
|
|
24
24
|
The welcome screen says it plainly: nothing runs until you approve the plan (unless autorun is on).
|
|
25
25
|
|
|
26
26
|
`/settings` walks autonomy, supervisor, merge automatically, autorun and parallel
|
|
27
|
-
in one panel and saves only what you changed. `/
|
|
28
|
-
|
|
29
|
-
full key sheet; the footer shows only the keys that apply
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
in one panel and saves only what you changed. `/planner` walks harness, model and
|
|
28
|
+
effort in one flow, so there is no separate model or effort command. Press `?` in
|
|
29
|
+
the plan pane for the full key sheet; the footer shows only the keys that apply
|
|
30
|
+
to the selected task.
|
|
31
|
+
|
|
32
|
+
Every command in the terminal UI is also a subcommand, except `/settings`: it is
|
|
33
|
+
a panel over headless commands that remain for scripts (`ordewell auto`,
|
|
34
|
+
`supervisor`, `automerge`, `autorun` and `parallel`). `/planner` has its own
|
|
35
|
+
`ordewell planner`, and its model and effort steps are `ordewell model` and
|
|
36
|
+
`ordewell planner-effort`.
|
|
33
37
|
|
|
34
38
|
```bash
|
|
35
39
|
export AI_PROVIDER=claude-code # plan with Claude Code, Codex or OpenCode
|
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_core51 = require("@ordewell/core");
|
|
28
28
|
|
|
29
29
|
// src/utils/env.ts
|
|
30
30
|
var import_fs = require("fs");
|
|
@@ -129,9 +129,10 @@ function printHelp() {
|
|
|
129
129
|
console.log(`
|
|
130
130
|
Ordewell: task orchestration for coding agents
|
|
131
131
|
|
|
132
|
-
Run "ordewell" with no arguments for the TUI.
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
Run "ordewell" with no arguments for the TUI. Where a command has a slash
|
|
133
|
+
command, both take the same name. The headless run-setting and planner-step
|
|
134
|
+
commands marked "(headless)" are set in /settings and /planner in the TUI and
|
|
135
|
+
VS Code.
|
|
135
136
|
|
|
136
137
|
Planning:
|
|
137
138
|
ordewell Full-screen terminal UI (everything the VS Code extension does)
|
|
@@ -172,17 +173,17 @@ Per-task assignment (omit the value to list the options):
|
|
|
172
173
|
|
|
173
174
|
Planner, models and runners:
|
|
174
175
|
ordewell planner [<provider>] Choose who plans: an API provider or a coding agent (no API key)
|
|
175
|
-
ordewell model [set <id>] Show or set the planner model
|
|
176
|
-
ordewell planner-effort [lvl] Thinking effort for a coding-agent planner
|
|
176
|
+
ordewell model [set <id>] (headless) Show or set the planner model; /planner covers it in the TUI and VS Code
|
|
177
|
+
ordewell planner-effort [lvl] (headless) Thinking effort for a coding-agent planner; /planner covers it
|
|
177
178
|
ordewell key [set <p> <key>] Show which providers have a key, or store one
|
|
178
179
|
ordewell runners [<id> on|off] Enable or disable runners (${runnerIdList()})
|
|
179
180
|
ordewell allowlist set|clear|show Limit which models a runner may use
|
|
180
|
-
ordewell auto [full|guarded] Autonomy level for new plans
|
|
181
|
-
ordewell supervisor [off|watch|act] Whether the planner watches or acts on your runs
|
|
182
|
-
also: supervisor retries <n>, supervisor reads <n
|
|
183
|
-
ordewell automerge [on|off] Merge
|
|
184
|
-
ordewell autorun [on|off] Start each plan the planner submits, without review
|
|
185
|
-
ordewell parallel [<n>] How many AI tasks run at once
|
|
181
|
+
ordewell auto [full|guarded] (headless) Autonomy level for new plans, Full or Guarded; /settings covers it
|
|
182
|
+
ordewell supervisor [off|watch|act] (headless) Whether the planner watches or acts on your runs;
|
|
183
|
+
also: supervisor retries <n>, supervisor reads <n>; /settings covers it
|
|
184
|
+
ordewell automerge [on|off] (headless) Merge at merge gates and at the end of a run; /settings covers it
|
|
185
|
+
ordewell autorun [on|off] (headless) Start each plan the planner submits, without review; /settings covers it
|
|
186
|
+
ordewell parallel [<n>] (headless) How many AI tasks run at once, a live run included; /settings covers it
|
|
186
187
|
ordewell refresh Re-discover runners and model catalogs
|
|
187
188
|
ordewell models List every provider's catalog (works without a server)
|
|
188
189
|
|
|
@@ -2574,7 +2575,7 @@ function runnerCommandLines(block2, cols, detailAll) {
|
|
|
2574
2575
|
return [head, ...underHeader(shown.map(style.grey))];
|
|
2575
2576
|
}
|
|
2576
2577
|
function compactionLine(block2, cols) {
|
|
2577
|
-
const sizes = block2.preTokens !== void 0 && block2.postTokens !== void 0 ? ` \xB7 ${
|
|
2578
|
+
const sizes = block2.preTokens !== void 0 && block2.postTokens !== void 0 ? ` \xB7 ${(0, import_core14.formatTokenCount)(block2.preTokens)} \u2192 ${(0, import_core14.formatTokenCount)(block2.postTokens)} tokens` : "";
|
|
2578
2579
|
const text = block2.trigger === "auto" && !sizes ? "\u2261 Context compacted by the runner on its own" : `\u2261 Context compacted${sizes}`;
|
|
2579
2580
|
return style.grey(truncate(text, cols));
|
|
2580
2581
|
}
|
|
@@ -2650,37 +2651,10 @@ function conversationLines(blocks2, cols, detailAll, answering) {
|
|
|
2650
2651
|
}
|
|
2651
2652
|
return lines;
|
|
2652
2653
|
}
|
|
2653
|
-
function compactCount(n) {
|
|
2654
|
-
if (n < 1e3) return String(n);
|
|
2655
|
-
const [value, unit] = n < 999950 ? [n / 1e3, "k"] : [n / 1e6, "M"];
|
|
2656
|
-
return `${value.toFixed(1).replace(/\.0$/, "")}${unit}`;
|
|
2657
|
-
}
|
|
2658
|
-
function formatCost(currency, amount) {
|
|
2659
|
-
const [whole, frac = ""] = amount.toFixed(4).replace(/0+$/, "").split(".");
|
|
2660
|
-
const value = `${whole}.${frac.padEnd(2, "0")}`;
|
|
2661
|
-
return currency.toLowerCase() === "usd" ? `$${value}` : `${value} ${currency.toUpperCase()}`;
|
|
2662
|
-
}
|
|
2663
2654
|
function tokenLine(blocks2, cols) {
|
|
2664
2655
|
const usage = blocks2[blocks2.length - 1];
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
if (usage.model && !usage.contextFill) parts.push("ctx unknown");
|
|
2668
|
-
if (usage.contextFill) parts.splice(2, 0, `${Math.round(usage.contextFill.usedTokens / usage.contextFill.windowTokens * 100)}% ctx`);
|
|
2669
|
-
return parts.length > 0 ? style.grey(truncate(parts.join(" \xB7 "), cols)) : null;
|
|
2670
|
-
}
|
|
2671
|
-
function usageMeasures(totals) {
|
|
2672
|
-
return [
|
|
2673
|
-
...totals.inputTokens !== void 0 ? [`${compactCount(totals.inputTokens)} in`] : [],
|
|
2674
|
-
...totals.outputTokens !== void 0 ? [`${compactCount(totals.outputTokens)} out`] : [],
|
|
2675
|
-
...totals.cachedInputTokens !== void 0 ? [`${compactCount(totals.cachedInputTokens)} cached`] : [],
|
|
2676
|
-
...Object.entries(totals.reportedCost ?? {}).map(([currency, amount]) => formatCost(currency, amount))
|
|
2677
|
-
];
|
|
2678
|
-
}
|
|
2679
|
-
function taskUsageText(usage) {
|
|
2680
|
-
return [
|
|
2681
|
-
...usageMeasures(usage.totals),
|
|
2682
|
-
...usage.attempt !== void 0 ? [usage.contextFill ? `ctx ${Math.round(usage.contextFill.usedTokens / usage.contextFill.windowTokens * 100)}%` : "ctx unknown"] : []
|
|
2683
|
-
].join(" \xB7 ");
|
|
2656
|
+
const text = usage?.type === "usage" ? (0, import_core14.usageText)(usage) : null;
|
|
2657
|
+
return text ? style.grey(truncate(text, cols)) : null;
|
|
2684
2658
|
}
|
|
2685
2659
|
function assignmentFlagText(row) {
|
|
2686
2660
|
return `${row.assignmentFlag} \u2014 ${row.assignmentConsequence}`;
|
|
@@ -2767,8 +2741,8 @@ function printOneSession(sessionId, meta, plan, runnerScope) {
|
|
|
2767
2741
|
if (isolation) console.log(`Base: ${handoffBase(isolation.handoff, 8)}`);
|
|
2768
2742
|
console.log(`Tasks: ${everyTask.length} total | ${count("completed")} done | ${count("failed")} failed | ${count("in_progress")} running | ${count("blocked")} blocked | ${count("skipped")} skipped
|
|
2769
2743
|
`);
|
|
2770
|
-
const
|
|
2771
|
-
if (
|
|
2744
|
+
const total = (0, import_core15.tasksTotalText)(allTasks);
|
|
2745
|
+
if (total) console.log(total);
|
|
2772
2746
|
const record = servedApprovalRecord(plan);
|
|
2773
2747
|
const approval = (row, ref) => row.waitsForApproval ? `${row.waitsForApproval}: \`ordewell force-start ${ref}\` approves it, \`ordewell run\` approves all` : null;
|
|
2774
2748
|
for (const t of allTasks) {
|
|
@@ -2782,7 +2756,8 @@ function printOneSession(sessionId, meta, plan, runnerScope) {
|
|
|
2782
2756
|
if (row.assignmentFlag) console.log(` \u26A0 ${assignmentFlagText(row)}`);
|
|
2783
2757
|
if (row.blockedBy) console.log(` ${(0, import_core15.blockedByLabel)(row.blockedBy)}`);
|
|
2784
2758
|
if (row.status === "skipped") console.log(` ${(0, import_core15.skippedLabel)(row.skipReason)}`);
|
|
2785
|
-
|
|
2759
|
+
const usage = row.usage && (0, import_core15.usageText)(row.usage);
|
|
2760
|
+
if (usage) console.log(` ${usage}`);
|
|
2786
2761
|
for (const sub of t.subtasks || []) {
|
|
2787
2762
|
const subIcon = iconFor(blocked.has(sub.id) ? "blocked" : sub.status);
|
|
2788
2763
|
const subModel = sub.assignedModel ? ` (${sub.assignedModel.modelLabel})` : "";
|
|
@@ -2794,7 +2769,8 @@ function printOneSession(sessionId, meta, plan, runnerScope) {
|
|
|
2794
2769
|
if (subRow.assignmentFlag) console.log(` \u26A0 ${assignmentFlagText(subRow)}`);
|
|
2795
2770
|
if (subRow.blockedBy) console.log(` ${(0, import_core15.blockedByLabel)(subRow.blockedBy)}`);
|
|
2796
2771
|
if (subRow.status === "skipped") console.log(` ${(0, import_core15.skippedLabel)(subRow.skipReason)}`);
|
|
2797
|
-
|
|
2772
|
+
const subUsage = subRow.usage && (0, import_core15.usageText)(subRow.usage);
|
|
2773
|
+
if (subUsage) console.log(` ${subUsage}`);
|
|
2798
2774
|
}
|
|
2799
2775
|
}
|
|
2800
2776
|
}
|
|
@@ -4697,7 +4673,7 @@ ${namedOf(tasks, task)} is ${task.ops ? "an ops task: it runs in your checkout o
|
|
|
4697
4673
|
}
|
|
4698
4674
|
|
|
4699
4675
|
// src/tui/index.ts
|
|
4700
|
-
var
|
|
4676
|
+
var import_core50 = require("@ordewell/core");
|
|
4701
4677
|
|
|
4702
4678
|
// src/tui/slash.ts
|
|
4703
4679
|
var import_core30 = require("@ordewell/core");
|
|
@@ -4730,16 +4706,9 @@ var SLASH_COMMANDS = [
|
|
|
4730
4706
|
{ name: "task-ops", usage: "/task-ops <id> [on|off]", description: "Choose between an ops task (runs in your checkout once its dependencies are merged) and a change task", category: "tasks" },
|
|
4731
4707
|
// Models & providers
|
|
4732
4708
|
{ name: "planner", usage: "/planner [<provider>]", description: "Pick the planner: harness, model and effort in one go", category: "models" },
|
|
4733
|
-
{ name: "model", usage: "/model [set <id>]", description: "Show or set the planner model", category: "models" },
|
|
4734
|
-
{ name: "planner-effort", usage: "/planner-effort [<level>]", description: "Thinking effort for a coding-agent planner", category: "models" },
|
|
4735
4709
|
{ name: "key", usage: "/key [set <provider> <key>]", description: "Configure API provider keys", category: "models" },
|
|
4736
4710
|
{ name: "allowlist", usage: "/allowlist [set <runner> <ids> | clear <runner>]", description: "Limit which models a runner may use", category: "models" },
|
|
4737
4711
|
{ name: "runners", usage: "/runners [<id> on|off]", description: `Enable or disable runners (${runnerIdList()})`, category: "models" },
|
|
4738
|
-
{ name: "auto", usage: "/auto [full|guarded]", description: "Autonomy level for new plans: Full or Guarded", category: "models" },
|
|
4739
|
-
{ 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" },
|
|
4740
|
-
{ 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" },
|
|
4741
|
-
{ name: "autorun", usage: "/autorun [on|off]", description: "Start each plan the planner submits, without review", category: "models" },
|
|
4742
|
-
{ name: "parallel", usage: "/parallel [<n>]", description: "How many AI tasks run at once (applies to a live run)", category: "models" },
|
|
4743
4712
|
{ name: "settings", usage: "/settings", description: "Run settings: autonomy, supervisor, merging, autorun, parallel tasks", category: "models" },
|
|
4744
4713
|
{ name: "refresh", usage: "/refresh", description: "Re-discover runners and model catalogs", category: "models" },
|
|
4745
4714
|
// Sessions
|
|
@@ -4880,8 +4849,7 @@ function refillPicker(state, kinds) {
|
|
|
4880
4849
|
const overlay = state.overlay;
|
|
4881
4850
|
if (overlay?.kind !== "picker" || !kinds.includes(overlay.picker.action.kind)) return state;
|
|
4882
4851
|
const items = pickerItemsFor(state, overlay.picker.action);
|
|
4883
|
-
|
|
4884
|
-
return { ...state, overlay: { kind: "picker", picker: { ...overlay.picker, items, hint, index: 0 } } };
|
|
4852
|
+
return { ...state, overlay: { kind: "picker", picker: { ...overlay.picker, items, index: 0 } } };
|
|
4885
4853
|
}
|
|
4886
4854
|
function reseedRunnerChoice(before, after) {
|
|
4887
4855
|
const overlay = after.overlay;
|
|
@@ -4895,16 +4863,20 @@ function reseedRunnerChoice(before, after) {
|
|
|
4895
4863
|
function modelDetail(m) {
|
|
4896
4864
|
return [m.provider, m.pricing].filter(Boolean).join(" \xB7 ") || void 0;
|
|
4897
4865
|
}
|
|
4898
|
-
function providerErrorHint(state) {
|
|
4899
|
-
const failed = Object.keys(state.providerErrors ?? {});
|
|
4900
|
-
if (failed.length === 0) return void 0;
|
|
4901
|
-
const names = failed.map((p) => (0, import_core31.getProviderMeta)(p)?.label ?? p);
|
|
4902
|
-
return `\u26A0 Unavailable (key or fetch failed): ${names.join(", ")}. Showing working providers only.`;
|
|
4903
|
-
}
|
|
4904
4866
|
function plannerModelItems(state, provider, selectedId) {
|
|
4905
4867
|
const runner = (0, import_core31.runnerForProvider)(provider);
|
|
4906
4868
|
if (!runner) {
|
|
4907
|
-
|
|
4869
|
+
const failed = Object.entries(state.providerErrors ?? {});
|
|
4870
|
+
const unavailable = failed.length === 0 ? [] : [{
|
|
4871
|
+
id: "",
|
|
4872
|
+
label: "Some providers are unavailable",
|
|
4873
|
+
detail: `\u26A0 ${failed.map(([id]) => (0, import_core31.getProviderMeta)(id)?.label ?? id).join(", ")}: key or fetch failed`,
|
|
4874
|
+
disabled: true
|
|
4875
|
+
}];
|
|
4876
|
+
return [
|
|
4877
|
+
...unavailable,
|
|
4878
|
+
...state.orchestratorModels.map((m) => ({ id: m.id, label: m.label, detail: modelDetail(m), selected: m.id === selectedId }))
|
|
4879
|
+
];
|
|
4908
4880
|
}
|
|
4909
4881
|
const items = state.models.filter((m) => m.runners?.includes(runner)).map((m) => ({
|
|
4910
4882
|
id: m.id,
|
|
@@ -4927,7 +4899,7 @@ function plannerEffortItems(state, provider, modelId, selectedEffort) {
|
|
|
4927
4899
|
}
|
|
4928
4900
|
const model = plannerHarnessModel(state, provider, modelId);
|
|
4929
4901
|
if (!model) {
|
|
4930
|
-
return [{ id: "", label: "No planner model selected", detail: "pick one with /
|
|
4902
|
+
return [{ id: "", label: "No planner model selected", detail: "pick one with /planner", disabled: true }];
|
|
4931
4903
|
}
|
|
4932
4904
|
const variants = model.variants ?? [];
|
|
4933
4905
|
if (variants.length === 0) {
|
|
@@ -4939,12 +4911,6 @@ function plannerEffortItems(state, provider, modelId, selectedEffort) {
|
|
|
4939
4911
|
];
|
|
4940
4912
|
}
|
|
4941
4913
|
function pickerItemsFor(state, action) {
|
|
4942
|
-
if (action.kind === "set-model") {
|
|
4943
|
-
return plannerModelItems(state, state.plannerProvider, state.orchestratorModel);
|
|
4944
|
-
}
|
|
4945
|
-
if (action.kind === "set-planner-effort") {
|
|
4946
|
-
return plannerEffortItems(state, state.plannerProvider, state.orchestratorModel, state.plannerEffort);
|
|
4947
|
-
}
|
|
4948
4914
|
if (action.kind === "rewind") {
|
|
4949
4915
|
if (state.rewindTargets === null) return [];
|
|
4950
4916
|
if (state.rewindTargets.length === 0) {
|
|
@@ -5373,11 +5339,11 @@ function taskUsageFooter(state, tv, blocks2, cols) {
|
|
|
5373
5339
|
const reported = task?.attemptUsage ?? [];
|
|
5374
5340
|
if (!task || reported.length === 0) return tokenRow(blocks2, cols);
|
|
5375
5341
|
const onScreen = tv.attempt > 0 ? reported.find((a) => a.attempt === tv.attempt) : reported.at(-1);
|
|
5376
|
-
const
|
|
5377
|
-
const
|
|
5378
|
-
if (onScreen === reported.at(-1)) return
|
|
5379
|
-
const own = onScreen ?
|
|
5380
|
-
return [...own
|
|
5342
|
+
const total = (0, import_core34.usageText)((0, import_core34.taskUsageSummary)(task));
|
|
5343
|
+
const totalRow = total ? [style.grey(truncate(onScreen === reported.at(-1) ? total : `task total: ${total}`, cols))] : [];
|
|
5344
|
+
if (onScreen === reported.at(-1)) return totalRow;
|
|
5345
|
+
const own = onScreen ? (0, import_core34.usageText)({ totals: onScreen.totals, contextFill: (0, import_core34.plannerContextFill)(onScreen) }) : null;
|
|
5346
|
+
return [...onScreen ? own ? [style.grey(truncate(`attempt ${onScreen.attempt}: ${own}`, cols))] : [] : tokenRow(blocks2, cols), ...totalRow];
|
|
5381
5347
|
}
|
|
5382
5348
|
function chatScrollMax(state) {
|
|
5383
5349
|
return chatLayout(state, bodyRows(state), chatPaneWidth(state)).maxScroll;
|
|
@@ -5533,18 +5499,18 @@ var STATUS_ICON = {
|
|
|
5533
5499
|
var inRow = (label) => label.charAt(0).toLowerCase() + label.slice(1);
|
|
5534
5500
|
function planLayout(state, rows, cols) {
|
|
5535
5501
|
const done = state.tasks.filter((t) => t.status === "completed").length;
|
|
5536
|
-
const totalUsage = (0, import_core34.
|
|
5502
|
+
const totalUsage = (0, import_core34.tasksTotalText)(state.tasks);
|
|
5537
5503
|
const unmerged = state.runMerge?.handoff.landed.length ?? 0;
|
|
5538
5504
|
const count = `${done}/${state.tasks.length}`;
|
|
5539
5505
|
const hints = runHints(state);
|
|
5540
5506
|
const hint = hints.find((h) => width(`Plan ${count} \xB7 ${h}`) <= cols) ?? hints.at(-1);
|
|
5541
5507
|
const lines = [
|
|
5542
5508
|
truncate(`${style.bold(style.brand("Plan"))} ${style.grey(`${count}${hint ? ` \xB7 ${hint}` : ""}`)}`, cols),
|
|
5543
|
-
totalUsage
|
|
5509
|
+
totalUsage ? style.grey(truncate(totalUsage, cols)) : ""
|
|
5544
5510
|
];
|
|
5545
5511
|
if (unmerged > 0) {
|
|
5546
5512
|
const landed = style.dim(truncate(`${unmerged} landed task${unmerged === 1 ? "" : "s"} not merged: /handoff merge`, cols));
|
|
5547
|
-
if (totalUsage
|
|
5513
|
+
if (totalUsage) lines.push(landed);
|
|
5548
5514
|
else lines[1] = landed;
|
|
5549
5515
|
}
|
|
5550
5516
|
const firstRowLine = lines.length;
|
|
@@ -5721,7 +5687,7 @@ function taskLines(state, planRow, index, cols) {
|
|
|
5721
5687
|
lines.push(...taskText("Forced", `Started before the work of ${row.forcedPastGate.join(", ")} was merged into your branch.`, cols, bodyPad));
|
|
5722
5688
|
}
|
|
5723
5689
|
if (row.autonomous) {
|
|
5724
|
-
lines.push(...taskText("Autonomy", "Runs without permission prompts (Full). Change the level with /
|
|
5690
|
+
lines.push(...taskText("Autonomy", "Runs without permission prompts (Full). Change the level with /settings.", cols, bodyPad));
|
|
5725
5691
|
}
|
|
5726
5692
|
const editableSeed = task.prompt ?? task.description ?? task.title;
|
|
5727
5693
|
if (task.description && task.description !== task.title && task.description !== editableSeed) {
|
|
@@ -6301,10 +6267,10 @@ function frame(title, body, rows, cols) {
|
|
|
6301
6267
|
}
|
|
6302
6268
|
|
|
6303
6269
|
// src/tui/reducer.ts
|
|
6304
|
-
var
|
|
6270
|
+
var import_core48 = require("@ordewell/core");
|
|
6305
6271
|
|
|
6306
6272
|
// src/tui/reducers/overlays.ts
|
|
6307
|
-
var
|
|
6273
|
+
var import_core47 = require("@ordewell/core");
|
|
6308
6274
|
|
|
6309
6275
|
// src/tui/reducers/approvals.ts
|
|
6310
6276
|
var import_core37 = require("@ordewell/core");
|
|
@@ -6373,7 +6339,7 @@ function handleApprovalKey(state, overlay, key) {
|
|
|
6373
6339
|
}
|
|
6374
6340
|
|
|
6375
6341
|
// src/tui/reducers/commands.ts
|
|
6376
|
-
var
|
|
6342
|
+
var import_core46 = require("@ordewell/core");
|
|
6377
6343
|
|
|
6378
6344
|
// src/tui/reducers/plannerStepper.ts
|
|
6379
6345
|
var import_core38 = require("@ordewell/core");
|
|
@@ -7329,73 +7295,8 @@ function followSession(state, message) {
|
|
|
7329
7295
|
return message.type === "approval_settled" ? dropApproval(heard, message.id) : heard;
|
|
7330
7296
|
}
|
|
7331
7297
|
|
|
7332
|
-
// src/tui/reducers/runSettings.ts
|
|
7333
|
-
var import_core45 = require("@ordewell/core");
|
|
7334
|
-
function runSettingsEffect(state, changes) {
|
|
7335
|
-
return { type: "setRunSettings", changes, ...state.sessionId ? { sessionId: state.sessionId } : {} };
|
|
7336
|
-
}
|
|
7337
|
-
function supervisorCommand(state, args) {
|
|
7338
|
-
const [arg, value] = args;
|
|
7339
|
-
if (arg === void 0) {
|
|
7340
|
-
return step(say(state, "system", `${(0, import_core45.supervisorSummary)(state.runSettings)}: /supervisor off|watch|act, /supervisor retries <n>, /supervisor reads <n>.`));
|
|
7341
|
-
}
|
|
7342
|
-
if (arg === "retries") {
|
|
7343
|
-
const n = (0, import_core45.parseCount)(value, 0);
|
|
7344
|
-
return n === null ? fail3(state, "Usage: /supervisor retries <whole number, 0 or more>") : step(state, [runSettingsEffect(state, { supervisorRetryLimit: n })]);
|
|
7345
|
-
}
|
|
7346
|
-
if (arg === "reads") {
|
|
7347
|
-
const n = (0, import_core45.parseCount)(value, 1);
|
|
7348
|
-
return n === null ? fail3(state, "Usage: /supervisor reads <whole number, 1 or more>") : step(state, [runSettingsEffect(state, { wakeUpReadBudget: n })]);
|
|
7349
|
-
}
|
|
7350
|
-
if (arg === "act") return confirmSupervisorAct(state);
|
|
7351
|
-
if (arg === "off" || arg === "watch") return step(state, [runSettingsEffect(state, { supervisorLevel: arg })]);
|
|
7352
|
-
return fail3(state, "Usage: /supervisor [off|watch|act] \xB7 /supervisor retries <n> \xB7 /supervisor reads <n>");
|
|
7353
|
-
}
|
|
7354
|
-
function automergeCommand(state, arg) {
|
|
7355
|
-
if (arg === void 0) {
|
|
7356
|
-
return step(say(state, "system", `${(0, import_core45.automergeSummary)(state.runSettings)}: /automerge on|off.`));
|
|
7357
|
-
}
|
|
7358
|
-
const enabled = (0, import_core45.parseSwitch)(arg);
|
|
7359
|
-
if (enabled === null) return fail3(state, "Usage: /automerge [on|off]");
|
|
7360
|
-
return step(state, [runSettingsEffect(state, { mergeAtGatesAutomatically: enabled })]);
|
|
7361
|
-
}
|
|
7362
|
-
function autorunCommand(state, arg) {
|
|
7363
|
-
if (arg === void 0) {
|
|
7364
|
-
return step(say(state, "system", `${(0, import_core45.autorunSummary)(state.runSettings)}: /autorun on starts each plan the planner submits, without review.`));
|
|
7365
|
-
}
|
|
7366
|
-
const enabled = (0, import_core45.parseSwitch)(arg);
|
|
7367
|
-
if (enabled === null) return fail3(state, "Usage: /autorun [on|off]");
|
|
7368
|
-
if (enabled) return confirmAutorun(state);
|
|
7369
|
-
return step(state, [runSettingsEffect(state, { autorun: false })]);
|
|
7370
|
-
}
|
|
7371
|
-
function confirmSupervisorAct(state) {
|
|
7372
|
-
return step({
|
|
7373
|
-
...state,
|
|
7374
|
-
overlay: {
|
|
7375
|
-
kind: "confirm",
|
|
7376
|
-
title: "Let the supervisor act?",
|
|
7377
|
-
message: "At Act the supervisor runs, stops and retries tasks, answers their requests (never allowing), edits the plan and merges, without asking you.",
|
|
7378
|
-
note: `${import_core45.ACT_RISK}
|
|
7379
|
-
It applies to this session's run now, and to every later run.`,
|
|
7380
|
-
action: { kind: "supervisor-act" }
|
|
7381
|
-
}
|
|
7382
|
-
});
|
|
7383
|
-
}
|
|
7384
|
-
function confirmAutorun(state) {
|
|
7385
|
-
return step({
|
|
7386
|
-
...state,
|
|
7387
|
-
overlay: {
|
|
7388
|
-
kind: "confirm",
|
|
7389
|
-
title: "Start plans without review?",
|
|
7390
|
-
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.",
|
|
7391
|
-
note: import_core45.AUTORUN_RISK,
|
|
7392
|
-
action: { kind: "autorun-on" }
|
|
7393
|
-
}
|
|
7394
|
-
});
|
|
7395
|
-
}
|
|
7396
|
-
|
|
7397
7298
|
// src/tui/reducers/settings.ts
|
|
7398
|
-
var
|
|
7299
|
+
var import_core45 = require("@ordewell/core");
|
|
7399
7300
|
var SUPERVISOR_DETAIL = {
|
|
7400
7301
|
off: "The planner speaks only when you write",
|
|
7401
7302
|
watch: "The planner follows your runs and suggests what to do",
|
|
@@ -7420,7 +7321,7 @@ var SETTINGS = {
|
|
|
7420
7321
|
{
|
|
7421
7322
|
id: "guarded",
|
|
7422
7323
|
label: "Guarded",
|
|
7423
|
-
detail: [`New plans run tasks in each runner's safer mode`, (0,
|
|
7324
|
+
detail: [`New plans run tasks in each runner's safer mode`, (0, import_core45.codexSandboxNotice)(state.modesByRunner)?.line].filter(Boolean).join(" \xB7 "),
|
|
7424
7325
|
selected: !state.autonomous
|
|
7425
7326
|
}
|
|
7426
7327
|
]
|
|
@@ -7430,7 +7331,7 @@ var SETTINGS = {
|
|
|
7430
7331
|
label: "Supervisor",
|
|
7431
7332
|
items: (state) => ["off", "watch", "act"].map((level) => ({
|
|
7432
7333
|
id: level,
|
|
7433
|
-
label:
|
|
7334
|
+
label: import_core45.SUPERVISOR_LEVEL_LABEL[level],
|
|
7434
7335
|
detail: SUPERVISOR_DETAIL[level],
|
|
7435
7336
|
selected: state.runSettings.supervisorLevel === level
|
|
7436
7337
|
}))
|
|
@@ -7484,12 +7385,12 @@ function saveChoices(state, choices) {
|
|
|
7484
7385
|
const autonomous = choices.autonomy === "full";
|
|
7485
7386
|
if (autonomous !== state.autonomous) {
|
|
7486
7387
|
save2.autonomous = autonomous;
|
|
7487
|
-
changed.push(`Autonomy ${(0,
|
|
7388
|
+
changed.push(`Autonomy ${(0, import_core45.autonomyLevelLabel)(autonomous)}`);
|
|
7488
7389
|
}
|
|
7489
7390
|
const level = choices.supervisor;
|
|
7490
7391
|
if (level !== state.runSettings.supervisorLevel) {
|
|
7491
7392
|
run.supervisorLevel = level;
|
|
7492
|
-
changed.push(`Supervisor ${
|
|
7393
|
+
changed.push(`Supervisor ${import_core45.SUPERVISOR_LEVEL_LABEL[level]}`);
|
|
7493
7394
|
}
|
|
7494
7395
|
if (choices.retries !== void 0 && Number(choices.retries) !== state.runSettings.supervisorRetryLimit) {
|
|
7495
7396
|
run.supervisorRetryLimit = Number(choices.retries);
|
|
@@ -7516,7 +7417,7 @@ function saveChoices(state, choices) {
|
|
|
7516
7417
|
}
|
|
7517
7418
|
if (changed.length === 0) return step(state);
|
|
7518
7419
|
const effect = { ...save2, message: `Settings: ${changed.join(" \xB7 ")}` };
|
|
7519
|
-
const risks = [...run.supervisorLevel === "act" ? [
|
|
7420
|
+
const risks = [...run.supervisorLevel === "act" ? [import_core45.ACT_RISK] : [], ...run.autorun ? [import_core45.AUTORUN_RISK] : []];
|
|
7520
7421
|
if (risks.length === 0) return saveSettings(state, effect);
|
|
7521
7422
|
return step({
|
|
7522
7423
|
...state,
|
|
@@ -7567,28 +7468,14 @@ function runCommand(state, { name, args }) {
|
|
|
7567
7468
|
state,
|
|
7568
7469
|
(sessionId) => plannerInFlight(state) ? stopPlanning(state, sessionId) : step(state, [{ type: "stopExecution", sessionId }])
|
|
7569
7470
|
);
|
|
7570
|
-
case "model":
|
|
7571
|
-
return setModel(state, args);
|
|
7572
7471
|
case "planner":
|
|
7573
7472
|
return setPlanner(state, args);
|
|
7574
|
-
case "planner-effort":
|
|
7575
|
-
return setPlannerEffort(state, args);
|
|
7576
7473
|
case "key":
|
|
7577
7474
|
return setKey(state, args);
|
|
7578
7475
|
case "allowlist":
|
|
7579
7476
|
return allowlist(state, args);
|
|
7580
7477
|
case "runners":
|
|
7581
7478
|
return runners(state, args);
|
|
7582
|
-
case "auto":
|
|
7583
|
-
return setAutonomous(state, args[0]);
|
|
7584
|
-
case "supervisor":
|
|
7585
|
-
return supervisorCommand(state, args);
|
|
7586
|
-
case "automerge":
|
|
7587
|
-
return automergeCommand(state, args[0]);
|
|
7588
|
-
case "autorun":
|
|
7589
|
-
return autorunCommand(state, args[0]);
|
|
7590
|
-
case "parallel":
|
|
7591
|
-
return setMaxParallel(state, args[0]);
|
|
7592
7479
|
case "settings":
|
|
7593
7480
|
return openSettings(state);
|
|
7594
7481
|
case "mouse":
|
|
@@ -7709,8 +7596,8 @@ function newSession(state) {
|
|
|
7709
7596
|
goal: "",
|
|
7710
7597
|
taskView: null,
|
|
7711
7598
|
planApproved: false,
|
|
7712
|
-
conversation:
|
|
7713
|
-
turnGate:
|
|
7599
|
+
conversation: import_core46.EMPTY_CONVERSATION,
|
|
7600
|
+
turnGate: import_core46.NO_TURN,
|
|
7714
7601
|
selectedTask: 0,
|
|
7715
7602
|
expandedTaskId: null,
|
|
7716
7603
|
taskEditor: null,
|
|
@@ -7721,40 +7608,16 @@ function newSession(state) {
|
|
|
7721
7608
|
// Prompts belong to the session that raised them; the old planner is gone
|
|
7722
7609
|
// and its pending requests deny on their own timeout.
|
|
7723
7610
|
pendingApprovals: [],
|
|
7724
|
-
queuedPrompts:
|
|
7611
|
+
queuedPrompts: import_core46.EMPTY_HOLD,
|
|
7725
7612
|
stopArmed: false,
|
|
7726
7613
|
forceSendPending: null,
|
|
7727
7614
|
overlay: state.overlay?.kind === "approval" ? null : state.overlay
|
|
7728
|
-
},
|
|
7729
|
-
}
|
|
7730
|
-
function setModel(state, args) {
|
|
7731
|
-
if (args[0] === "set" && args[1]) {
|
|
7732
|
-
const runner = (0, import_core47.runnerForProvider)(state.plannerProvider);
|
|
7733
|
-
const known = runner ? modelsForRunner(state.models, runner) : [];
|
|
7734
|
-
if (runner && known.length > 0 && !known.some((m) => m.id === args[1])) {
|
|
7735
|
-
return fail3(state, `${args[1]} was not discovered for ${runner}.`);
|
|
7736
|
-
}
|
|
7737
|
-
const refusal = known.length === 0 ? vendorModelRefusal(state.plannerProvider, args[1], import_core47.TERMINAL_UI_COMMANDS.pickPlanner) : null;
|
|
7738
|
-
if (refusal) return fail3(state, refusal);
|
|
7739
|
-
return step(state, [{ type: "setModel", modelId: args[1] }]);
|
|
7740
|
-
}
|
|
7741
|
-
if (args.length > 0 && args[0] !== "set") return fail3(state, "Usage: /model [set <model-id>]");
|
|
7742
|
-
const items = pickerItemsFor(state, { kind: "set-model" });
|
|
7743
|
-
return step(
|
|
7744
|
-
{
|
|
7745
|
-
...state,
|
|
7746
|
-
overlay: {
|
|
7747
|
-
kind: "picker",
|
|
7748
|
-
picker: picker("Planner model", items, { kind: "set-model" }, { hint: providerErrorHint(state), filterable: true })
|
|
7749
|
-
}
|
|
7750
|
-
},
|
|
7751
|
-
[{ type: "loadModels" }]
|
|
7752
|
-
);
|
|
7615
|
+
}, import_core46.EMPTY_RUN), closeEffects);
|
|
7753
7616
|
}
|
|
7754
7617
|
function setPlanner(state, args) {
|
|
7755
7618
|
if (args[0]) {
|
|
7756
7619
|
const id = args[0].toLowerCase();
|
|
7757
|
-
if (!(0,
|
|
7620
|
+
if (!(0, import_core46.isPlannerBackend)(id)) {
|
|
7758
7621
|
return fail3(state, `Unknown planner: ${id}. Run /planner with no arguments to see the list.`);
|
|
7759
7622
|
}
|
|
7760
7623
|
return step(state, [{ type: "setPlanner", provider: id }]);
|
|
@@ -7762,31 +7625,10 @@ function setPlanner(state, args) {
|
|
|
7762
7625
|
const opened = openStepper(state, plannerStepper);
|
|
7763
7626
|
return { ...opened, effects: [...opened.effects, { type: "loadModels" }] };
|
|
7764
7627
|
}
|
|
7765
|
-
function setPlannerEffort(state, args) {
|
|
7766
|
-
const items = plannerEffortItems(state, state.plannerProvider, state.orchestratorModel, state.plannerEffort);
|
|
7767
|
-
if (args[0]) {
|
|
7768
|
-
const wanted = args[0].toLowerCase();
|
|
7769
|
-
const match = items.find((i) => !i.disabled && (i.id === wanted || wanted === "default" && i.id === DEFAULT_EFFORT));
|
|
7770
|
-
if (!match) {
|
|
7771
|
-
const available = items.filter((i) => !i.disabled && i.id !== DEFAULT_EFFORT).map((i) => i.id);
|
|
7772
|
-
return fail3(state, available.length > 0 ? `Unknown effort: ${args[0]}. Available: ${available.join(", ")}, default.` : items[0]?.label ?? "No effort levels available.");
|
|
7773
|
-
}
|
|
7774
|
-
return step(state, [{ type: "setPlannerEffort", effort: match.id === DEFAULT_EFFORT ? "" : match.id }]);
|
|
7775
|
-
}
|
|
7776
|
-
return step({
|
|
7777
|
-
...state,
|
|
7778
|
-
overlay: {
|
|
7779
|
-
kind: "picker",
|
|
7780
|
-
picker: picker("Planner thinking effort", items, { kind: "set-planner-effort" }, {
|
|
7781
|
-
hint: "How hard the planning agent thinks per turn. Higher costs latency and tokens against your subscription."
|
|
7782
|
-
})
|
|
7783
|
-
}
|
|
7784
|
-
});
|
|
7785
|
-
}
|
|
7786
7628
|
function setKey(state, args) {
|
|
7787
7629
|
if (args[0] === "set" && args[1]) {
|
|
7788
7630
|
const provider = args[1].toLowerCase();
|
|
7789
|
-
if (!(0,
|
|
7631
|
+
if (!(0, import_core46.isApiProvider)(provider)) {
|
|
7790
7632
|
return fail3(state, `Unknown provider: ${provider}. Run /key with no arguments to see the list.`);
|
|
7791
7633
|
}
|
|
7792
7634
|
if (!args[2]) {
|
|
@@ -7797,16 +7639,16 @@ function setKey(state, args) {
|
|
|
7797
7639
|
}
|
|
7798
7640
|
return step(state, [{ type: "setApiKey", provider, key: args.slice(2).join(" ") }]);
|
|
7799
7641
|
}
|
|
7800
|
-
const items =
|
|
7642
|
+
const items = import_core46.PROVIDER_PRIORITY.map((id) => ({
|
|
7801
7643
|
id,
|
|
7802
|
-
label: (0,
|
|
7803
|
-
detail: (0,
|
|
7644
|
+
label: (0, import_core46.getProviderMeta)(id).label,
|
|
7645
|
+
detail: (0, import_core46.getProviderMeta)(id).apiKeyEnvVar,
|
|
7804
7646
|
selected: state.configuredProviders.includes(id)
|
|
7805
7647
|
}));
|
|
7806
7648
|
return step({ ...state, overlay: { kind: "picker", picker: picker("API provider key", items, { kind: "set-key" }) } });
|
|
7807
7649
|
}
|
|
7808
7650
|
function keyPrompt(provider) {
|
|
7809
|
-
const meta = (0,
|
|
7651
|
+
const meta = (0, import_core46.getProviderMeta)(provider);
|
|
7810
7652
|
return {
|
|
7811
7653
|
kind: "prompt",
|
|
7812
7654
|
title: `${meta.label} API key`,
|
|
@@ -7881,18 +7723,6 @@ function runners(state, args) {
|
|
|
7881
7723
|
})
|
|
7882
7724
|
} }, [{ type: "loadRunners" }]);
|
|
7883
7725
|
}
|
|
7884
|
-
function setMaxParallel(state, arg) {
|
|
7885
|
-
if (!arg) return step(say(state, "system", `Up to ${state.maxParallel} AI task${state.maxParallel === 1 ? "" : "s"} run at once: /parallel <n> changes it.`));
|
|
7886
|
-
const limit = (0, import_core47.parseMaxParallel)(arg);
|
|
7887
|
-
if (limit === null) return fail3(state, "Usage: /parallel [<number of tasks, 1 or more>]");
|
|
7888
|
-
return step({ ...state, maxParallel: limit }, [{ type: "setMaxParallel", limit }]);
|
|
7889
|
-
}
|
|
7890
|
-
function setAutonomous(state, arg) {
|
|
7891
|
-
if (arg === void 0) return step(say(state, "system", `Autonomy level: ${(0, import_core47.autonomyLevelLabel)(state.autonomous)}. /auto full or /auto guarded changes it for new plans.`));
|
|
7892
|
-
const enabled = (0, import_core47.parseAutonomyLevel)(arg);
|
|
7893
|
-
if (enabled === null) return fail3(state, "Usage: /auto [full|guarded]");
|
|
7894
|
-
return step({ ...state, autonomous: enabled }, [{ type: "setAutonomous", enabled }]);
|
|
7895
|
-
}
|
|
7896
7726
|
function setMouseCapture(state, arg) {
|
|
7897
7727
|
const enabled = resolveToggle(arg, state.mouseCapture);
|
|
7898
7728
|
if (enabled === null) return fail3(state, "Usage: /mouse [on|off]");
|
|
@@ -7983,8 +7813,6 @@ function runConfirm(state, overlay) {
|
|
|
7983
7813
|
if (!state.sessionId) return step(closed);
|
|
7984
7814
|
return step(closed, [taskActionEffect(closed, state.sessionId, overlay.action.taskId, "force-start")]);
|
|
7985
7815
|
}
|
|
7986
|
-
if (overlay.action.kind === "supervisor-act") return step(closed, [runSettingsEffect(closed, { supervisorLevel: "act" })]);
|
|
7987
|
-
if (overlay.action.kind === "autorun-on") return step(closed, [runSettingsEffect(closed, { autorun: true })]);
|
|
7988
7816
|
if (overlay.action.kind === "save-settings") return answerSaveSettings(state, overlay.action, true);
|
|
7989
7817
|
if (overlay.action.kind === "merge-run" || overlay.action.kind === "discard-run") {
|
|
7990
7818
|
return confirmedHandoff(state, overlay.action.kind);
|
|
@@ -8087,10 +7915,6 @@ function choose2(state, picker2, item) {
|
|
|
8087
7915
|
return step(say(state, "error", item.detail ? `${item.label}: ${item.detail}` : `${item.label} is not available.`));
|
|
8088
7916
|
}
|
|
8089
7917
|
switch (picker2.action.kind) {
|
|
8090
|
-
case "set-model":
|
|
8091
|
-
return step(closed, [{ type: "setModel", modelId: item.id }]);
|
|
8092
|
-
case "set-planner-effort":
|
|
8093
|
-
return step(closed, [{ type: "setPlannerEffort", effort: item.id === DEFAULT_EFFORT ? "" : item.id }]);
|
|
8094
7918
|
case "load-session":
|
|
8095
7919
|
return step(closed, [{ type: "loadSession", sessionId: item.id }]);
|
|
8096
7920
|
case "rewind":
|
|
@@ -8098,7 +7922,7 @@ function choose2(state, picker2, item) {
|
|
|
8098
7922
|
case "delete-session":
|
|
8099
7923
|
return step(closed, [{ type: "deleteSession", sessionId: item.id }]);
|
|
8100
7924
|
case "set-key":
|
|
8101
|
-
return (0,
|
|
7925
|
+
return (0, import_core47.isApiProvider)(item.id) ? step({ ...state, overlay: keyPrompt(item.id) }) : step(closed);
|
|
8102
7926
|
case "choose-allowlist-runner": {
|
|
8103
7927
|
const action = { kind: "set-allowlist", runner: item.id };
|
|
8104
7928
|
const items = pickerItemsFor(state, action);
|
|
@@ -8174,7 +7998,7 @@ function reduceAction(state, action) {
|
|
|
8174
7998
|
// (`task-1`), so nothing of the last one's — a merge gate, a checkpoint, its
|
|
8175
7999
|
// tasks — may carry over into this.
|
|
8176
8000
|
case "sessionStarted":
|
|
8177
|
-
return step(withRun({ ...state, sessionId: action.sessionId, goal: action.goal, taskView: null },
|
|
8001
|
+
return step(withRun({ ...state, sessionId: action.sessionId, goal: action.goal, taskView: null }, import_core48.EMPTY_RUN));
|
|
8178
8002
|
// A loaded session is a different one: the turn the old one had out, the
|
|
8179
8003
|
// prompts held behind it and a stop armed against it are not this one's.
|
|
8180
8004
|
// (`sessionStarted` cannot reset them: `startConversation` dispatches it
|
|
@@ -8186,13 +8010,13 @@ function reduceAction(state, action) {
|
|
|
8186
8010
|
goal: action.goal,
|
|
8187
8011
|
taskView: null,
|
|
8188
8012
|
planner: "idle",
|
|
8189
|
-
turnGate:
|
|
8013
|
+
turnGate: import_core48.NO_TURN,
|
|
8190
8014
|
pendingApprovals: [],
|
|
8191
|
-
queuedPrompts:
|
|
8015
|
+
queuedPrompts: import_core48.EMPTY_HOLD,
|
|
8192
8016
|
stopArmed: false,
|
|
8193
8017
|
forceSendPending: null,
|
|
8194
8018
|
overlay: state.overlay?.kind === "approval" ? null : state.overlay
|
|
8195
|
-
},
|
|
8019
|
+
}, import_core48.EMPTY_RUN));
|
|
8196
8020
|
// The daemon registers a session only once planning succeeds; when it does
|
|
8197
8021
|
// not, holding on to the id would send every next message to a session the
|
|
8198
8022
|
// server never had.
|
|
@@ -8202,20 +8026,20 @@ function reduceAction(state, action) {
|
|
|
8202
8026
|
sessionId: null,
|
|
8203
8027
|
goal: "",
|
|
8204
8028
|
taskView: null,
|
|
8205
|
-
turnGate:
|
|
8029
|
+
turnGate: import_core48.NO_TURN,
|
|
8206
8030
|
pendingApprovals: [],
|
|
8207
|
-
queuedPrompts:
|
|
8031
|
+
queuedPrompts: import_core48.EMPTY_HOLD,
|
|
8208
8032
|
stopArmed: false,
|
|
8209
8033
|
forceSendPending: null,
|
|
8210
8034
|
overlay: state.overlay?.kind === "approval" ? null : state.overlay
|
|
8211
|
-
},
|
|
8035
|
+
}, import_core48.EMPTY_RUN));
|
|
8212
8036
|
// Deleting the session on screen stops it in the daemon; a view left on it
|
|
8213
8037
|
// would answer every next message with a session-not-found.
|
|
8214
8038
|
case "sessionDeleted":
|
|
8215
8039
|
return action.sessionId === state.sessionId ? newSession(state) : step(state);
|
|
8216
8040
|
case "chatRestored":
|
|
8217
8041
|
if (stale(state, action.sessionId)) return step(state);
|
|
8218
|
-
return step({ ...state, conversation: (0,
|
|
8042
|
+
return step({ ...state, conversation: (0, import_core48.fromTranscript)(action.history, action.researchLog, action.plannerUsage, action.pendingTurns), scroll: 0 });
|
|
8219
8043
|
case "planRefreshed":
|
|
8220
8044
|
if (stale(state, action.sessionId)) return step(state);
|
|
8221
8045
|
return step(showPlan(state, action.plan));
|
|
@@ -8268,9 +8092,9 @@ function reduceAction(state, action) {
|
|
|
8268
8092
|
taskId: action.taskId,
|
|
8269
8093
|
order: action.order ?? 0,
|
|
8270
8094
|
title: action.title,
|
|
8271
|
-
runner: action.runner ??
|
|
8095
|
+
runner: action.runner ?? import_core48.DEFAULT_RUNNERS[0]
|
|
8272
8096
|
});
|
|
8273
|
-
const spoken = say(folded, "system", (0,
|
|
8097
|
+
const spoken = say(folded, "system", (0, import_core48.taskStartedNotice)(action.title, action.runner));
|
|
8274
8098
|
return step({ ...spoken, status: "executing" });
|
|
8275
8099
|
}
|
|
8276
8100
|
case "taskCheckpoint":
|
|
@@ -8322,7 +8146,7 @@ function reduceAction(state, action) {
|
|
|
8322
8146
|
completed: state.tasks.filter((t) => t.status === "completed").length,
|
|
8323
8147
|
total: state.tasks.length,
|
|
8324
8148
|
failed: state.tasks.filter((t) => t.status === "failed").length,
|
|
8325
|
-
blocked: (0,
|
|
8149
|
+
blocked: (0, import_core48.blockingFailures)(state.tasks).size,
|
|
8326
8150
|
skipped: state.tasks.filter((t) => t.status === "skipped").length
|
|
8327
8151
|
};
|
|
8328
8152
|
const failures = `${failed > 0 ? ` \xB7 ${failed} failed` : ""}${blocked ? ` \xB7 ${blocked} blocked` : ""}${skipped ? ` \xB7 ${skipped} skipped` : ""}`;
|
|
@@ -8365,7 +8189,7 @@ function reduceAction(state, action) {
|
|
|
8365
8189
|
providerErrors: action.providerErrors ?? state.providerErrors,
|
|
8366
8190
|
modesByRunner: action.modesByRunner ?? state.modesByRunner
|
|
8367
8191
|
},
|
|
8368
|
-
["set-
|
|
8192
|
+
["set-task-model", "set-task-effort", "set-task-mode"]
|
|
8369
8193
|
)
|
|
8370
8194
|
));
|
|
8371
8195
|
case "sessionsLoaded":
|
|
@@ -8385,14 +8209,14 @@ function reduceAction(state, action) {
|
|
|
8385
8209
|
taskView: null,
|
|
8386
8210
|
status: "idle",
|
|
8387
8211
|
planner: "idle",
|
|
8388
|
-
turnGate:
|
|
8212
|
+
turnGate: import_core48.NO_TURN,
|
|
8389
8213
|
planApproved: false,
|
|
8390
8214
|
pendingApprovals: [],
|
|
8391
|
-
queuedPrompts:
|
|
8215
|
+
queuedPrompts: import_core48.EMPTY_HOLD,
|
|
8392
8216
|
stopArmed: false,
|
|
8393
8217
|
forceSendPending: null,
|
|
8394
8218
|
overlay: state.overlay?.kind === "approval" ? null : state.overlay
|
|
8395
|
-
},
|
|
8219
|
+
}, import_core48.EMPTY_RUN));
|
|
8396
8220
|
// The rewound message comes back as a draft to edit and resend, so it lands
|
|
8397
8221
|
// as if just typed: history is not being browsed, and nothing is parked.
|
|
8398
8222
|
case "inputPrefilled":
|
|
@@ -8568,7 +8392,7 @@ function submit(state) {
|
|
|
8568
8392
|
const builtIn = builtInCommand(text);
|
|
8569
8393
|
if (builtIn) return runCommand(cleared, builtIn);
|
|
8570
8394
|
if (plannerInFlight(state)) {
|
|
8571
|
-
return step({ ...cleared, queuedPrompts: (0,
|
|
8395
|
+
return step({ ...cleared, queuedPrompts: (0, import_core48.holdPrompt)(state.queuedPrompts, text) });
|
|
8572
8396
|
}
|
|
8573
8397
|
const spoken = say(cleared, "user", text);
|
|
8574
8398
|
const effect = state.sessionId ? { type: "sendMessage", sessionId: state.sessionId, message: text } : { type: "startConversation", goal: text };
|
|
@@ -8643,7 +8467,7 @@ function createApp(deps) {
|
|
|
8643
8467
|
|
|
8644
8468
|
// src/tui/effects.ts
|
|
8645
8469
|
var import_child_process3 = require("child_process");
|
|
8646
|
-
var
|
|
8470
|
+
var import_core49 = require("@ordewell/core");
|
|
8647
8471
|
|
|
8648
8472
|
// src/tui/inbound.ts
|
|
8649
8473
|
var CONVERSATION_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -9071,9 +8895,9 @@ function plannerModelNotice(recall2) {
|
|
|
9071
8895
|
case "remembered":
|
|
9072
8896
|
return `Restored ${recall2.model}.`;
|
|
9073
8897
|
case "catalog-default":
|
|
9074
|
-
return `Using its default model, ${recall2.model}. Pick another with /
|
|
8898
|
+
return `Using its default model, ${recall2.model}. Pick another with /planner.`;
|
|
9075
8899
|
case "none":
|
|
9076
|
-
return "Pick a model with /
|
|
8900
|
+
return "Pick a model with /planner.";
|
|
9077
8901
|
}
|
|
9078
8902
|
}
|
|
9079
8903
|
async function perform(effect, deps) {
|
|
@@ -9133,24 +8957,18 @@ async function perform(effect, deps) {
|
|
|
9133
8957
|
await refreshPlan(deps, sessionId);
|
|
9134
8958
|
return;
|
|
9135
8959
|
}
|
|
9136
|
-
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,
|
|
8960
|
+
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_core49.markRequestFor)(action) === "uncomplete" ? () => api.markTaskIncomplete(sessionId, taskId) : () => api.markTaskComplete(sessionId, taskId);
|
|
9137
8961
|
await (effect.watch ? withExecutionStream(deps, sessionId, request) : request());
|
|
9138
8962
|
await refreshPlan(deps, sessionId);
|
|
9139
8963
|
return;
|
|
9140
8964
|
}
|
|
9141
8965
|
case "addTask": {
|
|
9142
|
-
const fields = (0,
|
|
8966
|
+
const fields = (0, import_core49.newTaskFields)(effect.title);
|
|
9143
8967
|
if (!fields) return;
|
|
9144
8968
|
await api.addTask(effect.sessionId, { ...fields });
|
|
9145
8969
|
await refreshPlan(deps, effect.sessionId);
|
|
9146
8970
|
return;
|
|
9147
8971
|
}
|
|
9148
|
-
case "setRunSettings": {
|
|
9149
|
-
const settings = await api.updateRunSettings(effect.changes, effect.sessionId);
|
|
9150
|
-
dispatch({ type: "settingsLoaded", settings });
|
|
9151
|
-
if (effect.sessionId) await refreshPlan(deps, effect.sessionId);
|
|
9152
|
-
return;
|
|
9153
|
-
}
|
|
9154
8972
|
case "updateTask":
|
|
9155
8973
|
await api.updateTask(effect.sessionId, effect.taskId, effect.changes);
|
|
9156
8974
|
await refreshPlan(deps, effect.sessionId);
|
|
@@ -9234,20 +9052,12 @@ async function perform(effect, deps) {
|
|
|
9234
9052
|
case "interruptTask":
|
|
9235
9053
|
await api.interruptTask(effect.sessionId, effect.taskId);
|
|
9236
9054
|
return;
|
|
9237
|
-
case "setModel": {
|
|
9238
|
-
const settled = await api.updateSettings({ orchestratorModel: effect.modelId });
|
|
9239
|
-
const plannerThinkingEffort = typeof settled.plannerThinkingEffort === "string" ? settled.plannerThinkingEffort : "";
|
|
9240
|
-
persistAfterDaemon(deps, { ORCHESTRATOR_MODEL: effect.modelId, ORDEWELL_PLANNER_EFFORT: plannerThinkingEffort });
|
|
9241
|
-
dispatch({ type: "settingsLoaded", settings: { orchestratorModel: effect.modelId, plannerThinkingEffort } });
|
|
9242
|
-
dispatch({ type: "notice", message: `Planner model set to ${effect.modelId}.` });
|
|
9243
|
-
return;
|
|
9244
|
-
}
|
|
9245
9055
|
case "setPlanner": {
|
|
9246
|
-
const meta = (0,
|
|
9056
|
+
const meta = (0, import_core49.getProviderMeta)(effect.provider);
|
|
9247
9057
|
if (!meta) throw new Error(`Unknown planner: ${effect.provider}`);
|
|
9248
|
-
if ((0,
|
|
9058
|
+
if ((0, import_core49.isCliProvider)(effect.provider)) {
|
|
9249
9059
|
const installed = ((await api.getRunners()).runners ?? []).map((r) => r.id);
|
|
9250
|
-
const refusal = uninstalledPlannerRefusal(effect.provider, installed,
|
|
9060
|
+
const refusal = uninstalledPlannerRefusal(effect.provider, installed, import_core49.TERMINAL_UI_COMMANDS.pickPlanner);
|
|
9251
9061
|
if (refusal) throw new Error(refusal);
|
|
9252
9062
|
}
|
|
9253
9063
|
const env = { AI_PROVIDER: effect.provider };
|
|
@@ -9260,7 +9070,7 @@ async function perform(effect, deps) {
|
|
|
9260
9070
|
});
|
|
9261
9071
|
dispatch({
|
|
9262
9072
|
type: "notice",
|
|
9263
|
-
message: `${(0,
|
|
9073
|
+
message: `${(0, import_core49.isCliProvider)(effect.provider) ? `Planning with ${meta.label}: no API key needed.` : `Planner set to ${meta.label}.`} ${plannerModelNotice(recall2)}`
|
|
9264
9074
|
});
|
|
9265
9075
|
await loadModels(deps);
|
|
9266
9076
|
return;
|
|
@@ -9281,14 +9091,8 @@ async function perform(effect, deps) {
|
|
|
9281
9091
|
dispatch({ type: "notice", message: effect.notice });
|
|
9282
9092
|
return;
|
|
9283
9093
|
}
|
|
9284
|
-
case "setPlannerEffort":
|
|
9285
|
-
await api.updateSettings({ env: { ORDEWELL_PLANNER_EFFORT: effect.effort } });
|
|
9286
|
-
deps.setEnvVar("ORDEWELL_PLANNER_EFFORT", effect.effort);
|
|
9287
|
-
dispatch({ type: "settingsLoaded", settings: { plannerThinkingEffort: effect.effort } });
|
|
9288
|
-
dispatch({ type: "notice", message: `Planner effort set to ${effect.effort || "the runner default"}.` });
|
|
9289
|
-
return;
|
|
9290
9094
|
case "setApiKey": {
|
|
9291
|
-
const meta = (0,
|
|
9095
|
+
const meta = (0, import_core49.isApiProvider)(effect.provider) ? (0, import_core49.getProviderMeta)(effect.provider) : void 0;
|
|
9292
9096
|
if (!meta) throw new Error(`Unknown provider: ${effect.provider}`);
|
|
9293
9097
|
await api.updateSettings({ env: { [meta.apiKeyEnvVar]: effect.key } });
|
|
9294
9098
|
deps.setEnvVar(meta.apiKeyEnvVar, effect.key);
|
|
@@ -9319,10 +9123,6 @@ async function perform(effect, deps) {
|
|
|
9319
9123
|
dispatch({ type: "notice", message: effect.message });
|
|
9320
9124
|
return;
|
|
9321
9125
|
}
|
|
9322
|
-
case "setMaxParallel":
|
|
9323
|
-
await saveMaxParallel(deps, effect.limit);
|
|
9324
|
-
dispatch({ type: "notice", message: `Up to ${effect.limit} AI task${effect.limit === 1 ? "" : "s"} now run at once.` });
|
|
9325
|
-
return;
|
|
9326
9126
|
case "saveSettings": {
|
|
9327
9127
|
if (Object.keys(effect.run).length > 0) {
|
|
9328
9128
|
const settings = await api.updateRunSettings(effect.run, effect.sessionId);
|
|
@@ -9334,12 +9134,6 @@ async function perform(effect, deps) {
|
|
|
9334
9134
|
dispatch({ type: "notice", message: overridden ? `${effect.message}: ORDEWELL_AUTONOMOUS_MODE in the environment decides the autonomy level until it is unset.` : effect.message });
|
|
9335
9135
|
return;
|
|
9336
9136
|
}
|
|
9337
|
-
case "setAutonomous": {
|
|
9338
|
-
const { overridden } = deps.saveAutonomy(effect.enabled);
|
|
9339
|
-
const level = (0, import_core50.autonomyLevelLabel)(effect.enabled);
|
|
9340
|
-
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.` });
|
|
9341
|
-
return;
|
|
9342
|
-
}
|
|
9343
9137
|
case "setMouseCapture":
|
|
9344
9138
|
deps.setMouseCapture(effect.enabled);
|
|
9345
9139
|
deps.setEnvVar("ORDEWELL_TUI_MOUSE", String(effect.enabled));
|
|
@@ -9512,7 +9306,7 @@ async function saveMaxParallel(deps, limit) {
|
|
|
9512
9306
|
function copySelection(deps, text) {
|
|
9513
9307
|
if (!text) return;
|
|
9514
9308
|
const lines = text.split("\n").length;
|
|
9515
|
-
const command = (0,
|
|
9309
|
+
const command = (0, import_core49.clipboardCopyCommand)(deps.hasBin);
|
|
9516
9310
|
if (command) {
|
|
9517
9311
|
try {
|
|
9518
9312
|
(deps.pipeToClipboard ?? pipeToClipboardDefault)(command, text);
|
|
@@ -9617,7 +9411,7 @@ function turnReplies(plan) {
|
|
|
9617
9411
|
const replies = [];
|
|
9618
9412
|
for (let i = history.length - 1; i >= 0; i--) {
|
|
9619
9413
|
const entry = history[i];
|
|
9620
|
-
if ((0,
|
|
9414
|
+
if ((0, import_core49.isUserMessage)(entry)) break;
|
|
9621
9415
|
if (entry.role === "assistant" && entry.kind === void 0) {
|
|
9622
9416
|
const { content, timestamp, runs } = entry;
|
|
9623
9417
|
replies.unshift({ content, ...timestamp ? { timestamp } : {}, ...runs ? { runs } : {} });
|
|
@@ -9973,7 +9767,7 @@ async function handleTui(subArgs) {
|
|
|
9973
9767
|
}
|
|
9974
9768
|
const workspace = flag(subArgs, "--workspace") || process.cwd();
|
|
9975
9769
|
try {
|
|
9976
|
-
(0,
|
|
9770
|
+
(0, import_core50.assertWorkspaceExists)(workspace);
|
|
9977
9771
|
} catch {
|
|
9978
9772
|
console.error(
|
|
9979
9773
|
`Workspace "${workspace}" does not exist.
|
|
@@ -9982,7 +9776,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
|
|
|
9982
9776
|
);
|
|
9983
9777
|
process.exit(1);
|
|
9984
9778
|
}
|
|
9985
|
-
const discoveredSkills = (0,
|
|
9779
|
+
const discoveredSkills = (0, import_core50.createSkillsService)(workspace, new import_core50.EnvConfig().workspaceRepos).listSkills();
|
|
9986
9780
|
registerSkillCommands(discoveredSkills);
|
|
9987
9781
|
const taskSkills = discoveredSkills.filter((s) => s.appliesTo === "task").map((s) => ({ name: s.name, description: s.description }));
|
|
9988
9782
|
const explicitPort = flag(subArgs, "--port") || process.env.ORDEWELL_PORT;
|
|
@@ -9992,7 +9786,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
|
|
|
9992
9786
|
const api = new ApiClient(port, workspace);
|
|
9993
9787
|
let terminal;
|
|
9994
9788
|
const mouseCapture = process.env.ORDEWELL_TUI_MOUSE !== "false" && process.env.ORDEWELL_TUI_MOUSE !== "0";
|
|
9995
|
-
const settings = new
|
|
9789
|
+
const settings = new import_core50.SettingsService();
|
|
9996
9790
|
const app = createApp({
|
|
9997
9791
|
// The level the daemon plans with: the saved one, unless the environment overrides it (ADR-0030).
|
|
9998
9792
|
// The run settings are seeded from the same file because the first frame is
|
|
@@ -10014,13 +9808,13 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
|
|
|
10014
9808
|
workspace,
|
|
10015
9809
|
port,
|
|
10016
9810
|
dispatch: (action) => app.dispatch(action),
|
|
10017
|
-
newSessionId: () => (0,
|
|
9811
|
+
newSessionId: () => (0, import_core50.mintSessionId)(),
|
|
10018
9812
|
setEnvVar: (key, value) => {
|
|
10019
9813
|
writeEnvVar(findEnvFile(), key, value);
|
|
10020
9814
|
process.env[key] = value;
|
|
10021
9815
|
},
|
|
10022
9816
|
saveAutonomy: (enabled) => {
|
|
10023
|
-
const settings2 = new
|
|
9817
|
+
const settings2 = new import_core50.SettingsService();
|
|
10024
9818
|
settings2.setAutonomousMode(enabled);
|
|
10025
9819
|
return { overridden: settings2.autonomousModeOverridden() };
|
|
10026
9820
|
},
|
|
@@ -10137,7 +9931,7 @@ var COMMANDS = {
|
|
|
10137
9931
|
// src/main.ts
|
|
10138
9932
|
var TUI_FLAGS = /* @__PURE__ */ new Set(["--workspace", "--port"]);
|
|
10139
9933
|
async function main() {
|
|
10140
|
-
(0,
|
|
9934
|
+
(0, import_core51.migrateOldConfigDir)();
|
|
10141
9935
|
moveAutonomyToSettings();
|
|
10142
9936
|
loadEnvFile();
|
|
10143
9937
|
const argv = process.argv.slice(2);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ordewell/cli",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.11",
|
|
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",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"typecheck": "tsc --noEmit"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@ordewell/core": "^0.10.
|
|
55
|
-
"@ordewell/web": "^0.10.
|
|
54
|
+
"@ordewell/core": "^0.10.11",
|
|
55
|
+
"@ordewell/web": "^0.10.11",
|
|
56
56
|
"string-width": "^7.2.0",
|
|
57
57
|
"ws": "^8.18.0"
|
|
58
58
|
},
|