@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
@@ -0,0 +1,89 @@
1
+ /** Confirmation and information panes owned by the provider editor. */
2
+ import { truncateToWidth } from "@earendil-works/pi-tui";
3
+ import { keyHint } from "../../../modes/interactive/components/keybinding-hints.js";
4
+ import { CURSOR, renderInfoLine, renderPlainLine } from "./value-row.js";
5
+ /** Static dim text lines (e.g. action-row explanations); optionally Enter-activatable. */
6
+ export class InfoPane {
7
+ constructor(host, lines, onConfirm) {
8
+ this.focused = false;
9
+ this.host = host;
10
+ this.lines = lines;
11
+ this.onConfirm = onConfirm;
12
+ }
13
+ render(width) {
14
+ // A confirmable InfoPane carries the pane's single focus marker; pure
15
+ // guard text offers no action, so it stays an unmarked hint.
16
+ if (this.focused && this.onConfirm) {
17
+ return this.lines.map((line, index) => {
18
+ if (index > 0)
19
+ return renderInfoLine(this.host.theme, line, width);
20
+ return truncateToWidth(this.host.theme.fg("accent", `${CURSOR} `) + this.host.theme.fg("text", line), width);
21
+ });
22
+ }
23
+ return this.lines.map((line) => renderInfoLine(this.host.theme, line, width));
24
+ }
25
+ handleInput(data) {
26
+ if (this.host.keybindings.matches(data, "tui.select.cancel")) {
27
+ this.host.popPane();
28
+ return;
29
+ }
30
+ // A focused InfoPane stands in for its left-column action row.
31
+ if (this.onConfirm && this.host.keybindings.matches(data, "tui.select.confirm"))
32
+ this.onConfirm();
33
+ }
34
+ setFocused(focused) {
35
+ this.focused = focused;
36
+ }
37
+ hints() {
38
+ const hints = [];
39
+ if (this.onConfirm)
40
+ hints.push(keyHint("tui.select.confirm", "proceed"));
41
+ hints.push(keyHint("tui.select.cancel", "back"));
42
+ return hints.join(" ");
43
+ }
44
+ }
45
+ /** Yes/No confirm for destructive actions, pushed into the right column. */
46
+ export class ConfirmPane {
47
+ constructor(host, message, actionLabel, action) {
48
+ this.crumb = "Confirm";
49
+ this.index = 1; // default to Cancel
50
+ this.focused = false;
51
+ this.host = host;
52
+ this.message = message;
53
+ this.actionLabel = actionLabel;
54
+ this.action = action;
55
+ }
56
+ render(width) {
57
+ const theme = this.host.theme;
58
+ return [
59
+ truncateToWidth(theme.fg("warning", this.message), width),
60
+ renderPlainLine(theme, this.actionLabel, { active: this.index === 0, paneFocused: this.focused, width }),
61
+ renderPlainLine(theme, "Cancel", { active: this.index === 1, paneFocused: this.focused, width }),
62
+ ];
63
+ }
64
+ handleInput(data) {
65
+ const kb = this.host.keybindings;
66
+ if (kb.matches(data, "tui.select.up") || kb.matches(data, "tui.select.down")) {
67
+ this.index = this.index === 0 ? 1 : 0;
68
+ this.host.refresh();
69
+ return;
70
+ }
71
+ if (kb.matches(data, "tui.select.cancel")) {
72
+ this.host.popPane();
73
+ return;
74
+ }
75
+ if (kb.matches(data, "tui.select.confirm")) {
76
+ if (this.index === 0)
77
+ this.action();
78
+ else
79
+ this.host.popPane();
80
+ }
81
+ }
82
+ setFocused(focused) {
83
+ this.focused = focused;
84
+ }
85
+ hints() {
86
+ return [keyHint("tui.select.confirm", "choose"), keyHint("tui.select.cancel", "cancel")].join(" ");
87
+ }
88
+ }
89
+ //# sourceMappingURL=dialogs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialogs.js","sourceRoot":"","sources":["../../../../src/extensions/provider/ui/dialogs.ts"],"names":[],"mappings":"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","sourcesContent":["/** Confirmation and information panes owned by the provider editor. */\n\nimport { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.ts\";\nimport type { EditorHost, EditorPane } from \"./pane.ts\";\nimport { CURSOR, renderInfoLine, renderPlainLine } from \"./value-row.ts\";\n\n/** Static dim text lines (e.g. action-row explanations); optionally Enter-activatable. */\nexport class InfoPane implements EditorPane {\n\tprivate readonly lines: string[];\n\tprivate readonly onConfirm: (() => void) | undefined;\n\tprivate focused = false;\n\tprivate readonly host: EditorHost;\n\tconstructor(host: EditorHost, lines: string[], onConfirm?: () => void) {\n\t\tthis.host = host;\n\n\t\tthis.lines = lines;\n\t\tthis.onConfirm = onConfirm;\n\t}\n\trender(width: number): string[] {\n\t\t// A confirmable InfoPane carries the pane's single focus marker; pure\n\t\t// guard text offers no action, so it stays an unmarked hint.\n\t\tif (this.focused && this.onConfirm) {\n\t\t\treturn this.lines.map((line, index) => {\n\t\t\t\tif (index > 0) return renderInfoLine(this.host.theme, line, width);\n\t\t\t\treturn truncateToWidth(\n\t\t\t\t\tthis.host.theme.fg(\"accent\", `${CURSOR} `) + this.host.theme.fg(\"text\", line),\n\t\t\t\t\twidth,\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t\treturn this.lines.map((line) => renderInfoLine(this.host.theme, line, width));\n\t}\n\thandleInput(data: string): void {\n\t\tif (this.host.keybindings.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.host.popPane();\n\t\t\treturn;\n\t\t}\n\t\t// A focused InfoPane stands in for its left-column action row.\n\t\tif (this.onConfirm && this.host.keybindings.matches(data, \"tui.select.confirm\")) this.onConfirm();\n\t}\n\tsetFocused(focused: boolean): void {\n\t\tthis.focused = focused;\n\t}\n\thints(): string {\n\t\tconst hints: string[] = [];\n\t\tif (this.onConfirm) hints.push(keyHint(\"tui.select.confirm\", \"proceed\"));\n\t\thints.push(keyHint(\"tui.select.cancel\", \"back\"));\n\t\treturn hints.join(\" \");\n\t}\n}\n\n/** Yes/No confirm for destructive actions, pushed into the right column. */\nexport class ConfirmPane implements EditorPane {\n\treadonly crumb = \"Confirm\";\n\tprivate index = 1; // default to Cancel\n\tprivate focused = false;\n\n\tprivate readonly host: EditorHost;\n\tprivate readonly message: string;\n\tprivate readonly actionLabel: string;\n\tprivate readonly action: () => void;\n\n\tconstructor(host: EditorHost, message: string, actionLabel: string, action: () => void) {\n\t\tthis.host = host;\n\t\tthis.message = message;\n\t\tthis.actionLabel = actionLabel;\n\t\tthis.action = action;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst theme = this.host.theme;\n\t\treturn [\n\t\t\ttruncateToWidth(theme.fg(\"warning\", this.message), width),\n\t\t\trenderPlainLine(theme, this.actionLabel, { active: this.index === 0, paneFocused: this.focused, width }),\n\t\t\trenderPlainLine(theme, \"Cancel\", { active: this.index === 1, paneFocused: this.focused, width }),\n\t\t];\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = this.host.keybindings;\n\t\tif (kb.matches(data, \"tui.select.up\") || kb.matches(data, \"tui.select.down\")) {\n\t\t\tthis.index = this.index === 0 ? 1 : 0;\n\t\t\tthis.host.refresh();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.host.popPane();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.confirm\")) {\n\t\t\tif (this.index === 0) this.action();\n\t\t\telse this.host.popPane();\n\t\t}\n\t}\n\n\tsetFocused(focused: boolean): void {\n\t\tthis.focused = focused;\n\t}\n\n\thints(): string {\n\t\treturn [keyHint(\"tui.select.confirm\", \"choose\"), keyHint(\"tui.select.cancel\", \"cancel\")].join(\" \");\n\t}\n}\n"]}
@@ -0,0 +1,29 @@
1
+ /** Open chat-template dictionaries, with typed value-entry states. */
2
+ import type { EditorHost, EditorPane, ModelHandle } from "./pane.ts";
3
+ import { type ScrollWindowInfo } from "./value-row.ts";
4
+ export declare class DictPane implements EditorPane {
5
+ readonly crumb: string;
6
+ private index;
7
+ private mode;
8
+ private error;
9
+ private focused;
10
+ private readonly host;
11
+ private readonly model;
12
+ private readonly dictKey;
13
+ constructor(host: EditorHost, model: ModelHandle, dictKey: string);
14
+ private dict;
15
+ private entries;
16
+ render(width: number): string[];
17
+ scrollWindow(): ScrollWindowInfo;
18
+ private renderMode;
19
+ handleInput(data: string): void;
20
+ private handlePick;
21
+ private handleList;
22
+ private startValueForKind;
23
+ private commitScalar;
24
+ private writeEntry;
25
+ setFocused(focused: boolean): void;
26
+ isEditing(): boolean;
27
+ hints(): string;
28
+ }
29
+ //# sourceMappingURL=dictionary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dictionary.d.ts","sourceRoot":"","sources":["../../../../src/extensions/provider/ui/dictionary.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAMtE,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,EAIN,KAAK,gBAAgB,EAErB,MAAM,gBAAgB,CAAC;AA4BxB,qBAAa,QAAS,YAAW,UAAU;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,IAAI,CAA8B;IAC1C,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBACrB,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM;IAQjE,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,OAAO;IAIf,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAmC/B,YAAY,IAAI,gBAAgB;IAOhC,OAAO,CAAC,UAAU;IAmElB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA8C/B,OAAO,CAAC,UAAU;IA0BlB,OAAO,CAAC,UAAU;IA+FlB,OAAO,CAAC,iBAAiB;IAgCzB,OAAO,CAAC,YAAY;IAsBpB,OAAO,CAAC,UAAU;IAUlB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKlC,SAAS,IAAI,OAAO;IAIpB,KAAK,IAAI,MAAM;CAmBf"}
@@ -0,0 +1,385 @@
1
+ /** Open chat-template dictionaries, with typed value-entry states. */
2
+ import { keyHint, rawKeyHint } from "../../../modes/interactive/components/keybinding-hints.js";
3
+ import { THINKING_VARIABLES, validateChatTemplateKwarg } from "../compat-fields.js";
4
+ import { truncate } from "../constants.js";
5
+ import { DELETE } from "../store.js";
6
+ import { renderInfoLine, renderKeyValueLine, renderPlainLine, ValueEditor, } from "./value-row.js";
7
+ function compatObject(handle) {
8
+ const compat = handle.read().compat;
9
+ return typeof compat === "object" && compat !== null && !Array.isArray(compat)
10
+ ? compat
11
+ : {};
12
+ }
13
+ function scalarText(value) {
14
+ if (value === null)
15
+ return "null";
16
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
17
+ return String(value);
18
+ return JSON.stringify(value) ?? String(value);
19
+ }
20
+ const DICT_VALUE_KINDS = ["string", "number", "boolean", "null", "$var"];
21
+ const VAR_OPTIONS = THINKING_VARIABLES;
22
+ export class DictPane {
23
+ constructor(host, model, dictKey) {
24
+ this.index = 0;
25
+ this.mode = { type: "list" };
26
+ this.focused = false;
27
+ this.host = host;
28
+ this.model = model;
29
+ this.dictKey = dictKey;
30
+ this.crumb = `compat · ${dictKey}`;
31
+ }
32
+ dict() {
33
+ const value = compatObject(this.model)[this.dictKey];
34
+ return typeof value === "object" && value !== null && !Array.isArray(value)
35
+ ? value
36
+ : {};
37
+ }
38
+ entries() {
39
+ return Object.entries(this.dict());
40
+ }
41
+ render(width) {
42
+ const theme = this.host.theme;
43
+ const lines = [
44
+ renderInfoLine(theme, `free-form keys; values: string · number · boolean · null · $var`, width),
45
+ ];
46
+ if (this.mode.type !== "list") {
47
+ lines.push(...this.renderMode(width));
48
+ if (this.error)
49
+ lines.push(renderInfoLine(theme, this.error, width));
50
+ return lines;
51
+ }
52
+ const entries = this.entries();
53
+ // All entries render; the editor's fixed window scrolls around scrollWindow().
54
+ for (const [rowIndex, [key, value]] of entries.entries()) {
55
+ const active = rowIndex === this.index;
56
+ lines.push(renderKeyValueLine(theme, {
57
+ keyLabel: key,
58
+ valueText: scalarText(value),
59
+ active,
60
+ paneFocused: this.focused,
61
+ width,
62
+ }));
63
+ }
64
+ lines.push(renderPlainLine(theme, "+ Add Entry", {
65
+ active: this.index === entries.length && this.mode.type === "list",
66
+ paneFocused: this.focused,
67
+ width,
68
+ }));
69
+ if (this.error)
70
+ lines.push(theme.fg("error", truncate(this.error, Math.max(10, width - 2))));
71
+ return lines;
72
+ }
73
+ scrollWindow() {
74
+ // The format header pins above; errors pin below. Entry flows are short
75
+ // enough to fit, so only the list mode reports a meaningful cursor.
76
+ if (this.mode.type !== "list")
77
+ return { top: 1, bottom: this.error ? 1 : 0 };
78
+ return { top: 1, bottom: this.error ? 1 : 0, cursor: 1 + this.index };
79
+ }
80
+ renderMode(width) {
81
+ const theme = this.host.theme;
82
+ const mode = this.mode;
83
+ switch (mode.type) {
84
+ case "keyEdit":
85
+ return [renderInfoLine(theme, "new key:", width), mode.editor.renderLine(width)];
86
+ case "kindPick": {
87
+ return [
88
+ renderInfoLine(theme, `${mode.key} · value kind`, width),
89
+ ...DICT_VALUE_KINDS.map((kind, kindIndex) => renderPlainLine(theme, kind, {
90
+ active: kindIndex === mode.index,
91
+ paneFocused: this.focused,
92
+ width,
93
+ })),
94
+ ];
95
+ }
96
+ case "valueEdit":
97
+ return [
98
+ renderInfoLine(theme, `${mode.key} · ${mode.kind}`, width),
99
+ renderKeyValueLine(theme, {
100
+ keyLabel: mode.key,
101
+ active: true,
102
+ paneFocused: this.focused,
103
+ editing: mode.editor,
104
+ width,
105
+ }),
106
+ ];
107
+ case "boolPick":
108
+ return [
109
+ renderInfoLine(theme, `${mode.key} · boolean`, width),
110
+ ...["true", "false"].map((option, optionIndex) => renderPlainLine(theme, option, {
111
+ active: optionIndex === mode.index,
112
+ paneFocused: this.focused,
113
+ width,
114
+ })),
115
+ ];
116
+ case "varPick":
117
+ return [
118
+ renderInfoLine(theme, `${mode.key} · $var`, width),
119
+ ...VAR_OPTIONS.map((option, optionIndex) => renderPlainLine(theme, option, {
120
+ active: optionIndex === mode.index,
121
+ paneFocused: this.focused,
122
+ width,
123
+ })),
124
+ ];
125
+ case "omitPick":
126
+ return [
127
+ renderInfoLine(theme, `${mode.key} · omitWhenOff`, width),
128
+ ...["default", "true", "false"].map((option, optionIndex) => renderPlainLine(theme, option, {
129
+ active: optionIndex === mode.index,
130
+ paneFocused: this.focused,
131
+ width,
132
+ })),
133
+ ];
134
+ default:
135
+ return [];
136
+ }
137
+ }
138
+ handleInput(data) {
139
+ const kb = this.host.keybindings;
140
+ const mode = this.mode;
141
+ switch (mode.type) {
142
+ case "keyEdit":
143
+ case "valueEdit":
144
+ if (kb.matches(data, "tui.select.up") || kb.matches(data, "tui.select.down"))
145
+ return;
146
+ mode.editor.handleInput(data);
147
+ this.host.refresh();
148
+ return;
149
+ case "kindPick":
150
+ this.handlePick(data, mode, DICT_VALUE_KINDS.length, (index) => {
151
+ const key = mode.key;
152
+ const kind = DICT_VALUE_KINDS[index];
153
+ this.startValueForKind(key, kind);
154
+ });
155
+ return;
156
+ case "boolPick":
157
+ this.handlePick(data, mode, 2, (index) => {
158
+ const key = mode.key;
159
+ this.mode = { type: "list" };
160
+ this.writeEntry(key, index === 0);
161
+ });
162
+ return;
163
+ case "varPick":
164
+ this.handlePick(data, mode, VAR_OPTIONS.length, (index) => {
165
+ const key = mode.key;
166
+ this.mode = { type: "omitPick", key, $var: VAR_OPTIONS[index], index: 0 };
167
+ this.host.refresh();
168
+ });
169
+ return;
170
+ case "omitPick":
171
+ this.handlePick(data, mode, 3, (index) => {
172
+ this.mode = { type: "list" };
173
+ this.writeEntry(mode.key, index === 0 ? { $var: mode.$var } : { $var: mode.$var, omitWhenOff: index === 1 });
174
+ });
175
+ return;
176
+ case "list":
177
+ this.handleList(data);
178
+ return;
179
+ }
180
+ }
181
+ handlePick(data, mode, count, choose) {
182
+ const kb = this.host.keybindings;
183
+ const index = mode.index;
184
+ if (kb.matches(data, "tui.select.up")) {
185
+ mode.index = index === 0 ? count - 1 : index - 1;
186
+ this.host.refresh();
187
+ return;
188
+ }
189
+ if (kb.matches(data, "tui.select.down")) {
190
+ mode.index = (index + 1) % count;
191
+ this.host.refresh();
192
+ return;
193
+ }
194
+ if (kb.matches(data, "tui.select.cancel")) {
195
+ this.mode = { type: "list" };
196
+ this.host.refresh();
197
+ return;
198
+ }
199
+ if (kb.matches(data, "tui.select.confirm"))
200
+ choose(index);
201
+ }
202
+ handleList(data) {
203
+ const kb = this.host.keybindings;
204
+ const rowCount = this.entries().length + 1;
205
+ if (kb.matches(data, "tui.select.up")) {
206
+ this.index = this.index === 0 ? rowCount - 1 : this.index - 1;
207
+ this.host.refresh();
208
+ return;
209
+ }
210
+ if (kb.matches(data, "tui.select.down")) {
211
+ this.index = (this.index + 1) % rowCount;
212
+ this.host.refresh();
213
+ return;
214
+ }
215
+ if (kb.matches(data, "tui.select.cancel")) {
216
+ this.host.popPane();
217
+ return;
218
+ }
219
+ if (kb.matches(data, "app.provider.removeEntry")) {
220
+ const entry = this.entries()[this.index];
221
+ if (!entry)
222
+ return;
223
+ this.host.mutate(() => this.model.setField(["compat", this.dictKey, entry[0]], DELETE));
224
+ this.index = Math.max(0, Math.min(this.index, this.entries().length - 1));
225
+ return;
226
+ }
227
+ if (kb.matches(data, "tui.select.confirm") || kb.matches(data, "app.list.toggle")) {
228
+ const entry = this.entries()[this.index];
229
+ if (!entry) {
230
+ // + Add Entry: key first, then the value flow.
231
+ const editor = new ValueEditor({
232
+ onCommit: (raw) => {
233
+ const key = raw.trim();
234
+ if (!key) {
235
+ this.error = "Key must be non-empty.";
236
+ return this.host.refresh();
237
+ }
238
+ if (Object.hasOwn(this.dict(), key)) {
239
+ this.error = `"${key}" already exists.`;
240
+ return this.host.refresh();
241
+ }
242
+ this.error = undefined;
243
+ this.mode = { type: "kindPick", key, index: 0 };
244
+ this.host.refresh();
245
+ },
246
+ onCancel: () => {
247
+ this.mode = { type: "list" };
248
+ this.error = undefined;
249
+ this.host.refresh();
250
+ },
251
+ });
252
+ editor.focused = this.focused;
253
+ this.mode = { type: "keyEdit", editor };
254
+ this.host.refresh();
255
+ return;
256
+ }
257
+ const [key, value] = entry;
258
+ if (typeof value === "boolean") {
259
+ this.writeEntry(key, !value);
260
+ return;
261
+ }
262
+ if (value === null)
263
+ return; // null entries: remove + re-add to change
264
+ if (typeof value === "object") {
265
+ const record = value;
266
+ if (record.$var === "thinking.enabled" ||
267
+ record.$var === "thinking.effort" ||
268
+ record.$var === "thinking.budget") {
269
+ this.mode = {
270
+ type: "omitPick",
271
+ key,
272
+ $var: record.$var,
273
+ index: record.omitWhenOff === undefined ? 0 : record.omitWhenOff ? 1 : 2,
274
+ };
275
+ this.host.refresh();
276
+ return;
277
+ }
278
+ return; // unexpected object: remove + re-add
279
+ }
280
+ const kind = typeof value === "number" ? "number" : "string";
281
+ const editor = new ValueEditor({
282
+ onCommit: (raw) => this.commitScalar(key, kind, raw),
283
+ onCancel: () => {
284
+ this.mode = { type: "list" };
285
+ this.error = undefined;
286
+ this.host.refresh();
287
+ },
288
+ });
289
+ editor.beginTweak(String(value));
290
+ editor.focused = this.focused;
291
+ this.mode = { type: "valueEdit", key, kind, editor };
292
+ this.host.refresh();
293
+ return;
294
+ }
295
+ }
296
+ startValueForKind(key, kind) {
297
+ switch (kind) {
298
+ case "string":
299
+ case "number": {
300
+ const editor = new ValueEditor({
301
+ onCommit: (raw) => this.commitScalar(key, kind, raw),
302
+ onCancel: () => {
303
+ this.mode = { type: "list" };
304
+ this.error = undefined;
305
+ this.host.refresh();
306
+ },
307
+ });
308
+ editor.focused = this.focused;
309
+ this.mode = { type: "valueEdit", key, kind, editor };
310
+ this.host.refresh();
311
+ return;
312
+ }
313
+ case "boolean":
314
+ this.mode = { type: "boolPick", key, index: 0 };
315
+ this.host.refresh();
316
+ return;
317
+ case "null":
318
+ this.mode = { type: "list" };
319
+ this.writeEntry(key, null);
320
+ return;
321
+ case "$var":
322
+ this.mode = { type: "varPick", key, index: 0 };
323
+ this.host.refresh();
324
+ return;
325
+ }
326
+ }
327
+ commitScalar(key, kind, raw) {
328
+ let value = raw;
329
+ if (kind === "number") {
330
+ const parsed = Number(raw.trim());
331
+ if (!Number.isFinite(parsed)) {
332
+ this.error = `${key} must be a number.`;
333
+ this.host.refresh();
334
+ return;
335
+ }
336
+ value = parsed;
337
+ }
338
+ const invalid = validateChatTemplateKwarg(value);
339
+ if (invalid) {
340
+ this.error = invalid;
341
+ this.host.refresh();
342
+ return;
343
+ }
344
+ this.error = undefined;
345
+ this.mode = { type: "list" };
346
+ this.writeEntry(key, value);
347
+ }
348
+ writeEntry(key, value) {
349
+ const invalid = validateChatTemplateKwarg(value);
350
+ if (invalid) {
351
+ this.error = invalid;
352
+ this.host.refresh();
353
+ return;
354
+ }
355
+ this.host.mutate(() => this.model.setField(["compat", this.dictKey, key], value));
356
+ }
357
+ setFocused(focused) {
358
+ this.focused = focused;
359
+ if (this.mode.type === "keyEdit" || this.mode.type === "valueEdit")
360
+ this.mode.editor.focused = focused;
361
+ }
362
+ isEditing() {
363
+ return this.mode.type === "keyEdit" || this.mode.type === "valueEdit";
364
+ }
365
+ hints() {
366
+ switch (this.mode.type) {
367
+ case "keyEdit":
368
+ case "valueEdit":
369
+ return [keyHint("tui.input.submit", "save"), keyHint("tui.select.cancel", "cancel")].join(" ");
370
+ case "list":
371
+ return [
372
+ keyHint("tui.select.confirm", "edit / add"),
373
+ keyHint("app.provider.removeEntry", "remove"),
374
+ keyHint("tui.select.cancel", "back"),
375
+ ].join(" ");
376
+ default:
377
+ return [
378
+ rawKeyHint("↑↓", "move"),
379
+ keyHint("tui.select.confirm", "choose"),
380
+ keyHint("tui.select.cancel", "cancel"),
381
+ ].join(" ");
382
+ }
383
+ }
384
+ }
385
+ //# sourceMappingURL=dictionary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dictionary.js","sourceRoot":"","sources":["../../../../src/extensions/provider/ui/dictionary.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,2DAA2D,CAAC;AAChG,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EACN,cAAc,EACd,kBAAkB,EAClB,eAAe,EAEf,WAAW,GACX,MAAM,gBAAgB,CAAC;AAExB,SAAS,YAAY,CAAC,MAAmB;IACxC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;IACpC,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAC7E,CAAC,CAAE,MAAkC;QACrC,CAAC,CAAC,EAAE,CAAC;AACP,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IACjC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/G,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC;AAGD,MAAM,gBAAgB,GAA6B,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AACnG,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAWvC,MAAM,OAAO,QAAQ;IAUpB,YAAY,IAAgB,EAAE,KAAkB,EAAE,OAAe;QARzD,UAAK,GAAG,CAAC,CAAC;QACV,SAAI,GAAa,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAElC,YAAO,GAAG,KAAK,CAAC;QAMvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAEvB,IAAI,CAAC,KAAK,GAAG,YAAY,OAAO,EAAE,CAAC;IACpC,CAAC;IAEO,IAAI;QACX,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAC1E,CAAC,CAAE,KAAiC;YACpC,CAAC,CAAC,EAAE,CAAC;IACP,CAAC;IAEO,OAAO;QACd,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,CAAC,KAAa;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;QAC9B,MAAM,KAAK,GAAa;YACvB,cAAc,CAAC,KAAK,EAAE,iEAAiE,EAAE,KAAK,CAAC;SAC/F,CAAC;QACF,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;YACtC,IAAI,IAAI,CAAC,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;YACrE,OAAO,KAAK,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,+EAA+E;QAC/E,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC1D,MAAM,MAAM,GAAG,QAAQ,KAAK,IAAI,CAAC,KAAK,CAAC;YACvC,KAAK,CAAC,IAAI,CACT,kBAAkB,CAAC,KAAK,EAAE;gBACzB,QAAQ,EAAE,GAAG;gBACb,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC;gBAC5B,MAAM;gBACN,WAAW,EAAE,IAAI,CAAC,OAAO;gBACzB,KAAK;aACL,CAAC,CACF,CAAC;QACH,CAAC;QACD,KAAK,CAAC,IAAI,CACT,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE;YACrC,MAAM,EAAE,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM;YAClE,WAAW,EAAE,IAAI,CAAC,OAAO;YACzB,KAAK;SACL,CAAC,CACF,CAAC;QACF,IAAI,IAAI,CAAC,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7F,OAAO,KAAK,CAAC;IACd,CAAC;IAED,YAAY;QACX,wEAAwE;QACxE,oEAAoE;QACpE,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IACvE,CAAC;IAEO,UAAU,CAAC,KAAa;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,SAAS;gBACb,OAAO,CAAC,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;YAClF,KAAK,UAAU,CAAC,CAAC,CAAC;gBACjB,OAAO;oBACN,cAAc,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,eAAe,EAAE,KAAK,CAAC;oBACxD,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAC3C,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE;wBAC5B,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC,KAAK;wBAChC,WAAW,EAAE,IAAI,CAAC,OAAO;wBACzB,KAAK;qBACL,CAAC,CACF;iBACD,CAAC;YACH,CAAC;YACD,KAAK,WAAW;gBACf,OAAO;oBACN,cAAc,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC;oBAC1D,kBAAkB,CAAC,KAAK,EAAE;wBACzB,QAAQ,EAAE,IAAI,CAAC,GAAG;wBAClB,MAAM,EAAE,IAAI;wBACZ,WAAW,EAAE,IAAI,CAAC,OAAO;wBACzB,OAAO,EAAE,IAAI,CAAC,MAAM;wBACpB,KAAK;qBACL,CAAC;iBACF,CAAC;YACH,KAAK,UAAU;gBACd,OAAO;oBACN,cAAc,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,YAAY,EAAE,KAAK,CAAC;oBACrD,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,CAChD,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE;wBAC9B,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC,KAAK;wBAClC,WAAW,EAAE,IAAI,CAAC,OAAO;wBACzB,KAAK;qBACL,CAAC,CACF;iBACD,CAAC;YACH,KAAK,SAAS;gBACb,OAAO;oBACN,cAAc,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC;oBAClD,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,CAC1C,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE;wBAC9B,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC,KAAK;wBAClC,WAAW,EAAE,IAAI,CAAC,OAAO;wBACzB,KAAK;qBACL,CAAC,CACF;iBACD,CAAC;YACH,KAAK,UAAU;gBACd,OAAO;oBACN,cAAc,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,gBAAgB,EAAE,KAAK,CAAC;oBACzD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,CAC3D,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE;wBAC9B,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC,KAAK;wBAClC,WAAW,EAAE,IAAI,CAAC,OAAO;wBACzB,KAAK;qBACL,CAAC,CACF;iBACD,CAAC;YACH;gBACC,OAAO,EAAE,CAAC;QACZ,CAAC;IACF,CAAC;IAED,WAAW,CAAC,IAAY;QACvB,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,SAAS,CAAC;YACf,KAAK,WAAW;gBACf,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC;oBAAE,OAAO;gBACrF,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;gBAC9B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO;YACR,KAAK,UAAU;gBACd,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,gBAAgB,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;oBAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;oBACrB,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAE,CAAC;oBACtC,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACnC,CAAC,CAAC,CAAC;gBACH,OAAO;YACR,KAAK,UAAU;gBACd,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;oBACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;oBACrB,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oBAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC;gBACnC,CAAC,CAAC,CAAC;gBACH,OAAO;YACR,KAAK,SAAS;gBACb,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;oBACzD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;oBACrB,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,CAAC,KAAK,CAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;oBAC3E,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACrB,CAAC,CAAC,CAAC;gBACH,OAAO;YACR,KAAK,UAAU;gBACd,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;oBACxC,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oBAC7B,IAAI,CAAC,UAAU,CACd,IAAI,CAAC,GAAG,EACR,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,KAAK,CAAC,EAAE,CACjF,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,OAAO;YACR,KAAK,MAAM;gBACV,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBACtB,OAAO;QACT,CAAC;IACF,CAAC;IAEO,UAAU,CACjB,IAAY,EACZ,IAA0C,EAC1C,KAAa,EACb,MAA+B;QAE/B,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,KAAK,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;YACjD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QACD,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QACD,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,mBAAmB,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QACD,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,oBAAoB,CAAC;YAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC;IAEO,UAAU,CAAC,IAAY;QAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QAC3C,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;YAC9D,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QACD,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;YACzC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QACD,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,mBAAmB,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QACD,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,0BAA0B,CAAC,EAAE,CAAC;YAClD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;YACxF,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YAC1E,OAAO;QACR,CAAC;QACD,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,oBAAoB,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE,CAAC;YACnF,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACZ,+CAA+C;gBAC/C,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC;oBAC9B,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE;wBACjB,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;wBACvB,IAAI,CAAC,GAAG,EAAE,CAAC;4BACV,IAAI,CAAC,KAAK,GAAG,wBAAwB,CAAC;4BACtC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;wBAC5B,CAAC;wBACD,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC;4BACrC,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,mBAAmB,CAAC;4BACxC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;wBAC5B,CAAC;wBACD,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;wBACvB,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;wBAChD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;oBACrB,CAAC;oBACD,QAAQ,EAAE,GAAG,EAAE;wBACd,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wBAC7B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;wBACvB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;oBACrB,CAAC;iBACD,CAAC,CAAC;gBACH,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;gBAC9B,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;gBACxC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO;YACR,CAAC;YACD,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC;YAC3B,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;gBAChC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;gBAC7B,OAAO;YACR,CAAC;YACD,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,CAAC,0CAA0C;YACtE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC/B,MAAM,MAAM,GAAG,KAAgC,CAAC;gBAChD,IACC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAClC,MAAM,CAAC,IAAI,KAAK,iBAAiB;oBACjC,MAAM,CAAC,IAAI,KAAK,iBAAiB,EAChC,CAAC;oBACF,IAAI,CAAC,IAAI,GAAG;wBACX,IAAI,EAAE,UAAU;wBAChB,GAAG;wBACH,IAAI,EAAE,MAAM,CAAC,IAAI;wBACjB,KAAK,EAAE,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;qBACxE,CAAC;oBACF,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;oBACpB,OAAO;gBACR,CAAC;gBACD,OAAO,CAAC,qCAAqC;YAC9C,CAAC;YACD,MAAM,IAAI,GAAwB,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;YAClF,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC;gBAC9B,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC;gBACpD,QAAQ,EAAE,GAAG,EAAE;oBACd,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oBAC7B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;oBACvB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACrB,CAAC;aACD,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACjC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YAC9B,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YACrD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;IACF,CAAC;IAEO,iBAAiB,CAAC,GAAW,EAAE,IAAmB;QACzD,QAAQ,IAAI,EAAE,CAAC;YACd,KAAK,QAAQ,CAAC;YACd,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACf,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC;oBAC9B,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC;oBACpD,QAAQ,EAAE,GAAG,EAAE;wBACd,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wBAC7B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;wBACvB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;oBACrB,CAAC;iBACD,CAAC,CAAC;gBACH,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;gBAC9B,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gBACrD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO;YACR,CAAC;YACD,KAAK,SAAS;gBACb,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;gBAChD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO;YACR,KAAK,MAAM;gBACV,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC3B,OAAO;YACR,KAAK,MAAM;gBACV,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;gBAC/C,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO;QACT,CAAC;IACF,CAAC;IAEO,YAAY,CAAC,GAAW,EAAE,IAAyB,EAAE,GAAW;QACvE,IAAI,KAAK,GAAoB,GAAG,CAAC;QACjC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9B,IAAI,CAAC,KAAK,GAAG,GAAG,GAAG,oBAAoB,CAAC;gBACxC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO;YACR,CAAC;YACD,KAAK,GAAG,MAAM,CAAC;QAChB,CAAC;QACD,MAAM,OAAO,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;QACjD,IAAI,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;YACrB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAEO,UAAU,CAAC,GAAW,EAAE,KAAc;QAC7C,MAAM,OAAO,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;QACjD,IAAI,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;YACrB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACnF,CAAC;IAED,UAAU,CAAC,OAAgB;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW;YAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IACxG,CAAC;IAED,SAAS;QACR,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC;IACvE,CAAC;IAED,KAAK;QACJ,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,KAAK,SAAS,CAAC;YACf,KAAK,WAAW;gBACf,OAAO,CAAC,OAAO,CAAC,kBAAkB,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjG,KAAK,MAAM;gBACV,OAAO;oBACN,OAAO,CAAC,oBAAoB,EAAE,YAAY,CAAC;oBAC3C,OAAO,CAAC,0BAA0B,EAAE,QAAQ,CAAC;oBAC7C,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC;iBACpC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACd;gBACC,OAAO;oBACN,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC;oBACxB,OAAO,CAAC,oBAAoB,EAAE,QAAQ,CAAC;oBACvC,OAAO,CAAC,mBAAmB,EAAE,QAAQ,CAAC;iBACtC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,CAAC;IACF,CAAC;CACD","sourcesContent":["/** Open chat-template dictionaries, with typed value-entry states. */\n\nimport { keyHint, rawKeyHint } from \"../../../modes/interactive/components/keybinding-hints.ts\";\nimport { THINKING_VARIABLES, validateChatTemplateKwarg } from \"../compat-fields.ts\";\nimport { truncate } from \"../constants.ts\";\nimport { DELETE } from \"../store.ts\";\nimport type { EditorHost, EditorPane, ModelHandle } from \"./pane.ts\";\nimport {\n\trenderInfoLine,\n\trenderKeyValueLine,\n\trenderPlainLine,\n\ttype ScrollWindowInfo,\n\tValueEditor,\n} from \"./value-row.ts\";\n\nfunction compatObject(handle: ModelHandle): Record<string, unknown> {\n\tconst compat = handle.read().compat;\n\treturn typeof compat === \"object\" && compat !== null && !Array.isArray(compat)\n\t\t? (compat as Record<string, unknown>)\n\t\t: {};\n}\n\nfunction scalarText(value: unknown): string {\n\tif (value === null) return \"null\";\n\tif (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n\treturn JSON.stringify(value) ?? String(value);\n}\n\ntype DictValueKind = \"string\" | \"number\" | \"boolean\" | \"null\" | \"$var\";\nconst DICT_VALUE_KINDS: readonly DictValueKind[] = [\"string\", \"number\", \"boolean\", \"null\", \"$var\"];\nconst VAR_OPTIONS = THINKING_VARIABLES;\n\ntype DictMode =\n\t| { type: \"list\" }\n\t| { type: \"keyEdit\"; editor: ValueEditor }\n\t| { type: \"kindPick\"; key: string; index: number }\n\t| { type: \"valueEdit\"; key: string; kind: \"string\" | \"number\"; editor: ValueEditor }\n\t| { type: \"boolPick\"; key: string; index: number }\n\t| { type: \"varPick\"; key: string; index: number }\n\t| { type: \"omitPick\"; key: string; $var: (typeof VAR_OPTIONS)[number]; index: number };\n\nexport class DictPane implements EditorPane {\n\treadonly crumb: string;\n\tprivate index = 0;\n\tprivate mode: DictMode = { type: \"list\" };\n\tprivate error: string | undefined;\n\tprivate focused = false;\n\n\tprivate readonly host: EditorHost;\n\tprivate readonly model: ModelHandle;\n\tprivate readonly dictKey: string;\n\tconstructor(host: EditorHost, model: ModelHandle, dictKey: string) {\n\t\tthis.host = host;\n\t\tthis.model = model;\n\t\tthis.dictKey = dictKey;\n\n\t\tthis.crumb = `compat · ${dictKey}`;\n\t}\n\n\tprivate dict(): Record<string, unknown> {\n\t\tconst value = compatObject(this.model)[this.dictKey];\n\t\treturn typeof value === \"object\" && value !== null && !Array.isArray(value)\n\t\t\t? (value as Record<string, unknown>)\n\t\t\t: {};\n\t}\n\n\tprivate entries(): [string, unknown][] {\n\t\treturn Object.entries(this.dict());\n\t}\n\n\trender(width: number): string[] {\n\t\tconst theme = this.host.theme;\n\t\tconst lines: string[] = [\n\t\t\trenderInfoLine(theme, `free-form keys; values: string · number · boolean · null · $var`, width),\n\t\t];\n\t\tif (this.mode.type !== \"list\") {\n\t\t\tlines.push(...this.renderMode(width));\n\t\t\tif (this.error) lines.push(renderInfoLine(theme, this.error, width));\n\t\t\treturn lines;\n\t\t}\n\t\tconst entries = this.entries();\n\t\t// All entries render; the editor's fixed window scrolls around scrollWindow().\n\t\tfor (const [rowIndex, [key, value]] of entries.entries()) {\n\t\t\tconst active = rowIndex === this.index;\n\t\t\tlines.push(\n\t\t\t\trenderKeyValueLine(theme, {\n\t\t\t\t\tkeyLabel: key,\n\t\t\t\t\tvalueText: scalarText(value),\n\t\t\t\t\tactive,\n\t\t\t\t\tpaneFocused: this.focused,\n\t\t\t\t\twidth,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tlines.push(\n\t\t\trenderPlainLine(theme, \"+ Add Entry\", {\n\t\t\t\tactive: this.index === entries.length && this.mode.type === \"list\",\n\t\t\t\tpaneFocused: this.focused,\n\t\t\t\twidth,\n\t\t\t}),\n\t\t);\n\t\tif (this.error) lines.push(theme.fg(\"error\", truncate(this.error, Math.max(10, width - 2))));\n\t\treturn lines;\n\t}\n\n\tscrollWindow(): ScrollWindowInfo {\n\t\t// The format header pins above; errors pin below. Entry flows are short\n\t\t// enough to fit, so only the list mode reports a meaningful cursor.\n\t\tif (this.mode.type !== \"list\") return { top: 1, bottom: this.error ? 1 : 0 };\n\t\treturn { top: 1, bottom: this.error ? 1 : 0, cursor: 1 + this.index };\n\t}\n\n\tprivate renderMode(width: number): string[] {\n\t\tconst theme = this.host.theme;\n\t\tconst mode = this.mode;\n\t\tswitch (mode.type) {\n\t\t\tcase \"keyEdit\":\n\t\t\t\treturn [renderInfoLine(theme, \"new key:\", width), mode.editor.renderLine(width)];\n\t\t\tcase \"kindPick\": {\n\t\t\t\treturn [\n\t\t\t\t\trenderInfoLine(theme, `${mode.key} · value kind`, width),\n\t\t\t\t\t...DICT_VALUE_KINDS.map((kind, kindIndex) =>\n\t\t\t\t\t\trenderPlainLine(theme, kind, {\n\t\t\t\t\t\t\tactive: kindIndex === mode.index,\n\t\t\t\t\t\t\tpaneFocused: this.focused,\n\t\t\t\t\t\t\twidth,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t];\n\t\t\t}\n\t\t\tcase \"valueEdit\":\n\t\t\t\treturn [\n\t\t\t\t\trenderInfoLine(theme, `${mode.key} · ${mode.kind}`, width),\n\t\t\t\t\trenderKeyValueLine(theme, {\n\t\t\t\t\t\tkeyLabel: mode.key,\n\t\t\t\t\t\tactive: true,\n\t\t\t\t\t\tpaneFocused: this.focused,\n\t\t\t\t\t\tediting: mode.editor,\n\t\t\t\t\t\twidth,\n\t\t\t\t\t}),\n\t\t\t\t];\n\t\t\tcase \"boolPick\":\n\t\t\t\treturn [\n\t\t\t\t\trenderInfoLine(theme, `${mode.key} · boolean`, width),\n\t\t\t\t\t...[\"true\", \"false\"].map((option, optionIndex) =>\n\t\t\t\t\t\trenderPlainLine(theme, option, {\n\t\t\t\t\t\t\tactive: optionIndex === mode.index,\n\t\t\t\t\t\t\tpaneFocused: this.focused,\n\t\t\t\t\t\t\twidth,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t];\n\t\t\tcase \"varPick\":\n\t\t\t\treturn [\n\t\t\t\t\trenderInfoLine(theme, `${mode.key} · $var`, width),\n\t\t\t\t\t...VAR_OPTIONS.map((option, optionIndex) =>\n\t\t\t\t\t\trenderPlainLine(theme, option, {\n\t\t\t\t\t\t\tactive: optionIndex === mode.index,\n\t\t\t\t\t\t\tpaneFocused: this.focused,\n\t\t\t\t\t\t\twidth,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t];\n\t\t\tcase \"omitPick\":\n\t\t\t\treturn [\n\t\t\t\t\trenderInfoLine(theme, `${mode.key} · omitWhenOff`, width),\n\t\t\t\t\t...[\"default\", \"true\", \"false\"].map((option, optionIndex) =>\n\t\t\t\t\t\trenderPlainLine(theme, option, {\n\t\t\t\t\t\t\tactive: optionIndex === mode.index,\n\t\t\t\t\t\t\tpaneFocused: this.focused,\n\t\t\t\t\t\t\twidth,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t];\n\t\t\tdefault:\n\t\t\t\treturn [];\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = this.host.keybindings;\n\t\tconst mode = this.mode;\n\t\tswitch (mode.type) {\n\t\t\tcase \"keyEdit\":\n\t\t\tcase \"valueEdit\":\n\t\t\t\tif (kb.matches(data, \"tui.select.up\") || kb.matches(data, \"tui.select.down\")) return;\n\t\t\t\tmode.editor.handleInput(data);\n\t\t\t\tthis.host.refresh();\n\t\t\t\treturn;\n\t\t\tcase \"kindPick\":\n\t\t\t\tthis.handlePick(data, mode, DICT_VALUE_KINDS.length, (index) => {\n\t\t\t\t\tconst key = mode.key;\n\t\t\t\t\tconst kind = DICT_VALUE_KINDS[index]!;\n\t\t\t\t\tthis.startValueForKind(key, kind);\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\tcase \"boolPick\":\n\t\t\t\tthis.handlePick(data, mode, 2, (index) => {\n\t\t\t\t\tconst key = mode.key;\n\t\t\t\t\tthis.mode = { type: \"list\" };\n\t\t\t\t\tthis.writeEntry(key, index === 0);\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\tcase \"varPick\":\n\t\t\t\tthis.handlePick(data, mode, VAR_OPTIONS.length, (index) => {\n\t\t\t\t\tconst key = mode.key;\n\t\t\t\t\tthis.mode = { type: \"omitPick\", key, $var: VAR_OPTIONS[index]!, index: 0 };\n\t\t\t\t\tthis.host.refresh();\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\tcase \"omitPick\":\n\t\t\t\tthis.handlePick(data, mode, 3, (index) => {\n\t\t\t\t\tthis.mode = { type: \"list\" };\n\t\t\t\t\tthis.writeEntry(\n\t\t\t\t\t\tmode.key,\n\t\t\t\t\t\tindex === 0 ? { $var: mode.$var } : { $var: mode.$var, omitWhenOff: index === 1 },\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\tcase \"list\":\n\t\t\t\tthis.handleList(data);\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate handlePick(\n\t\tdata: string,\n\t\tmode: Extract<DictMode, { index: number }>,\n\t\tcount: number,\n\t\tchoose: (index: number) => void,\n\t): void {\n\t\tconst kb = this.host.keybindings;\n\t\tconst index = mode.index;\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tmode.index = index === 0 ? count - 1 : index - 1;\n\t\t\tthis.host.refresh();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tmode.index = (index + 1) % count;\n\t\t\tthis.host.refresh();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.mode = { type: \"list\" };\n\t\t\tthis.host.refresh();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.confirm\")) choose(index);\n\t}\n\n\tprivate handleList(data: string): void {\n\t\tconst kb = this.host.keybindings;\n\t\tconst rowCount = this.entries().length + 1;\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tthis.index = this.index === 0 ? rowCount - 1 : this.index - 1;\n\t\t\tthis.host.refresh();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tthis.index = (this.index + 1) % rowCount;\n\t\t\tthis.host.refresh();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.host.popPane();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"app.provider.removeEntry\")) {\n\t\t\tconst entry = this.entries()[this.index];\n\t\t\tif (!entry) return;\n\t\t\tthis.host.mutate(() => this.model.setField([\"compat\", this.dictKey, entry[0]], DELETE));\n\t\t\tthis.index = Math.max(0, Math.min(this.index, this.entries().length - 1));\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.confirm\") || kb.matches(data, \"app.list.toggle\")) {\n\t\t\tconst entry = this.entries()[this.index];\n\t\t\tif (!entry) {\n\t\t\t\t// + Add Entry: key first, then the value flow.\n\t\t\t\tconst editor = new ValueEditor({\n\t\t\t\t\tonCommit: (raw) => {\n\t\t\t\t\t\tconst key = raw.trim();\n\t\t\t\t\t\tif (!key) {\n\t\t\t\t\t\t\tthis.error = \"Key must be non-empty.\";\n\t\t\t\t\t\t\treturn this.host.refresh();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (Object.hasOwn(this.dict(), key)) {\n\t\t\t\t\t\t\tthis.error = `\"${key}\" already exists.`;\n\t\t\t\t\t\t\treturn this.host.refresh();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.error = undefined;\n\t\t\t\t\t\tthis.mode = { type: \"kindPick\", key, index: 0 };\n\t\t\t\t\t\tthis.host.refresh();\n\t\t\t\t\t},\n\t\t\t\t\tonCancel: () => {\n\t\t\t\t\t\tthis.mode = { type: \"list\" };\n\t\t\t\t\t\tthis.error = undefined;\n\t\t\t\t\t\tthis.host.refresh();\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\teditor.focused = this.focused;\n\t\t\t\tthis.mode = { type: \"keyEdit\", editor };\n\t\t\t\tthis.host.refresh();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst [key, value] = entry;\n\t\t\tif (typeof value === \"boolean\") {\n\t\t\t\tthis.writeEntry(key, !value);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (value === null) return; // null entries: remove + re-add to change\n\t\t\tif (typeof value === \"object\") {\n\t\t\t\tconst record = value as Record<string, unknown>;\n\t\t\t\tif (\n\t\t\t\t\trecord.$var === \"thinking.enabled\" ||\n\t\t\t\t\trecord.$var === \"thinking.effort\" ||\n\t\t\t\t\trecord.$var === \"thinking.budget\"\n\t\t\t\t) {\n\t\t\t\t\tthis.mode = {\n\t\t\t\t\t\ttype: \"omitPick\",\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\t$var: record.$var,\n\t\t\t\t\t\tindex: record.omitWhenOff === undefined ? 0 : record.omitWhenOff ? 1 : 2,\n\t\t\t\t\t};\n\t\t\t\t\tthis.host.refresh();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treturn; // unexpected object: remove + re-add\n\t\t\t}\n\t\t\tconst kind: \"string\" | \"number\" = typeof value === \"number\" ? \"number\" : \"string\";\n\t\t\tconst editor = new ValueEditor({\n\t\t\t\tonCommit: (raw) => this.commitScalar(key, kind, raw),\n\t\t\t\tonCancel: () => {\n\t\t\t\t\tthis.mode = { type: \"list\" };\n\t\t\t\t\tthis.error = undefined;\n\t\t\t\t\tthis.host.refresh();\n\t\t\t\t},\n\t\t\t});\n\t\t\teditor.beginTweak(String(value));\n\t\t\teditor.focused = this.focused;\n\t\t\tthis.mode = { type: \"valueEdit\", key, kind, editor };\n\t\t\tthis.host.refresh();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate startValueForKind(key: string, kind: DictValueKind): void {\n\t\tswitch (kind) {\n\t\t\tcase \"string\":\n\t\t\tcase \"number\": {\n\t\t\t\tconst editor = new ValueEditor({\n\t\t\t\t\tonCommit: (raw) => this.commitScalar(key, kind, raw),\n\t\t\t\t\tonCancel: () => {\n\t\t\t\t\t\tthis.mode = { type: \"list\" };\n\t\t\t\t\t\tthis.error = undefined;\n\t\t\t\t\t\tthis.host.refresh();\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\teditor.focused = this.focused;\n\t\t\t\tthis.mode = { type: \"valueEdit\", key, kind, editor };\n\t\t\t\tthis.host.refresh();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"boolean\":\n\t\t\t\tthis.mode = { type: \"boolPick\", key, index: 0 };\n\t\t\t\tthis.host.refresh();\n\t\t\t\treturn;\n\t\t\tcase \"null\":\n\t\t\t\tthis.mode = { type: \"list\" };\n\t\t\t\tthis.writeEntry(key, null);\n\t\t\t\treturn;\n\t\t\tcase \"$var\":\n\t\t\t\tthis.mode = { type: \"varPick\", key, index: 0 };\n\t\t\t\tthis.host.refresh();\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate commitScalar(key: string, kind: \"string\" | \"number\", raw: string): void {\n\t\tlet value: string | number = raw;\n\t\tif (kind === \"number\") {\n\t\t\tconst parsed = Number(raw.trim());\n\t\t\tif (!Number.isFinite(parsed)) {\n\t\t\t\tthis.error = `${key} must be a number.`;\n\t\t\t\tthis.host.refresh();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvalue = parsed;\n\t\t}\n\t\tconst invalid = validateChatTemplateKwarg(value);\n\t\tif (invalid) {\n\t\t\tthis.error = invalid;\n\t\t\tthis.host.refresh();\n\t\t\treturn;\n\t\t}\n\t\tthis.error = undefined;\n\t\tthis.mode = { type: \"list\" };\n\t\tthis.writeEntry(key, value);\n\t}\n\n\tprivate writeEntry(key: string, value: unknown): void {\n\t\tconst invalid = validateChatTemplateKwarg(value);\n\t\tif (invalid) {\n\t\t\tthis.error = invalid;\n\t\t\tthis.host.refresh();\n\t\t\treturn;\n\t\t}\n\t\tthis.host.mutate(() => this.model.setField([\"compat\", this.dictKey, key], value));\n\t}\n\n\tsetFocused(focused: boolean): void {\n\t\tthis.focused = focused;\n\t\tif (this.mode.type === \"keyEdit\" || this.mode.type === \"valueEdit\") this.mode.editor.focused = focused;\n\t}\n\n\tisEditing(): boolean {\n\t\treturn this.mode.type === \"keyEdit\" || this.mode.type === \"valueEdit\";\n\t}\n\n\thints(): string {\n\t\tswitch (this.mode.type) {\n\t\t\tcase \"keyEdit\":\n\t\t\tcase \"valueEdit\":\n\t\t\t\treturn [keyHint(\"tui.input.submit\", \"save\"), keyHint(\"tui.select.cancel\", \"cancel\")].join(\" \");\n\t\t\tcase \"list\":\n\t\t\t\treturn [\n\t\t\t\t\tkeyHint(\"tui.select.confirm\", \"edit / add\"),\n\t\t\t\t\tkeyHint(\"app.provider.removeEntry\", \"remove\"),\n\t\t\t\t\tkeyHint(\"tui.select.cancel\", \"back\"),\n\t\t\t\t].join(\" \");\n\t\t\tdefault:\n\t\t\t\treturn [\n\t\t\t\t\trawKeyHint(\"↑↓\", \"move\"),\n\t\t\t\t\tkeyHint(\"tui.select.confirm\", \"choose\"),\n\t\t\t\t\tkeyHint(\"tui.select.cancel\", \"cancel\"),\n\t\t\t\t].join(\" \");\n\t\t}\n\t}\n}\n"]}