pi-agent-flow 1.8.40 → 2.0.1
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 +33 -37
- package/agents/audit.md +21 -22
- package/agents/build.md +23 -22
- package/agents/craft.md +23 -27
- package/agents/debug.md +24 -28
- package/agents/ideas.md +21 -101
- package/agents/scout.md +20 -19
- package/dist/batch/batch-bash.d.ts +2 -2
- package/dist/batch/batch-bash.d.ts.map +1 -1
- package/dist/batch/batch-bash.js +30 -7
- package/dist/batch/batch-bash.js.map +1 -1
- package/dist/batch/constants.d.ts +31 -5
- package/dist/batch/constants.d.ts.map +1 -1
- package/dist/batch/constants.js +50 -3
- package/dist/batch/constants.js.map +1 -1
- package/dist/batch/execute.d.ts +0 -1
- package/dist/batch/execute.d.ts.map +1 -1
- package/dist/batch/execute.js +210 -6
- package/dist/batch/execute.js.map +1 -1
- package/dist/batch/fuzzy-edit.d.ts +0 -6
- package/dist/batch/fuzzy-edit.d.ts.map +1 -1
- package/dist/batch/fuzzy-edit.js +1 -1
- package/dist/batch/fuzzy-edit.js.map +1 -1
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +87 -16
- package/dist/batch/index.js.map +1 -1
- package/dist/batch/render.d.ts +0 -1
- package/dist/batch/render.d.ts.map +1 -1
- package/dist/batch/render.js +7 -101
- package/dist/batch/render.js.map +1 -1
- package/dist/batch/shell-compress.d.ts +25 -0
- package/dist/batch/shell-compress.d.ts.map +1 -0
- package/dist/batch/shell-compress.js +602 -0
- package/dist/batch/shell-compress.js.map +1 -0
- package/dist/batch/summary.d.ts +5 -0
- package/dist/batch/summary.d.ts.map +1 -0
- package/dist/batch/summary.js +101 -0
- package/dist/batch/summary.js.map +1 -0
- package/dist/batch/symbols.d.ts.map +1 -1
- package/dist/batch/symbols.js +12 -7
- package/dist/batch/symbols.js.map +1 -1
- package/dist/{config.d.ts → config/config.d.ts} +39 -2
- package/dist/config/config.d.ts.map +1 -0
- package/dist/{config.js → config/config.js} +220 -9
- package/dist/config/config.js.map +1 -0
- package/dist/config/log.d.ts +27 -0
- package/dist/config/log.d.ts.map +1 -0
- package/dist/config/log.js +104 -0
- package/dist/config/log.js.map +1 -0
- package/dist/config/models.d.ts +2 -0
- package/dist/config/models.d.ts.map +1 -0
- package/dist/config/models.js +49 -0
- package/dist/config/models.js.map +1 -0
- package/dist/{settings-resolver.d.ts → config/settings-resolver.d.ts} +9 -2
- package/dist/config/settings-resolver.d.ts.map +1 -0
- package/dist/config/settings-resolver.js +275 -0
- package/dist/config/settings-resolver.js.map +1 -0
- package/dist/core/agents.d.ts.map +1 -0
- package/dist/{agents.js → core/agents.js} +13 -12
- package/dist/core/agents.js.map +1 -0
- package/dist/core/delegation.d.ts +24 -0
- package/dist/core/delegation.d.ts.map +1 -0
- package/dist/core/delegation.js +48 -0
- package/dist/core/delegation.js.map +1 -0
- package/dist/core/depth.d.ts.map +1 -0
- package/dist/{depth.js → core/depth.js} +9 -8
- package/dist/core/depth.js.map +1 -0
- package/dist/{executor.d.ts → core/executor.d.ts} +18 -3
- package/dist/core/executor.d.ts.map +1 -0
- package/dist/{executor.js → core/executor.js} +53 -14
- package/dist/core/executor.js.map +1 -0
- package/dist/{flow.d.ts → core/flow.d.ts} +13 -1
- package/dist/core/flow.d.ts.map +1 -0
- package/dist/{flow.js → core/flow.js} +125 -64
- package/dist/core/flow.js.map +1 -0
- package/dist/{session-mode.d.ts → core/session-mode.d.ts} +2 -1
- package/dist/core/session-mode.d.ts.map +1 -0
- package/dist/{session-mode.js → core/session-mode.js} +2 -1
- package/dist/core/session-mode.js.map +1 -0
- package/dist/core/session-registry.d.ts +16 -0
- package/dist/core/session-registry.d.ts.map +1 -0
- package/dist/core/session-registry.js +30 -0
- package/dist/core/session-registry.js.map +1 -0
- package/dist/core/transitions.d.ts.map +1 -0
- package/dist/{transitions.js → core/transitions.js} +1 -1
- package/dist/core/transitions.js.map +1 -0
- package/dist/flow/auto-warp.d.ts +12 -0
- package/dist/flow/auto-warp.d.ts.map +1 -0
- package/dist/flow/auto-warp.js +29 -0
- package/dist/flow/auto-warp.js.map +1 -0
- package/dist/flow/command.d.ts +8 -0
- package/dist/flow/command.d.ts.map +1 -0
- package/dist/flow/command.js +194 -0
- package/dist/flow/command.js.map +1 -0
- package/dist/flow/continuation.d.ts +16 -0
- package/dist/flow/continuation.d.ts.map +1 -0
- package/dist/flow/continuation.js +188 -0
- package/dist/flow/continuation.js.map +1 -0
- package/dist/flow/index.d.ts +18 -0
- package/dist/flow/index.d.ts.map +1 -0
- package/dist/flow/index.js +25 -0
- package/dist/flow/index.js.map +1 -0
- package/dist/flow/loop-command.d.ts +8 -0
- package/dist/flow/loop-command.d.ts.map +1 -0
- package/dist/flow/loop-command.js +99 -0
- package/dist/flow/loop-command.js.map +1 -0
- package/dist/flow/loop-templates.d.ts +7 -0
- package/dist/flow/loop-templates.d.ts.map +1 -0
- package/dist/flow/loop-templates.js +38 -0
- package/dist/flow/loop-templates.js.map +1 -0
- package/dist/flow/loop.d.ts +19 -0
- package/dist/flow/loop.d.ts.map +1 -0
- package/dist/flow/loop.js +95 -0
- package/dist/flow/loop.js.map +1 -0
- package/dist/flow/perform-warp.d.ts +28 -0
- package/dist/flow/perform-warp.d.ts.map +1 -0
- package/dist/flow/perform-warp.js +127 -0
- package/dist/flow/perform-warp.js.map +1 -0
- package/dist/flow/settings-command.d.ts +51 -0
- package/dist/flow/settings-command.d.ts.map +1 -0
- package/dist/flow/settings-command.js +937 -0
- package/dist/flow/settings-command.js.map +1 -0
- package/dist/flow/store.d.ts +26 -0
- package/dist/flow/store.d.ts.map +1 -0
- package/dist/flow/store.js +166 -0
- package/dist/flow/store.js.map +1 -0
- package/dist/flow/template-shared.d.ts +9 -0
- package/dist/flow/template-shared.d.ts.map +1 -0
- package/dist/flow/template-shared.js +13 -0
- package/dist/flow/template-shared.js.map +1 -0
- package/dist/flow/template-strings.d.ts +8 -0
- package/dist/flow/template-strings.d.ts.map +1 -0
- package/dist/flow/template-strings.js +36 -0
- package/dist/flow/template-strings.js.map +1 -0
- package/dist/flow/types.d.ts +61 -0
- package/dist/flow/types.d.ts.map +1 -0
- package/dist/flow/types.js +5 -0
- package/dist/flow/types.js.map +1 -0
- package/dist/flow/warp-command.d.ts +8 -0
- package/dist/flow/warp-command.d.ts.map +1 -0
- package/dist/flow/warp-command.js +144 -0
- package/dist/flow/warp-command.js.map +1 -0
- package/dist/flow/warp-utils.d.ts +11 -0
- package/dist/flow/warp-utils.d.ts.map +1 -0
- package/dist/flow/warp-utils.js +187 -0
- package/dist/flow/warp-utils.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +115 -31
- package/dist/index.js.map +1 -1
- package/dist/{notify-state.d.ts → notify/notify-state.d.ts} +2 -1
- package/dist/notify/notify-state.d.ts.map +1 -0
- package/dist/notify/notify-state.js.map +1 -0
- package/dist/notify/notify.d.ts.map +1 -0
- package/dist/{notify.js → notify/notify.js} +3 -2
- package/dist/notify/notify.js.map +1 -0
- package/dist/{cli-args.d.ts → snapshot/cli-args.d.ts} +4 -2
- package/dist/snapshot/cli-args.d.ts.map +1 -0
- package/dist/{cli-args.js → snapshot/cli-args.js} +13 -1
- package/dist/snapshot/cli-args.js.map +1 -0
- package/dist/snapshot/index.d.ts +2 -0
- package/dist/snapshot/index.d.ts.map +1 -0
- package/dist/snapshot/index.js +2 -0
- package/dist/snapshot/index.js.map +1 -0
- package/dist/{reasoning-strip.d.ts → snapshot/reasoning-strip.d.ts} +0 -4
- package/dist/snapshot/reasoning-strip.d.ts.map +1 -0
- package/dist/{reasoning-strip.js → snapshot/reasoning-strip.js} +2 -2
- package/dist/snapshot/reasoning-strip.js.map +1 -0
- package/dist/snapshot/runner-events.d.ts.map +1 -0
- package/dist/{runner-events.js → snapshot/runner-events.js} +1 -1
- package/dist/snapshot/runner-events.js.map +1 -0
- package/dist/{snapshot.d.ts → snapshot/snapshot.d.ts} +24 -18
- package/dist/snapshot/snapshot.d.ts.map +1 -0
- package/dist/snapshot/snapshot.js +1791 -0
- package/dist/snapshot/snapshot.js.map +1 -0
- package/dist/{structured-output.d.ts → snapshot/structured-output.d.ts} +1 -1
- package/dist/snapshot/structured-output.d.ts.map +1 -0
- package/dist/snapshot/structured-output.js.map +1 -0
- package/dist/{flow-prompt.d.ts → steering/flow-prompt.d.ts} +2 -2
- package/dist/steering/flow-prompt.d.ts.map +1 -0
- package/dist/{flow-prompt.js → steering/flow-prompt.js} +1 -1
- package/dist/steering/flow-prompt.js.map +1 -0
- package/dist/{sliding-prompt.d.ts → steering/sliding-prompt.d.ts} +8 -7
- package/dist/steering/sliding-prompt.d.ts.map +1 -0
- package/dist/{sliding-prompt.js → steering/sliding-prompt.js} +18 -64
- package/dist/steering/sliding-prompt.js.map +1 -0
- package/dist/{tool-utils.d.ts → steering/tool-utils.d.ts} +1 -0
- package/dist/steering/tool-utils.d.ts.map +1 -0
- package/dist/{tool-utils.js → steering/tool-utils.js} +10 -3
- package/dist/steering/tool-utils.js.map +1 -0
- package/dist/{ask-user.d.ts → tools/ask-user.d.ts} +3 -15
- package/dist/tools/ask-user.d.ts.map +1 -0
- package/dist/tools/ask-user.js +778 -0
- package/dist/tools/ask-user.js.map +1 -0
- package/dist/{timed-bash.d.ts → tools/timed-bash.d.ts} +2 -7
- package/dist/tools/timed-bash.d.ts.map +1 -0
- package/dist/{timed-bash.js → tools/timed-bash.js} +11 -2
- package/dist/tools/timed-bash.js.map +1 -0
- package/dist/{web-tool.d.ts → tools/web-tool.d.ts} +1 -1
- package/dist/tools/web-tool.d.ts.map +1 -0
- package/dist/{web-tool.js → tools/web-tool.js} +8 -7
- package/dist/tools/web-tool.js.map +1 -0
- package/dist/tui/flow-colors.d.ts +55 -0
- package/dist/tui/flow-colors.d.ts.map +1 -0
- package/dist/tui/flow-colors.js +22 -0
- package/dist/tui/flow-colors.js.map +1 -0
- package/dist/{render-utils.d.ts → tui/render-utils.d.ts} +6 -2
- package/dist/tui/render-utils.d.ts.map +1 -0
- package/dist/{render-utils.js → tui/render-utils.js} +40 -12
- package/dist/tui/render-utils.js.map +1 -0
- package/dist/tui/render.d.ts +21 -0
- package/dist/tui/render.d.ts.map +1 -0
- package/dist/tui/render.js +786 -0
- package/dist/tui/render.js.map +1 -0
- package/dist/tui/scramble/algorithm.d.ts +7 -0
- package/dist/tui/scramble/algorithm.d.ts.map +1 -0
- package/dist/tui/scramble/algorithm.js +227 -0
- package/dist/tui/scramble/algorithm.js.map +1 -0
- package/dist/tui/scramble/constants.d.ts +99 -0
- package/dist/tui/scramble/constants.d.ts.map +1 -0
- package/dist/tui/scramble/constants.js +101 -0
- package/dist/tui/scramble/constants.js.map +1 -0
- package/dist/tui/scramble/index.d.ts +6 -0
- package/dist/tui/scramble/index.d.ts.map +1 -0
- package/dist/tui/scramble/index.js +6 -0
- package/dist/tui/scramble/index.js.map +1 -0
- package/dist/tui/scramble/manager.d.ts +44 -0
- package/dist/tui/scramble/manager.d.ts.map +1 -0
- package/dist/tui/scramble/manager.js +899 -0
- package/dist/tui/scramble/manager.js.map +1 -0
- package/dist/tui/scramble/utils.d.ts +18 -0
- package/dist/tui/scramble/utils.d.ts.map +1 -0
- package/dist/tui/scramble/utils.js +145 -0
- package/dist/tui/scramble/utils.js.map +1 -0
- package/dist/tui/single-select-layout.d.ts +17 -0
- package/dist/tui/single-select-layout.d.ts.map +1 -0
- package/dist/{single-select-layout.js → tui/single-select-layout.js} +8 -25
- package/dist/tui/single-select-layout.js.map +1 -0
- package/dist/types/flow.d.ts +112 -0
- package/dist/types/flow.d.ts.map +1 -0
- package/dist/{types.js → types/flow.js} +3 -54
- package/dist/types/flow.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/output.d.ts +110 -0
- package/dist/types/output.d.ts.map +1 -0
- package/dist/types/output.js +5 -0
- package/dist/types/output.js.map +1 -0
- package/dist/types/ui.d.ts +24 -0
- package/dist/types/ui.d.ts.map +1 -0
- package/dist/types/ui.js +55 -0
- package/dist/types/ui.js.map +1 -0
- package/package.json +1 -1
- package/dist/agents.d.ts.map +0 -1
- package/dist/agents.js.map +0 -1
- package/dist/ask-user.d.ts.map +0 -1
- package/dist/ask-user.js +0 -1405
- package/dist/ask-user.js.map +0 -1
- package/dist/batch.d.ts +0 -12
- package/dist/batch.d.ts.map +0 -1
- package/dist/batch.js +0 -11
- package/dist/batch.js.map +0 -1
- package/dist/cli-args.d.ts.map +0 -1
- package/dist/cli-args.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/depth.d.ts.map +0 -1
- package/dist/depth.js.map +0 -1
- package/dist/executor.d.ts.map +0 -1
- package/dist/executor.js.map +0 -1
- package/dist/flow-prompt.d.ts.map +0 -1
- package/dist/flow-prompt.js.map +0 -1
- package/dist/flow.d.ts.map +0 -1
- package/dist/flow.js.map +0 -1
- package/dist/notify-state.d.ts.map +0 -1
- package/dist/notify-state.js.map +0 -1
- package/dist/notify.d.ts.map +0 -1
- package/dist/notify.js.map +0 -1
- package/dist/reasoning-strip.d.ts.map +0 -1
- package/dist/reasoning-strip.js.map +0 -1
- package/dist/render-utils.d.ts.map +0 -1
- package/dist/render-utils.js.map +0 -1
- package/dist/render.d.ts +0 -24
- package/dist/render.d.ts.map +0 -1
- package/dist/render.js +0 -592
- package/dist/render.js.map +0 -1
- package/dist/runner-events.d.ts.map +0 -1
- package/dist/runner-events.js.map +0 -1
- package/dist/scramble.d.ts +0 -183
- package/dist/scramble.d.ts.map +0 -1
- package/dist/scramble.js +0 -2478
- package/dist/scramble.js.map +0 -1
- package/dist/session-mode.d.ts.map +0 -1
- package/dist/session-mode.js.map +0 -1
- package/dist/settings-resolver.d.ts.map +0 -1
- package/dist/settings-resolver.js +0 -148
- package/dist/settings-resolver.js.map +0 -1
- package/dist/single-select-layout.d.ts +0 -20
- package/dist/single-select-layout.d.ts.map +0 -1
- package/dist/single-select-layout.js.map +0 -1
- package/dist/sliding-prompt.d.ts.map +0 -1
- package/dist/sliding-prompt.js.map +0 -1
- package/dist/snapshot.d.ts.map +0 -1
- package/dist/snapshot.js +0 -797
- package/dist/snapshot.js.map +0 -1
- package/dist/spec-mode.d.ts +0 -13
- package/dist/spec-mode.d.ts.map +0 -1
- package/dist/spec-mode.js +0 -90
- package/dist/spec-mode.js.map +0 -1
- package/dist/structured-output.d.ts.map +0 -1
- package/dist/structured-output.js.map +0 -1
- package/dist/timed-bash.d.ts.map +0 -1
- package/dist/timed-bash.js.map +0 -1
- package/dist/tool-utils.d.ts.map +0 -1
- package/dist/tool-utils.js.map +0 -1
- package/dist/transitions.d.ts.map +0 -1
- package/dist/transitions.js.map +0 -1
- package/dist/types.d.ts +0 -224
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/web-tool.d.ts.map +0 -1
- package/dist/web-tool.js.map +0 -1
- /package/dist/{agents.d.ts → core/agents.d.ts} +0 -0
- /package/dist/{depth.d.ts → core/depth.d.ts} +0 -0
- /package/dist/{transitions.d.ts → core/transitions.d.ts} +0 -0
- /package/dist/{notify-state.js → notify/notify-state.js} +0 -0
- /package/dist/{notify.d.ts → notify/notify.d.ts} +0 -0
- /package/dist/{runner-events.d.ts → snapshot/runner-events.d.ts} +0 -0
- /package/dist/{structured-output.js → snapshot/structured-output.js} +0 -0
|
@@ -0,0 +1,937 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /flow:settings slash command registration.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands: steering, strategic-hint, animation, glitch,
|
|
5
|
+
* tool-optimize, structured-output, session-mode, max-concurrency, reset
|
|
6
|
+
*
|
|
7
|
+
* When called with no arguments, opens an interactive TUI overlay.
|
|
8
|
+
*/
|
|
9
|
+
import { DynamicBorder } from "@mariozechner/pi-coding-agent";
|
|
10
|
+
import { loadFlowSettings, writeFlowSetting, loadFlowModelConfigs, writeGlobalFlowMode, writeFlowModelConfig } from "../config/config.js";
|
|
11
|
+
import { configureSteering } from "../steering/sliding-prompt.js";
|
|
12
|
+
import { configureStrategicHint } from "../steering/tool-utils.js";
|
|
13
|
+
import { scrambleManager } from "../tui/scramble/index.js";
|
|
14
|
+
import { getLoop } from "./loop.js";
|
|
15
|
+
import { Container, Input, matchesKey, SelectList, Key, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from "@mariozechner/pi-tui";
|
|
16
|
+
// Module-level refs for submenu builders (set during handler call)
|
|
17
|
+
let _modelRegistry = null;
|
|
18
|
+
let _theme = null;
|
|
19
|
+
let _keybindings = null;
|
|
20
|
+
export class SettingsList {
|
|
21
|
+
items;
|
|
22
|
+
theme;
|
|
23
|
+
selectedIndex = 0;
|
|
24
|
+
maxVisible;
|
|
25
|
+
onChange;
|
|
26
|
+
onCancel;
|
|
27
|
+
keybindings;
|
|
28
|
+
submenuComponent = null;
|
|
29
|
+
submenuItemIndex = null;
|
|
30
|
+
constructor(items, maxVisible, theme, keybindings, onChange, onCancel) {
|
|
31
|
+
this.items = items;
|
|
32
|
+
this.maxVisible = maxVisible;
|
|
33
|
+
this.theme = theme;
|
|
34
|
+
this.keybindings = keybindings;
|
|
35
|
+
this.onChange = onChange;
|
|
36
|
+
this.onCancel = onCancel;
|
|
37
|
+
}
|
|
38
|
+
updateValue(id, newValue) {
|
|
39
|
+
const item = this.items.find((i) => i.id === id);
|
|
40
|
+
if (item) {
|
|
41
|
+
item.currentValue = newValue;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
invalidate() {
|
|
45
|
+
this.submenuComponent?.invalidate?.();
|
|
46
|
+
}
|
|
47
|
+
render(width) {
|
|
48
|
+
if (this.submenuComponent) {
|
|
49
|
+
return this.submenuComponent.render(width);
|
|
50
|
+
}
|
|
51
|
+
return this.renderMainList(width);
|
|
52
|
+
}
|
|
53
|
+
renderMainList(width) {
|
|
54
|
+
const lines = [];
|
|
55
|
+
if (this.items.length === 0) {
|
|
56
|
+
lines.push(this.theme.hint(" No settings available"));
|
|
57
|
+
this.addHintLine(lines);
|
|
58
|
+
return lines;
|
|
59
|
+
}
|
|
60
|
+
const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.items.length - this.maxVisible));
|
|
61
|
+
const endIndex = Math.min(startIndex + this.maxVisible, this.items.length);
|
|
62
|
+
const maxLabelWidth = Math.min(30, Math.max(...this.items.map((item) => visibleWidth(item.label))));
|
|
63
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
64
|
+
const item = this.items[i];
|
|
65
|
+
if (!item)
|
|
66
|
+
continue;
|
|
67
|
+
const isSelected = i === this.selectedIndex;
|
|
68
|
+
const prefix = isSelected ? this.theme.cursor : " ";
|
|
69
|
+
const prefixWidth = visibleWidth(prefix);
|
|
70
|
+
const labelPadded = item.label + " ".repeat(Math.max(0, maxLabelWidth - visibleWidth(item.label)));
|
|
71
|
+
const labelText = this.theme.label(labelPadded, isSelected);
|
|
72
|
+
const separator = " ";
|
|
73
|
+
const usedWidth = prefixWidth + maxLabelWidth + visibleWidth(separator);
|
|
74
|
+
const valueMaxWidth = Math.max(1, width - usedWidth - 2);
|
|
75
|
+
const optionLines = isSelected && item.values && item.values.length > 0
|
|
76
|
+
? wrapTextWithAnsi(this.formatOptionsInline(item, item.values), valueMaxWidth)
|
|
77
|
+
: null;
|
|
78
|
+
const valueText = optionLines
|
|
79
|
+
? optionLines[0] ?? ""
|
|
80
|
+
: this.theme.value(truncateToWidth(item.currentValue, valueMaxWidth, ""), isSelected);
|
|
81
|
+
const line = prefix + labelText + separator + valueText;
|
|
82
|
+
lines.push(truncateToWidth(line, width, ""));
|
|
83
|
+
if (optionLines && optionLines.length > 1) {
|
|
84
|
+
const indent = " ".repeat(prefixWidth + maxLabelWidth + visibleWidth(separator));
|
|
85
|
+
for (const continuation of optionLines.slice(1)) {
|
|
86
|
+
lines.push(truncateToWidth(indent + continuation, width, ""));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (startIndex > 0 || endIndex < this.items.length) {
|
|
91
|
+
const scrollText = ` (${this.selectedIndex + 1}/${this.items.length})`;
|
|
92
|
+
lines.push(this.theme.hint(truncateToWidth(scrollText, width - 2, "")));
|
|
93
|
+
}
|
|
94
|
+
const selectedItem = this.items[this.selectedIndex];
|
|
95
|
+
if (selectedItem?.description) {
|
|
96
|
+
lines.push("");
|
|
97
|
+
const wrapWidth = Math.max(1, width - 4);
|
|
98
|
+
const wrappedDesc = wrapTextWithAnsi(selectedItem.description, wrapWidth);
|
|
99
|
+
for (const line of wrappedDesc) {
|
|
100
|
+
const prefixed = ` ${line}`;
|
|
101
|
+
lines.push(this.theme.description(truncateToWidth(prefixed, width, "")));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
this.addHintLine(lines);
|
|
105
|
+
return lines;
|
|
106
|
+
}
|
|
107
|
+
handleInput(data) {
|
|
108
|
+
if (this.submenuComponent) {
|
|
109
|
+
this.submenuComponent.handleInput?.(data);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (this.keybindings.matches(data, "tui.select.up") || matchesKey(data, Key.ctrl("k"))) {
|
|
113
|
+
if (this.items.length === 0)
|
|
114
|
+
return;
|
|
115
|
+
this.selectedIndex = this.selectedIndex === 0 ? this.items.length - 1 : this.selectedIndex - 1;
|
|
116
|
+
}
|
|
117
|
+
else if (this.keybindings.matches(data, "tui.select.down") || matchesKey(data, Key.ctrl("j"))) {
|
|
118
|
+
if (this.items.length === 0)
|
|
119
|
+
return;
|
|
120
|
+
this.selectedIndex = this.selectedIndex === this.items.length - 1 ? 0 : this.selectedIndex + 1;
|
|
121
|
+
}
|
|
122
|
+
else if (this.keybindings.matches(data, "tui.editor.cursorLeft") || data === "\u001b[D") {
|
|
123
|
+
this.stepValue(-1);
|
|
124
|
+
}
|
|
125
|
+
else if (this.keybindings.matches(data, "tui.editor.cursorRight") || data === "\u001b[C") {
|
|
126
|
+
this.stepValue(1);
|
|
127
|
+
}
|
|
128
|
+
else if (this.keybindings.matches(data, "tui.select.confirm") ||
|
|
129
|
+
data === "\r" ||
|
|
130
|
+
data === "\n" ||
|
|
131
|
+
data === " ") {
|
|
132
|
+
this.activateItem();
|
|
133
|
+
}
|
|
134
|
+
else if (this.keybindings.matches(data, "tui.select.cancel") || matchesKey(data, Key.escape)) {
|
|
135
|
+
this.onCancel();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
stepValue(direction) {
|
|
139
|
+
const item = this.items[this.selectedIndex];
|
|
140
|
+
if (!item || !item.values || item.values.length === 0)
|
|
141
|
+
return;
|
|
142
|
+
const values = item.values;
|
|
143
|
+
let currentIndex = values.indexOf(item.currentValue);
|
|
144
|
+
if (currentIndex === -1) {
|
|
145
|
+
currentIndex = direction > 0 ? 0 : values.length - 1;
|
|
146
|
+
}
|
|
147
|
+
const nextIndex = (currentIndex + direction + values.length) % values.length;
|
|
148
|
+
const newValue = values[nextIndex];
|
|
149
|
+
item.currentValue = newValue;
|
|
150
|
+
this.onChange(item.id, newValue);
|
|
151
|
+
}
|
|
152
|
+
activateItem() {
|
|
153
|
+
const item = this.items[this.selectedIndex];
|
|
154
|
+
if (!item)
|
|
155
|
+
return;
|
|
156
|
+
if (item.submenu) {
|
|
157
|
+
this.openSubmenu(item);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
closeSubmenu() {
|
|
161
|
+
this.submenuComponent = null;
|
|
162
|
+
if (this.submenuItemIndex !== null) {
|
|
163
|
+
this.selectedIndex = this.submenuItemIndex;
|
|
164
|
+
this.submenuItemIndex = null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
formatOptionsInline(item, values) {
|
|
168
|
+
const separator = this.theme.description(" • ");
|
|
169
|
+
return values
|
|
170
|
+
.map((value) => {
|
|
171
|
+
const selected = value === item.currentValue;
|
|
172
|
+
return this.theme.value(value, selected);
|
|
173
|
+
})
|
|
174
|
+
.join(separator);
|
|
175
|
+
}
|
|
176
|
+
openSubmenu(item) {
|
|
177
|
+
if (!item.submenu)
|
|
178
|
+
return;
|
|
179
|
+
this.submenuItemIndex = this.selectedIndex;
|
|
180
|
+
this.submenuComponent = item.submenu(item.currentValue, (selectedValue) => {
|
|
181
|
+
if (selectedValue !== undefined) {
|
|
182
|
+
item.currentValue = selectedValue;
|
|
183
|
+
this.onChange(item.id, selectedValue);
|
|
184
|
+
}
|
|
185
|
+
this.closeSubmenu();
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
addHintLine(lines) {
|
|
189
|
+
lines.push("");
|
|
190
|
+
lines.push(this.theme.hint(" ←/→ change • Enter/Space edit custom • Esc to cancel"));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function getMainMenuItems(settings, cwd) {
|
|
194
|
+
const steeringEnabled = settings.steering?.enabled ?? true;
|
|
195
|
+
const animationEnabled = settings.animation?.enabled ?? true;
|
|
196
|
+
const toolOptimize = settings.toolOptimize ?? true;
|
|
197
|
+
const structuredOutput = settings.structuredOutput ?? true;
|
|
198
|
+
const sessionMode = settings.sessionMode ?? "default";
|
|
199
|
+
const askUserEnabled = settings.askUser?.enabled ?? false;
|
|
200
|
+
const askUserTimeout = settings.askUser?.timeout ?? 300;
|
|
201
|
+
const loaded = loadFlowModelConfigs(cwd);
|
|
202
|
+
const strategyName = loaded.selectedName;
|
|
203
|
+
const litePrimary = loaded.strategy.lite?.primary ?? "(default)";
|
|
204
|
+
const primaryModelShort = litePrimary.includes("/") ? litePrimary.split("/").pop() : litePrimary;
|
|
205
|
+
const loop = getLoop(cwd);
|
|
206
|
+
const loopDescription = loop ? `${loop.status} • ${loop.sessionCount} sessions` : "none";
|
|
207
|
+
return [
|
|
208
|
+
{
|
|
209
|
+
value: "steering",
|
|
210
|
+
label: "Steering Settings",
|
|
211
|
+
description: steeringEnabled ? "enabled" : "disabled",
|
|
212
|
+
tooltip: "Configure orchestrator steering and strategic hints",
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
value: "animation",
|
|
216
|
+
label: "Animation Settings",
|
|
217
|
+
description: animationEnabled ? "enabled" : "disabled",
|
|
218
|
+
tooltip: "Toggle animation effects and glitch/scramble",
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
value: "tools",
|
|
222
|
+
label: "Tool Settings",
|
|
223
|
+
description: `tool-optimize: ${toolOptimize ? "on" : "off"}, structured-output: ${structuredOutput ? "on" : "off"}`,
|
|
224
|
+
tooltip: "Configure tool optimization and structured output",
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
value: "session",
|
|
228
|
+
label: "Session Settings",
|
|
229
|
+
description: `mode: ${sessionMode}`,
|
|
230
|
+
tooltip: "Set default session mode and concurrency",
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
value: "ask-user",
|
|
234
|
+
label: "Ask User Settings",
|
|
235
|
+
description: `enabled: ${askUserEnabled ? "on" : "off"}, timeout: ${askUserTimeout}s`,
|
|
236
|
+
tooltip: "Configure ask_user timeout and countdown",
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
value: "model-config",
|
|
240
|
+
label: "Model Config",
|
|
241
|
+
description: `${strategyName} ▸ lite: ${primaryModelShort}`,
|
|
242
|
+
tooltip: "Configure LLM models for lite, flash, and full flow tiers",
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
value: "loop",
|
|
246
|
+
label: "Loop Status",
|
|
247
|
+
description: loopDescription,
|
|
248
|
+
tooltip: "Endless loop state and statistics",
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
value: "reset",
|
|
252
|
+
label: "Reset to Defaults",
|
|
253
|
+
description: "restore all settings",
|
|
254
|
+
tooltip: "Restore all flow settings to their default values",
|
|
255
|
+
},
|
|
256
|
+
];
|
|
257
|
+
}
|
|
258
|
+
function getSteeringItems(settings) {
|
|
259
|
+
const steering = settings.steering ?? {};
|
|
260
|
+
return [
|
|
261
|
+
{
|
|
262
|
+
id: "steering.enabled",
|
|
263
|
+
label: "enabled",
|
|
264
|
+
description: "Toggle steering injection",
|
|
265
|
+
currentValue: (steering.enabled ?? true) ? "on" : "off",
|
|
266
|
+
values: ["on", "off"],
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
id: "steering.strategicHint",
|
|
270
|
+
label: "strategic-hint",
|
|
271
|
+
description: "Toggle [Hint: Plan next step...]",
|
|
272
|
+
currentValue: (steering.strategicHint ?? true) ? "on" : "off",
|
|
273
|
+
values: ["on", "off"],
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
id: "steering.customPrompt",
|
|
277
|
+
label: "custom-prompt",
|
|
278
|
+
description: "Enter custom steering prompt or type 'default' to reset",
|
|
279
|
+
currentValue: steering.customPrompt ?? "(default)",
|
|
280
|
+
submenu: buildInputSubmenu("Custom prompt (or 'default')", (v) => {
|
|
281
|
+
const trimmed = v.trim();
|
|
282
|
+
if (!trimmed || trimmed.toLowerCase() === "default")
|
|
283
|
+
return "(default)";
|
|
284
|
+
return trimmed;
|
|
285
|
+
}),
|
|
286
|
+
},
|
|
287
|
+
];
|
|
288
|
+
}
|
|
289
|
+
function getAnimationItems(settings) {
|
|
290
|
+
const animation = settings.animation ?? {};
|
|
291
|
+
return [
|
|
292
|
+
{
|
|
293
|
+
id: "animation.enabled",
|
|
294
|
+
label: "enabled",
|
|
295
|
+
description: "Master animation switch",
|
|
296
|
+
currentValue: (animation.enabled ?? true) ? "on" : "off",
|
|
297
|
+
values: ["on", "off"],
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
id: "animation.glitch",
|
|
301
|
+
label: "glitch",
|
|
302
|
+
description: "Glitch/scramble effect",
|
|
303
|
+
currentValue: (animation.glitch ?? true) ? "on" : "off",
|
|
304
|
+
values: ["on", "off"],
|
|
305
|
+
},
|
|
306
|
+
];
|
|
307
|
+
}
|
|
308
|
+
function getToolItems(settings) {
|
|
309
|
+
return [
|
|
310
|
+
{
|
|
311
|
+
id: "toolOptimize",
|
|
312
|
+
label: "tool-optimize",
|
|
313
|
+
description: "Unified batch tool vs separate tools",
|
|
314
|
+
currentValue: (settings.toolOptimize ?? true) ? "on" : "off",
|
|
315
|
+
values: ["on", "off"],
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
id: "structuredOutput",
|
|
319
|
+
label: "structured-output",
|
|
320
|
+
description: "Structured JSON output from flows",
|
|
321
|
+
currentValue: (settings.structuredOutput ?? true) ? "on" : "off",
|
|
322
|
+
values: ["on", "off"],
|
|
323
|
+
},
|
|
324
|
+
];
|
|
325
|
+
}
|
|
326
|
+
function getSessionItems(settings) {
|
|
327
|
+
return [
|
|
328
|
+
{
|
|
329
|
+
id: "sessionMode",
|
|
330
|
+
label: "session-mode",
|
|
331
|
+
description: "Session safety mode",
|
|
332
|
+
currentValue: settings.sessionMode ?? "default",
|
|
333
|
+
values: ["fast", "default", "long", "extreme_long"],
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
id: "maxConcurrency",
|
|
337
|
+
label: "max-concurrency",
|
|
338
|
+
description: "Maximum concurrent flows",
|
|
339
|
+
currentValue: String(settings.maxConcurrency ?? 4),
|
|
340
|
+
values: ["1", "2", "3", "4", "5", "6", "7", "8"],
|
|
341
|
+
submenu: buildInputSubmenu("Max concurrency (1-20)", (v) => {
|
|
342
|
+
const n = Number(v.trim());
|
|
343
|
+
if (!Number.isSafeInteger(n) || n < 1 || n > 20)
|
|
344
|
+
return null;
|
|
345
|
+
return String(n);
|
|
346
|
+
}),
|
|
347
|
+
},
|
|
348
|
+
];
|
|
349
|
+
}
|
|
350
|
+
function getAskUserItems(settings) {
|
|
351
|
+
const askUser = settings.askUser ?? {};
|
|
352
|
+
return [
|
|
353
|
+
{
|
|
354
|
+
id: "askUser.enabled",
|
|
355
|
+
label: "enabled",
|
|
356
|
+
description: "Show countdown timer in ask_user prompt",
|
|
357
|
+
currentValue: (askUser.enabled ?? false) ? "on" : "off",
|
|
358
|
+
values: ["on", "off"],
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
id: "askUser.timeout",
|
|
362
|
+
label: "timeout",
|
|
363
|
+
description: "Auto-dismiss timeout in seconds",
|
|
364
|
+
currentValue: String(askUser.timeout ?? 300),
|
|
365
|
+
values: ["30", "60", "120", "300", "600"],
|
|
366
|
+
submenu: buildInputSubmenu("Timeout in seconds (10-3600)", (v) => {
|
|
367
|
+
const n = Number(v.trim());
|
|
368
|
+
if (!Number.isSafeInteger(n) || n < 10 || n > 3600)
|
|
369
|
+
return null;
|
|
370
|
+
return String(n);
|
|
371
|
+
}),
|
|
372
|
+
},
|
|
373
|
+
];
|
|
374
|
+
}
|
|
375
|
+
function getLoopItems(_settings, cwd) {
|
|
376
|
+
const loop = getLoop(cwd);
|
|
377
|
+
if (!loop) {
|
|
378
|
+
return [
|
|
379
|
+
{
|
|
380
|
+
id: "loop.status",
|
|
381
|
+
label: "status",
|
|
382
|
+
description: "No active loop",
|
|
383
|
+
currentValue: "none",
|
|
384
|
+
},
|
|
385
|
+
];
|
|
386
|
+
}
|
|
387
|
+
return [
|
|
388
|
+
{
|
|
389
|
+
id: "loop.status",
|
|
390
|
+
label: "status",
|
|
391
|
+
description: "Current loop status",
|
|
392
|
+
currentValue: loop.status,
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
id: "loop.objective",
|
|
396
|
+
label: "objective",
|
|
397
|
+
description: "Loop objective",
|
|
398
|
+
currentValue: loop.objective,
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
id: "loop.sessions",
|
|
402
|
+
label: "sessions",
|
|
403
|
+
description: "Number of warped sessions",
|
|
404
|
+
currentValue: String(loop.sessionCount),
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
id: "loop.flows",
|
|
408
|
+
label: "flows",
|
|
409
|
+
description: "Total flows across sessions",
|
|
410
|
+
currentValue: String(loop.totalFlowsAcrossSessions),
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
id: "loop.tokens",
|
|
414
|
+
label: "tokens",
|
|
415
|
+
description: "Total tokens across sessions",
|
|
416
|
+
currentValue: String(loop.totalTokensAcrossSessions),
|
|
417
|
+
},
|
|
418
|
+
];
|
|
419
|
+
}
|
|
420
|
+
function getModelConfigItems(settings, cwd) {
|
|
421
|
+
const loaded = loadFlowModelConfigs(cwd);
|
|
422
|
+
const strategyName = loaded.selectedName;
|
|
423
|
+
const strategy = loaded.strategy;
|
|
424
|
+
const items = [
|
|
425
|
+
{
|
|
426
|
+
id: "modelConfig.strategy",
|
|
427
|
+
label: "strategy",
|
|
428
|
+
description: "Active model strategy",
|
|
429
|
+
currentValue: strategyName,
|
|
430
|
+
values: Object.keys(loaded.configs).sort(),
|
|
431
|
+
},
|
|
432
|
+
];
|
|
433
|
+
for (const tier of ["lite", "flash", "full"]) {
|
|
434
|
+
const tierConfig = strategy[tier];
|
|
435
|
+
const primary = tierConfig?.primary ?? "(default)";
|
|
436
|
+
const failover = tierConfig?.failover?.join(", ") ?? "(none)";
|
|
437
|
+
items.push({
|
|
438
|
+
id: `modelConfig.${tier}.primary`,
|
|
439
|
+
label: `${tier}: primary`,
|
|
440
|
+
description: `Primary model for ${tier} tier`,
|
|
441
|
+
currentValue: primary,
|
|
442
|
+
submenu: buildModelPickerSubmenu(primary, tier, "primary"),
|
|
443
|
+
});
|
|
444
|
+
items.push({
|
|
445
|
+
id: `modelConfig.${tier}.failover`,
|
|
446
|
+
label: `${tier}: failover`,
|
|
447
|
+
description: `Failover models for ${tier} tier`,
|
|
448
|
+
currentValue: failover,
|
|
449
|
+
submenu: buildModelPickerSubmenu(failover, tier, "failover"),
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
return items;
|
|
453
|
+
}
|
|
454
|
+
// ---------------------------------------------------------------------------
|
|
455
|
+
// Submenu helpers
|
|
456
|
+
// ---------------------------------------------------------------------------
|
|
457
|
+
function buildInputSubmenu(label, parseValue) {
|
|
458
|
+
return (currentValue, done) => {
|
|
459
|
+
const input = new Input();
|
|
460
|
+
input.focused = true;
|
|
461
|
+
input.setValue(currentValue);
|
|
462
|
+
input.onSubmit = (value) => {
|
|
463
|
+
const parsed = parseValue(value);
|
|
464
|
+
if (parsed === null)
|
|
465
|
+
return;
|
|
466
|
+
done(parsed);
|
|
467
|
+
};
|
|
468
|
+
input.onEscape = () => {
|
|
469
|
+
done();
|
|
470
|
+
};
|
|
471
|
+
const container = new Container();
|
|
472
|
+
container.addChild(new Text(label, 1, 0));
|
|
473
|
+
container.addChild(new Spacer(1));
|
|
474
|
+
container.addChild(input);
|
|
475
|
+
return {
|
|
476
|
+
render: (width) => container.render(width),
|
|
477
|
+
invalidate: () => container.invalidate(),
|
|
478
|
+
handleInput: (data) => input.handleInput(data),
|
|
479
|
+
};
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
function buildModelPickerSubmenu(currentValue, tier, slot) {
|
|
483
|
+
return (_currentValue, done) => {
|
|
484
|
+
const models = _modelRegistry?.getAvailable() ?? [];
|
|
485
|
+
const items = models.map((m) => ({
|
|
486
|
+
value: `${m.provider}/${m.id}`,
|
|
487
|
+
label: `${m.provider}/${m.id}`,
|
|
488
|
+
description: m.name ?? "",
|
|
489
|
+
}));
|
|
490
|
+
items.unshift({ value: "(default)", label: "(default)", description: "Use the default model" });
|
|
491
|
+
const selectList = new SelectList(items, 15, {
|
|
492
|
+
selectedPrefix: (t) => _theme?.fg("accent", t) ?? t,
|
|
493
|
+
selectedText: (t) => _theme?.fg("accent", t) ?? t,
|
|
494
|
+
description: (t) => _theme?.fg("muted", t) ?? t,
|
|
495
|
+
scrollInfo: (t) => _theme?.fg("dim", t) ?? t,
|
|
496
|
+
noMatch: (t) => _theme?.fg("warning", t) ?? t,
|
|
497
|
+
});
|
|
498
|
+
selectList.onSelect = (item) => {
|
|
499
|
+
done(item.value);
|
|
500
|
+
};
|
|
501
|
+
selectList.onCancel = () => {
|
|
502
|
+
done();
|
|
503
|
+
};
|
|
504
|
+
return {
|
|
505
|
+
render(width) {
|
|
506
|
+
return selectList.render(width);
|
|
507
|
+
},
|
|
508
|
+
invalidate() {
|
|
509
|
+
selectList.invalidate?.();
|
|
510
|
+
},
|
|
511
|
+
handleInput(data) {
|
|
512
|
+
selectList.handleInput(data);
|
|
513
|
+
},
|
|
514
|
+
};
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
// ---------------------------------------------------------------------------
|
|
518
|
+
// Command registration
|
|
519
|
+
// ---------------------------------------------------------------------------
|
|
520
|
+
export function setupSettingsCommand(pi) {
|
|
521
|
+
pi.registerCommand("flow:settings", {
|
|
522
|
+
description: "Manage flow settings. Subcommands: steering <on|off>, strategic-hint <on|off>, animation <on|off>, glitch <on|off>, tool-optimize <on|off>, structured-output <on|off>, session-mode <mode>, max-concurrency <n>, ask-user {enabled <on|off> | timeout <seconds>}, reset. Call with no args for interactive TUI.",
|
|
523
|
+
handler: async (args, ctx) => {
|
|
524
|
+
const cwd = ctx.cwd;
|
|
525
|
+
const trimmed = args.trim().toLowerCase();
|
|
526
|
+
const parts = trimmed.split(/\s+/);
|
|
527
|
+
const sub = parts[0] ?? "";
|
|
528
|
+
const value = parts[1] ?? "";
|
|
529
|
+
if (!sub) {
|
|
530
|
+
const settings = loadFlowSettings(cwd);
|
|
531
|
+
_modelRegistry = ctx.modelRegistry;
|
|
532
|
+
await ctx.ui.custom((tui, theme, keybindings, done) => {
|
|
533
|
+
_theme = theme;
|
|
534
|
+
_keybindings = keybindings;
|
|
535
|
+
let currentCategory = "main";
|
|
536
|
+
let container = new Container();
|
|
537
|
+
let activeList = null;
|
|
538
|
+
function rebuild() {
|
|
539
|
+
container = new Container();
|
|
540
|
+
activeList = null;
|
|
541
|
+
// Header
|
|
542
|
+
container.addChild(new DynamicBorder());
|
|
543
|
+
container.addChild(new Text(theme.fg("accent", theme.bold("Flow Settings")), 1, 0));
|
|
544
|
+
container.addChild(new Spacer(1));
|
|
545
|
+
const currentSettings = loadFlowSettings(cwd);
|
|
546
|
+
if (currentCategory === "main") {
|
|
547
|
+
const items = getMainMenuItems(currentSettings, cwd);
|
|
548
|
+
const selectList = new SelectList(items, Math.min(items.length, 10), {
|
|
549
|
+
selectedPrefix: (t) => theme.fg("accent", t),
|
|
550
|
+
selectedText: (t) => theme.fg("accent", t),
|
|
551
|
+
description: (t) => theme.fg("muted", t),
|
|
552
|
+
scrollInfo: (t) => theme.fg("dim", t),
|
|
553
|
+
noMatch: (t) => theme.fg("warning", t),
|
|
554
|
+
});
|
|
555
|
+
selectList.onSelect = (item) => {
|
|
556
|
+
if (item.value === "reset") {
|
|
557
|
+
writeFlowSetting(cwd, "", {});
|
|
558
|
+
configureSteering({ enabled: true, customPrompt: undefined });
|
|
559
|
+
configureStrategicHint(true);
|
|
560
|
+
scrambleManager.setAnimationConfig({ enabled: true, glitch: true });
|
|
561
|
+
ctx.ui.notify?.("Flow settings reset to defaults", "info");
|
|
562
|
+
rebuild();
|
|
563
|
+
tui.requestRender();
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
currentCategory = item.value;
|
|
567
|
+
rebuild();
|
|
568
|
+
tui.requestRender();
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
selectList.onCancel = () => {
|
|
572
|
+
done(loadFlowSettings(cwd));
|
|
573
|
+
};
|
|
574
|
+
activeList = selectList;
|
|
575
|
+
container.addChild(selectList);
|
|
576
|
+
const tooltipText = new Text("", 1, 0);
|
|
577
|
+
selectList.onSelectionChange = (item) => {
|
|
578
|
+
tooltipText.setText(theme.fg("dim", item.tooltip ?? ""));
|
|
579
|
+
};
|
|
580
|
+
const initialItem = selectList.getSelectedItem();
|
|
581
|
+
if (initialItem) {
|
|
582
|
+
tooltipText.setText(theme.fg("dim", initialItem.tooltip ?? ""));
|
|
583
|
+
}
|
|
584
|
+
container.addChild(new Spacer(1));
|
|
585
|
+
container.addChild(tooltipText);
|
|
586
|
+
container.addChild(new Spacer(1));
|
|
587
|
+
container.addChild(new Text(theme.fg("dim", "▲▼ navigate • Enter/Space select • Esc back"), 1, 0));
|
|
588
|
+
container.addChild(new DynamicBorder());
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
let items;
|
|
592
|
+
let handleChange;
|
|
593
|
+
const backCategory = "main";
|
|
594
|
+
if (currentCategory === "steering") {
|
|
595
|
+
items = getSteeringItems(currentSettings);
|
|
596
|
+
handleChange = (id, value) => {
|
|
597
|
+
if (id === "steering.enabled") {
|
|
598
|
+
const boolValue = value === "on";
|
|
599
|
+
writeFlowSetting(cwd, "steering.enabled", boolValue);
|
|
600
|
+
configureSteering({
|
|
601
|
+
enabled: boolValue,
|
|
602
|
+
customPrompt: currentSettings.steering?.customPrompt,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
else if (id === "steering.strategicHint") {
|
|
606
|
+
const boolValue = value === "on";
|
|
607
|
+
writeFlowSetting(cwd, "steering.strategicHint", boolValue);
|
|
608
|
+
configureStrategicHint(boolValue);
|
|
609
|
+
}
|
|
610
|
+
else if (id === "steering.customPrompt") {
|
|
611
|
+
if (value === "(default)") {
|
|
612
|
+
writeFlowSetting(cwd, "steering.customPrompt", undefined);
|
|
613
|
+
configureSteering({
|
|
614
|
+
enabled: currentSettings.steering?.enabled ?? true,
|
|
615
|
+
customPrompt: undefined,
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
writeFlowSetting(cwd, "steering.customPrompt", value);
|
|
620
|
+
configureSteering({
|
|
621
|
+
enabled: currentSettings.steering?.enabled ?? true,
|
|
622
|
+
customPrompt: value,
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
rebuild();
|
|
627
|
+
tui.requestRender();
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
else if (currentCategory === "animation") {
|
|
631
|
+
items = getAnimationItems(currentSettings);
|
|
632
|
+
handleChange = (id, value) => {
|
|
633
|
+
if (id === "animation.enabled") {
|
|
634
|
+
const boolValue = value === "on";
|
|
635
|
+
writeFlowSetting(cwd, "animation.enabled", boolValue);
|
|
636
|
+
scrambleManager.setAnimationConfig({
|
|
637
|
+
enabled: boolValue,
|
|
638
|
+
glitch: currentSettings.animation?.glitch ?? true,
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
else if (id === "animation.glitch") {
|
|
642
|
+
const boolValue = value === "on";
|
|
643
|
+
writeFlowSetting(cwd, "animation.glitch", boolValue);
|
|
644
|
+
scrambleManager.setAnimationConfig({
|
|
645
|
+
enabled: currentSettings.animation?.enabled ?? true,
|
|
646
|
+
glitch: boolValue,
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
rebuild();
|
|
650
|
+
tui.requestRender();
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
else if (currentCategory === "tools") {
|
|
654
|
+
items = getToolItems(currentSettings);
|
|
655
|
+
handleChange = (id, value) => {
|
|
656
|
+
if (id === "toolOptimize") {
|
|
657
|
+
writeFlowSetting(cwd, "toolOptimize", value === "on");
|
|
658
|
+
}
|
|
659
|
+
else if (id === "structuredOutput") {
|
|
660
|
+
writeFlowSetting(cwd, "structuredOutput", value === "on");
|
|
661
|
+
}
|
|
662
|
+
rebuild();
|
|
663
|
+
tui.requestRender();
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
else if (currentCategory === "session") {
|
|
667
|
+
items = getSessionItems(currentSettings);
|
|
668
|
+
handleChange = (id, value) => {
|
|
669
|
+
if (id === "sessionMode") {
|
|
670
|
+
writeFlowSetting(cwd, "sessionMode", value);
|
|
671
|
+
}
|
|
672
|
+
else if (id === "maxConcurrency") {
|
|
673
|
+
writeFlowSetting(cwd, "maxConcurrency", Number(value));
|
|
674
|
+
}
|
|
675
|
+
rebuild();
|
|
676
|
+
tui.requestRender();
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
else if (currentCategory === "ask-user") {
|
|
680
|
+
items = getAskUserItems(currentSettings);
|
|
681
|
+
handleChange = (id, value) => {
|
|
682
|
+
if (id === "askUser.enabled") {
|
|
683
|
+
writeFlowSetting(cwd, "askUser.enabled", value === "on");
|
|
684
|
+
}
|
|
685
|
+
else if (id === "askUser.timeout") {
|
|
686
|
+
writeFlowSetting(cwd, "askUser.timeout", Number(value));
|
|
687
|
+
}
|
|
688
|
+
rebuild();
|
|
689
|
+
tui.requestRender();
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
else if (currentCategory === "model-config") {
|
|
693
|
+
items = getModelConfigItems(currentSettings, cwd);
|
|
694
|
+
handleChange = (id, value) => {
|
|
695
|
+
if (id === "modelConfig.strategy") {
|
|
696
|
+
try {
|
|
697
|
+
writeGlobalFlowMode(value);
|
|
698
|
+
}
|
|
699
|
+
catch (e) {
|
|
700
|
+
/* ignore */
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
else if (id.startsWith("modelConfig.")) {
|
|
704
|
+
const match = id.match(/^modelConfig\.(lite|flash|full)\.(primary|failover)$/);
|
|
705
|
+
if (match) {
|
|
706
|
+
const tier = match[1];
|
|
707
|
+
const slot = match[2];
|
|
708
|
+
const loaded = loadFlowModelConfigs(cwd);
|
|
709
|
+
const strategyName = loaded.selectedName;
|
|
710
|
+
if (slot === "primary") {
|
|
711
|
+
if (value === "(default)") {
|
|
712
|
+
writeFlowModelConfig(cwd, strategyName, tier, { primary: null, failover: null });
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
writeFlowModelConfig(cwd, strategyName, tier, { primary: value });
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
if (value === "(default)") {
|
|
720
|
+
writeFlowModelConfig(cwd, strategyName, tier, { failover: [] });
|
|
721
|
+
}
|
|
722
|
+
else {
|
|
723
|
+
writeFlowModelConfig(cwd, strategyName, tier, { failover: [value] });
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
rebuild();
|
|
729
|
+
tui.requestRender();
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
else if (currentCategory === "loop") {
|
|
733
|
+
items = getLoopItems(currentSettings, cwd);
|
|
734
|
+
handleChange = () => { };
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
items = [];
|
|
738
|
+
handleChange = () => { };
|
|
739
|
+
}
|
|
740
|
+
const settingsTheme = {
|
|
741
|
+
label: (text, selected) => selected ? theme.fg("accent", theme.bold(text)) : theme.fg("text", text),
|
|
742
|
+
value: (text, selected) => selected ? theme.fg("accent", text) : theme.fg("muted", text),
|
|
743
|
+
description: (text) => theme.fg("muted", text),
|
|
744
|
+
cursor: theme.fg("accent", "▶ "),
|
|
745
|
+
hint: (text) => theme.fg("dim", text),
|
|
746
|
+
};
|
|
747
|
+
const settingsList = new SettingsList(items, Math.min(items.length + 2, 15), settingsTheme, keybindings, handleChange, () => {
|
|
748
|
+
currentCategory = backCategory;
|
|
749
|
+
rebuild();
|
|
750
|
+
tui.requestRender();
|
|
751
|
+
});
|
|
752
|
+
activeList = settingsList;
|
|
753
|
+
container.addChild(settingsList);
|
|
754
|
+
container.addChild(new DynamicBorder());
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
rebuild();
|
|
758
|
+
return {
|
|
759
|
+
render(width) {
|
|
760
|
+
return container.render(width);
|
|
761
|
+
},
|
|
762
|
+
invalidate() {
|
|
763
|
+
container.invalidate();
|
|
764
|
+
},
|
|
765
|
+
handleInput(data) {
|
|
766
|
+
if (activeList?.handleInput) {
|
|
767
|
+
activeList.handleInput(data);
|
|
768
|
+
}
|
|
769
|
+
tui.requestRender();
|
|
770
|
+
},
|
|
771
|
+
};
|
|
772
|
+
});
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
// -----------------------------------------------------------------
|
|
776
|
+
// Text-based fallback for subcommands with arguments
|
|
777
|
+
// -----------------------------------------------------------------
|
|
778
|
+
const parseOnOff = (v) => {
|
|
779
|
+
if (v === "on" || v === "true" || v === "1")
|
|
780
|
+
return true;
|
|
781
|
+
if (v === "off" || v === "false" || v === "0")
|
|
782
|
+
return false;
|
|
783
|
+
return null;
|
|
784
|
+
};
|
|
785
|
+
switch (sub) {
|
|
786
|
+
case "steering": {
|
|
787
|
+
const parsed = parseOnOff(value);
|
|
788
|
+
if (parsed === null) {
|
|
789
|
+
ctx.ui.notify?.("Usage: /flow:settings steering <on|off>", "error");
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
writeFlowSetting(cwd, "steering.enabled", parsed);
|
|
793
|
+
configureSteering({ enabled: parsed, customPrompt: undefined });
|
|
794
|
+
ctx.ui.notify?.(`steering.enabled = ${parsed}`, "info");
|
|
795
|
+
break;
|
|
796
|
+
}
|
|
797
|
+
case "strategic-hint": {
|
|
798
|
+
const parsed = parseOnOff(value);
|
|
799
|
+
if (parsed === null) {
|
|
800
|
+
ctx.ui.notify?.("Usage: /flow:settings strategic-hint <on|off>", "error");
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
writeFlowSetting(cwd, "steering.strategicHint", parsed);
|
|
804
|
+
configureStrategicHint(parsed);
|
|
805
|
+
ctx.ui.notify?.(`steering.strategicHint = ${parsed}`, "info");
|
|
806
|
+
break;
|
|
807
|
+
}
|
|
808
|
+
case "animation": {
|
|
809
|
+
const parsed = parseOnOff(value);
|
|
810
|
+
if (parsed === null) {
|
|
811
|
+
ctx.ui.notify?.("Usage: /flow:settings animation <on|off>", "error");
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
writeFlowSetting(cwd, "animation.enabled", parsed);
|
|
815
|
+
scrambleManager.setAnimationConfig({ enabled: parsed, glitch: true });
|
|
816
|
+
ctx.ui.notify?.(`animation.enabled = ${parsed}`, "info");
|
|
817
|
+
break;
|
|
818
|
+
}
|
|
819
|
+
case "glitch": {
|
|
820
|
+
const parsed = parseOnOff(value);
|
|
821
|
+
if (parsed === null) {
|
|
822
|
+
ctx.ui.notify?.("Usage: /flow:settings glitch <on|off>", "error");
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
writeFlowSetting(cwd, "animation.glitch", parsed);
|
|
826
|
+
scrambleManager.setAnimationConfig({ enabled: true, glitch: parsed });
|
|
827
|
+
ctx.ui.notify?.(`animation.glitch = ${parsed}`, "info");
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
case "tool-optimize": {
|
|
831
|
+
const parsed = parseOnOff(value);
|
|
832
|
+
if (parsed === null) {
|
|
833
|
+
ctx.ui.notify?.("Usage: /flow:settings tool-optimize <on|off>", "error");
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
writeFlowSetting(cwd, "toolOptimize", parsed);
|
|
837
|
+
ctx.ui.notify?.(`toolOptimize = ${parsed}`, "info");
|
|
838
|
+
break;
|
|
839
|
+
}
|
|
840
|
+
case "structured-output": {
|
|
841
|
+
const parsed = parseOnOff(value);
|
|
842
|
+
if (parsed === null) {
|
|
843
|
+
ctx.ui.notify?.("Usage: /flow:settings structured-output <on|off>", "error");
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
writeFlowSetting(cwd, "structuredOutput", parsed);
|
|
847
|
+
ctx.ui.notify?.(`structuredOutput = ${parsed}`, "info");
|
|
848
|
+
break;
|
|
849
|
+
}
|
|
850
|
+
case "session-mode": {
|
|
851
|
+
const validModes = ["snap", "fast", "default", "long", "extreme_long"];
|
|
852
|
+
if (!validModes.includes(value)) {
|
|
853
|
+
ctx.ui.notify?.("Usage: /flow:settings session-mode <snap|fast|default|long|extreme_long>", "error");
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
writeFlowSetting(cwd, "sessionMode", value);
|
|
857
|
+
ctx.ui.notify?.(`sessionMode = ${value}`, "info");
|
|
858
|
+
break;
|
|
859
|
+
}
|
|
860
|
+
case "max-concurrency": {
|
|
861
|
+
const n = Number(value);
|
|
862
|
+
if (!Number.isSafeInteger(n) || n < 1) {
|
|
863
|
+
ctx.ui.notify?.("Usage: /flow:settings max-concurrency <n>", "error");
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
writeFlowSetting(cwd, "maxConcurrency", n);
|
|
867
|
+
ctx.ui.notify?.(`maxConcurrency = ${n}`, "info");
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
case "ask-user": {
|
|
871
|
+
const askParts = trimmed.split(/\s+/);
|
|
872
|
+
const askSub = askParts[1] ?? "";
|
|
873
|
+
const askValue = askParts[2] ?? "";
|
|
874
|
+
if (askSub === "enabled") {
|
|
875
|
+
const parsed = parseOnOff(askValue);
|
|
876
|
+
if (parsed === null) {
|
|
877
|
+
ctx.ui.notify?.("Usage: /flow:settings ask-user enabled <on|off>", "error");
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
writeFlowSetting(cwd, "askUser.enabled", parsed);
|
|
881
|
+
ctx.ui.notify?.(`askUser.enabled = ${parsed}`, "info");
|
|
882
|
+
}
|
|
883
|
+
else if (askSub === "timeout") {
|
|
884
|
+
const n = Number(askValue);
|
|
885
|
+
if (!Number.isSafeInteger(n) || n < 10) {
|
|
886
|
+
ctx.ui.notify?.("Usage: /flow:settings ask-user timeout <seconds>", "error");
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
writeFlowSetting(cwd, "askUser.timeout", n);
|
|
890
|
+
ctx.ui.notify?.(`askUser.timeout = ${n}`, "info");
|
|
891
|
+
}
|
|
892
|
+
else {
|
|
893
|
+
ctx.ui.notify?.("Usage: /flow:settings ask-user {enabled <on|off> | timeout <seconds>}", "error");
|
|
894
|
+
}
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
case "reset": {
|
|
898
|
+
writeFlowSetting(cwd, "", {});
|
|
899
|
+
ctx.ui.notify?.("Flow settings reset to defaults", "info");
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
902
|
+
case "show": {
|
|
903
|
+
const currentSettings = loadFlowSettings(cwd);
|
|
904
|
+
const loop = getLoop(cwd);
|
|
905
|
+
const lines = [
|
|
906
|
+
`toolOptimize: ${currentSettings.toolOptimize ?? true}`,
|
|
907
|
+
`structuredOutput: ${currentSettings.structuredOutput ?? true}`,
|
|
908
|
+
`sessionMode: ${currentSettings.sessionMode ?? "default"}`,
|
|
909
|
+
`maxConcurrency: ${currentSettings.maxConcurrency ?? 4}`,
|
|
910
|
+
`steering.enabled: ${currentSettings.steering?.enabled ?? true}`,
|
|
911
|
+
`steering.strategicHint: ${currentSettings.steering?.strategicHint ?? true}`,
|
|
912
|
+
`animation.enabled: ${currentSettings.animation?.enabled ?? true}`,
|
|
913
|
+
`animation.glitch: ${currentSettings.animation?.glitch ?? true}`,
|
|
914
|
+
`askUser.enabled: ${currentSettings.askUser?.enabled ?? false}`,
|
|
915
|
+
`askUser.timeout: ${currentSettings.askUser?.timeout ?? 300}`,
|
|
916
|
+
];
|
|
917
|
+
if (loop) {
|
|
918
|
+
lines.push("");
|
|
919
|
+
lines.push(`loop.status: ${loop.status}`);
|
|
920
|
+
lines.push(`loop.objective: ${loop.objective}`);
|
|
921
|
+
lines.push(`loop.sessions: ${loop.sessionCount}`);
|
|
922
|
+
lines.push(`loop.flows: ${loop.totalFlowsAcrossSessions}`);
|
|
923
|
+
lines.push(`loop.tokens: ${loop.totalTokensAcrossSessions}`);
|
|
924
|
+
if (loop.terminationReason)
|
|
925
|
+
lines.push(`loop.terminationReason: ${loop.terminationReason}`);
|
|
926
|
+
}
|
|
927
|
+
ctx.ui.notify?.(lines.join("\n"), "info");
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
default: {
|
|
931
|
+
ctx.ui.notify?.("Unknown subcommand. Usage: /flow:settings {steering|strategic-hint|animation|glitch|tool-optimize|structured-output|session-mode|max-concurrency|ask-user|reset|show}", "error");
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
},
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
//# sourceMappingURL=settings-command.js.map
|