@astralyn/pi 0.85.1 → 0.85.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/cli.js +94 -91
  3. package/dist/core/agent-session.js +2 -2
  4. package/dist/core/agent-session.js.map +1 -1
  5. package/dist/core/background/history.d.ts.map +1 -1
  6. package/dist/core/background/history.js +6 -0
  7. package/dist/core/background/history.js.map +1 -1
  8. package/dist/core/background/presentation.d.ts.map +1 -1
  9. package/dist/core/background/presentation.js +41 -4
  10. package/dist/core/background/presentation.js.map +1 -1
  11. package/dist/core/background/service.d.ts +2 -2
  12. package/dist/core/background/service.d.ts.map +1 -1
  13. package/dist/core/background/service.js +38 -15
  14. package/dist/core/background/service.js.map +1 -1
  15. package/dist/core/background/types.d.ts +9 -0
  16. package/dist/core/background/types.d.ts.map +1 -1
  17. package/dist/core/background/types.js +4 -0
  18. package/dist/core/background/types.js.map +1 -1
  19. package/dist/core/compaction/compaction.d.ts +5 -12
  20. package/dist/core/compaction/compaction.d.ts.map +1 -1
  21. package/dist/core/compaction/compaction.js +11 -19
  22. package/dist/core/compaction/compaction.js.map +1 -1
  23. package/dist/core/compaction/settings.d.ts +27 -0
  24. package/dist/core/compaction/settings.d.ts.map +1 -0
  25. package/dist/core/compaction/settings.js +40 -0
  26. package/dist/core/compaction/settings.js.map +1 -0
  27. package/dist/core/keybindings.d.ts +15 -0
  28. package/dist/core/keybindings.d.ts.map +1 -1
  29. package/dist/core/keybindings.js +12 -0
  30. package/dist/core/keybindings.js.map +1 -1
  31. package/dist/core/model-config.d.ts +32 -10
  32. package/dist/core/model-config.d.ts.map +1 -1
  33. package/dist/core/model-config.js +38 -1
  34. package/dist/core/model-config.js.map +1 -1
  35. package/dist/core/model-runtime.d.ts +2 -0
  36. package/dist/core/model-runtime.d.ts.map +1 -1
  37. package/dist/core/model-runtime.js +4 -0
  38. package/dist/core/model-runtime.js.map +1 -1
  39. package/dist/core/settings-manager.d.ts +4 -7
  40. package/dist/core/settings-manager.d.ts.map +1 -1
  41. package/dist/core/settings-manager.js +7 -6
  42. package/dist/core/settings-manager.js.map +1 -1
  43. package/dist/core/tools/bash.js +1 -1
  44. package/dist/core/tools/bash.js.map +1 -1
  45. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  46. package/dist/core/tools/shell-execution.js +3 -1
  47. package/dist/core/tools/shell-execution.js.map +1 -1
  48. package/dist/extensions/background/manager.d.ts +8 -5
  49. package/dist/extensions/background/manager.d.ts.map +1 -1
  50. package/dist/extensions/background/manager.js +115 -39
  51. package/dist/extensions/background/manager.js.map +1 -1
  52. package/dist/extensions/background/task-view.d.ts +5 -0
  53. package/dist/extensions/background/task-view.d.ts.map +1 -1
  54. package/dist/extensions/background/task-view.js +4 -0
  55. package/dist/extensions/background/task-view.js.map +1 -1
  56. package/dist/extensions/btw/controller.d.ts +1 -1
  57. package/dist/extensions/btw/controller.d.ts.map +1 -1
  58. package/dist/extensions/btw/controller.js +4 -4
  59. package/dist/extensions/btw/controller.js.map +1 -1
  60. package/dist/extensions/btw/index.js +3 -3
  61. package/dist/extensions/btw/index.js.map +1 -1
  62. package/dist/extensions/index.js +2 -2
  63. package/dist/extensions/index.js.map +1 -1
  64. package/dist/extensions/provider/catalog.d.ts +57 -0
  65. package/dist/extensions/provider/catalog.d.ts.map +1 -0
  66. package/dist/extensions/provider/catalog.js +181 -0
  67. package/dist/extensions/provider/catalog.js.map +1 -0
  68. package/dist/extensions/provider/compat-fields.d.ts +25 -0
  69. package/dist/extensions/provider/compat-fields.d.ts.map +1 -0
  70. package/dist/extensions/provider/compat-fields.js +148 -0
  71. package/dist/extensions/provider/compat-fields.js.map +1 -0
  72. package/dist/extensions/provider/configuration.d.ts +8 -0
  73. package/dist/extensions/provider/configuration.d.ts.map +1 -0
  74. package/dist/extensions/provider/configuration.js +21 -0
  75. package/dist/extensions/provider/configuration.js.map +1 -0
  76. package/dist/extensions/provider/connection.d.ts +14 -0
  77. package/dist/extensions/provider/connection.d.ts.map +1 -0
  78. package/dist/extensions/provider/connection.js +86 -0
  79. package/dist/extensions/provider/connection.js.map +1 -0
  80. package/dist/extensions/provider/constants.d.ts +38 -0
  81. package/dist/extensions/provider/constants.d.ts.map +1 -0
  82. package/dist/extensions/provider/constants.js +75 -0
  83. package/dist/extensions/provider/constants.js.map +1 -0
  84. package/dist/extensions/provider/index.d.ts +4 -0
  85. package/dist/extensions/provider/index.d.ts.map +1 -0
  86. package/dist/extensions/provider/index.js +65 -0
  87. package/dist/extensions/provider/index.js.map +1 -0
  88. package/dist/extensions/provider/probe.d.ts +34 -0
  89. package/dist/extensions/provider/probe.d.ts.map +1 -0
  90. package/dist/extensions/provider/probe.js +178 -0
  91. package/dist/extensions/provider/probe.js.map +1 -0
  92. package/dist/extensions/provider/refresh.d.ts +30 -0
  93. package/dist/extensions/provider/refresh.d.ts.map +1 -0
  94. package/dist/extensions/provider/refresh.js +66 -0
  95. package/dist/extensions/provider/refresh.js.map +1 -0
  96. package/dist/extensions/provider/store.d.ts +131 -0
  97. package/dist/extensions/provider/store.d.ts.map +1 -0
  98. package/dist/extensions/provider/store.js +503 -0
  99. package/dist/extensions/provider/store.js.map +1 -0
  100. package/dist/extensions/provider/ui/app.d.ts +25 -0
  101. package/dist/extensions/provider/ui/app.d.ts.map +1 -0
  102. package/dist/extensions/provider/ui/app.js +153 -0
  103. package/dist/extensions/provider/ui/app.js.map +1 -0
  104. package/dist/extensions/provider/ui/builtin-data.d.ts +53 -0
  105. package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -0
  106. package/dist/extensions/provider/ui/builtin-data.js +315 -0
  107. package/dist/extensions/provider/ui/builtin-data.js.map +1 -0
  108. package/dist/extensions/provider/ui/compat.d.ts +57 -0
  109. package/dist/extensions/provider/ui/compat.d.ts.map +1 -0
  110. package/dist/extensions/provider/ui/compat.js +427 -0
  111. package/dist/extensions/provider/ui/compat.js.map +1 -0
  112. package/dist/extensions/provider/ui/dialogs.d.ts +30 -0
  113. package/dist/extensions/provider/ui/dialogs.d.ts.map +1 -0
  114. package/dist/extensions/provider/ui/dialogs.js +89 -0
  115. package/dist/extensions/provider/ui/dialogs.js.map +1 -0
  116. package/dist/extensions/provider/ui/dictionary.d.ts +29 -0
  117. package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -0
  118. package/dist/extensions/provider/ui/dictionary.js +385 -0
  119. package/dist/extensions/provider/ui/dictionary.js.map +1 -0
  120. package/dist/extensions/provider/ui/editor.d.ts +91 -0
  121. package/dist/extensions/provider/ui/editor.d.ts.map +1 -0
  122. package/dist/extensions/provider/ui/editor.js +667 -0
  123. package/dist/extensions/provider/ui/editor.js.map +1 -0
  124. package/dist/extensions/provider/ui/fetch-models.d.ts +39 -0
  125. package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -0
  126. package/dist/extensions/provider/ui/fetch-models.js +320 -0
  127. package/dist/extensions/provider/ui/fetch-models.js.map +1 -0
  128. package/dist/extensions/provider/ui/model-fields.d.ts +43 -0
  129. package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -0
  130. package/dist/extensions/provider/ui/model-fields.js +441 -0
  131. package/dist/extensions/provider/ui/model-fields.js.map +1 -0
  132. package/dist/extensions/provider/ui/model-options.d.ts +93 -0
  133. package/dist/extensions/provider/ui/model-options.d.ts.map +1 -0
  134. package/dist/extensions/provider/ui/model-options.js +529 -0
  135. package/dist/extensions/provider/ui/model-options.js.map +1 -0
  136. package/dist/extensions/provider/ui/pane.d.ts +81 -0
  137. package/dist/extensions/provider/ui/pane.d.ts.map +1 -0
  138. package/dist/extensions/provider/ui/pane.js +3 -0
  139. package/dist/extensions/provider/ui/pane.js.map +1 -0
  140. package/dist/extensions/provider/ui/provider-fields.d.ts +60 -0
  141. package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -0
  142. package/dist/extensions/provider/ui/provider-fields.js +326 -0
  143. package/dist/extensions/provider/ui/provider-fields.js.map +1 -0
  144. package/dist/extensions/provider/ui/provider-list.d.ts +34 -0
  145. package/dist/extensions/provider/ui/provider-list.d.ts.map +1 -0
  146. package/dist/extensions/provider/ui/provider-list.js +162 -0
  147. package/dist/extensions/provider/ui/provider-list.js.map +1 -0
  148. package/dist/extensions/provider/ui/session.d.ts +20 -0
  149. package/dist/extensions/provider/ui/session.d.ts.map +1 -0
  150. package/dist/extensions/provider/ui/session.js +52 -0
  151. package/dist/extensions/provider/ui/session.js.map +1 -0
  152. package/dist/extensions/provider/ui/thinking-map.d.ts +20 -0
  153. package/dist/extensions/provider/ui/thinking-map.d.ts.map +1 -0
  154. package/dist/extensions/provider/ui/thinking-map.js +166 -0
  155. package/dist/extensions/provider/ui/thinking-map.js.map +1 -0
  156. package/dist/extensions/provider/ui/value-row.d.ts +88 -0
  157. package/dist/extensions/provider/ui/value-row.d.ts.map +1 -0
  158. package/dist/extensions/provider/ui/value-row.js +158 -0
  159. package/dist/extensions/provider/ui/value-row.js.map +1 -0
  160. package/dist/extensions/statusline/index.js +2 -2
  161. package/dist/extensions/statusline/index.js.map +1 -1
  162. package/dist/extensions/subagent/index.d.ts.map +1 -1
  163. package/dist/extensions/subagent/index.js +4 -2
  164. package/dist/extensions/subagent/index.js.map +1 -1
  165. package/dist/extensions/subagent/resolve.d.ts +5 -0
  166. package/dist/extensions/subagent/resolve.d.ts.map +1 -1
  167. package/dist/extensions/subagent/resolve.js +15 -7
  168. package/dist/extensions/subagent/resolve.js.map +1 -1
  169. package/dist/extensions/subagent/schema.d.ts +2 -0
  170. package/dist/extensions/subagent/schema.d.ts.map +1 -1
  171. package/dist/extensions/subagent/schema.js +1 -0
  172. package/dist/extensions/subagent/schema.js.map +1 -1
  173. package/dist/modes/interactive/components/tool-execution.d.ts +10 -0
  174. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  175. package/dist/modes/interactive/components/tool-execution.js +20 -2
  176. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  177. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  178. package/dist/modes/interactive/interactive-mode.js +6 -1
  179. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  180. package/dist/rpc-entry.js +94 -91
  181. package/docs/bundled/README.md +1 -1
  182. package/docs/bundled/extensions/background.md +5 -5
  183. package/docs/bundled/extensions/provider.md +117 -0
  184. package/docs/bundled/extensions/statusline.md +1 -1
  185. package/docs/bundled/extensions/subagent.md +7 -3
  186. package/docs/compaction.md +16 -6
  187. package/docs/docs.json +2 -2
  188. package/docs/keybindings.md +3 -0
  189. package/docs/settings.md +11 -7
  190. package/npm-shrinkwrap.json +2 -2
  191. package/package.json +1 -1
  192. package/dist/extensions/router/constants.d.ts +0 -23
  193. package/dist/extensions/router/constants.d.ts.map +0 -1
  194. package/dist/extensions/router/constants.js +0 -30
  195. package/dist/extensions/router/constants.js.map +0 -1
  196. package/dist/extensions/router/dialog-host.d.ts +0 -60
  197. package/dist/extensions/router/dialog-host.d.ts.map +0 -1
  198. package/dist/extensions/router/dialog-host.js +0 -196
  199. package/dist/extensions/router/dialog-host.js.map +0 -1
  200. package/dist/extensions/router/dialog.d.ts +0 -45
  201. package/dist/extensions/router/dialog.d.ts.map +0 -1
  202. package/dist/extensions/router/dialog.js +0 -378
  203. package/dist/extensions/router/dialog.js.map +0 -1
  204. package/dist/extensions/router/identity.d.ts +0 -15
  205. package/dist/extensions/router/identity.d.ts.map +0 -1
  206. package/dist/extensions/router/identity.js +0 -173
  207. package/dist/extensions/router/identity.js.map +0 -1
  208. package/dist/extensions/router/index.d.ts +0 -15
  209. package/dist/extensions/router/index.d.ts.map +0 -1
  210. package/dist/extensions/router/index.js +0 -70
  211. package/dist/extensions/router/index.js.map +0 -1
  212. package/dist/extensions/router/presets.d.ts +0 -51
  213. package/dist/extensions/router/presets.d.ts.map +0 -1
  214. package/dist/extensions/router/presets.js +0 -108
  215. package/dist/extensions/router/presets.js.map +0 -1
  216. package/dist/extensions/router/probe.d.ts +0 -26
  217. package/dist/extensions/router/probe.d.ts.map +0 -1
  218. package/dist/extensions/router/probe.js +0 -216
  219. package/dist/extensions/router/probe.js.map +0 -1
  220. package/dist/extensions/router/register.d.ts +0 -12
  221. package/dist/extensions/router/register.d.ts.map +0 -1
  222. package/dist/extensions/router/register.js +0 -90
  223. package/dist/extensions/router/register.js.map +0 -1
  224. package/dist/extensions/router/state.d.ts +0 -20
  225. package/dist/extensions/router/state.d.ts.map +0 -1
  226. package/dist/extensions/router/state.js +0 -169
  227. package/dist/extensions/router/state.js.map +0 -1
  228. package/dist/extensions/router/store.d.ts +0 -12
  229. package/dist/extensions/router/store.d.ts.map +0 -1
  230. package/dist/extensions/router/store.js +0 -266
  231. package/dist/extensions/router/store.js.map +0 -1
  232. package/dist/extensions/router/stream.d.ts +0 -12
  233. package/dist/extensions/router/stream.d.ts.map +0 -1
  234. package/dist/extensions/router/stream.js +0 -233
  235. package/dist/extensions/router/stream.js.map +0 -1
  236. package/dist/extensions/router/transport.d.ts +0 -9
  237. package/dist/extensions/router/transport.d.ts.map +0 -1
  238. package/dist/extensions/router/transport.js +0 -81
  239. package/dist/extensions/router/transport.js.map +0 -1
  240. package/dist/extensions/router/types.d.ts +0 -39
  241. package/dist/extensions/router/types.d.ts.map +0 -1
  242. package/dist/extensions/router/types.js +0 -2
  243. package/dist/extensions/router/types.js.map +0 -1
  244. package/dist/extensions/router/ui.d.ts +0 -26
  245. package/dist/extensions/router/ui.d.ts.map +0 -1
  246. package/dist/extensions/router/ui.js +0 -897
  247. package/dist/extensions/router/ui.js.map +0 -1
  248. package/docs/bundled/extensions/router.md +0 -197
