@kata-sh/cli 0.1.0 β†’ 0.1.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 (199) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +156 -0
  3. package/dist/app-paths.d.ts +4 -0
  4. package/dist/app-paths.js +6 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.js +56 -0
  7. package/dist/loader.d.ts +2 -0
  8. package/dist/loader.js +95 -0
  9. package/dist/resource-loader.d.ts +18 -0
  10. package/dist/resource-loader.js +50 -0
  11. package/dist/wizard.d.ts +15 -0
  12. package/dist/wizard.js +159 -0
  13. package/package.json +50 -21
  14. package/pkg/dist/modes/interactive/theme/dark.json +85 -0
  15. package/pkg/dist/modes/interactive/theme/light.json +84 -0
  16. package/pkg/dist/modes/interactive/theme/theme-schema.json +335 -0
  17. package/pkg/dist/modes/interactive/theme/theme.d.ts +78 -0
  18. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -0
  19. package/pkg/dist/modes/interactive/theme/theme.js +949 -0
  20. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -0
  21. package/pkg/package.json +8 -0
  22. package/scripts/postinstall.js +45 -0
  23. package/src/resources/AGENTS.md +108 -0
  24. package/src/resources/KATA-WORKFLOW.md +661 -0
  25. package/src/resources/agents/researcher.md +29 -0
  26. package/src/resources/agents/scout.md +56 -0
  27. package/src/resources/agents/worker.md +31 -0
  28. package/src/resources/extensions/ask-user-questions.ts +200 -0
  29. package/src/resources/extensions/bg-shell/index.ts +2758 -0
  30. package/src/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
  31. package/src/resources/extensions/browser-tools/core.js +1057 -0
  32. package/src/resources/extensions/browser-tools/index.ts +4916 -0
  33. package/src/resources/extensions/browser-tools/package.json +20 -0
  34. package/src/resources/extensions/context7/index.ts +428 -0
  35. package/src/resources/extensions/context7/package.json +11 -0
  36. package/src/resources/extensions/get-secrets-from-user.ts +352 -0
  37. package/src/resources/extensions/github/formatters.ts +207 -0
  38. package/src/resources/extensions/github/gh-api.ts +537 -0
  39. package/src/resources/extensions/github/index.ts +778 -0
  40. package/src/resources/extensions/kata/activity-log.ts +88 -0
  41. package/src/resources/extensions/kata/auto.ts +2786 -0
  42. package/src/resources/extensions/kata/commands.ts +355 -0
  43. package/src/resources/extensions/kata/crash-recovery.ts +85 -0
  44. package/src/resources/extensions/kata/dashboard-overlay.ts +516 -0
  45. package/src/resources/extensions/kata/docs/preferences-reference.md +103 -0
  46. package/src/resources/extensions/kata/doctor.ts +683 -0
  47. package/src/resources/extensions/kata/files.ts +730 -0
  48. package/src/resources/extensions/kata/gitignore.ts +165 -0
  49. package/src/resources/extensions/kata/guided-flow.ts +976 -0
  50. package/src/resources/extensions/kata/index.ts +556 -0
  51. package/src/resources/extensions/kata/metrics.ts +397 -0
  52. package/src/resources/extensions/kata/observability-validator.ts +408 -0
  53. package/src/resources/extensions/kata/package.json +11 -0
  54. package/src/resources/extensions/kata/paths.ts +346 -0
  55. package/src/resources/extensions/kata/preferences.ts +695 -0
  56. package/src/resources/extensions/kata/prompt-loader.ts +50 -0
  57. package/src/resources/extensions/kata/prompts/complete-milestone.md +25 -0
  58. package/src/resources/extensions/kata/prompts/complete-slice.md +27 -0
  59. package/src/resources/extensions/kata/prompts/discuss.md +151 -0
  60. package/src/resources/extensions/kata/prompts/doctor-heal.md +29 -0
  61. package/src/resources/extensions/kata/prompts/execute-task.md +64 -0
  62. package/src/resources/extensions/kata/prompts/guided-complete-slice.md +1 -0
  63. package/src/resources/extensions/kata/prompts/guided-discuss-milestone.md +3 -0
  64. package/src/resources/extensions/kata/prompts/guided-discuss-slice.md +59 -0
  65. package/src/resources/extensions/kata/prompts/guided-execute-task.md +1 -0
  66. package/src/resources/extensions/kata/prompts/guided-plan-milestone.md +23 -0
  67. package/src/resources/extensions/kata/prompts/guided-plan-slice.md +1 -0
  68. package/src/resources/extensions/kata/prompts/guided-research-slice.md +11 -0
  69. package/src/resources/extensions/kata/prompts/guided-resume-task.md +1 -0
  70. package/src/resources/extensions/kata/prompts/plan-milestone.md +47 -0
  71. package/src/resources/extensions/kata/prompts/plan-slice.md +63 -0
  72. package/src/resources/extensions/kata/prompts/queue.md +85 -0
  73. package/src/resources/extensions/kata/prompts/reassess-roadmap.md +48 -0
  74. package/src/resources/extensions/kata/prompts/replan-slice.md +39 -0
  75. package/src/resources/extensions/kata/prompts/research-milestone.md +37 -0
  76. package/src/resources/extensions/kata/prompts/research-slice.md +28 -0
  77. package/src/resources/extensions/kata/prompts/run-uat.md +109 -0
  78. package/src/resources/extensions/kata/prompts/system.md +341 -0
  79. package/src/resources/extensions/kata/session-forensics.ts +550 -0
  80. package/src/resources/extensions/kata/skill-discovery.ts +137 -0
  81. package/src/resources/extensions/kata/state.ts +509 -0
  82. package/src/resources/extensions/kata/templates/context.md +76 -0
  83. package/src/resources/extensions/kata/templates/decisions.md +8 -0
  84. package/src/resources/extensions/kata/templates/milestone-summary.md +73 -0
  85. package/src/resources/extensions/kata/templates/plan.md +133 -0
  86. package/src/resources/extensions/kata/templates/preferences.md +15 -0
  87. package/src/resources/extensions/kata/templates/project.md +31 -0
  88. package/src/resources/extensions/kata/templates/reassessment.md +28 -0
  89. package/src/resources/extensions/kata/templates/requirements.md +81 -0
  90. package/src/resources/extensions/kata/templates/research.md +46 -0
  91. package/src/resources/extensions/kata/templates/roadmap.md +118 -0
  92. package/src/resources/extensions/kata/templates/slice-context.md +58 -0
  93. package/src/resources/extensions/kata/templates/slice-summary.md +99 -0
  94. package/src/resources/extensions/kata/templates/state.md +19 -0
  95. package/src/resources/extensions/kata/templates/task-plan.md +52 -0
  96. package/src/resources/extensions/kata/templates/task-summary.md +57 -0
  97. package/src/resources/extensions/kata/templates/uat.md +54 -0
  98. package/src/resources/extensions/kata/tests/activity-log-prune.test.ts +327 -0
  99. package/src/resources/extensions/kata/tests/auto-preflight.test.ts +97 -0
  100. package/src/resources/extensions/kata/tests/auto-supervisor.test.mjs +53 -0
  101. package/src/resources/extensions/kata/tests/complete-milestone.test.ts +317 -0
  102. package/src/resources/extensions/kata/tests/cost-projection.test.ts +160 -0
  103. package/src/resources/extensions/kata/tests/derive-state-deps.test.ts +477 -0
  104. package/src/resources/extensions/kata/tests/derive-state.test.ts +1013 -0
  105. package/src/resources/extensions/kata/tests/doctor.test.ts +718 -0
  106. package/src/resources/extensions/kata/tests/idle-recovery.test.ts +490 -0
  107. package/src/resources/extensions/kata/tests/metrics-io.test.ts +254 -0
  108. package/src/resources/extensions/kata/tests/metrics.test.ts +217 -0
  109. package/src/resources/extensions/kata/tests/must-have-parser.test.ts +309 -0
  110. package/src/resources/extensions/kata/tests/parsers.test.ts +1257 -0
  111. package/src/resources/extensions/kata/tests/plan-milestone.test.ts +185 -0
  112. package/src/resources/extensions/kata/tests/plan-quality-validator.test.ts +386 -0
  113. package/src/resources/extensions/kata/tests/reassess-prompt.test.ts +208 -0
  114. package/src/resources/extensions/kata/tests/replan-slice.test.ts +686 -0
  115. package/src/resources/extensions/kata/tests/requirements.test.ts +151 -0
  116. package/src/resources/extensions/kata/tests/resolve-ts-hooks.mjs +17 -0
  117. package/src/resources/extensions/kata/tests/resolve-ts.mjs +11 -0
  118. package/src/resources/extensions/kata/tests/run-uat.test.ts +383 -0
  119. package/src/resources/extensions/kata/tests/unit-runtime.test.ts +388 -0
  120. package/src/resources/extensions/kata/tests/workspace-index.test.ts +118 -0
  121. package/src/resources/extensions/kata/tests/worktree.test.ts +222 -0
  122. package/src/resources/extensions/kata/types.ts +159 -0
  123. package/src/resources/extensions/kata/unit-runtime.ts +163 -0
  124. package/src/resources/extensions/kata/workspace-index.ts +203 -0
  125. package/src/resources/extensions/kata/worktree.ts +182 -0
  126. package/src/resources/extensions/mac-tools/index.ts +852 -0
  127. package/src/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
  128. package/src/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
  129. package/src/resources/extensions/search-the-web/cache.ts +78 -0
  130. package/src/resources/extensions/search-the-web/format.ts +258 -0
  131. package/src/resources/extensions/search-the-web/http.ts +238 -0
  132. package/src/resources/extensions/search-the-web/index.ts +68 -0
  133. package/src/resources/extensions/search-the-web/tool-fetch-page.ts +519 -0
  134. package/src/resources/extensions/search-the-web/tool-llm-context.ts +404 -0
  135. package/src/resources/extensions/search-the-web/tool-search.ts +503 -0
  136. package/src/resources/extensions/search-the-web/url-utils.ts +91 -0
  137. package/src/resources/extensions/shared/confirm-ui.ts +126 -0
  138. package/src/resources/extensions/shared/interview-ui.ts +822 -0
  139. package/src/resources/extensions/shared/next-action-ui.ts +235 -0
  140. package/src/resources/extensions/shared/progress-widget.ts +282 -0
  141. package/src/resources/extensions/shared/thinking-widget.ts +107 -0
  142. package/src/resources/extensions/shared/ui.ts +400 -0
  143. package/src/resources/extensions/shared/wizard-ui.ts +551 -0
  144. package/src/resources/extensions/slash-commands/audit.ts +92 -0
  145. package/src/resources/extensions/slash-commands/create-extension.ts +375 -0
  146. package/src/resources/extensions/slash-commands/create-slash-command.ts +280 -0
  147. package/src/resources/extensions/slash-commands/index.ts +12 -0
  148. package/src/resources/extensions/slash-commands/kata-run.ts +34 -0
  149. package/src/resources/extensions/subagent/agents.ts +126 -0
  150. package/src/resources/extensions/subagent/index.ts +1293 -0
  151. package/src/resources/skills/debug-like-expert/SKILL.md +231 -0
  152. package/src/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
  153. package/src/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
  154. package/src/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
  155. package/src/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
  156. package/src/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
  157. package/src/resources/skills/frontend-design/SKILL.md +45 -0
  158. package/src/resources/skills/swiftui/SKILL.md +208 -0
  159. package/src/resources/skills/swiftui/references/animations.md +921 -0
  160. package/src/resources/skills/swiftui/references/architecture.md +1561 -0
  161. package/src/resources/skills/swiftui/references/layout-system.md +1186 -0
  162. package/src/resources/skills/swiftui/references/navigation.md +1492 -0
  163. package/src/resources/skills/swiftui/references/networking-async.md +214 -0
  164. package/src/resources/skills/swiftui/references/performance.md +1706 -0
  165. package/src/resources/skills/swiftui/references/platform-integration.md +204 -0
  166. package/src/resources/skills/swiftui/references/state-management.md +1443 -0
  167. package/src/resources/skills/swiftui/references/swiftdata.md +297 -0
  168. package/src/resources/skills/swiftui/references/testing-debugging.md +247 -0
  169. package/src/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
  170. package/src/resources/skills/swiftui/workflows/add-feature.md +191 -0
  171. package/src/resources/skills/swiftui/workflows/build-new-app.md +311 -0
  172. package/src/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
  173. package/src/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
  174. package/src/resources/skills/swiftui/workflows/ship-app.md +203 -0
  175. package/src/resources/skills/swiftui/workflows/write-tests.md +235 -0
  176. package/dist/commands/task.d.ts +0 -9
  177. package/dist/commands/task.d.ts.map +0 -1
  178. package/dist/commands/task.js +0 -129
  179. package/dist/commands/task.js.map +0 -1
  180. package/dist/commands/task.test.d.ts +0 -2
  181. package/dist/commands/task.test.d.ts.map +0 -1
  182. package/dist/commands/task.test.js +0 -169
  183. package/dist/commands/task.test.js.map +0 -1
  184. package/dist/e2e/task-e2e.test.d.ts +0 -2
  185. package/dist/e2e/task-e2e.test.d.ts.map +0 -1
  186. package/dist/e2e/task-e2e.test.js +0 -173
  187. package/dist/e2e/task-e2e.test.js.map +0 -1
  188. package/dist/index.d.ts +0 -3
  189. package/dist/index.d.ts.map +0 -1
  190. package/dist/index.js +0 -93
  191. package/dist/index.js.map +0 -1
  192. package/dist/slug.d.ts +0 -2
  193. package/dist/slug.d.ts.map +0 -1
  194. package/dist/slug.js +0 -12
  195. package/dist/slug.js.map +0 -1
  196. package/dist/slug.test.d.ts +0 -2
  197. package/dist/slug.test.d.ts.map +0 -1
  198. package/dist/slug.test.js +0 -32
  199. package/dist/slug.test.js.map +0 -1
