@wrongstack/tui 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +37 -1
- package/dist/index.js +227 -6
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -31,19 +31,53 @@ interface RunTuiOptions {
|
|
|
31
31
|
/** Query live YOLO state from the permission policy. */
|
|
32
32
|
getYolo?: () => boolean;
|
|
33
33
|
/** Query the live autonomy mode. */
|
|
34
|
-
getAutonomy?: () => 'off' | 'suggest' | 'auto' | 'eternal';
|
|
34
|
+
getAutonomy?: () => 'off' | 'suggest' | 'auto' | 'eternal' | 'eternal-parallel';
|
|
35
35
|
/**
|
|
36
36
|
* Access the eternal-autonomy engine. When autonomy mode flips to
|
|
37
37
|
* 'eternal' the TUI drives `runOneIteration()` from the post-slash hook
|
|
38
38
|
* so the engine and TUI never race for the shared Context.
|
|
39
39
|
*/
|
|
40
40
|
getEternalEngine?: () => _wrongstack_core.EternalAutonomyEngine | null;
|
|
41
|
+
/**
|
|
42
|
+
* Access the parallel-eternal engine. When autonomy mode flips to
|
|
43
|
+
* 'eternal-parallel' the TUI drives `runOneIteration()` from the post-slash
|
|
44
|
+
* hook so the engine and TUI never race for the shared Context.
|
|
45
|
+
*/
|
|
46
|
+
getParallelEngine?: () => _wrongstack_core.ParallelEternalEngine | null;
|
|
41
47
|
/**
|
|
42
48
|
* Subscribe to live per-iteration events from the eternal engine.
|
|
43
49
|
* Returns an unsubscribe function. TUI uses this to render each
|
|
44
50
|
* iteration as a live timeline entry as it lands.
|
|
45
51
|
*/
|
|
46
52
|
subscribeEternalIteration?: (fn: (entry: _wrongstack_core.JournalEntry) => void) => () => void;
|
|
53
|
+
/**
|
|
54
|
+
* Subscribe to per-iteration stage transitions from the eternal engine.
|
|
55
|
+
* TUI uses this to render live status (decide → execute → reflect →
|
|
56
|
+
* sleep/paused/stopped) in the status bar.
|
|
57
|
+
*/
|
|
58
|
+
subscribeEternalStage?: (fn: (stage: {
|
|
59
|
+
phase: 'idle';
|
|
60
|
+
} | {
|
|
61
|
+
phase: 'decide';
|
|
62
|
+
reason: string;
|
|
63
|
+
} | {
|
|
64
|
+
phase: 'execute';
|
|
65
|
+
task: string;
|
|
66
|
+
} | {
|
|
67
|
+
phase: 'reflect';
|
|
68
|
+
status: 'success' | 'failure' | 'aborted' | 'skipped';
|
|
69
|
+
note?: string;
|
|
70
|
+
} | {
|
|
71
|
+
phase: 'sleep';
|
|
72
|
+
ms: number;
|
|
73
|
+
} | {
|
|
74
|
+
phase: 'paused';
|
|
75
|
+
} | {
|
|
76
|
+
phase: 'stopped';
|
|
77
|
+
} | {
|
|
78
|
+
phase: 'error';
|
|
79
|
+
message: string;
|
|
80
|
+
}) => void) => () => void;
|
|
47
81
|
/** Renders in the startup banner. Read from the CLI's package.json. */
|
|
48
82
|
appVersion?: string;
|
|
49
83
|
/** Provider id for the startup banner ("openai", "anthropic", ...). */
|
|
@@ -56,6 +90,8 @@ interface RunTuiOptions {
|
|
|
56
90
|
getPickableProviders?: () => Promise<ProviderOption[]>;
|
|
57
91
|
/** Apply a (provider, model) pair after the picker confirms. Returns an error string on failure. */
|
|
58
92
|
switchProviderAndModel?: (providerId: string, modelId: string) => string | null;
|
|
93
|
+
/** Apply an autonomy mode after the picker confirms. Returns an error string on failure. */
|
|
94
|
+
switchAutonomy?: (mode: 'off' | 'suggest' | 'auto' | 'eternal' | 'eternal-parallel') => string | null;
|
|
59
95
|
/**
|
|
60
96
|
* Model-specific maxContext (tokens), resolved by the CLI via the
|
|
61
97
|
* ModelsRegistry. When omitted, the TUI falls back to the provider
|
package/dist/index.js
CHANGED
|
@@ -1550,6 +1550,25 @@ function LiveActivityStrip({
|
|
|
1550
1550
|
] }) }) : null
|
|
1551
1551
|
] });
|
|
1552
1552
|
}
|
|
1553
|
+
var AUTONOMY_OPTIONS = [
|
|
1554
|
+
{ mode: "off", label: "OFF", description: "Agent stops after each turn (normal interactive mode)", color: "green" },
|
|
1555
|
+
{ mode: "suggest", label: "SUGGEST", description: "Shows next-step suggestions after each turn", color: "cyan" },
|
|
1556
|
+
{ mode: "auto", label: "AUTO", description: "Self-driving \u2014 agent picks next step and continues", color: "yellow" },
|
|
1557
|
+
{ mode: "eternal", label: "ETERNAL", description: "Goal-driven loop \u2014 requires /goal set first", color: "red" },
|
|
1558
|
+
{ mode: "eternal-parallel", label: "PARALLEL", description: "Fan-out 4\u20138 subagents per tick \u2014 requires /goal", color: "magenta" }
|
|
1559
|
+
];
|
|
1560
|
+
function AutonomyPicker({ options, selected, hint }) {
|
|
1561
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
1562
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Autonomy Mode \u2501\u2501" }),
|
|
1563
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
|
|
1564
|
+
options.map((opt, i) => /* @__PURE__ */ jsxs(Text, { color: i === selected ? opt.color : void 0, inverse: i === selected, children: [
|
|
1565
|
+
i === selected ? "\u203A " : " ",
|
|
1566
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: opt.label.padEnd(12) }),
|
|
1567
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: opt.description })
|
|
1568
|
+
] }, opt.mode)),
|
|
1569
|
+
hint ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: hint }) : null
|
|
1570
|
+
] });
|
|
1571
|
+
}
|
|
1553
1572
|
function ModelPicker({
|
|
1554
1573
|
step,
|
|
1555
1574
|
providerOptions,
|
|
@@ -1634,7 +1653,8 @@ function StatusBar({
|
|
|
1634
1653
|
context,
|
|
1635
1654
|
projectName,
|
|
1636
1655
|
processCount,
|
|
1637
|
-
hiddenItems
|
|
1656
|
+
hiddenItems,
|
|
1657
|
+
eternalStage
|
|
1638
1658
|
}) {
|
|
1639
1659
|
const hiddenSet = new Set(hiddenItems);
|
|
1640
1660
|
const usage = tokenCounter?.total();
|
|
@@ -1730,8 +1750,12 @@ function StatusBar({
|
|
|
1730
1750
|
}
|
|
1731
1751
|
)
|
|
1732
1752
|
] }) : null,
|
|
1753
|
+
eternalStage ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1754
|
+
yolo || autonomy && autonomy !== "off" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
1755
|
+
/* @__PURE__ */ jsx(EternalStageChip, { stage: eternalStage })
|
|
1756
|
+
] }) : null,
|
|
1733
1757
|
elapsedMs !== void 0 && !hiddenSet.has("elapsed") ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1734
|
-
yolo ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
1758
|
+
yolo || autonomy && autonomy !== "off" || eternalStage ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) : null,
|
|
1735
1759
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1736
1760
|
"\u23F1 ",
|
|
1737
1761
|
fmtElapsed2(elapsedMs)
|
|
@@ -1855,6 +1879,45 @@ function StatusBar({
|
|
|
1855
1879
|
}
|
|
1856
1880
|
);
|
|
1857
1881
|
}
|
|
1882
|
+
function EternalStageChip({
|
|
1883
|
+
stage
|
|
1884
|
+
}) {
|
|
1885
|
+
switch (stage.phase) {
|
|
1886
|
+
case "idle":
|
|
1887
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2B1C idle" });
|
|
1888
|
+
case "decide":
|
|
1889
|
+
return /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
1890
|
+
"\u2B07 decide: ",
|
|
1891
|
+
stage.reason
|
|
1892
|
+
] });
|
|
1893
|
+
case "execute":
|
|
1894
|
+
return /* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
1895
|
+
"\u25B6 ",
|
|
1896
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "execute" }),
|
|
1897
|
+
stage.task ? `(${stage.task})` : ""
|
|
1898
|
+
] });
|
|
1899
|
+
case "reflect":
|
|
1900
|
+
return /* @__PURE__ */ jsxs(Text, { color: stage.status === "success" ? "green" : stage.status === "failure" ? "red" : "yellow", children: [
|
|
1901
|
+
"\u21A9 reflect: ",
|
|
1902
|
+
stage.status
|
|
1903
|
+
] });
|
|
1904
|
+
case "sleep":
|
|
1905
|
+
return /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1906
|
+
"\u{1F4A4} sleep ",
|
|
1907
|
+
Math.round(stage.ms / 1e3),
|
|
1908
|
+
"s"
|
|
1909
|
+
] });
|
|
1910
|
+
case "paused":
|
|
1911
|
+
return /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u23F8 paused" });
|
|
1912
|
+
case "stopped":
|
|
1913
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25A0 stopped" });
|
|
1914
|
+
case "error":
|
|
1915
|
+
return /* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
1916
|
+
"\u26A0 error: ",
|
|
1917
|
+
stage.message
|
|
1918
|
+
] });
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1858
1921
|
function ContextChip({ ctx }) {
|
|
1859
1922
|
const ratio = Math.max(0, Math.min(1, ctx.used / ctx.max));
|
|
1860
1923
|
const pct = Math.round(ratio * 100);
|
|
@@ -2451,6 +2514,30 @@ function reducer(state, action) {
|
|
|
2451
2514
|
...state,
|
|
2452
2515
|
modelPicker: { ...state.modelPicker, hint: action.text }
|
|
2453
2516
|
};
|
|
2517
|
+
case "autonomyPickerOpen":
|
|
2518
|
+
return {
|
|
2519
|
+
...state,
|
|
2520
|
+
autonomyPicker: { open: true, options: action.options, selected: 0, hint: void 0 }
|
|
2521
|
+
};
|
|
2522
|
+
case "autonomyPickerClose":
|
|
2523
|
+
return {
|
|
2524
|
+
...state,
|
|
2525
|
+
autonomyPicker: { open: false, options: [], selected: 0 }
|
|
2526
|
+
};
|
|
2527
|
+
case "autonomyPickerMove": {
|
|
2528
|
+
const n = state.autonomyPicker.options.length;
|
|
2529
|
+
if (n === 0) return state;
|
|
2530
|
+
const next = (state.autonomyPicker.selected + action.delta + n) % n;
|
|
2531
|
+
return {
|
|
2532
|
+
...state,
|
|
2533
|
+
autonomyPicker: { ...state.autonomyPicker, selected: next }
|
|
2534
|
+
};
|
|
2535
|
+
}
|
|
2536
|
+
case "autonomyPickerHint":
|
|
2537
|
+
return {
|
|
2538
|
+
...state,
|
|
2539
|
+
autonomyPicker: { ...state.autonomyPicker, hint: action.text }
|
|
2540
|
+
};
|
|
2454
2541
|
case "confirmOpen":
|
|
2455
2542
|
return { ...state, confirmQueue: [...state.confirmQueue, action.info] };
|
|
2456
2543
|
case "confirmClose":
|
|
@@ -2666,6 +2753,9 @@ function reducer(state, action) {
|
|
|
2666
2753
|
rewindOverlay: null
|
|
2667
2754
|
};
|
|
2668
2755
|
}
|
|
2756
|
+
case "eternalStage": {
|
|
2757
|
+
return { ...state, eternalStage: action.stage };
|
|
2758
|
+
}
|
|
2669
2759
|
}
|
|
2670
2760
|
}
|
|
2671
2761
|
var PASTE_THRESHOLD_CHARS = 200;
|
|
@@ -2718,7 +2808,9 @@ function App({
|
|
|
2718
2808
|
getYolo,
|
|
2719
2809
|
getAutonomy,
|
|
2720
2810
|
getEternalEngine,
|
|
2811
|
+
getParallelEngine,
|
|
2721
2812
|
subscribeEternalIteration,
|
|
2813
|
+
subscribeEternalStage,
|
|
2722
2814
|
getSDDContext,
|
|
2723
2815
|
onSDDOutput,
|
|
2724
2816
|
appVersion,
|
|
@@ -2727,6 +2819,7 @@ function App({
|
|
|
2727
2819
|
keyTail,
|
|
2728
2820
|
getPickableProviders,
|
|
2729
2821
|
switchProviderAndModel,
|
|
2822
|
+
switchAutonomy,
|
|
2730
2823
|
effectiveMaxContext,
|
|
2731
2824
|
onExit,
|
|
2732
2825
|
director,
|
|
@@ -2789,13 +2882,15 @@ function App({
|
|
|
2789
2882
|
modelOptions: [],
|
|
2790
2883
|
selected: 0
|
|
2791
2884
|
},
|
|
2885
|
+
autonomyPicker: { open: false, options: [], selected: 0 },
|
|
2792
2886
|
confirmQueue: [],
|
|
2793
2887
|
contextChipVersion: 0,
|
|
2794
2888
|
fleet: {},
|
|
2795
2889
|
fleetCost: 0,
|
|
2796
2890
|
streamFleet: true,
|
|
2797
2891
|
checkpoints: [],
|
|
2798
|
-
rewindOverlay: null
|
|
2892
|
+
rewindOverlay: null,
|
|
2893
|
+
eternalStage: null
|
|
2799
2894
|
});
|
|
2800
2895
|
const builderRef = useRef(null);
|
|
2801
2896
|
if (builderRef.current === null) {
|
|
@@ -3282,6 +3377,22 @@ function App({
|
|
|
3282
3377
|
slashRegistry.unregister("model");
|
|
3283
3378
|
};
|
|
3284
3379
|
}, [slashRegistry, getPickableProviders, switchProviderAndModel]);
|
|
3380
|
+
useEffect(() => {
|
|
3381
|
+
if (!switchAutonomy) return;
|
|
3382
|
+
const cmd = {
|
|
3383
|
+
name: "autonomy",
|
|
3384
|
+
aliases: ["auto"],
|
|
3385
|
+
description: "Pick an autonomy mode interactively (picker).",
|
|
3386
|
+
async run() {
|
|
3387
|
+
dispatch({ type: "autonomyPickerOpen", options: AUTONOMY_OPTIONS });
|
|
3388
|
+
return { message: void 0 };
|
|
3389
|
+
}
|
|
3390
|
+
};
|
|
3391
|
+
slashRegistry.register(cmd);
|
|
3392
|
+
return () => {
|
|
3393
|
+
slashRegistry.unregister("autonomy");
|
|
3394
|
+
};
|
|
3395
|
+
}, [slashRegistry, switchAutonomy]);
|
|
3285
3396
|
useEffect(() => {
|
|
3286
3397
|
const FLUSH_MS = 100;
|
|
3287
3398
|
const flush = () => {
|
|
@@ -3471,6 +3582,7 @@ function App({
|
|
|
3471
3582
|
const offBudgetWarning = events.on("subagent.budget_warning", (e) => {
|
|
3472
3583
|
const lbl = labelFor(e.subagentId);
|
|
3473
3584
|
dispatch({ type: "fleetBudgetWarning", id: e.subagentId, kind: e.kind, used: e.used, limit: e.limit });
|
|
3585
|
+
const timeoutSuffix = e.kind === "timeout" ? " (subagent continues running)" : " \u2014 extending";
|
|
3474
3586
|
dispatch({
|
|
3475
3587
|
type: "addEntry",
|
|
3476
3588
|
entry: {
|
|
@@ -3478,12 +3590,27 @@ function App({
|
|
|
3478
3590
|
agentLabel: lbl.label,
|
|
3479
3591
|
agentColor: lbl.color,
|
|
3480
3592
|
icon: "\u26A1",
|
|
3481
|
-
text: `hitting ${e.kind} limit (${e.used}/${e.limit})
|
|
3593
|
+
text: `hitting ${e.kind} limit (${e.used}/${e.limit})${timeoutSuffix}`
|
|
3594
|
+
}
|
|
3595
|
+
});
|
|
3596
|
+
});
|
|
3597
|
+
const offIterationSummary = events.on("subagent.iteration_summary", (e) => {
|
|
3598
|
+
const lbl = labelFor(e.subagentId);
|
|
3599
|
+
const costStr = e.costUsd > 0 ? ` \xB7 ${e.costUsd.toFixed(3)}` : "";
|
|
3600
|
+
const toolStr = e.currentTool ? ` \xB7 doing ${e.currentTool}` : "";
|
|
3601
|
+
const partial = e.partialText ? ` \xB7 "${e.partialText.slice(0, 60)}${e.partialText.length > 60 ? "\u2026" : ""}"` : "";
|
|
3602
|
+
dispatch({
|
|
3603
|
+
type: "addEntry",
|
|
3604
|
+
entry: {
|
|
3605
|
+
kind: "subagent",
|
|
3606
|
+
agentLabel: lbl.label,
|
|
3607
|
+
agentColor: lbl.color,
|
|
3608
|
+
icon: "\u{1F4AC}",
|
|
3609
|
+
text: `L${e.iteration} \xB7 ${e.toolCalls} tools${costStr}${toolStr}${partial}`
|
|
3482
3610
|
}
|
|
3483
3611
|
});
|
|
3484
3612
|
});
|
|
3485
3613
|
const offTool = events.on("subagent.tool_executed", (e) => {
|
|
3486
|
-
if (director) return;
|
|
3487
3614
|
dispatch({
|
|
3488
3615
|
type: "fleetTool",
|
|
3489
3616
|
id: e.subagentId,
|
|
@@ -3499,6 +3626,7 @@ function App({
|
|
|
3499
3626
|
offStarted();
|
|
3500
3627
|
offCompleted();
|
|
3501
3628
|
offBudgetWarning();
|
|
3629
|
+
offIterationSummary();
|
|
3502
3630
|
offTool();
|
|
3503
3631
|
};
|
|
3504
3632
|
}, [events, director]);
|
|
@@ -3912,6 +4040,32 @@ function App({
|
|
|
3912
4040
|
}
|
|
3913
4041
|
return;
|
|
3914
4042
|
}
|
|
4043
|
+
if (state.autonomyPicker.open) {
|
|
4044
|
+
if (key.escape) {
|
|
4045
|
+
dispatch({ type: "autonomyPickerClose" });
|
|
4046
|
+
return;
|
|
4047
|
+
}
|
|
4048
|
+
if (key.upArrow) {
|
|
4049
|
+
dispatch({ type: "autonomyPickerMove", delta: -1 });
|
|
4050
|
+
return;
|
|
4051
|
+
}
|
|
4052
|
+
if (key.downArrow) {
|
|
4053
|
+
dispatch({ type: "autonomyPickerMove", delta: 1 });
|
|
4054
|
+
return;
|
|
4055
|
+
}
|
|
4056
|
+
if (isEnter) {
|
|
4057
|
+
const opt = state.autonomyPicker.options[state.autonomyPicker.selected];
|
|
4058
|
+
if (!opt) return;
|
|
4059
|
+
const err = switchAutonomy?.(opt.mode);
|
|
4060
|
+
if (err) {
|
|
4061
|
+
dispatch({ type: "autonomyPickerHint", text: err });
|
|
4062
|
+
return;
|
|
4063
|
+
}
|
|
4064
|
+
dispatch({ type: "autonomyPickerClose" });
|
|
4065
|
+
return;
|
|
4066
|
+
}
|
|
4067
|
+
return;
|
|
4068
|
+
}
|
|
3915
4069
|
if (state.slashPicker.open) {
|
|
3916
4070
|
if (key.escape) {
|
|
3917
4071
|
dispatch({ type: "slashPickerClose" });
|
|
@@ -4111,6 +4265,18 @@ function App({
|
|
|
4111
4265
|
setDraft(next2, lastWordStart);
|
|
4112
4266
|
return;
|
|
4113
4267
|
}
|
|
4268
|
+
if (key.delete || key.ctrl && input === "d") {
|
|
4269
|
+
if (cursor >= buffer.length) return;
|
|
4270
|
+
const next2 = buffer.slice(0, cursor) + buffer.slice(cursor + 1);
|
|
4271
|
+
setDraft(next2, cursor);
|
|
4272
|
+
return;
|
|
4273
|
+
}
|
|
4274
|
+
if (key.ctrl && input === "k") {
|
|
4275
|
+
if (cursor >= buffer.length) return;
|
|
4276
|
+
const next2 = buffer.slice(0, cursor);
|
|
4277
|
+
setDraft(next2, cursor);
|
|
4278
|
+
return;
|
|
4279
|
+
}
|
|
4114
4280
|
if (key.meta && input === "v") {
|
|
4115
4281
|
await pasteClipboardImage();
|
|
4116
4282
|
return;
|
|
@@ -4269,6 +4435,39 @@ function App({
|
|
|
4269
4435
|
const eternalLoopRunningRef = useRef(false);
|
|
4270
4436
|
const runEternalLoopRef = useRef(runEternalLoop);
|
|
4271
4437
|
runEternalLoopRef.current = runEternalLoop;
|
|
4438
|
+
const runParallelLoop = async () => {
|
|
4439
|
+
const engine = getParallelEngine?.();
|
|
4440
|
+
if (!engine) return;
|
|
4441
|
+
if (parallelLoopRunningRef.current) return;
|
|
4442
|
+
parallelLoopRunningRef.current = true;
|
|
4443
|
+
try {
|
|
4444
|
+
while (true) {
|
|
4445
|
+
const liveMode = getAutonomy?.() ?? "off";
|
|
4446
|
+
if (liveMode !== "eternal-parallel") break;
|
|
4447
|
+
if (engine.currentState === "stopped") break;
|
|
4448
|
+
dispatch({ type: "status", status: "running" });
|
|
4449
|
+
try {
|
|
4450
|
+
await engine.runOneIteration();
|
|
4451
|
+
} catch (err) {
|
|
4452
|
+
dispatch({
|
|
4453
|
+
type: "addEntry",
|
|
4454
|
+
entry: { kind: "error", text: `[parallel] ${err instanceof Error ? err.message : String(err)}` }
|
|
4455
|
+
});
|
|
4456
|
+
}
|
|
4457
|
+
dispatch({ type: "status", status: "idle" });
|
|
4458
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
4459
|
+
}
|
|
4460
|
+
} finally {
|
|
4461
|
+
parallelLoopRunningRef.current = false;
|
|
4462
|
+
if (getAutonomy) {
|
|
4463
|
+
const finalMode = getAutonomy();
|
|
4464
|
+
if (finalMode !== autonomyLive) setAutonomyLive(finalMode);
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
};
|
|
4468
|
+
const parallelLoopRunningRef = useRef(false);
|
|
4469
|
+
const runParallelLoopRef = useRef(runParallelLoop);
|
|
4470
|
+
runParallelLoopRef.current = runParallelLoop;
|
|
4272
4471
|
useEffect(() => {
|
|
4273
4472
|
if (!subscribeEternalIteration) return;
|
|
4274
4473
|
const unsub = subscribeEternalIteration((entry) => {
|
|
@@ -4280,6 +4479,13 @@ function App({
|
|
|
4280
4479
|
});
|
|
4281
4480
|
return unsub;
|
|
4282
4481
|
}, [subscribeEternalIteration]);
|
|
4482
|
+
useEffect(() => {
|
|
4483
|
+
if (!subscribeEternalStage) return;
|
|
4484
|
+
const unsub = subscribeEternalStage((stage) => {
|
|
4485
|
+
dispatch({ type: "eternalStage", stage });
|
|
4486
|
+
});
|
|
4487
|
+
return unsub;
|
|
4488
|
+
}, [subscribeEternalStage]);
|
|
4283
4489
|
const submit = async (overrideRaw) => {
|
|
4284
4490
|
const raw = overrideRaw ?? draftRef.current.buffer;
|
|
4285
4491
|
const trimmed = raw.trim();
|
|
@@ -4317,6 +4523,9 @@ function App({
|
|
|
4317
4523
|
if (currentAutonomy === "eternal" && getEternalEngine) {
|
|
4318
4524
|
void runEternalLoopRef.current();
|
|
4319
4525
|
}
|
|
4526
|
+
if (currentAutonomy === "eternal-parallel" && getParallelEngine) {
|
|
4527
|
+
void runParallelLoopRef.current();
|
|
4528
|
+
}
|
|
4320
4529
|
}
|
|
4321
4530
|
if (res?.exit) {
|
|
4322
4531
|
exit();
|
|
@@ -4462,6 +4671,14 @@ User message:
|
|
|
4462
4671
|
hint: state.modelPicker.hint
|
|
4463
4672
|
}
|
|
4464
4673
|
) : null,
|
|
4674
|
+
state.autonomyPicker.open ? /* @__PURE__ */ jsx(
|
|
4675
|
+
AutonomyPicker,
|
|
4676
|
+
{
|
|
4677
|
+
options: state.autonomyPicker.options,
|
|
4678
|
+
selected: state.autonomyPicker.selected,
|
|
4679
|
+
hint: state.autonomyPicker.hint
|
|
4680
|
+
}
|
|
4681
|
+
) : null,
|
|
4465
4682
|
state.rewindOverlay ? /* @__PURE__ */ jsx(
|
|
4466
4683
|
CheckpointTimeline,
|
|
4467
4684
|
{
|
|
@@ -4510,7 +4727,8 @@ User message:
|
|
|
4510
4727
|
projectName,
|
|
4511
4728
|
subagentCount: Object.keys(state.fleet).length,
|
|
4512
4729
|
processCount: getProcessRegistry().activeCount,
|
|
4513
|
-
hiddenItems
|
|
4730
|
+
hiddenItems,
|
|
4731
|
+
eternalStage: state.eternalStage
|
|
4514
4732
|
}
|
|
4515
4733
|
),
|
|
4516
4734
|
director ? /* @__PURE__ */ jsx(FleetPanel, { entries: state.fleet, totalCost: state.fleetCost, roster: fleetRoster }) : null
|
|
@@ -4639,13 +4857,16 @@ async function runTui(opts) {
|
|
|
4639
4857
|
getYolo: opts.getYolo,
|
|
4640
4858
|
getAutonomy: opts.getAutonomy,
|
|
4641
4859
|
getEternalEngine: opts.getEternalEngine,
|
|
4860
|
+
getParallelEngine: opts.getParallelEngine,
|
|
4642
4861
|
subscribeEternalIteration: opts.subscribeEternalIteration,
|
|
4862
|
+
subscribeEternalStage: opts.subscribeEternalStage,
|
|
4643
4863
|
appVersion: opts.appVersion,
|
|
4644
4864
|
provider: opts.provider,
|
|
4645
4865
|
family: opts.family,
|
|
4646
4866
|
keyTail: opts.keyTail,
|
|
4647
4867
|
getPickableProviders: opts.getPickableProviders,
|
|
4648
4868
|
switchProviderAndModel: opts.switchProviderAndModel,
|
|
4869
|
+
switchAutonomy: opts.switchAutonomy,
|
|
4649
4870
|
effectiveMaxContext: opts.effectiveMaxContext,
|
|
4650
4871
|
onExit,
|
|
4651
4872
|
director: opts.director ?? null,
|