@kata-sh/cli 0.1.0 β 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +156 -0
- package/dist/app-paths.d.ts +4 -0
- package/dist/app-paths.js +6 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +56 -0
- package/dist/loader.d.ts +2 -0
- package/dist/loader.js +95 -0
- package/dist/resource-loader.d.ts +18 -0
- package/dist/resource-loader.js +50 -0
- package/dist/wizard.d.ts +15 -0
- package/dist/wizard.js +159 -0
- package/package.json +50 -21
- package/pkg/dist/modes/interactive/theme/dark.json +85 -0
- package/pkg/dist/modes/interactive/theme/light.json +84 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts +78 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme.js +949 -0
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -0
- package/pkg/package.json +8 -0
- package/scripts/postinstall.js +45 -0
- package/src/resources/AGENTS.md +108 -0
- package/src/resources/KATA-WORKFLOW.md +661 -0
- package/src/resources/agents/researcher.md +29 -0
- package/src/resources/agents/scout.md +56 -0
- package/src/resources/agents/worker.md +31 -0
- package/src/resources/extensions/ask-user-questions.ts +200 -0
- package/src/resources/extensions/bg-shell/index.ts +2758 -0
- package/src/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
- package/src/resources/extensions/browser-tools/core.js +1057 -0
- package/src/resources/extensions/browser-tools/index.ts +4916 -0
- package/src/resources/extensions/browser-tools/package.json +20 -0
- package/src/resources/extensions/context7/index.ts +428 -0
- package/src/resources/extensions/context7/package.json +11 -0
- package/src/resources/extensions/get-secrets-from-user.ts +352 -0
- package/src/resources/extensions/github/formatters.ts +207 -0
- package/src/resources/extensions/github/gh-api.ts +537 -0
- package/src/resources/extensions/github/index.ts +778 -0
- package/src/resources/extensions/kata/activity-log.ts +88 -0
- package/src/resources/extensions/kata/auto.ts +2786 -0
- package/src/resources/extensions/kata/commands.ts +355 -0
- package/src/resources/extensions/kata/crash-recovery.ts +85 -0
- package/src/resources/extensions/kata/dashboard-overlay.ts +516 -0
- package/src/resources/extensions/kata/docs/preferences-reference.md +103 -0
- package/src/resources/extensions/kata/doctor.ts +683 -0
- package/src/resources/extensions/kata/files.ts +730 -0
- package/src/resources/extensions/kata/gitignore.ts +165 -0
- package/src/resources/extensions/kata/guided-flow.ts +976 -0
- package/src/resources/extensions/kata/index.ts +556 -0
- package/src/resources/extensions/kata/metrics.ts +397 -0
- package/src/resources/extensions/kata/observability-validator.ts +408 -0
- package/src/resources/extensions/kata/package.json +11 -0
- package/src/resources/extensions/kata/paths.ts +346 -0
- package/src/resources/extensions/kata/preferences.ts +695 -0
- package/src/resources/extensions/kata/prompt-loader.ts +50 -0
- package/src/resources/extensions/kata/prompts/complete-milestone.md +25 -0
- package/src/resources/extensions/kata/prompts/complete-slice.md +27 -0
- package/src/resources/extensions/kata/prompts/discuss.md +151 -0
- package/src/resources/extensions/kata/prompts/doctor-heal.md +29 -0
- package/src/resources/extensions/kata/prompts/execute-task.md +64 -0
- package/src/resources/extensions/kata/prompts/guided-complete-slice.md +1 -0
- package/src/resources/extensions/kata/prompts/guided-discuss-milestone.md +3 -0
- package/src/resources/extensions/kata/prompts/guided-discuss-slice.md +59 -0
- package/src/resources/extensions/kata/prompts/guided-execute-task.md +1 -0
- package/src/resources/extensions/kata/prompts/guided-plan-milestone.md +23 -0
- package/src/resources/extensions/kata/prompts/guided-plan-slice.md +1 -0
- package/src/resources/extensions/kata/prompts/guided-research-slice.md +11 -0
- package/src/resources/extensions/kata/prompts/guided-resume-task.md +1 -0
- package/src/resources/extensions/kata/prompts/plan-milestone.md +47 -0
- package/src/resources/extensions/kata/prompts/plan-slice.md +63 -0
- package/src/resources/extensions/kata/prompts/queue.md +85 -0
- package/src/resources/extensions/kata/prompts/reassess-roadmap.md +48 -0
- package/src/resources/extensions/kata/prompts/replan-slice.md +39 -0
- package/src/resources/extensions/kata/prompts/research-milestone.md +37 -0
- package/src/resources/extensions/kata/prompts/research-slice.md +28 -0
- package/src/resources/extensions/kata/prompts/run-uat.md +109 -0
- package/src/resources/extensions/kata/prompts/system.md +341 -0
- package/src/resources/extensions/kata/session-forensics.ts +550 -0
- package/src/resources/extensions/kata/skill-discovery.ts +137 -0
- package/src/resources/extensions/kata/state.ts +509 -0
- package/src/resources/extensions/kata/templates/context.md +76 -0
- package/src/resources/extensions/kata/templates/decisions.md +8 -0
- package/src/resources/extensions/kata/templates/milestone-summary.md +73 -0
- package/src/resources/extensions/kata/templates/plan.md +133 -0
- package/src/resources/extensions/kata/templates/preferences.md +15 -0
- package/src/resources/extensions/kata/templates/project.md +31 -0
- package/src/resources/extensions/kata/templates/reassessment.md +28 -0
- package/src/resources/extensions/kata/templates/requirements.md +81 -0
- package/src/resources/extensions/kata/templates/research.md +46 -0
- package/src/resources/extensions/kata/templates/roadmap.md +118 -0
- package/src/resources/extensions/kata/templates/slice-context.md +58 -0
- package/src/resources/extensions/kata/templates/slice-summary.md +99 -0
- package/src/resources/extensions/kata/templates/state.md +19 -0
- package/src/resources/extensions/kata/templates/task-plan.md +52 -0
- package/src/resources/extensions/kata/templates/task-summary.md +57 -0
- package/src/resources/extensions/kata/templates/uat.md +54 -0
- package/src/resources/extensions/kata/tests/activity-log-prune.test.ts +327 -0
- package/src/resources/extensions/kata/tests/auto-preflight.test.ts +97 -0
- package/src/resources/extensions/kata/tests/auto-supervisor.test.mjs +53 -0
- package/src/resources/extensions/kata/tests/complete-milestone.test.ts +317 -0
- package/src/resources/extensions/kata/tests/cost-projection.test.ts +160 -0
- package/src/resources/extensions/kata/tests/derive-state-deps.test.ts +477 -0
- package/src/resources/extensions/kata/tests/derive-state.test.ts +1013 -0
- package/src/resources/extensions/kata/tests/doctor.test.ts +718 -0
- package/src/resources/extensions/kata/tests/idle-recovery.test.ts +490 -0
- package/src/resources/extensions/kata/tests/metrics-io.test.ts +254 -0
- package/src/resources/extensions/kata/tests/metrics.test.ts +217 -0
- package/src/resources/extensions/kata/tests/must-have-parser.test.ts +309 -0
- package/src/resources/extensions/kata/tests/parsers.test.ts +1257 -0
- package/src/resources/extensions/kata/tests/plan-milestone.test.ts +185 -0
- package/src/resources/extensions/kata/tests/plan-quality-validator.test.ts +386 -0
- package/src/resources/extensions/kata/tests/reassess-prompt.test.ts +208 -0
- package/src/resources/extensions/kata/tests/replan-slice.test.ts +686 -0
- package/src/resources/extensions/kata/tests/requirements.test.ts +151 -0
- package/src/resources/extensions/kata/tests/resolve-ts-hooks.mjs +17 -0
- package/src/resources/extensions/kata/tests/resolve-ts.mjs +11 -0
- package/src/resources/extensions/kata/tests/run-uat.test.ts +383 -0
- package/src/resources/extensions/kata/tests/unit-runtime.test.ts +388 -0
- package/src/resources/extensions/kata/tests/workspace-index.test.ts +118 -0
- package/src/resources/extensions/kata/tests/worktree.test.ts +222 -0
- package/src/resources/extensions/kata/types.ts +159 -0
- package/src/resources/extensions/kata/unit-runtime.ts +163 -0
- package/src/resources/extensions/kata/workspace-index.ts +203 -0
- package/src/resources/extensions/kata/worktree.ts +182 -0
- package/src/resources/extensions/mac-tools/index.ts +852 -0
- package/src/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
- package/src/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
- package/src/resources/extensions/search-the-web/cache.ts +78 -0
- package/src/resources/extensions/search-the-web/format.ts +258 -0
- package/src/resources/extensions/search-the-web/http.ts +238 -0
- package/src/resources/extensions/search-the-web/index.ts +68 -0
- package/src/resources/extensions/search-the-web/tool-fetch-page.ts +519 -0
- package/src/resources/extensions/search-the-web/tool-llm-context.ts +404 -0
- package/src/resources/extensions/search-the-web/tool-search.ts +503 -0
- package/src/resources/extensions/search-the-web/url-utils.ts +91 -0
- package/src/resources/extensions/shared/confirm-ui.ts +126 -0
- package/src/resources/extensions/shared/interview-ui.ts +822 -0
- package/src/resources/extensions/shared/next-action-ui.ts +235 -0
- package/src/resources/extensions/shared/progress-widget.ts +282 -0
- package/src/resources/extensions/shared/thinking-widget.ts +107 -0
- package/src/resources/extensions/shared/ui.ts +400 -0
- package/src/resources/extensions/shared/wizard-ui.ts +551 -0
- package/src/resources/extensions/slash-commands/audit.ts +92 -0
- package/src/resources/extensions/slash-commands/create-extension.ts +375 -0
- package/src/resources/extensions/slash-commands/create-slash-command.ts +280 -0
- package/src/resources/extensions/slash-commands/index.ts +12 -0
- package/src/resources/extensions/slash-commands/kata-run.ts +34 -0
- package/src/resources/extensions/subagent/agents.ts +126 -0
- package/src/resources/extensions/subagent/index.ts +1293 -0
- package/src/resources/skills/debug-like-expert/SKILL.md +231 -0
- package/src/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
- package/src/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
- package/src/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
- package/src/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
- package/src/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
- package/src/resources/skills/frontend-design/SKILL.md +45 -0
- package/src/resources/skills/swiftui/SKILL.md +208 -0
- package/src/resources/skills/swiftui/references/animations.md +921 -0
- package/src/resources/skills/swiftui/references/architecture.md +1561 -0
- package/src/resources/skills/swiftui/references/layout-system.md +1186 -0
- package/src/resources/skills/swiftui/references/navigation.md +1492 -0
- package/src/resources/skills/swiftui/references/networking-async.md +214 -0
- package/src/resources/skills/swiftui/references/performance.md +1706 -0
- package/src/resources/skills/swiftui/references/platform-integration.md +204 -0
- package/src/resources/skills/swiftui/references/state-management.md +1443 -0
- package/src/resources/skills/swiftui/references/swiftdata.md +297 -0
- package/src/resources/skills/swiftui/references/testing-debugging.md +247 -0
- package/src/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
- package/src/resources/skills/swiftui/workflows/add-feature.md +191 -0
- package/src/resources/skills/swiftui/workflows/build-new-app.md +311 -0
- package/src/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
- package/src/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
- package/src/resources/skills/swiftui/workflows/ship-app.md +203 -0
- package/src/resources/skills/swiftui/workflows/write-tests.md +235 -0
- package/dist/commands/task.d.ts +0 -9
- package/dist/commands/task.d.ts.map +0 -1
- package/dist/commands/task.js +0 -129
- package/dist/commands/task.js.map +0 -1
- package/dist/commands/task.test.d.ts +0 -2
- package/dist/commands/task.test.d.ts.map +0 -1
- package/dist/commands/task.test.js +0 -169
- package/dist/commands/task.test.js.map +0 -1
- package/dist/e2e/task-e2e.test.d.ts +0 -2
- package/dist/e2e/task-e2e.test.d.ts.map +0 -1
- package/dist/e2e/task-e2e.test.js +0 -173
- package/dist/e2e/task-e2e.test.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -93
- package/dist/index.js.map +0 -1
- package/dist/slug.d.ts +0 -2
- package/dist/slug.d.ts.map +0 -1
- package/dist/slug.js +0 -12
- package/dist/slug.js.map +0 -1
- package/dist/slug.test.d.ts +0 -2
- package/dist/slug.test.d.ts.map +0 -1
- package/dist/slug.test.js +0 -32
- 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
|
+
}
|