@@ -0,0 +1,400 @@
1
+ /**
2
+ * Shared UI design system for Kata/interview TUI components.
3
+ *
4
+ * Centralises all colours, glyphs, spacing, and layout helpers so every
5
+ * screen looks consistent and can be restyled from one place.
6
+ *
7
+ * Usage:
8
+ *
9
+ * import { makeUI } from "./shared/ui.js";
10
+ *
11
+ * // Inside ctx.ui.custom((tui, theme, _kb, done) => { ... }):
12
+ * const ui = makeUI(theme, width);
13
+ *
14
+ * // Then in render(width):
15
+ * const ui = makeUI(theme, width);
16
+ * lines.push(...ui.bar());
17
+ * lines.push(...ui.header("New Project"));
18
+ * lines.push(...ui.blank());
19
+ * lines.push(...ui.question("What do you want to build?"));
20
+ * lines.push(...ui.optionSelected(1, "Describe it now", "Type what you want."));
21
+ * lines.push(...ui.optionUnselected(2, "Provide a file", "Point to an existing doc."));
22
+ * lines.push(...ui.blank());
23
+ * lines.push(...ui.hints(["↑/↓ to move", "enter to select"]));
24
+ * lines.push(...ui.bar());
25
+ *
26
+ * Every method returns string[] (one or more lines) so you can spread
27
+ * directly into your lines array. Width is passed once to makeUI so
28
+ * individual methods don't need it.
29
+ */
30
+
31
+ import { type Theme } from "@mariozechner/pi-coding-agent";
32
+ import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@mariozechner/pi-tui";
33
+
34
+ // ─── Glyphs ───────────────────────────────────────────────────────────────────
35
+ // Change these to restyle every cursor, checkbox, and indicator at once.
36
+
37
+ export const GLYPH = {
38
+ cursor: "β€Ί",
39
+ check: "βœ“",
40
+ checkedBox: "[x]",
41
+ uncheckedBox: "[ ]",
42
+ dotActive: "●",
43
+ dotDone: "●",
44
+ squareFilled: "β– ",
45
+ squareEmpty: "β–‘",
46
+ separator: "─",
47
+ statusPending: "β—‹",
48
+ statusActive: "●",
49
+ statusDone: "βœ“",
50
+ statusFailed: "βœ—",
51
+ statusPaused: "⏸",
52
+ statusWarning: "⚠",
53
+ statusSkipped: "–",
54
+ } as const;
55
+
56
+ // ─── Status vocabulary ────────────────────────────────────────────────────────
57
+ // Shared status type and visual mappings used by any component that renders
58
+ // progress or state indicators.
59
+
60
+ export type ProgressStatus =
61
+ | "pending"
62
+ | "active"
63
+ | "done"
64
+ | "failed"
65
+ | "paused"
66
+ | "warning"
67
+ | "skipped";
68
+
69
+ export const STATUS_COLOR: Record<ProgressStatus, "dim" | "accent" | "success" | "error" | "warning"> = {
70
+ pending: "dim",
71
+ active: "accent",
72
+ done: "success",
73
+ failed: "error",
74
+ paused: "warning",
75
+ warning: "warning",
76
+ skipped: "dim",
77
+ };
78
+
79
+ export const STATUS_GLYPH: Record<ProgressStatus, string> = {
80
+ pending: GLYPH.statusPending,
81
+ active: GLYPH.statusActive,
82
+ done: GLYPH.statusDone,
83
+ failed: GLYPH.statusFailed,
84
+ paused: GLYPH.statusPaused,
85
+ warning: GLYPH.statusWarning,
86
+ skipped: GLYPH.statusSkipped,
87
+ };
88
+
89
+ // ─── Spacing ──────────────────────────────────────────────────────────────────
90
+ // All indentation constants in one place.
91
+
92
+ export const INDENT = {
93
+ /** Standard left margin for all content lines */
94
+ base: " ",
95
+ /** Option label indent (same as base, kept separate for clarity) */
96
+ option: " ",
97
+ /** Description line below an option label */
98
+ description: " ",
99
+ /** Note line below a review answer */
100
+ note: " ",
101
+ /** Cursor + space (replaces base when cursor is shown) */
102
+ cursor: "β€Ί ",
103
+ } as const;
104
+
105
+ // ─── Factory ──────────────────────────────────────────────────────────────────
106
+
107
+ export interface UI {
108
+ // ── Layout ────────────────────────────────────────────────────────────────
109
+ /** Full-width accent separator bar */
110
+ bar(): string[];
111
+ /** Empty line */
112
+ blank(): string[];
113
+
114
+ // ── Text elements ─────────────────────────────────────────────────────────
115
+ /** Bold accent title β€” used for screen headings */
116
+ header(text: string): string[];
117
+ /** Standard question or page subtitle */
118
+ question(text: string): string[];
119
+ /** Muted secondary text β€” used for subtitles and review question labels */
120
+ subtitle(text: string): string[];
121
+ /** Dim metadata / progress line */
122
+ meta(text: string): string[];
123
+ /** Dim footer hint line β€” pipe-separated hints */
124
+ hints(parts: string[]): string[];
125
+ /** Dim note line (e.g. "note: ...") */
126
+ note(text: string): string[];
127
+ /** Success-coloured confirmed answer line (e.g. "βœ“ Option A") */
128
+ answer(text: string): string[];
129
+
130
+ // ── Select options ────────────────────────────────────────────────────────
131
+ /**
132
+ * Single-select option row β€” cursor highlighted.
133
+ * Pass isCommitted=true to show the βœ“ marker.
134
+ */
135
+ optionSelected(num: number, label: string, description: string, isCommitted?: boolean): string[];
136
+ /**
137
+ * Single-select option row β€” not under cursor.
138
+ * Pass isFocusDimmed=true when notes field is focused (dims everything).
139
+ */
140
+ optionUnselected(num: number, label: string, description: string, opts?: { isCommitted?: boolean; isFocusDimmed?: boolean }): string[];
141
+
142
+ // ── Checkbox options ──────────────────────────────────────────────────────
143
+ /** Multi-select option row β€” cursor highlighted */
144
+ checkboxSelected(label: string, description: string, isChecked: boolean): string[];
145
+ /** Multi-select option row β€” not under cursor */
146
+ checkboxUnselected(label: string, description: string, isChecked: boolean, isFocusDimmed?: boolean): string[];
147
+
148
+ // ── Special slots ─────────────────────────────────────────────────────────
149
+ /** "None of the above" / "Done" slot β€” selected state */
150
+ slotSelected(label: string, description: string, isCommitted?: boolean): string[];
151
+ /** "None of the above" / "Done" slot β€” unselected state */
152
+ slotUnselected(label: string, description: string, opts?: { isCommitted?: boolean; isFocusDimmed?: boolean }): string[];
153
+ /** Multi-select "Done" slot β€” selected */
154
+ doneSelected(): string[];
155
+ /** Multi-select "Done" slot β€” unselected */
156
+ doneUnselected(): string[];
157
+
158
+ // ── Action items (next-action style) ──────────────────────────────────────
159
+ /** Accent action item with cursor β€” used in next-action and review screens */
160
+ actionSelected(num: number, label: string, description?: string, tag?: string): string[];
161
+ /** Unselected action item */
162
+ actionUnselected(num: number, label: string, description?: string, tag?: string): string[];
163
+ /** Dim "not yet" style action β€” least prominent */
164
+ actionDim(num: number, label: string, description?: string): string[];
165
+
166
+ // ── Progress indicators ───────────────────────────────────────────────────
167
+ /** Row of page dots for wizard navigation */
168
+ pageDots(total: number, currentIndex: number): string[];
169
+ /** Interview question tab bar */
170
+ questionTabs(headers: string[], currentIndex: number, answeredIndices: Set<number>): string[];
171
+
172
+ // ── Status primitives ─────────────────────────────────────────────────────
173
+ /** Render a status glyph in the appropriate theme color */
174
+ statusGlyph(status: ProgressStatus): string;
175
+ /** Render a status badge β€” bold text in the appropriate status color */
176
+ statusBadge(text: string, status: ProgressStatus): string[];
177
+ /** Render a progress item row: glyph + label + optional detail */
178
+ progressItem(
179
+ label: string,
180
+ status: ProgressStatus,
181
+ opts?: { detail?: string; emphasized?: boolean },
182
+ ): string[];
183
+ /** Render an indented annotation line below a progress item */
184
+ progressAnnotation(text: string): string[];
185
+
186
+ // ── Notes area ────────────────────────────────────────────────────────────
187
+ /** Notes section label β€” accent when focused, muted when not */
188
+ notesLabel(focused: boolean): string[];
189
+ /** Inline note text (dim) */
190
+ notesText(text: string): string[];
191
+
192
+ // ── Editor theme ──────────────────────────────────────────────────────────
193
+ /** Standard EditorTheme object for use with the Editor component */
194
+ editorTheme: import("@mariozechner/pi-tui").EditorTheme;
195
+ }
196
+
197
+ /**
198
+ * Create a UI helper bound to the current theme and render width.
199
+ * Call once per render() invocation (width may change between renders).
200
+ */
201
+ export function makeUI(theme: Theme, width: number): UI {
202
+ // ── Internal helpers ───────────────────────────────────────────────────────
203
+
204
+ const add = (s: string): string => truncateToWidth(s, width);
205
+ const wrap = (s: string): string[] => wrapTextWithAnsi(s, width);
206
+
207
+ function wrapIndented(s: string, indent: string): string[] {
208
+ const indentWidth = visibleWidth(indent);
209
+ const wrapped = wrapTextWithAnsi(s, width - indentWidth);
210
+ for (let i = 1; i < wrapped.length; i++) wrapped[i] = indent + wrapped[i];
211
+ return wrapped;
212
+ }
213
+
214
+ const bar = theme.fg("accent", GLYPH.separator.repeat(width));
215
+
216
+ // ── EditorTheme ────────────────────────────────────────────────────────────
217
+
218
+ const editorTheme: import("@mariozechner/pi-tui").EditorTheme = {
219
+ borderColor: (s) => theme.fg("accent", s),
220
+ selectList: {
221
+ selectedPrefix: (t) => theme.fg("accent", t),
222
+ selectedText: (t) => theme.fg("accent", t),
223
+ description: (t) => theme.fg("muted", t),
224
+ scrollInfo: (t) => theme.fg("dim", t),
225
+ noMatch: (t) => theme.fg("warning", t),
226
+ },
227
+ };
228
+
229
+ // ── UI implementation ──────────────────────────────────────────────────────
230
+
231
+ return {
232
+ editorTheme,
233
+
234
+ // ── Layout ──────────────────────────────────────────────────────────────
235
+
236
+ bar: () => [bar],
237
+ blank: () => [""],
238
+
239
+ // ── Text elements ────────────────────────────────────────────────────────
240
+
241
+ header: (text) => [add(theme.fg("accent", theme.bold(text)))],
242
+
243
+ question: (text) => wrap(theme.fg("text", text)),
244
+
245
+ subtitle: (text) => wrap(theme.fg("text", text)),
246
+
247
+ meta: (text) => [add(theme.fg("dim", text))],
248
+
249
+ hints: (parts) => [add(theme.fg("dim", ` ${parts.join(" | ")}`))],
250
+
251
+ note: (text) => [add(theme.fg("dim", text))],
252
+
253
+ answer: (text) => [add(theme.fg("success", text))],
254
+
255
+ // ── Single-select options ────────────────────────────────────────────────
256
+
257
+ optionSelected: (num, label, description, isCommitted = false) => {
258
+ const marker = isCommitted ? theme.fg("success", ` ${GLYPH.check}`) : "";
259
+ const prefix = `${INDENT.option}${theme.fg("accent", INDENT.cursor)}`;
260
+ return [
261
+ ...wrap(`${prefix}${theme.fg("accent", `${num}. ${label}`)}${marker}`),
262
+ ...wrapIndented(`${INDENT.description}${theme.fg("muted", description)}`, INDENT.description),
263
+ ];
264
+ },
265
+
266
+ optionUnselected: (num, label, description, opts = {}) => {
267
+ const { isCommitted = false, isFocusDimmed = false } = opts;
268
+ const marker = isCommitted ? theme.fg("success", ` ${GLYPH.check}`) : "";
269
+ const labelColor = isFocusDimmed ? (isCommitted ? "text" : "dim") : "text";
270
+ const descColor = isFocusDimmed ? (isCommitted ? "muted" : "dim") : "muted";
271
+ return [
272
+ ...wrap(`${INDENT.option} ${theme.fg(labelColor, `${num}. ${label}`)}${marker}`),
273
+ ...wrapIndented(`${INDENT.description}${theme.fg(descColor, description)}`, INDENT.description),
274
+ ];
275
+ },
276
+
277
+ // ── Multi-select options ─────────────────────────────────────────────────
278
+
279
+ checkboxSelected: (label, description, isChecked) => {
280
+ const box = isChecked ? theme.fg("success", GLYPH.checkedBox) : theme.fg("dim", GLYPH.uncheckedBox);
281
+ return [
282
+ add(`${INDENT.option}${theme.fg("accent", GLYPH.cursor)} ${box} ${theme.fg("accent", label)}`),
283
+ ...wrapIndented(`${INDENT.description}${theme.fg("muted", description)}`, INDENT.description),
284
+ ];
285
+ },
286
+
287
+ checkboxUnselected: (label, description, isChecked, isFocusDimmed = false) => {
288
+ const box = isChecked ? theme.fg("success", GLYPH.checkedBox) : theme.fg("dim", GLYPH.uncheckedBox);
289
+ const labelColor = isFocusDimmed ? (isChecked ? "text" : "dim") : "text";
290
+ const descColor = isFocusDimmed ? (isChecked ? "muted" : "dim") : "muted";
291
+ return [
292
+ add(`${INDENT.option} ${box} ${theme.fg(labelColor, label)}`),
293
+ ...wrapIndented(`${INDENT.description}${theme.fg(descColor, description)}`, INDENT.description),
294
+ ];
295
+ },
296
+
297
+ // ── Special slots ────────────────────────────────────────────────────────
298
+
299
+ slotSelected: (label, description, isCommitted = false) => {
300
+ const marker = isCommitted ? theme.fg("success", ` ${GLYPH.check}`) : "";
301
+ return [
302
+ ...wrap(`${INDENT.option}${theme.fg("accent", `${GLYPH.cursor}${label}`)}${marker}`),
303
+ ...wrapIndented(`${INDENT.description}${theme.fg("muted", description)}`, INDENT.description),
304
+ ];
305
+ },
306
+
307
+ slotUnselected: (label, description, opts = {}) => {
308
+ const { isCommitted = false, isFocusDimmed = false } = opts;
309
+ const marker = isCommitted ? theme.fg("success", ` ${GLYPH.check}`) : "";
310
+ const labelColor = isFocusDimmed ? "dim" : "text";
311
+ const descColor = isFocusDimmed ? "dim" : "muted";
312
+ return [
313
+ ...wrap(`${INDENT.option} ${theme.fg(labelColor, label)}${marker}`),
314
+ ...wrapIndented(`${INDENT.description}${theme.fg(descColor, description)}`, INDENT.description),
315
+ ];
316
+ },
317
+
318
+ doneSelected: () => [
319
+ add(`${INDENT.option}${theme.fg("accent", INDENT.cursor)}${theme.bold(theme.fg("accent", "Done"))}`),
320
+ ],
321
+
322
+ doneUnselected: () => [
323
+ add(theme.fg("dim", `${INDENT.option} Done`)),
324
+ ],
325
+
326
+ // ── Action items ─────────────────────────────────────────────────────────
327
+
328
+ actionSelected: (num, label, description, tag) => {
329
+ const tagStr = tag ? theme.fg("dim", ` ${tag}`) : "";
330
+ const lines = [add(`${INDENT.option}${theme.fg("accent", GLYPH.cursor)} ${theme.fg("accent", `${num}. ${label}`)}${tagStr}`)];
331
+ if (description) lines.push(...wrap(`${INDENT.description}${theme.fg("muted", description)}`));
332
+ return lines;
333
+ },
334
+
335
+ actionUnselected: (num, label, description, tag) => {
336
+ const tagStr = tag ? theme.fg("dim", ` ${tag}`) : "";
337
+ const lines = [add(`${INDENT.option} ${theme.fg("text", `${num}. ${label}`)}${tagStr}`)];
338
+ if (description) lines.push(...wrap(`${INDENT.description}${theme.fg("dim", description)}`));
339
+ return lines;
340
+ },
341
+
342
+ actionDim: (num, label, description) => {
343
+ const lines = [add(`${INDENT.option} ${theme.fg("dim", `${num}. ${label}`)}`)];
344
+ if (description) lines.push(...wrap(`${INDENT.description}${theme.fg("dim", description)}`));
345
+ return lines;
346
+ },
347
+
348
+ // ── Progress indicators ───────────────────────────────────────────────────
349
+
350
+ pageDots: (total, currentIndex) => {
351
+ const dots = Array.from({ length: total }, (_, i) =>
352
+ i === currentIndex
353
+ ? theme.fg("accent", GLYPH.dotActive)
354
+ : i < currentIndex
355
+ ? theme.fg("success", GLYPH.dotDone)
356
+ : theme.fg("dim", GLYPH.dotActive),
357
+ ).join(theme.fg("dim", " β†’ "));
358
+ return [add(`${INDENT.base}${dots}`)];
359
+ },
360
+
361
+ questionTabs: (headers, currentIndex, answeredIndices) => {
362
+ const parts = headers.map((header, i) => {
363
+ const isCurrent = i === currentIndex;
364
+ const isAnswered = answeredIndices.has(i);
365
+ const label = ` ${isAnswered ? GLYPH.squareFilled : GLYPH.squareEmpty} ${header} `;
366
+ return isCurrent
367
+ ? theme.bg("selectedBg", theme.fg("text", label))
368
+ : theme.fg(isAnswered ? "success" : "muted", label);
369
+ });
370
+ return [add(` ← ${parts.join(" ")} β†’`)];
371
+ },
372
+
373
+ // ── Status primitives ──────────────────────────────────────────────────────
374
+
375
+ statusGlyph: (status) => theme.fg(STATUS_COLOR[status], STATUS_GLYPH[status]),
376
+
377
+ statusBadge: (text, status) => {
378
+ const color = STATUS_COLOR[status];
379
+ return [add(`${INDENT.base}${theme.fg(color, theme.bold(text))}`)];
380
+ },
381
+
382
+ progressItem: (label, status, opts = {}) => {
383
+ const glyph = theme.fg(STATUS_COLOR[status], STATUS_GLYPH[status]);
384
+ const labelColor = status === "done" ? "muted" : status === "pending" || status === "skipped" ? "dim" : "text";
385
+ const labelText = opts.emphasized ? theme.bold(theme.fg(labelColor, label)) : theme.fg(labelColor, label);
386
+ const detailText = opts.detail ? ` ${theme.fg("dim", opts.detail)}` : "";
387
+ return [add(`${INDENT.base}${glyph} ${labelText}${detailText}`)];
388
+ },
389
+
390
+ progressAnnotation: (text) => [add(`${INDENT.description}${theme.fg("dim", text)}`)],
391
+
392
+ // ── Notes area ────────────────────────────────────────────────────────────
393
+
394
+ notesLabel: (focused) => [
395
+ add(focused ? theme.fg("accent", " Notes:") : theme.fg("muted", " Notes:")),
396
+ ],
397
+
398
+ notesText: (text) => wrapIndented(` ${theme.fg("dim", text)}`, " "),
399
+ };
400
+ }