@@ -1,196 +0,0 @@
1
- /** Extension-owned dialog host that keeps every /router TUI page in one modal lifecycle. */
2
- import { Container, isFocusable, Spacer, Text } from "@earendil-works/pi-tui";
3
- import { DynamicBorder } from "../../modes/interactive/components/dynamic-border.js";
4
- import { ExtensionInputComponent } from "../../modes/interactive/components/extension-input.js";
5
- import { ExtensionSelectorComponent } from "../../modes/interactive/components/extension-selector.js";
6
- import { keyLabel } from "../../modes/interactive/components/keybinding-hints.js";
7
- export class RouterTuiSessionClosedError extends Error {
8
- constructor() {
9
- super("Router TUI session is closed.");
10
- this.name = "RouterTuiSessionClosedError";
11
- }
12
- }
13
- export function createNativeRouterDialogs(ctx) {
14
- return {
15
- kind: "native",
16
- select: (title, options) => ctx.ui.select(title, options),
17
- input: (title, placeholder) => ctx.ui.input(title, placeholder),
18
- confirm: (title, message) => ctx.ui.confirm(title, message),
19
- };
20
- }
21
- /**
22
- * Persistent root mounted by one ctx.ui.custom() call. Child dialogs resolve
23
- * without closing this root, so async flow continuations can replace them
24
- * without exposing the main editor between pages.
25
- */
26
- export class RouterTuiSession extends Container {
27
- constructor(tui, theme, keybindings, onTransitionClose) {
28
- super();
29
- this.kind = "tui";
30
- this.acceptsInput = false;
31
- this.closeRequested = false;
32
- this.disposed = false;
33
- this._focused = false;
34
- this.tui = tui;
35
- this.theme = theme;
36
- this.keybindings = keybindings;
37
- this.onTransitionClose = onTransitionClose;
38
- const loading = new Container();
39
- loading.addChild(new DynamicBorder((text) => theme.fg("border", text)));
40
- loading.addChild(new Spacer(1));
41
- loading.addChild(new Text(theme.fg("muted", "Loading router…"), 1, 0));
42
- loading.addChild(new Spacer(1));
43
- loading.addChild(new DynamicBorder((text) => theme.fg("border", text)));
44
- this.activeScreen = loading;
45
- this.addChild(loading);
46
- }
47
- get focused() {
48
- return this._focused;
49
- }
50
- set focused(value) {
51
- this._focused = value;
52
- if (this.activeScreen && isFocusable(this.activeScreen)) {
53
- this.activeScreen.focused = value && this.acceptsInput;
54
- }
55
- }
56
- show(factory) {
57
- this.clearTransitionTimer();
58
- if (this.disposed || this.closeRequested)
59
- return Promise.reject(new RouterTuiSessionClosedError());
60
- if (this.pendingReject)
61
- return Promise.reject(new Error("Router TUI session already has an active dialog."));
62
- return new Promise((resolve, reject) => {
63
- let settled = false;
64
- const fail = (error) => {
65
- if (settled || this.disposed)
66
- return;
67
- settled = true;
68
- this.acceptsInput = false;
69
- if (this.pendingReject === reject)
70
- this.pendingReject = undefined;
71
- reject(error instanceof Error ? error : new Error(String(error)));
72
- };
73
- const done = (result) => {
74
- if (settled || this.disposed)
75
- return;
76
- settled = true;
77
- this.acceptsInput = false;
78
- if (this.activeScreen && isFocusable(this.activeScreen))
79
- this.activeScreen.focused = false;
80
- if (this.pendingReject === reject)
81
- this.pendingReject = undefined;
82
- this.tui.setFocus(this);
83
- this.beginTransition();
84
- resolve(result);
85
- };
86
- this.pendingReject = reject;
87
- let pending;
88
- try {
89
- pending = factory(this.tui, this.theme, this.keybindings, done);
90
- }
91
- catch (error) {
92
- fail(error);
93
- return;
94
- }
95
- void Promise.resolve(pending).then((component) => {
96
- if (settled || this.disposed) {
97
- this.disposeScreen(component);
98
- return;
99
- }
100
- try {
101
- this.setActiveScreen(component);
102
- }
103
- catch (error) {
104
- this.disposeScreen(component);
105
- fail(error);
106
- }
107
- }, fail);
108
- });
109
- }
110
- input(title, placeholder) {
111
- return this.show((tui, _theme, _keybindings, done) => new ExtensionInputComponent(title, placeholder, done, () => done(undefined), { tui }));
112
- }
113
- async confirm(title, message) {
114
- const selected = await this.show((tui, _theme, _keybindings, done) => new ExtensionSelectorComponent(title, ["Yes", "No"], done, () => done(undefined), {
115
- tui,
116
- subtitle: message,
117
- }));
118
- return selected === "Yes";
119
- }
120
- handleInput(data) {
121
- if (this.acceptsInput) {
122
- this.activeScreen?.handleInput?.(data);
123
- return;
124
- }
125
- if (this.closeRequested || !this.keybindings.matches(data, "tui.select.cancel"))
126
- return;
127
- this.closeRequested = true;
128
- this.onTransitionClose();
129
- }
130
- dispose() {
131
- if (this.disposed)
132
- return;
133
- this.disposed = true;
134
- this.acceptsInput = false;
135
- this.clearTransitionTimer();
136
- const reject = this.pendingReject;
137
- this.pendingReject = undefined;
138
- this.disposeActiveScreen();
139
- this.clear();
140
- reject?.(new RouterTuiSessionClosedError());
141
- }
142
- beginTransition() {
143
- this.clearTransitionTimer();
144
- this.transitionTimer = setTimeout(() => {
145
- this.transitionTimer = undefined;
146
- if (this.disposed || this.closeRequested || this.acceptsInput)
147
- return;
148
- const working = new Container();
149
- working.addChild(new DynamicBorder((text) => this.theme.fg("border", text)));
150
- working.addChild(new Spacer(1));
151
- const cancelKey = keyLabel("tui.select.cancel", { keybindings: this.keybindings });
152
- const closeHint = cancelKey ? `${cancelKey} closes /router` : "Close /router to continue";
153
- working.addChild(new Text(this.theme.fg("muted", `Working… ${closeHint}`), 1, 0));
154
- working.addChild(new Spacer(1));
155
- working.addChild(new DynamicBorder((text) => this.theme.fg("border", text)));
156
- this.disposeActiveScreen();
157
- this.clear();
158
- this.activeScreen = working;
159
- this.addChild(working);
160
- this.tui.requestRender();
161
- }, 150);
162
- }
163
- clearTransitionTimer() {
164
- if (this.transitionTimer === undefined)
165
- return;
166
- clearTimeout(this.transitionTimer);
167
- this.transitionTimer = undefined;
168
- }
169
- setActiveScreen(component) {
170
- this.disposeActiveScreen();
171
- this.clear();
172
- this.activeScreen = component;
173
- this.addChild(component);
174
- this.acceptsInput = true;
175
- this.tui.setFocus(component);
176
- this.tui.requestRender();
177
- }
178
- disposeActiveScreen() {
179
- const screen = this.activeScreen;
180
- this.activeScreen = undefined;
181
- if (screen)
182
- this.disposeScreen(screen);
183
- }
184
- disposeScreen(screen) {
185
- const dispose = screen.dispose;
186
- if (isFocusable(screen))
187
- screen.focused = false;
188
- try {
189
- dispose?.call(screen);
190
- }
191
- catch {
192
- // A child cleanup failure must not strand the outer custom lifecycle.
193
- }
194
- }
195
- }
196
- //# sourceMappingURL=dialog-host.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dialog-host.js","sourceRoot":"","sources":["../../../src/extensions/router/dialog-host.ts"],"names":[],"mappings":"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","sourcesContent":["/** Extension-owned dialog host that keeps every /router TUI page in one modal lifecycle. */\n\nimport { type Component, Container, type Focusable, isFocusable, Spacer, Text, type TUI } from \"@earendil-works/pi-tui\";\nimport type { ExtensionCommandContext } from \"../../core/extensions/types.ts\";\nimport type { KeybindingsManager } from \"../../core/keybindings.ts\";\nimport { DynamicBorder } from \"../../modes/interactive/components/dynamic-border.ts\";\nimport { ExtensionInputComponent } from \"../../modes/interactive/components/extension-input.ts\";\nimport { ExtensionSelectorComponent } from \"../../modes/interactive/components/extension-selector.ts\";\nimport { keyLabel } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\n\nexport type RouterComponent = Component & { dispose?(): void };\n\nexport type RouterComponentFactory<T> = (\n\ttui: TUI,\n\ttheme: Theme,\n\tkeybindings: KeybindingsManager,\n\tdone: (result: T) => void,\n) => RouterComponent | Promise<RouterComponent>;\n\ninterface RouterDialogBase {\n\tinput(title: string, placeholder?: string): Promise<string | undefined>;\n\tconfirm(title: string, message: string): Promise<boolean>;\n}\n\nexport interface RouterNativeDialogs extends RouterDialogBase {\n\treadonly kind: \"native\";\n\tselect(title: string, options: string[]): Promise<string | undefined>;\n}\n\nexport interface RouterTuiDialogs extends RouterDialogBase {\n\treadonly kind: \"tui\";\n\tshow<T>(factory: RouterComponentFactory<T>): Promise<T>;\n}\n\nexport type RouterDialogs = RouterNativeDialogs | RouterTuiDialogs;\n\nexport class RouterTuiSessionClosedError extends Error {\n\tconstructor() {\n\t\tsuper(\"Router TUI session is closed.\");\n\t\tthis.name = \"RouterTuiSessionClosedError\";\n\t}\n}\n\nexport function createNativeRouterDialogs(ctx: ExtensionCommandContext): RouterNativeDialogs {\n\treturn {\n\t\tkind: \"native\",\n\t\tselect: (title, options) => ctx.ui.select(title, options),\n\t\tinput: (title, placeholder) => ctx.ui.input(title, placeholder),\n\t\tconfirm: (title, message) => ctx.ui.confirm(title, message),\n\t};\n}\n\n/**\n * Persistent root mounted by one ctx.ui.custom() call. Child dialogs resolve\n * without closing this root, so async flow continuations can replace them\n * without exposing the main editor between pages.\n */\nexport class RouterTuiSession extends Container implements Focusable, RouterTuiDialogs {\n\treadonly kind = \"tui\" as const;\n\n\tprivate readonly tui: TUI;\n\tprivate readonly theme: Theme;\n\tprivate readonly keybindings: KeybindingsManager;\n\tprivate readonly onTransitionClose: () => void;\n\tprivate activeScreen: RouterComponent | undefined;\n\tprivate pendingReject: ((error: Error) => void) | undefined;\n\tprivate transitionTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate acceptsInput = false;\n\tprivate closeRequested = false;\n\tprivate disposed = false;\n\tprivate _focused = false;\n\n\tconstructor(tui: TUI, theme: Theme, keybindings: KeybindingsManager, onTransitionClose: () => void) {\n\t\tsuper();\n\t\tthis.tui = tui;\n\t\tthis.theme = theme;\n\t\tthis.keybindings = keybindings;\n\t\tthis.onTransitionClose = onTransitionClose;\n\n\t\tconst loading = new Container();\n\t\tloading.addChild(new DynamicBorder((text) => theme.fg(\"border\", text)));\n\t\tloading.addChild(new Spacer(1));\n\t\tloading.addChild(new Text(theme.fg(\"muted\", \"Loading router…\"), 1, 0));\n\t\tloading.addChild(new Spacer(1));\n\t\tloading.addChild(new DynamicBorder((text) => theme.fg(\"border\", text)));\n\t\tthis.activeScreen = loading;\n\t\tthis.addChild(loading);\n\t}\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tif (this.activeScreen && isFocusable(this.activeScreen)) {\n\t\t\tthis.activeScreen.focused = value && this.acceptsInput;\n\t\t}\n\t}\n\n\tshow<T>(factory: RouterComponentFactory<T>): Promise<T> {\n\t\tthis.clearTransitionTimer();\n\t\tif (this.disposed || this.closeRequested) return Promise.reject(new RouterTuiSessionClosedError());\n\t\tif (this.pendingReject) return Promise.reject(new Error(\"Router TUI session already has an active dialog.\"));\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tlet settled = false;\n\t\t\tconst fail = (error: unknown) => {\n\t\t\t\tif (settled || this.disposed) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.acceptsInput = false;\n\t\t\t\tif (this.pendingReject === reject) this.pendingReject = undefined;\n\t\t\t\treject(error instanceof Error ? error : new Error(String(error)));\n\t\t\t};\n\t\t\tconst done = (result: T) => {\n\t\t\t\tif (settled || this.disposed) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.acceptsInput = false;\n\t\t\t\tif (this.activeScreen && isFocusable(this.activeScreen)) this.activeScreen.focused = false;\n\t\t\t\tif (this.pendingReject === reject) this.pendingReject = undefined;\n\t\t\t\tthis.tui.setFocus(this);\n\t\t\t\tthis.beginTransition();\n\t\t\t\tresolve(result);\n\t\t\t};\n\t\t\tthis.pendingReject = reject;\n\t\t\tlet pending: RouterComponent | Promise<RouterComponent>;\n\t\t\ttry {\n\t\t\t\tpending = factory(this.tui, this.theme, this.keybindings, done);\n\t\t\t} catch (error) {\n\t\t\t\tfail(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvoid Promise.resolve(pending).then((component) => {\n\t\t\t\tif (settled || this.disposed) {\n\t\t\t\t\tthis.disposeScreen(component);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tthis.setActiveScreen(component);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.disposeScreen(component);\n\t\t\t\t\tfail(error);\n\t\t\t\t}\n\t\t\t}, fail);\n\t\t});\n\t}\n\n\tinput(title: string, placeholder?: string): Promise<string | undefined> {\n\t\treturn this.show<string | undefined>(\n\t\t\t(tui, _theme, _keybindings, done) =>\n\t\t\t\tnew ExtensionInputComponent(title, placeholder, done, () => done(undefined), { tui }),\n\t\t);\n\t}\n\n\tasync confirm(title: string, message: string): Promise<boolean> {\n\t\tconst selected = await this.show<string | undefined>(\n\t\t\t(tui, _theme, _keybindings, done) =>\n\t\t\t\tnew ExtensionSelectorComponent(title, [\"Yes\", \"No\"], done, () => done(undefined), {\n\t\t\t\t\ttui,\n\t\t\t\t\tsubtitle: message,\n\t\t\t\t}),\n\t\t);\n\t\treturn selected === \"Yes\";\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (this.acceptsInput) {\n\t\t\tthis.activeScreen?.handleInput?.(data);\n\t\t\treturn;\n\t\t}\n\t\tif (this.closeRequested || !this.keybindings.matches(data, \"tui.select.cancel\")) return;\n\t\tthis.closeRequested = true;\n\t\tthis.onTransitionClose();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.acceptsInput = false;\n\t\tthis.clearTransitionTimer();\n\t\tconst reject = this.pendingReject;\n\t\tthis.pendingReject = undefined;\n\t\tthis.disposeActiveScreen();\n\t\tthis.clear();\n\t\treject?.(new RouterTuiSessionClosedError());\n\t}\n\n\tprivate beginTransition(): void {\n\t\tthis.clearTransitionTimer();\n\t\tthis.transitionTimer = setTimeout(() => {\n\t\t\tthis.transitionTimer = undefined;\n\t\t\tif (this.disposed || this.closeRequested || this.acceptsInput) return;\n\t\t\tconst working = new Container();\n\t\t\tworking.addChild(new DynamicBorder((text) => this.theme.fg(\"border\", text)));\n\t\t\tworking.addChild(new Spacer(1));\n\t\t\tconst cancelKey = keyLabel(\"tui.select.cancel\", { keybindings: this.keybindings });\n\t\t\tconst closeHint = cancelKey ? `${cancelKey} closes /router` : \"Close /router to continue\";\n\t\t\tworking.addChild(new Text(this.theme.fg(\"muted\", `Working… ${closeHint}`), 1, 0));\n\t\t\tworking.addChild(new Spacer(1));\n\t\t\tworking.addChild(new DynamicBorder((text) => this.theme.fg(\"border\", text)));\n\t\t\tthis.disposeActiveScreen();\n\t\t\tthis.clear();\n\t\t\tthis.activeScreen = working;\n\t\t\tthis.addChild(working);\n\t\t\tthis.tui.requestRender();\n\t\t}, 150);\n\t}\n\n\tprivate clearTransitionTimer(): void {\n\t\tif (this.transitionTimer === undefined) return;\n\t\tclearTimeout(this.transitionTimer);\n\t\tthis.transitionTimer = undefined;\n\t}\n\n\tprivate setActiveScreen(component: RouterComponent): void {\n\t\tthis.disposeActiveScreen();\n\t\tthis.clear();\n\t\tthis.activeScreen = component;\n\t\tthis.addChild(component);\n\t\tthis.acceptsInput = true;\n\t\tthis.tui.setFocus(component);\n\t\tthis.tui.requestRender();\n\t}\n\n\tprivate disposeActiveScreen(): void {\n\t\tconst screen = this.activeScreen;\n\t\tthis.activeScreen = undefined;\n\t\tif (screen) this.disposeScreen(screen);\n\t}\n\n\tprivate disposeScreen(screen: RouterComponent): void {\n\t\tconst dispose = screen.dispose;\n\t\tif (isFocusable(screen)) screen.focused = false;\n\t\ttry {\n\t\t\tdispose?.call(screen);\n\t\t} catch {\n\t\t\t// A child cleanup failure must not strand the outer custom lifecycle.\n\t\t}\n\t}\n}\n"]}
@@ -1,45 +0,0 @@
1
- /** Private TUI primitives for /router. */
2
- import { Container, type KeybindingsManager, type TUI } from "@earendil-works/pi-tui";
3
- import type { Theme } from "../../modes/interactive/theme/theme.ts";
4
- import { type ThinkingLevel } from "./constants.ts";
5
- import type { ThinkingLevelMap } from "./types.ts";
6
- export interface SelectItem<T extends string = string> {
7
- value: T;
8
- label: string;
9
- description?: string;
10
- searchText?: string;
11
- }
12
- export declare function createSearchableSelector<T extends string>(opts: {
13
- title: string;
14
- subtitle?: string;
15
- items: ReadonlyArray<SelectItem<T>>;
16
- initialValue?: T;
17
- initialQuery?: string;
18
- maxVisible?: number;
19
- emptyMessage?: string;
20
- }): (tui: TUI, theme: Theme, keybindings: KeybindingsManager, done: (result: T | undefined) => void) => Container;
21
- export interface ModelChecklistItem {
22
- id: string;
23
- name?: string;
24
- unavailable?: boolean;
25
- }
26
- export declare function createModelChecklist(opts: {
27
- title: string;
28
- subtitle?: string;
29
- models: ReadonlyArray<ModelChecklistItem>;
30
- initiallySelected?: ReadonlySet<string>;
31
- /** Models that must remain selected while the checklist is open. */
32
- protectedIds?: ReadonlySet<string>;
33
- onChange?: (selectedIds: string[]) => void;
34
- onProtectedToggle?: (id: string) => void;
35
- }): (tui: TUI, theme: Theme, keybindings: KeybindingsManager, done: (result: {
36
- kind: "close";
37
- selectedIds: string[];
38
- }) => void) => Container;
39
- export declare function createThinkingMapEditor(opts: {
40
- title: string;
41
- map: ThinkingLevelMap;
42
- levels?: ReadonlyArray<ThinkingLevel>;
43
- onChange?: (map: ThinkingLevelMap) => void;
44
- }): (tui: TUI, theme: Theme, keybindings: KeybindingsManager, done: (result: ThinkingLevelMap | undefined) => void) => Container;
45
- //# sourceMappingURL=dialog.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/dialog.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAE1C,OAAO,EACN,SAAS,EAGT,KAAK,kBAAkB,EAIvB,KAAK,GAAG,EACR,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AACpE,OAAO,EAA0B,KAAK,aAAa,EAAY,MAAM,gBAAgB,CAAC;AAEtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACpD,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,YAAY,CAAC,EAAE,CAAC,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,KAAK,SAAS,CAsHhH;AAED,MAAM,WAAW,kBAAkB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;IAC1C,iBAAiB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACxC,oEAAoE;IACpE,YAAY,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC3C,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC,GAAG,CACH,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,kBAAkB,EAC/B,IAAI,EAAE,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,KAAK,IAAI,KAC5D,SAAS,CA8Jb;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,gBAAgB,CAAC;IACtB,MAAM,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC3C,GAAG,CACH,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,kBAAkB,EAC/B,IAAI,EAAE,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,KAAK,IAAI,KAChD,SAAS,CAiHb"}
@@ -1,378 +0,0 @@
1
- /** Private TUI primitives for /router. */
2
- import { Container, fuzzyFilter, Input, Spacer, Text, TruncatedText, } from "@earendil-works/pi-tui";
3
- import { DynamicBorder } from "../../modes/interactive/components/dynamic-border.js";
4
- import { keyHint, rawKeyHint } from "../../modes/interactive/components/keybinding-hints.js";
5
- import { ROUTER_THINKING_LEVELS, truncate } from "./constants.js";
6
- import { resolveRouterThinkingMap } from "./presets.js";
7
- export function createSearchableSelector(opts) {
8
- return (tui, theme, keybindings, done) => {
9
- const allItems = [...opts.items];
10
- let filteredItems = allItems;
11
- let selectedIndex = Math.max(0, allItems.findIndex((item) => item.value === opts.initialValue));
12
- const maxVisible = Math.max(1, opts.maxVisible ?? 10);
13
- const input = new Input();
14
- if (opts.initialQuery)
15
- input.setValue(opts.initialQuery);
16
- const list = new Container();
17
- const footer = new Text("", 1, 0);
18
- const container = new Container();
19
- const refresh = () => {
20
- list.clear();
21
- const start = Math.max(0, Math.min(selectedIndex - Math.floor(maxVisible / 2), Math.max(0, filteredItems.length - maxVisible)));
22
- const end = Math.min(start + maxVisible, filteredItems.length);
23
- for (let index = start; index < end; index++) {
24
- const item = filteredItems[index];
25
- if (!item)
26
- continue;
27
- const active = index === selectedIndex;
28
- const prefix = active ? theme.fg("accent", "→ ") : " ";
29
- const label = theme.fg(active ? "accent" : "text", item.label);
30
- const description = item.description ? theme.fg("muted", ` ${truncate(item.description, 48)}`) : "";
31
- list.addChild(new TruncatedText(prefix + label + description, 1, 0));
32
- }
33
- if (filteredItems.length === 0) {
34
- list.addChild(new Text(theme.fg("muted", ` ${opts.emptyMessage ?? "No matching items"}`), 1, 0));
35
- }
36
- else if (start > 0 || end < filteredItems.length) {
37
- list.addChild(new Text(theme.fg("muted", ` (${selectedIndex + 1}/${filteredItems.length})`), 1, 0));
38
- }
39
- const hints = [
40
- rawKeyHint("type", "filter"),
41
- rawKeyHint("↑↓", "navigate"),
42
- keyHint("tui.select.confirm", "select"),
43
- keyHint("tui.select.cancel", "back"),
44
- ];
45
- footer.setText(hints.join(" "));
46
- container.invalidate();
47
- tui.requestRender();
48
- };
49
- const applyFilter = (query, preferred) => {
50
- filteredItems = query
51
- ? fuzzyFilter(allItems, query, (item) => item.searchText ?? `${item.label} ${item.description ?? ""} ${item.value}`)
52
- : allItems;
53
- const preferredIndex = preferred ? filteredItems.findIndex((item) => item.value === preferred) : -1;
54
- selectedIndex = preferredIndex >= 0 ? preferredIndex : 0;
55
- refresh();
56
- };
57
- container.addChild(new DynamicBorder((text) => theme.fg("border", text)));
58
- container.addChild(new Spacer(1));
59
- container.addChild(new TruncatedText(theme.fg("accent", theme.bold(opts.title)), 1, 0));
60
- if (opts.subtitle)
61
- container.addChild(new TruncatedText(theme.fg("muted", opts.subtitle), 1, 0));
62
- container.addChild(new Spacer(1));
63
- // Keep the search row mounted even when empty, matching /model and
64
- // preventing the list from jumping when the first character is typed.
65
- container.addChild(input);
66
- container.addChild(new Spacer(1));
67
- container.addChild(list);
68
- container.addChild(new Spacer(1));
69
- container.addChild(footer);
70
- container.addChild(new Spacer(1));
71
- container.addChild(new DynamicBorder((text) => theme.fg("border", text)));
72
- Object.defineProperty(container, "focused", {
73
- get: () => input.focused,
74
- set: (focused) => {
75
- input.focused = focused;
76
- },
77
- });
78
- container.handleInput = (data) => {
79
- if (keybindings.matches(data, "tui.select.up")) {
80
- if (filteredItems.length > 0) {
81
- selectedIndex = selectedIndex === 0 ? filteredItems.length - 1 : selectedIndex - 1;
82
- refresh();
83
- }
84
- return;
85
- }
86
- if (keybindings.matches(data, "tui.select.down")) {
87
- if (filteredItems.length > 0) {
88
- selectedIndex = selectedIndex === filteredItems.length - 1 ? 0 : selectedIndex + 1;
89
- refresh();
90
- }
91
- return;
92
- }
93
- if (keybindings.matches(data, "tui.select.confirm")) {
94
- const item = filteredItems[selectedIndex];
95
- if (item)
96
- done(item.value);
97
- return;
98
- }
99
- if (keybindings.matches(data, "tui.select.cancel")) {
100
- done(undefined);
101
- return;
102
- }
103
- const before = input.getValue();
104
- input.handleInput(data);
105
- const after = input.getValue();
106
- if (after !== before)
107
- applyFilter(after);
108
- };
109
- applyFilter(opts.initialQuery ?? "", opts.initialValue);
110
- return container;
111
- };
112
- }
113
- export function createModelChecklist(opts) {
114
- return (tui, theme, keybindings, done) => {
115
- const items = opts.models.map((model) => ({
116
- id: model.id,
117
- label: model.name && model.name !== model.id ? `${model.id} · ${model.name}` : model.id,
118
- unavailable: model.unavailable ?? false,
119
- protected: opts.protectedIds?.has(model.id) ?? false,
120
- searchText: `${model.id} ${model.name ?? ""} ${model.unavailable ? "not returned unavailable" : ""}`,
121
- }));
122
- const selected = new Set(opts.initiallySelected ?? []);
123
- let filter = "";
124
- let selectedIndex = 0;
125
- const maxVisible = 10;
126
- const input = new Input();
127
- const list = new Container();
128
- const footer = new Text("", 1, 0);
129
- const container = new Container();
130
- const filtered = () => {
131
- const query = filter.trim();
132
- return query ? fuzzyFilter(items, query, (item) => item.searchText) : items;
133
- };
134
- const notifyChange = () => opts.onChange?.([...selected]);
135
- const selectionChanged = (before) => before.size !== selected.size || [...before].some((id) => !selected.has(id));
136
- const refresh = () => {
137
- const rows = filtered();
138
- if (selectedIndex >= rows.length)
139
- selectedIndex = Math.max(0, rows.length - 1);
140
- list.clear();
141
- const start = Math.max(0, Math.min(selectedIndex - Math.floor(maxVisible / 2), Math.max(0, rows.length - maxVisible)));
142
- const end = Math.min(start + maxVisible, rows.length);
143
- for (let index = start; index < end; index++) {
144
- const item = rows[index];
145
- const active = index === selectedIndex;
146
- const mark = selected.has(item.id) ? theme.fg("success", "[x]") : theme.fg("muted", "[ ]");
147
- const prefix = active ? theme.fg("accent", "→ ") : " ";
148
- const label = theme.fg(active ? "accent" : "text", item.label);
149
- const availability = item.unavailable ? theme.fg("warning", " (not returned)") : "";
150
- const current = item.protected ? theme.fg("success", " (current)") : "";
151
- list.addChild(new TruncatedText(`${prefix}${mark} ${label}${availability}${current}`, 1, 0));
152
- }
153
- if (rows.length === 0) {
154
- list.addChild(new Text(theme.fg("muted", " No matching models"), 1, 0));
155
- }
156
- else if (start > 0 || end < rows.length) {
157
- list.addChild(new Text(theme.fg("muted", ` (${selectedIndex + 1}/${rows.length})`), 1, 0));
158
- }
159
- const statusLine = theme.fg("muted", `${selected.size} selected · ${rows.length} shown`);
160
- const hints = [
161
- keyHint("app.list.toggle", "toggle"),
162
- keyHint("app.models.enableAll", "all"),
163
- keyHint("app.models.clearAll", "none"),
164
- rawKeyHint("type", "filter"),
165
- keyHint("tui.select.confirm", "done"),
166
- keyHint("tui.select.cancel", "back"),
167
- ];
168
- footer.setText(`${statusLine}\n${hints.join(" ")}`);
169
- container.invalidate();
170
- tui.requestRender();
171
- };
172
- container.addChild(new DynamicBorder((text) => theme.fg("border", text)));
173
- container.addChild(new Spacer(1));
174
- container.addChild(new TruncatedText(theme.fg("accent", theme.bold(opts.title)), 1, 0));
175
- if (opts.subtitle)
176
- container.addChild(new TruncatedText(theme.fg("muted", opts.subtitle), 1, 0));
177
- container.addChild(new Spacer(1));
178
- container.addChild(input);
179
- container.addChild(new Spacer(1));
180
- container.addChild(list);
181
- container.addChild(new Spacer(1));
182
- container.addChild(footer);
183
- container.addChild(new Spacer(1));
184
- container.addChild(new DynamicBorder((text) => theme.fg("border", text)));
185
- Object.defineProperty(container, "focused", {
186
- get: () => input.focused,
187
- set: (focused) => {
188
- input.focused = focused;
189
- },
190
- });
191
- container.handleInput = (data) => {
192
- const rows = filtered();
193
- if (keybindings.matches(data, "app.list.toggle")) {
194
- const item = rows[selectedIndex];
195
- if (item) {
196
- if (item.protected) {
197
- opts.onProtectedToggle?.(item.id);
198
- return;
199
- }
200
- if (selected.has(item.id))
201
- selected.delete(item.id);
202
- else
203
- selected.add(item.id);
204
- notifyChange();
205
- refresh();
206
- }
207
- return;
208
- }
209
- if (keybindings.matches(data, "app.models.enableAll")) {
210
- const before = new Set(selected);
211
- for (const item of rows)
212
- selected.add(item.id);
213
- if (selectionChanged(before))
214
- notifyChange();
215
- refresh();
216
- return;
217
- }
218
- if (keybindings.matches(data, "app.models.clearAll")) {
219
- const before = new Set(selected);
220
- let protectedId;
221
- for (const item of rows) {
222
- if (item.protected) {
223
- protectedId ??= item.id;
224
- continue;
225
- }
226
- selected.delete(item.id);
227
- }
228
- if (protectedId)
229
- opts.onProtectedToggle?.(protectedId);
230
- if (selectionChanged(before))
231
- notifyChange();
232
- refresh();
233
- return;
234
- }
235
- if (keybindings.matches(data, "tui.select.up")) {
236
- if (rows.length > 0) {
237
- selectedIndex = selectedIndex === 0 ? rows.length - 1 : selectedIndex - 1;
238
- refresh();
239
- }
240
- return;
241
- }
242
- if (keybindings.matches(data, "tui.select.down")) {
243
- if (rows.length > 0) {
244
- selectedIndex = selectedIndex === rows.length - 1 ? 0 : selectedIndex + 1;
245
- refresh();
246
- }
247
- return;
248
- }
249
- if (keybindings.matches(data, "tui.select.confirm") || keybindings.matches(data, "tui.select.cancel")) {
250
- done({ kind: "close", selectedIds: [...selected] });
251
- return;
252
- }
253
- const before = input.getValue();
254
- input.handleInput(data);
255
- const after = input.getValue();
256
- if (after !== before) {
257
- filter = after;
258
- selectedIndex = 0;
259
- refresh();
260
- }
261
- };
262
- refresh();
263
- return container;
264
- };
265
- }
266
- export function createThinkingMapEditor(opts) {
267
- return (tui, theme, keybindings, done) => {
268
- const levels = [...(opts.levels ?? ROUTER_THINKING_LEVELS)];
269
- const working = resolveRouterThinkingMap(opts.map);
270
- let index = 0;
271
- let mode = "levels";
272
- let choice = 0;
273
- const input = new Input();
274
- const container = new Container();
275
- let focused = false;
276
- const refresh = () => {
277
- container.clear();
278
- container.addChild(new DynamicBorder((text) => theme.fg("border", text)));
279
- container.addChild(new Text(theme.fg("accent", opts.title), 1, 1));
280
- if (mode === "levels") {
281
- for (const [i, level] of levels.entries()) {
282
- const value = working[level];
283
- const status = value === undefined ? "Inherit" : value === null ? "Hidden" : `→ ${value}`;
284
- container.addChild(new TruncatedText(theme.fg(i === index ? "accent" : "text", `${i === index ? "→" : " "} ${level} · ${status}`), 1, 0));
285
- }
286
- }
287
- else if (mode === "choice") {
288
- container.addChild(new Text(theme.fg("muted", `${levels[index]} · mapping`), 1, 0));
289
- for (const [i, label] of [
290
- "Inherit (Pi default)",
291
- "String target (provider effort)",
292
- "Hidden (null)",
293
- ].entries()) {
294
- container.addChild(new Text(theme.fg(i === choice ? "accent" : "text", `${i === choice ? "→" : " "} ${label}`), 1, 0));
295
- }
296
- }
297
- else {
298
- container.addChild(new Text(theme.fg("muted", `${levels[index]} · non-empty provider effort`), 1, 0));
299
- container.addChild(input);
300
- }
301
- input.focused = focused && mode === "target";
302
- container.addChild(new Text(`${keyHint("tui.select.confirm", mode === "target" ? "save" : "edit")} ${keyHint("tui.select.cancel", "back")}`, 1, 1));
303
- container.addChild(new DynamicBorder((text) => theme.fg("border", text)));
304
- container.invalidate();
305
- tui.requestRender();
306
- };
307
- const save = (value) => {
308
- const level = levels[index];
309
- if (value === undefined)
310
- delete working[level];
311
- else
312
- working[level] = value;
313
- opts.onChange?.({ ...working });
314
- mode = "levels";
315
- refresh();
316
- };
317
- Object.defineProperty(container, "focused", {
318
- get: () => focused,
319
- set: (value) => {
320
- focused = value;
321
- input.focused = value && mode === "target";
322
- },
323
- });
324
- container.handleInput = (data) => {
325
- if (keybindings.matches(data, "tui.select.cancel")) {
326
- if (mode === "levels")
327
- done(undefined);
328
- else {
329
- mode = mode === "target" ? "choice" : "levels";
330
- refresh();
331
- }
332
- return;
333
- }
334
- if (keybindings.matches(data, "tui.select.confirm")) {
335
- if (mode === "levels") {
336
- mode = "choice";
337
- choice = 0;
338
- }
339
- else if (mode === "choice") {
340
- if (choice === 0)
341
- return save(undefined);
342
- if (choice === 2)
343
- return save(null);
344
- mode = "target";
345
- input.setValue(working[levels[index]] ?? "");
346
- }
347
- else {
348
- const value = input.getValue().trim();
349
- if (value)
350
- save(value);
351
- return;
352
- }
353
- refresh();
354
- return;
355
- }
356
- if (mode === "target") {
357
- input.handleInput(data);
358
- tui.requestRender();
359
- return;
360
- }
361
- const delta = keybindings.matches(data, "tui.select.up")
362
- ? -1
363
- : keybindings.matches(data, "tui.select.down")
364
- ? 1
365
- : 0;
366
- if (delta) {
367
- if (mode === "levels")
368
- index = (index + delta + levels.length) % levels.length;
369
- else
370
- choice = (choice + delta + 3) % 3;
371
- refresh();
372
- }
373
- };
374
- refresh();
375
- return container;
376
- };
377
- }
378
- //# sourceMappingURL=dialog.js.map