@compilr-dev/cli 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -0
- package/dist/agent.d.ts +62 -0
- package/dist/agent.js +317 -0
- package/dist/agents/registry.d.ts +66 -0
- package/dist/agents/registry.js +238 -0
- package/dist/agents/types.d.ts +40 -0
- package/dist/agents/types.js +94 -0
- package/dist/commands/custom-registry.d.ts +69 -0
- package/dist/commands/custom-registry.js +246 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/types.d.ts +31 -0
- package/dist/commands/types.js +26 -0
- package/dist/commands.d.ts +63 -0
- package/dist/commands.js +324 -0
- package/dist/db/index.d.ts +42 -0
- package/dist/db/index.js +146 -0
- package/dist/db/repositories/document-repository.d.ts +63 -0
- package/dist/db/repositories/document-repository.js +184 -0
- package/dist/db/repositories/index.d.ts +9 -0
- package/dist/db/repositories/index.js +6 -0
- package/dist/db/repositories/project-repository.d.ts +132 -0
- package/dist/db/repositories/project-repository.js +337 -0
- package/dist/db/repositories/work-item-repository.d.ts +115 -0
- package/dist/db/repositories/work-item-repository.js +389 -0
- package/dist/db/schema.d.ts +83 -0
- package/dist/db/schema.js +143 -0
- package/dist/debug.d.ts +8 -0
- package/dist/debug.js +48 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +348 -0
- package/dist/index.old.d.ts +7 -0
- package/dist/index.old.js +1014 -0
- package/dist/repl.d.ts +121 -0
- package/dist/repl.js +1878 -0
- package/dist/settings/index.d.ts +80 -0
- package/dist/settings/index.js +195 -0
- package/dist/shared-handlers.d.ts +63 -0
- package/dist/shared-handlers.js +57 -0
- package/dist/slash-autocomplete.d.ts +41 -0
- package/dist/slash-autocomplete.js +638 -0
- package/dist/state.d.ts +75 -0
- package/dist/state.js +130 -0
- package/dist/tabbed-menu.d.ts +11 -0
- package/dist/tabbed-menu.js +328 -0
- package/dist/templates/backlog-md.d.ts +7 -0
- package/dist/templates/backlog-md.js +94 -0
- package/dist/templates/claude-md.d.ts +7 -0
- package/dist/templates/claude-md.js +189 -0
- package/dist/templates/coding-standards.d.ts +7 -0
- package/dist/templates/coding-standards.js +299 -0
- package/dist/templates/compilr-md.d.ts +7 -0
- package/dist/templates/compilr-md.js +189 -0
- package/dist/templates/config-json.d.ts +38 -0
- package/dist/templates/config-json.js +39 -0
- package/dist/templates/gitignore.d.ts +7 -0
- package/dist/templates/gitignore.js +85 -0
- package/dist/templates/index.d.ts +19 -0
- package/dist/templates/index.js +302 -0
- package/dist/templates/package-json.d.ts +7 -0
- package/dist/templates/package-json.js +111 -0
- package/dist/templates/readme-md.d.ts +7 -0
- package/dist/templates/readme-md.js +161 -0
- package/dist/templates/tsconfig.d.ts +7 -0
- package/dist/templates/tsconfig.js +61 -0
- package/dist/templates/types.d.ts +33 -0
- package/dist/templates/types.js +24 -0
- package/dist/test-autocomplete.d.ts +7 -0
- package/dist/test-autocomplete.js +85 -0
- package/dist/test-tabbed-menu.d.ts +7 -0
- package/dist/test-tabbed-menu.js +25 -0
- package/dist/themes/colors.d.ts +49 -0
- package/dist/themes/colors.js +135 -0
- package/dist/themes/index.d.ts +23 -0
- package/dist/themes/index.js +24 -0
- package/dist/themes/registry.d.ts +60 -0
- package/dist/themes/registry.js +195 -0
- package/dist/themes/types.d.ts +82 -0
- package/dist/themes/types.js +7 -0
- package/dist/tool-selector.d.ts +71 -0
- package/dist/tool-selector.js +184 -0
- package/dist/tools/ask-user-simple.d.ts +19 -0
- package/dist/tools/ask-user-simple.js +86 -0
- package/dist/tools/ask-user.d.ts +32 -0
- package/dist/tools/ask-user.js +113 -0
- package/dist/tools/backlog.d.ts +53 -0
- package/dist/tools/backlog.js +709 -0
- package/dist/tools.d.ts +15 -0
- package/dist/tools.js +121 -0
- package/dist/ui/agents-overlay.d.ts +12 -0
- package/dist/ui/agents-overlay.js +501 -0
- package/dist/ui/arch-type-overlay.d.ts +20 -0
- package/dist/ui/arch-type-overlay.js +229 -0
- package/dist/ui/ask-user-overlay.d.ts +26 -0
- package/dist/ui/ask-user-overlay.js +647 -0
- package/dist/ui/ask-user-simple-overlay.d.ts +25 -0
- package/dist/ui/ask-user-simple-overlay.js +242 -0
- package/dist/ui/backlog-overlay.d.ts +17 -0
- package/dist/ui/backlog-overlay.js +786 -0
- package/dist/ui/commands-overlay.d.ts +11 -0
- package/dist/ui/commands-overlay.js +410 -0
- package/dist/ui/config-overlay.d.ts +34 -0
- package/dist/ui/config-overlay.js +977 -0
- package/dist/ui/conversation.d.ts +82 -0
- package/dist/ui/conversation.js +508 -0
- package/dist/ui/diff.d.ts +38 -0
- package/dist/ui/diff.js +182 -0
- package/dist/ui/ephemeral.d.ts +111 -0
- package/dist/ui/ephemeral.js +413 -0
- package/dist/ui/file-autocomplete.d.ts +45 -0
- package/dist/ui/file-autocomplete.js +237 -0
- package/dist/ui/footer.d.ts +153 -0
- package/dist/ui/footer.js +422 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.js +15 -0
- package/dist/ui/init-overlay.d.ts +24 -0
- package/dist/ui/init-overlay.js +525 -0
- package/dist/ui/input-prompt-v2.d.ts +179 -0
- package/dist/ui/input-prompt-v2.js +991 -0
- package/dist/ui/input-prompt.d.ts +97 -0
- package/dist/ui/input-prompt.js +800 -0
- package/dist/ui/iteration-limit-overlay.d.ts +21 -0
- package/dist/ui/iteration-limit-overlay.js +150 -0
- package/dist/ui/keys-overlay.d.ts +14 -0
- package/dist/ui/keys-overlay.js +181 -0
- package/dist/ui/model-warning-overlay.d.ts +30 -0
- package/dist/ui/model-warning-overlay.js +171 -0
- package/dist/ui/overlay-controller.d.ts +25 -0
- package/dist/ui/overlay-controller.js +35 -0
- package/dist/ui/overlays.d.ts +47 -0
- package/dist/ui/overlays.js +627 -0
- package/dist/ui/permission-overlay.d.ts +16 -0
- package/dist/ui/permission-overlay.js +494 -0
- package/dist/ui/terminal.d.ts +117 -0
- package/dist/ui/terminal.js +237 -0
- package/dist/ui/todo-zone.d.ts +112 -0
- package/dist/ui/todo-zone.js +353 -0
- package/dist/ui/tools-overlay.d.ts +26 -0
- package/dist/ui/tools-overlay.js +278 -0
- package/dist/ui/tutorial-overlay.d.ts +10 -0
- package/dist/ui/tutorial-overlay.js +936 -0
- package/dist/ui/types.d.ts +103 -0
- package/dist/ui/types.js +33 -0
- package/dist/utils/credentials.d.ts +55 -0
- package/dist/utils/credentials.js +268 -0
- package/dist/utils/model-tiers.d.ts +37 -0
- package/dist/utils/model-tiers.js +118 -0
- package/dist/utils/project-memory.d.ts +47 -0
- package/dist/utils/project-memory.js +117 -0
- package/dist/utils/project-status.d.ts +56 -0
- package/dist/utils/project-status.js +237 -0
- package/package.json +66 -0
|
@@ -0,0 +1,936 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tutorial Overlay
|
|
3
|
+
*
|
|
4
|
+
* Interactive tutorial that guides users through the compilr.dev workflow.
|
|
5
|
+
* Supports guided sequential tour and topic-based navigation.
|
|
6
|
+
*/
|
|
7
|
+
import * as terminal from './terminal.js';
|
|
8
|
+
import { getStyles } from '../themes/index.js';
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Helper
|
|
11
|
+
// =============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Strip ANSI codes from string to get visible length
|
|
14
|
+
*/
|
|
15
|
+
function stripAnsi(str) {
|
|
16
|
+
// eslint-disable-next-line no-control-regex
|
|
17
|
+
return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
|
18
|
+
}
|
|
19
|
+
function getBorder() {
|
|
20
|
+
const s = getStyles();
|
|
21
|
+
const cols = terminal.getTerminalWidth();
|
|
22
|
+
return s.muted('─'.repeat(Math.max(1, cols - 1)));
|
|
23
|
+
}
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Content
|
|
26
|
+
// =============================================================================
|
|
27
|
+
function buildTopics() {
|
|
28
|
+
const s = getStyles();
|
|
29
|
+
return [
|
|
30
|
+
// =========================================================================
|
|
31
|
+
// Topic 1: Workflow Overview
|
|
32
|
+
// =========================================================================
|
|
33
|
+
{
|
|
34
|
+
id: 'overview',
|
|
35
|
+
name: 'Workflow Overview',
|
|
36
|
+
description: 'The philosophy and stages',
|
|
37
|
+
pages: [
|
|
38
|
+
{
|
|
39
|
+
title: 'Philosophy',
|
|
40
|
+
lines: [
|
|
41
|
+
'',
|
|
42
|
+
` ${s.primaryBold('compilr.dev')} is built on five core principles:`,
|
|
43
|
+
'',
|
|
44
|
+
` ${s.primary('1. Structured')}`,
|
|
45
|
+
` Follow an organized workflow instead of ad-hoc coding.`,
|
|
46
|
+
` Every project has clear phases and documentation.`,
|
|
47
|
+
'',
|
|
48
|
+
` ${s.primary('2. Disciplined')}`,
|
|
49
|
+
` Move through clear phases from design to delivery.`,
|
|
50
|
+
` Don't skip steps - each builds on the previous.`,
|
|
51
|
+
'',
|
|
52
|
+
` ${s.primary('3. Intentional')}`,
|
|
53
|
+
` Every feature starts with requirements, not code.`,
|
|
54
|
+
` Know what you're building before you build it.`,
|
|
55
|
+
'',
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: 'Philosophy (continued)',
|
|
60
|
+
lines: [
|
|
61
|
+
'',
|
|
62
|
+
` ${s.primary('4. Engineering-First')}`,
|
|
63
|
+
` Follow best practices: testing, documentation, code review.`,
|
|
64
|
+
` Build software that's maintainable long-term.`,
|
|
65
|
+
'',
|
|
66
|
+
` ${s.primary('5. Flexible')}`,
|
|
67
|
+
` Adapt the workflow to your needs.`,
|
|
68
|
+
` Use what works, skip what doesn't.`,
|
|
69
|
+
'',
|
|
70
|
+
` The AI assistant guides you through each stage, helping you build`,
|
|
71
|
+
` projects with ${s.primary('structure')} and ${s.primary('discipline')} - not just generating random code.`,
|
|
72
|
+
'',
|
|
73
|
+
` ${s.muted('The goal: sustainable development with AI assistance.')}`,
|
|
74
|
+
'',
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
title: 'The Workflow Stages',
|
|
79
|
+
lines: [
|
|
80
|
+
'',
|
|
81
|
+
` The development workflow has five main stages:`,
|
|
82
|
+
'',
|
|
83
|
+
` ${s.primary('/init')} Set up your project structure`,
|
|
84
|
+
` Creates COMPILR.md, backlog.md, and configuration`,
|
|
85
|
+
'',
|
|
86
|
+
` ${s.primary('/design')} Gather requirements and create a PRD`,
|
|
87
|
+
` Comprehensive planning through conversation`,
|
|
88
|
+
'',
|
|
89
|
+
` ${s.primary('/backlog')} Manage your work items`,
|
|
90
|
+
` Prioritize, track status, break down tasks`,
|
|
91
|
+
'',
|
|
92
|
+
` ${s.primary('/build')} Implement features from the backlog`,
|
|
93
|
+
` AI-assisted coding with your approval`,
|
|
94
|
+
'',
|
|
95
|
+
` ${s.secondary('Iterate')} Refine and improve continuously`,
|
|
96
|
+
` Use /refine, /arch, /prd to evolve the project`,
|
|
97
|
+
'',
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
// =========================================================================
|
|
103
|
+
// Topic 2: Initialize
|
|
104
|
+
// =========================================================================
|
|
105
|
+
{
|
|
106
|
+
id: 'init',
|
|
107
|
+
name: 'Initialize',
|
|
108
|
+
description: 'Setting up a new project',
|
|
109
|
+
pages: [
|
|
110
|
+
{
|
|
111
|
+
title: '/init Command',
|
|
112
|
+
lines: [
|
|
113
|
+
'',
|
|
114
|
+
` ${s.primaryBold('/init')} creates your project foundation through an 8-step wizard.`,
|
|
115
|
+
'',
|
|
116
|
+
` ${s.secondary('What it creates:')}`,
|
|
117
|
+
'',
|
|
118
|
+
` ${s.success('+')} Project directory with proper structure`,
|
|
119
|
+
` ${s.success('+')} ${s.primary('COMPILR.md')} - Context file for the AI assistant`,
|
|
120
|
+
` ${s.success('+')} ${s.primary('backlog.md')} - Work item tracking`,
|
|
121
|
+
` ${s.success('+')} ${s.primary('.compilr/config.json')} - Project configuration`,
|
|
122
|
+
` ${s.success('+')} Tech stack setup based on your choices`,
|
|
123
|
+
'',
|
|
124
|
+
` ${s.secondary('The wizard asks about:')}`,
|
|
125
|
+
` - Project name and description`,
|
|
126
|
+
` - Project type (web, api, cli, fullstack)`,
|
|
127
|
+
` - Tech stack preferences`,
|
|
128
|
+
` - Documentation setup (single or two repos)`,
|
|
129
|
+
'',
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
title: '/init - Setup Options',
|
|
134
|
+
lines: [
|
|
135
|
+
'',
|
|
136
|
+
` ${s.secondary('Single Repository Setup')}`,
|
|
137
|
+
` Everything in one directory: code, docs, and backlog.`,
|
|
138
|
+
` Best for: small projects, personal projects, quick starts.`,
|
|
139
|
+
'',
|
|
140
|
+
` ${s.secondary('Two Repository Setup')}`,
|
|
141
|
+
` Separate repository for documentation and planning.`,
|
|
142
|
+
` Best for: team projects, complex projects, when you want`,
|
|
143
|
+
` to keep planning separate from code.`,
|
|
144
|
+
'',
|
|
145
|
+
` ${s.muted('Tip: Run /init in an empty directory to start fresh.')}`,
|
|
146
|
+
'',
|
|
147
|
+
` After /init completes, the AI reads your COMPILR.md to understand`,
|
|
148
|
+
` your project context. You're ready for the next step: ${s.primary('/design')}`,
|
|
149
|
+
'',
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
// =========================================================================
|
|
155
|
+
// Topic 3: Design
|
|
156
|
+
// =========================================================================
|
|
157
|
+
{
|
|
158
|
+
id: 'design',
|
|
159
|
+
name: 'Design Your Project',
|
|
160
|
+
description: 'Requirements gathering',
|
|
161
|
+
pages: [
|
|
162
|
+
{
|
|
163
|
+
title: '/design Command',
|
|
164
|
+
lines: [
|
|
165
|
+
'',
|
|
166
|
+
` ${s.primaryBold('/design')} is comprehensive requirements gathering through conversation.`,
|
|
167
|
+
'',
|
|
168
|
+
` The AI guides you through three phases:`,
|
|
169
|
+
'',
|
|
170
|
+
` ${s.primary('Phase 1: Vision & Goals')}`,
|
|
171
|
+
` - What problem are you solving?`,
|
|
172
|
+
` - Who is your target user?`,
|
|
173
|
+
` - What does success look like?`,
|
|
174
|
+
'',
|
|
175
|
+
` ${s.primary('Phase 2: Features & Scope')}`,
|
|
176
|
+
` - What are the core features?`,
|
|
177
|
+
` - What's nice-to-have vs essential?`,
|
|
178
|
+
` - What's explicitly out of scope?`,
|
|
179
|
+
'',
|
|
180
|
+
` ${s.primary('Phase 3: Technical Context')}`,
|
|
181
|
+
` - What constraints exist?`,
|
|
182
|
+
` - What integrations are needed?`,
|
|
183
|
+
` - What are your preferences?`,
|
|
184
|
+
'',
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
title: '/design - Output',
|
|
189
|
+
lines: [
|
|
190
|
+
'',
|
|
191
|
+
` ${s.secondary('What /design creates:')}`,
|
|
192
|
+
'',
|
|
193
|
+
` ${s.success('+')} ${s.primary('Product Requirements Document (PRD)')}`,
|
|
194
|
+
` A comprehensive document capturing your vision,`,
|
|
195
|
+
` features, technical requirements, and constraints.`,
|
|
196
|
+
'',
|
|
197
|
+
` ${s.success('+')} ${s.primary('5-15 Backlog Items')}`,
|
|
198
|
+
` Auto-generated from your requirements,`,
|
|
199
|
+
` ready to be built with /build.`,
|
|
200
|
+
'',
|
|
201
|
+
` ${s.success('+')} ${s.primary('Clear Acceptance Criteria')}`,
|
|
202
|
+
` Each backlog item has defined done criteria`,
|
|
203
|
+
` so you know when it's complete.`,
|
|
204
|
+
'',
|
|
205
|
+
` ${s.muted('Best for: serious projects that need thorough planning upfront.')}`,
|
|
206
|
+
` ${s.muted('Expect: 30+ minute conversation to capture everything.')}`,
|
|
207
|
+
'',
|
|
208
|
+
],
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
title: '/sketch Command',
|
|
212
|
+
lines: [
|
|
213
|
+
'',
|
|
214
|
+
` ${s.primaryBold('/sketch')} is a quick alternative to /design.`,
|
|
215
|
+
'',
|
|
216
|
+
` Instead of a long conversation, it asks 6 simple questions:`,
|
|
217
|
+
'',
|
|
218
|
+
` ${s.muted('1.')} What are you building?`,
|
|
219
|
+
` ${s.muted('2.')} Who is it for?`,
|
|
220
|
+
` ${s.muted('3.')} What are the 3-5 main features?`,
|
|
221
|
+
` ${s.muted('4.')} What tech stack?`,
|
|
222
|
+
` ${s.muted('5.')} Any constraints or requirements?`,
|
|
223
|
+
` ${s.muted('6.')} What's the MVP scope?`,
|
|
224
|
+
'',
|
|
225
|
+
` ${s.secondary('Output:')} 3-8 backlog items, ready to build.`,
|
|
226
|
+
'',
|
|
227
|
+
` ${s.muted('Best for: small projects, prototypes, or when you just')}`,
|
|
228
|
+
` ${s.muted('want to get started quickly without detailed planning.')}`,
|
|
229
|
+
'',
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
title: '/refine Command',
|
|
234
|
+
lines: [
|
|
235
|
+
'',
|
|
236
|
+
` ${s.primaryBold('/refine')} improves existing backlog items.`,
|
|
237
|
+
'',
|
|
238
|
+
` ${s.secondary('Use it to:')}`,
|
|
239
|
+
'',
|
|
240
|
+
` ${s.muted('+')} Break down large items into smaller, actionable tasks`,
|
|
241
|
+
` ${s.muted('+')} Add acceptance criteria to vague items`,
|
|
242
|
+
` ${s.muted('+')} Clarify ambiguous requirements`,
|
|
243
|
+
` ${s.muted('+')} Add technical details discovered during work`,
|
|
244
|
+
'',
|
|
245
|
+
` ${s.secondary('Usage:')}`,
|
|
246
|
+
` ${s.primary('/refine')} Let the AI suggest what to refine`,
|
|
247
|
+
` ${s.primary('/refine REQ-003')} Refine a specific item`,
|
|
248
|
+
'',
|
|
249
|
+
` ${s.muted('Best for: after initial design when you discover items')}`,
|
|
250
|
+
` ${s.muted('are too big or need more detail before building.')}`,
|
|
251
|
+
'',
|
|
252
|
+
],
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
title: '/arch Command',
|
|
256
|
+
lines: [
|
|
257
|
+
'',
|
|
258
|
+
` ${s.primaryBold('/arch')} creates architecture documentation.`,
|
|
259
|
+
'',
|
|
260
|
+
` ${s.secondary('Document types you can create:')}`,
|
|
261
|
+
'',
|
|
262
|
+
` ${s.muted('1.')} ${s.primary('ADR')} - Architecture Decision Record`,
|
|
263
|
+
` Document key technical decisions and their rationale`,
|
|
264
|
+
'',
|
|
265
|
+
` ${s.muted('2.')} ${s.primary('System Diagram')} - Visual system overview`,
|
|
266
|
+
` Components, connections, data flow`,
|
|
267
|
+
'',
|
|
268
|
+
` ${s.muted('3.')} ${s.primary('Data Model')} - Database/entity design`,
|
|
269
|
+
` Tables, relationships, constraints`,
|
|
270
|
+
'',
|
|
271
|
+
` ${s.muted('4.')} ${s.primary('API Design')} - Endpoint documentation`,
|
|
272
|
+
` Routes, methods, request/response formats`,
|
|
273
|
+
'',
|
|
274
|
+
` ${s.muted('5.')} ${s.primary('Component Overview')} - Module documentation`,
|
|
275
|
+
` How pieces fit together`,
|
|
276
|
+
'',
|
|
277
|
+
],
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
title: '/prd Command',
|
|
281
|
+
lines: [
|
|
282
|
+
'',
|
|
283
|
+
` ${s.primaryBold('/prd')} lets you update your Product Requirements Document.`,
|
|
284
|
+
'',
|
|
285
|
+
` After /design creates your PRD, use /prd to amend it as`,
|
|
286
|
+
` your understanding evolves.`,
|
|
287
|
+
'',
|
|
288
|
+
` ${s.secondary('Usage:')}`,
|
|
289
|
+
` ${s.primary('/prd')} Interactive section selection`,
|
|
290
|
+
` ${s.primary('/prd vision')} Update vision section directly`,
|
|
291
|
+
` ${s.primary('/prd scope')} Update scope section directly`,
|
|
292
|
+
` ${s.primary('/prd features')} Update features section directly`,
|
|
293
|
+
'',
|
|
294
|
+
` ${s.secondary('Sections you can update:')}`,
|
|
295
|
+
` - Vision and goals`,
|
|
296
|
+
` - Features and scope`,
|
|
297
|
+
` - Technical context`,
|
|
298
|
+
` - Non-functional requirements`,
|
|
299
|
+
'',
|
|
300
|
+
],
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
},
|
|
304
|
+
// =========================================================================
|
|
305
|
+
// Topic 4: Backlog
|
|
306
|
+
// =========================================================================
|
|
307
|
+
{
|
|
308
|
+
id: 'backlog',
|
|
309
|
+
name: 'Manage Backlog',
|
|
310
|
+
description: 'Track and prioritize work',
|
|
311
|
+
pages: [
|
|
312
|
+
{
|
|
313
|
+
title: '/backlog Command',
|
|
314
|
+
lines: [
|
|
315
|
+
'',
|
|
316
|
+
` ${s.primaryBold('/backlog')} opens an interactive overlay to manage your work items.`,
|
|
317
|
+
'',
|
|
318
|
+
` ${s.secondary('Navigation:')}`,
|
|
319
|
+
` ${s.primary('↑/↓')} Navigate through items`,
|
|
320
|
+
` ${s.primary('←/→')} Navigate pages (if many items)`,
|
|
321
|
+
` ${s.primary('Tab')} Switch filter (All, Feature, Bug, etc.)`,
|
|
322
|
+
` ${s.primary('/')} Search items`,
|
|
323
|
+
` ${s.primary('Enter')} View/edit item details`,
|
|
324
|
+
'',
|
|
325
|
+
` ${s.secondary('Actions:')}`,
|
|
326
|
+
` ${s.primary('n')} Create new item`,
|
|
327
|
+
` ${s.primary('Space')} Toggle item status`,
|
|
328
|
+
` ${s.primary('p')} Change priority`,
|
|
329
|
+
` ${s.primary('Esc')} Close overlay`,
|
|
330
|
+
'',
|
|
331
|
+
],
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
title: '/backlog - Status Workflow',
|
|
335
|
+
lines: [
|
|
336
|
+
'',
|
|
337
|
+
` Items move through three statuses:`,
|
|
338
|
+
'',
|
|
339
|
+
` ${s.warning('pending')} Not started yet`,
|
|
340
|
+
` ${s.muted('↓')}`,
|
|
341
|
+
` ${s.primary('in-progress')} Currently being worked on`,
|
|
342
|
+
` ${s.muted('↓')}`,
|
|
343
|
+
` ${s.success('done')} Completed`,
|
|
344
|
+
'',
|
|
345
|
+
` ${s.secondary('Item Types:')}`,
|
|
346
|
+
` ${s.muted('Feature')} New functionality to build`,
|
|
347
|
+
` ${s.muted('Bug')} Something broken to fix`,
|
|
348
|
+
` ${s.muted('Tech-Debt')} Code improvements needed`,
|
|
349
|
+
` ${s.muted('Chore')} Maintenance tasks`,
|
|
350
|
+
'',
|
|
351
|
+
` Items are stored in ${s.primary('backlog.md')} and can also be edited manually.`,
|
|
352
|
+
'',
|
|
353
|
+
],
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
},
|
|
357
|
+
// =========================================================================
|
|
358
|
+
// Topic 5: Build
|
|
359
|
+
// =========================================================================
|
|
360
|
+
{
|
|
361
|
+
id: 'build',
|
|
362
|
+
name: 'Build',
|
|
363
|
+
description: 'Scaffold and implement',
|
|
364
|
+
pages: [
|
|
365
|
+
{
|
|
366
|
+
title: '/scaffold Command',
|
|
367
|
+
lines: [
|
|
368
|
+
'',
|
|
369
|
+
` ${s.primaryBold('/scaffold')} creates your project's foundation structure.`,
|
|
370
|
+
'',
|
|
371
|
+
` ${s.secondary('What it creates:')}`,
|
|
372
|
+
'',
|
|
373
|
+
` ${s.success('+')} Directory structure (src/, tests/, etc.)`,
|
|
374
|
+
` ${s.success('+')} Configuration files (package.json, tsconfig, etc.)`,
|
|
375
|
+
` ${s.success('+')} Dependencies installation`,
|
|
376
|
+
` ${s.success('+')} Basic boilerplate code`,
|
|
377
|
+
` ${s.success('+')} Development scripts`,
|
|
378
|
+
'',
|
|
379
|
+
` The agent reads your ${s.primary('COMPILR.md')} to understand your tech stack`,
|
|
380
|
+
` and creates an appropriate project structure.`,
|
|
381
|
+
'',
|
|
382
|
+
` ${s.muted('When to use: before implementing features, when starting')}`,
|
|
383
|
+
` ${s.muted('from an empty project directory.')}`,
|
|
384
|
+
'',
|
|
385
|
+
],
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
title: '/build Command',
|
|
389
|
+
lines: [
|
|
390
|
+
'',
|
|
391
|
+
` ${s.primaryBold('/build')} implements backlog items.`,
|
|
392
|
+
'',
|
|
393
|
+
` ${s.secondary('Usage:')}`,
|
|
394
|
+
` ${s.primary('/build')} Pick the highest priority pending item`,
|
|
395
|
+
` ${s.primary('/build REQ-003')} Build a specific item by ID`,
|
|
396
|
+
` ${s.primary('/build scaffold')} Same as /scaffold`,
|
|
397
|
+
'',
|
|
398
|
+
` ${s.secondary('The agent will:')}`,
|
|
399
|
+
` ${s.muted('1.')} Read and analyze the requirement`,
|
|
400
|
+
` ${s.muted('2.')} Plan the implementation approach`,
|
|
401
|
+
` ${s.muted('3.')} Write the code (with your approval)`,
|
|
402
|
+
` ${s.muted('4.')} Run tests if available`,
|
|
403
|
+
` ${s.muted('5.')} Update the backlog status to done`,
|
|
404
|
+
'',
|
|
405
|
+
],
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
title: '/build - Permissions',
|
|
409
|
+
lines: [
|
|
410
|
+
'',
|
|
411
|
+
` During /build, you'll see permission prompts for:`,
|
|
412
|
+
'',
|
|
413
|
+
` ${s.warning('File changes')}`,
|
|
414
|
+
` The AI shows exactly what will be changed`,
|
|
415
|
+
` with a diff view before you approve.`,
|
|
416
|
+
'',
|
|
417
|
+
` ${s.warning('Shell commands')}`,
|
|
418
|
+
` Commands like npm install or running tests`,
|
|
419
|
+
` require your explicit approval.`,
|
|
420
|
+
'',
|
|
421
|
+
` ${s.secondary('Review carefully before approving!')}`,
|
|
422
|
+
` The AI shows exactly what will happen so you stay in control.`,
|
|
423
|
+
'',
|
|
424
|
+
` ${s.muted('Tip: If /build detects an empty project, it will')}`,
|
|
425
|
+
` ${s.muted('suggest running /scaffold first.')}`,
|
|
426
|
+
'',
|
|
427
|
+
],
|
|
428
|
+
},
|
|
429
|
+
],
|
|
430
|
+
},
|
|
431
|
+
// =========================================================================
|
|
432
|
+
// Topic 6: Configuration
|
|
433
|
+
// =========================================================================
|
|
434
|
+
{
|
|
435
|
+
id: 'config',
|
|
436
|
+
name: 'Configuration',
|
|
437
|
+
description: 'Settings, keys, and themes',
|
|
438
|
+
pages: [
|
|
439
|
+
{
|
|
440
|
+
title: '/config Command',
|
|
441
|
+
lines: [
|
|
442
|
+
'',
|
|
443
|
+
` ${s.primaryBold('/config')} opens the settings panel.`,
|
|
444
|
+
'',
|
|
445
|
+
` ${s.secondary('Tabs:')}`,
|
|
446
|
+
` ${s.primary('Status')} Version, model, session info`,
|
|
447
|
+
` ${s.primary('Config')} Interactive settings`,
|
|
448
|
+
` ${s.primary('Usage')} Token usage statistics`,
|
|
449
|
+
'',
|
|
450
|
+
` ${s.secondary('Settings you can change:')}`,
|
|
451
|
+
` ${s.muted('Model')} Switch AI model/provider`,
|
|
452
|
+
` ${s.muted('Theme')} Choose from 400+ terminal themes`,
|
|
453
|
+
` ${s.muted('Permissions')} Control approval prompts`,
|
|
454
|
+
` ${s.muted('Output')} Verbose or minimal mode`,
|
|
455
|
+
` ${s.muted('Auto-compact')} Automatic context management`,
|
|
456
|
+
'',
|
|
457
|
+
],
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
title: '/keys Command',
|
|
461
|
+
lines: [
|
|
462
|
+
'',
|
|
463
|
+
` ${s.primaryBold('/keys')} manages your API keys for LLM providers.`,
|
|
464
|
+
'',
|
|
465
|
+
` ${s.secondary('Supported providers:')}`,
|
|
466
|
+
` ${s.primary('Claude')} Anthropic's models (best reasoning)`,
|
|
467
|
+
` ${s.primary('OpenAI')} GPT-4o and other models`,
|
|
468
|
+
` ${s.primary('Gemini')} Google AI models`,
|
|
469
|
+
` ${s.primary('Ollama')} Local models (no API key needed)`,
|
|
470
|
+
'',
|
|
471
|
+
` Keys are encrypted and stored locally in:`,
|
|
472
|
+
` ${s.muted('~/.compilr-dev/credentials.enc')}`,
|
|
473
|
+
'',
|
|
474
|
+
` ${s.muted('The CLI automatically opens /keys on first run')}`,
|
|
475
|
+
` ${s.muted('if no API key is configured.')}`,
|
|
476
|
+
'',
|
|
477
|
+
],
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
},
|
|
481
|
+
// =========================================================================
|
|
482
|
+
// Topic 7: Working with the Agent
|
|
483
|
+
// =========================================================================
|
|
484
|
+
{
|
|
485
|
+
id: 'agent',
|
|
486
|
+
name: 'Working with the Agent',
|
|
487
|
+
description: 'Chat, permissions, tips',
|
|
488
|
+
pages: [
|
|
489
|
+
{
|
|
490
|
+
title: 'Chatting with the AI',
|
|
491
|
+
lines: [
|
|
492
|
+
'',
|
|
493
|
+
` Just type naturally. The AI understands context and can help with:`,
|
|
494
|
+
'',
|
|
495
|
+
` ${s.muted('+')} Answering questions about your code`,
|
|
496
|
+
` ${s.muted('+')} Explaining how something works`,
|
|
497
|
+
` ${s.muted('+')} Writing new code or features`,
|
|
498
|
+
` ${s.muted('+')} Debugging issues`,
|
|
499
|
+
` ${s.muted('+')} Refactoring existing code`,
|
|
500
|
+
` ${s.muted('+')} Running commands and tests`,
|
|
501
|
+
'',
|
|
502
|
+
` ${s.secondary('File References')}`,
|
|
503
|
+
` Type ${s.primary('@')} to autocomplete file paths.`,
|
|
504
|
+
` Example: ${s.muted('"Fix the bug in @src/utils.ts"')}`,
|
|
505
|
+
'',
|
|
506
|
+
` The AI will read the file and understand the context.`,
|
|
507
|
+
'',
|
|
508
|
+
],
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
title: 'Permissions',
|
|
512
|
+
lines: [
|
|
513
|
+
'',
|
|
514
|
+
` The agent asks permission before:`,
|
|
515
|
+
'',
|
|
516
|
+
` ${s.warning('+')} Modifying or creating files`,
|
|
517
|
+
` ${s.warning('+')} Running shell commands`,
|
|
518
|
+
` ${s.warning('+')} Making git commits`,
|
|
519
|
+
'',
|
|
520
|
+
` ${s.secondary('For each action, you can:')}`,
|
|
521
|
+
` ${s.primary('Allow')} Approve this specific action`,
|
|
522
|
+
` ${s.primary('Allow Always')} Auto-approve this tool for the session`,
|
|
523
|
+
` ${s.primary('Deny')} Reject this action`,
|
|
524
|
+
'',
|
|
525
|
+
` For file edits, you'll see a diff showing exactly what changes.`,
|
|
526
|
+
` Review carefully - you're always in control.`,
|
|
527
|
+
'',
|
|
528
|
+
],
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
title: 'Suggestions',
|
|
532
|
+
lines: [
|
|
533
|
+
'',
|
|
534
|
+
` After completing tasks, the AI suggests next actions.`,
|
|
535
|
+
'',
|
|
536
|
+
` ${s.secondary('How it works:')}`,
|
|
537
|
+
` Suggestions appear as ${s.muted('ghost text')} in your input prompt.`,
|
|
538
|
+
` Press ${s.primary('Tab')} to accept the suggestion.`,
|
|
539
|
+
` Or just keep typing to ignore it.`,
|
|
540
|
+
'',
|
|
541
|
+
` ${s.secondary('Common suggestions:')}`,
|
|
542
|
+
` ${s.muted('"run the tests"')}`,
|
|
543
|
+
` ${s.muted('"commit the changes"')}`,
|
|
544
|
+
` ${s.muted('"build the next item"')}`,
|
|
545
|
+
'',
|
|
546
|
+
` Suggestions help maintain workflow momentum.`,
|
|
547
|
+
'',
|
|
548
|
+
],
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
title: 'Context Management',
|
|
552
|
+
lines: [
|
|
553
|
+
'',
|
|
554
|
+
` The AI has a limited context window. When it fills up:`,
|
|
555
|
+
'',
|
|
556
|
+
` ${s.primaryBold('/compact')}`,
|
|
557
|
+
` Summarizes old messages to free up space.`,
|
|
558
|
+
` The AI creates a summary and removes old messages.`,
|
|
559
|
+
'',
|
|
560
|
+
` ${s.primaryBold('/context')}`,
|
|
561
|
+
` Shows current context usage (tokens used / available).`,
|
|
562
|
+
'',
|
|
563
|
+
` ${s.primaryBold('/tokens')}`,
|
|
564
|
+
` Shows token usage statistics for the session.`,
|
|
565
|
+
'',
|
|
566
|
+
` ${s.muted('Tip: Auto-compact is enabled by default in settings.')}`,
|
|
567
|
+
` ${s.muted('The AI will automatically summarize when needed.')}`,
|
|
568
|
+
'',
|
|
569
|
+
],
|
|
570
|
+
},
|
|
571
|
+
],
|
|
572
|
+
},
|
|
573
|
+
// =========================================================================
|
|
574
|
+
// Topic 8: Tips & Tricks
|
|
575
|
+
// =========================================================================
|
|
576
|
+
{
|
|
577
|
+
id: 'tips',
|
|
578
|
+
name: 'Tips & Tricks',
|
|
579
|
+
description: 'Shortcuts and best practices',
|
|
580
|
+
pages: [
|
|
581
|
+
{
|
|
582
|
+
title: 'Keyboard Shortcuts',
|
|
583
|
+
lines: [
|
|
584
|
+
'',
|
|
585
|
+
` ${s.secondary('Input:')}`,
|
|
586
|
+
` ${s.primary('Tab')} Accept suggestion or autocomplete`,
|
|
587
|
+
` ${s.primary('Esc')} Cancel current operation`,
|
|
588
|
+
` ${s.primary('Ctrl+C')} Stop the agent or exit`,
|
|
589
|
+
'',
|
|
590
|
+
` ${s.secondary('In Overlays:')}`,
|
|
591
|
+
` ${s.primary('↑/↓')} Navigate options`,
|
|
592
|
+
` ${s.primary('←/→')} Navigate pages or tabs`,
|
|
593
|
+
` ${s.primary('Tab')} Switch tabs (where applicable)`,
|
|
594
|
+
` ${s.primary('Enter')} Confirm selection`,
|
|
595
|
+
` ${s.primary('Esc')} Go back or close`,
|
|
596
|
+
'',
|
|
597
|
+
` ${s.secondary('Special:')}`,
|
|
598
|
+
` ${s.primary('@')} Start file autocomplete`,
|
|
599
|
+
` ${s.primary('/')} Start command autocomplete`,
|
|
600
|
+
'',
|
|
601
|
+
],
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
title: 'Useful Commands',
|
|
605
|
+
lines: [
|
|
606
|
+
'',
|
|
607
|
+
` ${s.secondary('Information:')}`,
|
|
608
|
+
` ${s.primary('/help')} Full command reference`,
|
|
609
|
+
` ${s.primary('/status')} Version, model, mode info`,
|
|
610
|
+
` ${s.primary('/tools')} List available tools`,
|
|
611
|
+
'',
|
|
612
|
+
` ${s.secondary('Session:')}`,
|
|
613
|
+
` ${s.primary('/note')} Create session documentation`,
|
|
614
|
+
` ${s.primary('/export')} Export conversation`,
|
|
615
|
+
` ${s.primary('/clear')} Clear the screen`,
|
|
616
|
+
'',
|
|
617
|
+
` ${s.secondary('Mode:')}`,
|
|
618
|
+
` ${s.primary('/plan')} Switch to planning mode`,
|
|
619
|
+
` (focus on design, not implementation)`,
|
|
620
|
+
'',
|
|
621
|
+
],
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
title: 'Best Practices',
|
|
625
|
+
lines: [
|
|
626
|
+
'',
|
|
627
|
+
` ${s.primary('1.')} Start with ${s.primaryBold('/init')}, then ${s.primaryBold('/design')} or ${s.primaryBold('/sketch')}`,
|
|
628
|
+
` Don't skip planning - it pays off later.`,
|
|
629
|
+
'',
|
|
630
|
+
` ${s.primary('2.')} Keep backlog items small and focused`,
|
|
631
|
+
` Break large features into smaller tasks.`,
|
|
632
|
+
'',
|
|
633
|
+
` ${s.primary('3.')} Review AI suggestions before approving`,
|
|
634
|
+
` You're in control - understand what's changing.`,
|
|
635
|
+
'',
|
|
636
|
+
` ${s.primary('4.')} Use ${s.primaryBold('/arch')} to document key decisions`,
|
|
637
|
+
` Future you will thank present you.`,
|
|
638
|
+
'',
|
|
639
|
+
` ${s.primary('5.')} Try ${s.primaryBold('Ollama')} for offline development`,
|
|
640
|
+
` No API key needed, runs locally.`,
|
|
641
|
+
'',
|
|
642
|
+
],
|
|
643
|
+
},
|
|
644
|
+
],
|
|
645
|
+
},
|
|
646
|
+
];
|
|
647
|
+
}
|
|
648
|
+
// =============================================================================
|
|
649
|
+
// Rendering
|
|
650
|
+
// =============================================================================
|
|
651
|
+
function renderWelcome(state, previousLineCount) {
|
|
652
|
+
const s = getStyles();
|
|
653
|
+
const lines = [];
|
|
654
|
+
const border = getBorder();
|
|
655
|
+
if (previousLineCount > 0) {
|
|
656
|
+
terminal.clearLinesAbove(previousLineCount);
|
|
657
|
+
}
|
|
658
|
+
lines.push(border);
|
|
659
|
+
lines.push(` ${s.primaryBold('compilr.dev Tutorial')}`);
|
|
660
|
+
lines.push('');
|
|
661
|
+
lines.push(` Learn the AI-powered development workflow that takes you`);
|
|
662
|
+
lines.push(` from idea to implementation with structure and discipline.`);
|
|
663
|
+
lines.push('');
|
|
664
|
+
lines.push(` This tutorial covers: initialization, design, backlog`);
|
|
665
|
+
lines.push(` management, building, configuration, and best practices.`);
|
|
666
|
+
lines.push('');
|
|
667
|
+
lines.push(` ${s.muted('How would you like to explore?')}`);
|
|
668
|
+
lines.push('');
|
|
669
|
+
const options = [
|
|
670
|
+
{ label: 'Start Guided Tour', desc: 'Step-by-step walkthrough (recommended)' },
|
|
671
|
+
{ label: 'Jump to Topic', desc: 'Go directly to a specific topic' },
|
|
672
|
+
];
|
|
673
|
+
for (let i = 0; i < options.length; i++) {
|
|
674
|
+
const opt = options[i];
|
|
675
|
+
const selected = i === state.welcomeIndex;
|
|
676
|
+
const prefix = selected ? s.primary(' ❯ ') : ' ';
|
|
677
|
+
const label = selected ? s.primary(opt.label) : opt.label;
|
|
678
|
+
const desc = s.muted(opt.desc);
|
|
679
|
+
lines.push(`${prefix}${label.padEnd(22)} ${desc}`);
|
|
680
|
+
}
|
|
681
|
+
lines.push('');
|
|
682
|
+
lines.push(border);
|
|
683
|
+
lines.push(s.muted(' ↑↓ Navigate · Enter Select · Esc Exit'));
|
|
684
|
+
terminal.write(lines.join('\n'));
|
|
685
|
+
return lines.length;
|
|
686
|
+
}
|
|
687
|
+
function renderTopicList(state, topics, previousLineCount) {
|
|
688
|
+
const s = getStyles();
|
|
689
|
+
const lines = [];
|
|
690
|
+
const border = getBorder();
|
|
691
|
+
if (previousLineCount > 0) {
|
|
692
|
+
terminal.clearLinesAbove(previousLineCount);
|
|
693
|
+
}
|
|
694
|
+
lines.push(border);
|
|
695
|
+
lines.push(` ${s.primaryBold('Tutorial Topics')}`);
|
|
696
|
+
lines.push('');
|
|
697
|
+
for (let i = 0; i < topics.length; i++) {
|
|
698
|
+
const topic = topics[i];
|
|
699
|
+
const selected = i === state.topicListIndex;
|
|
700
|
+
const prefix = selected ? s.primary(' ❯ ') : ' ';
|
|
701
|
+
const name = selected ? s.primary(topic.name) : topic.name;
|
|
702
|
+
const desc = s.muted(topic.description);
|
|
703
|
+
const pages = s.muted(`(${String(topic.pages.length)} ${topic.pages.length === 1 ? 'page' : 'pages'})`);
|
|
704
|
+
lines.push(`${prefix}${name.padEnd(26)} ${desc.padEnd(30)} ${pages}`);
|
|
705
|
+
}
|
|
706
|
+
lines.push('');
|
|
707
|
+
lines.push(border);
|
|
708
|
+
lines.push(s.muted(' ↑↓ Navigate · Enter View · Esc Back'));
|
|
709
|
+
terminal.write(lines.join('\n'));
|
|
710
|
+
return lines.length;
|
|
711
|
+
}
|
|
712
|
+
function renderPage(state, topics, previousLineCount) {
|
|
713
|
+
const s = getStyles();
|
|
714
|
+
const lines = [];
|
|
715
|
+
const border = getBorder();
|
|
716
|
+
if (previousLineCount > 0) {
|
|
717
|
+
terminal.clearLinesAbove(previousLineCount);
|
|
718
|
+
}
|
|
719
|
+
const topic = topics[state.currentTopicIndex];
|
|
720
|
+
const page = topic.pages[state.currentPageIndex];
|
|
721
|
+
const totalPages = topic.pages.length;
|
|
722
|
+
// Calculate overall progress for guided mode
|
|
723
|
+
let progressText = `[${String(state.currentPageIndex + 1)}/${String(totalPages)}]`;
|
|
724
|
+
if (state.isGuidedMode) {
|
|
725
|
+
let totalPagesAll = 0;
|
|
726
|
+
let currentPageAll = 0;
|
|
727
|
+
for (let i = 0; i < topics.length; i++) {
|
|
728
|
+
if (i < state.currentTopicIndex) {
|
|
729
|
+
currentPageAll += topics[i].pages.length;
|
|
730
|
+
}
|
|
731
|
+
else if (i === state.currentTopicIndex) {
|
|
732
|
+
currentPageAll += state.currentPageIndex + 1;
|
|
733
|
+
}
|
|
734
|
+
totalPagesAll += topics[i].pages.length;
|
|
735
|
+
}
|
|
736
|
+
progressText = `[${String(currentPageAll)}/${String(totalPagesAll)}]`;
|
|
737
|
+
}
|
|
738
|
+
// Header - calculate padding to right-align progress indicator
|
|
739
|
+
const titleStyled = s.primaryBold(page.title);
|
|
740
|
+
const progressStyled = s.muted(progressText);
|
|
741
|
+
const titleLen = stripAnsi(titleStyled).length + 1; // +1 for leading space
|
|
742
|
+
const progressLen = stripAnsi(progressStyled).length;
|
|
743
|
+
const cols = terminal.getTerminalWidth();
|
|
744
|
+
const padding = Math.max(1, cols - titleLen - progressLen - 2); // -2 for margins
|
|
745
|
+
lines.push(border);
|
|
746
|
+
lines.push(` ${titleStyled}${' '.repeat(padding)}${progressStyled}`);
|
|
747
|
+
lines.push('');
|
|
748
|
+
// Content
|
|
749
|
+
for (const line of page.lines) {
|
|
750
|
+
lines.push(line);
|
|
751
|
+
}
|
|
752
|
+
// Pad to consistent height
|
|
753
|
+
while (lines.length < 20) {
|
|
754
|
+
lines.push('');
|
|
755
|
+
}
|
|
756
|
+
// Navigation footer
|
|
757
|
+
lines.push(border);
|
|
758
|
+
if (state.isGuidedMode) {
|
|
759
|
+
lines.push(s.muted(' ←/→ Navigate · Esc Exit Tour'));
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
762
|
+
lines.push(s.muted(' ←/→ Navigate · Esc Back to Topics'));
|
|
763
|
+
}
|
|
764
|
+
terminal.write(lines.join('\n'));
|
|
765
|
+
return lines.length;
|
|
766
|
+
}
|
|
767
|
+
function renderComplete(previousLineCount) {
|
|
768
|
+
const s = getStyles();
|
|
769
|
+
const lines = [];
|
|
770
|
+
const border = getBorder();
|
|
771
|
+
if (previousLineCount > 0) {
|
|
772
|
+
terminal.clearLinesAbove(previousLineCount);
|
|
773
|
+
}
|
|
774
|
+
lines.push(border);
|
|
775
|
+
lines.push(` ${s.success('Tutorial Complete!')}`);
|
|
776
|
+
lines.push('');
|
|
777
|
+
lines.push(` You've learned the compilr.dev workflow!`);
|
|
778
|
+
lines.push('');
|
|
779
|
+
lines.push(` ${s.secondary('Key commands to remember:')}`);
|
|
780
|
+
lines.push('');
|
|
781
|
+
lines.push(` ${s.primary('/init')} Start a new project`);
|
|
782
|
+
lines.push(` ${s.primary('/design')} Plan your requirements`);
|
|
783
|
+
lines.push(` ${s.primary('/backlog')} Manage your work items`);
|
|
784
|
+
lines.push(` ${s.primary('/build')} Implement features`);
|
|
785
|
+
lines.push(` ${s.primary('/help')} See all commands`);
|
|
786
|
+
lines.push('');
|
|
787
|
+
lines.push(` ${s.secondary('Ready to start?')}`);
|
|
788
|
+
lines.push(` Try ${s.primary('/init')} in a new directory!`);
|
|
789
|
+
lines.push('');
|
|
790
|
+
lines.push(border);
|
|
791
|
+
lines.push(s.muted(' Press any key to exit...'));
|
|
792
|
+
terminal.write(lines.join('\n'));
|
|
793
|
+
return lines.length;
|
|
794
|
+
}
|
|
795
|
+
function render(state, topics, previousLineCount) {
|
|
796
|
+
switch (state.mode) {
|
|
797
|
+
case 'welcome':
|
|
798
|
+
return renderWelcome(state, previousLineCount);
|
|
799
|
+
case 'topic-list':
|
|
800
|
+
return renderTopicList(state, topics, previousLineCount);
|
|
801
|
+
case 'viewing':
|
|
802
|
+
return renderPage(state, topics, previousLineCount);
|
|
803
|
+
case 'complete':
|
|
804
|
+
return renderComplete(previousLineCount);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
// =============================================================================
|
|
808
|
+
// Main Export
|
|
809
|
+
// =============================================================================
|
|
810
|
+
export async function showTutorialOverlay() {
|
|
811
|
+
const topics = buildTopics();
|
|
812
|
+
const state = {
|
|
813
|
+
mode: 'welcome',
|
|
814
|
+
welcomeIndex: 0,
|
|
815
|
+
topicListIndex: 0,
|
|
816
|
+
currentTopicIndex: 0,
|
|
817
|
+
currentPageIndex: 0,
|
|
818
|
+
isGuidedMode: false,
|
|
819
|
+
};
|
|
820
|
+
let lineCount = 0;
|
|
821
|
+
lineCount = render(state, topics, lineCount);
|
|
822
|
+
return new Promise((resolve) => {
|
|
823
|
+
const stdin = process.stdin;
|
|
824
|
+
stdin.setRawMode(true);
|
|
825
|
+
stdin.resume();
|
|
826
|
+
const cleanup = () => {
|
|
827
|
+
stdin.removeListener('data', handleKey);
|
|
828
|
+
stdin.setRawMode(false);
|
|
829
|
+
stdin.pause();
|
|
830
|
+
terminal.clearLinesAbove(lineCount);
|
|
831
|
+
};
|
|
832
|
+
const handleKey = (data) => {
|
|
833
|
+
const key = data.toString();
|
|
834
|
+
const isEscape = key === '\x1B' && data.length === 1;
|
|
835
|
+
const isEnter = key === '\r' || key === '\n';
|
|
836
|
+
const isUpArrow = key === '\x1B[A';
|
|
837
|
+
const isDownArrow = key === '\x1B[B';
|
|
838
|
+
const isLeftArrow = key === '\x1B[D';
|
|
839
|
+
const isRightArrow = key === '\x1B[C';
|
|
840
|
+
const isCtrlC = key === '\x03';
|
|
841
|
+
if (isCtrlC) {
|
|
842
|
+
cleanup();
|
|
843
|
+
resolve({ completed: false });
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
switch (state.mode) {
|
|
847
|
+
case 'welcome': {
|
|
848
|
+
if (isEscape) {
|
|
849
|
+
cleanup();
|
|
850
|
+
resolve({ completed: false });
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (isUpArrow && state.welcomeIndex > 0) {
|
|
854
|
+
state.welcomeIndex--;
|
|
855
|
+
}
|
|
856
|
+
else if (isDownArrow && state.welcomeIndex < 1) {
|
|
857
|
+
state.welcomeIndex++;
|
|
858
|
+
}
|
|
859
|
+
else if (isEnter) {
|
|
860
|
+
if (state.welcomeIndex === 0) {
|
|
861
|
+
state.isGuidedMode = true;
|
|
862
|
+
state.currentTopicIndex = 0;
|
|
863
|
+
state.currentPageIndex = 0;
|
|
864
|
+
state.mode = 'viewing';
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
state.mode = 'topic-list';
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
break;
|
|
871
|
+
}
|
|
872
|
+
case 'topic-list': {
|
|
873
|
+
if (isEscape) {
|
|
874
|
+
state.mode = 'welcome';
|
|
875
|
+
}
|
|
876
|
+
else if (isUpArrow && state.topicListIndex > 0) {
|
|
877
|
+
state.topicListIndex--;
|
|
878
|
+
}
|
|
879
|
+
else if (isDownArrow && state.topicListIndex < topics.length - 1) {
|
|
880
|
+
state.topicListIndex++;
|
|
881
|
+
}
|
|
882
|
+
else if (isEnter) {
|
|
883
|
+
state.isGuidedMode = false;
|
|
884
|
+
state.currentTopicIndex = state.topicListIndex;
|
|
885
|
+
state.currentPageIndex = 0;
|
|
886
|
+
state.mode = 'viewing';
|
|
887
|
+
}
|
|
888
|
+
break;
|
|
889
|
+
}
|
|
890
|
+
case 'viewing': {
|
|
891
|
+
const topic = topics[state.currentTopicIndex];
|
|
892
|
+
const totalPages = topic.pages.length;
|
|
893
|
+
if (isEscape) {
|
|
894
|
+
if (state.isGuidedMode) {
|
|
895
|
+
state.mode = 'welcome';
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
state.mode = 'topic-list';
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
else if (isLeftArrow || key === '\x7F') {
|
|
902
|
+
if (state.currentPageIndex > 0) {
|
|
903
|
+
state.currentPageIndex--;
|
|
904
|
+
}
|
|
905
|
+
else if (state.isGuidedMode && state.currentTopicIndex > 0) {
|
|
906
|
+
state.currentTopicIndex--;
|
|
907
|
+
state.currentPageIndex = topics[state.currentTopicIndex].pages.length - 1;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
else if (isRightArrow || isEnter) {
|
|
911
|
+
if (state.currentPageIndex < totalPages - 1) {
|
|
912
|
+
state.currentPageIndex++;
|
|
913
|
+
}
|
|
914
|
+
else if (state.isGuidedMode) {
|
|
915
|
+
if (state.currentTopicIndex < topics.length - 1) {
|
|
916
|
+
state.currentTopicIndex++;
|
|
917
|
+
state.currentPageIndex = 0;
|
|
918
|
+
}
|
|
919
|
+
else {
|
|
920
|
+
state.mode = 'complete';
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
case 'complete': {
|
|
927
|
+
cleanup();
|
|
928
|
+
resolve({ completed: true });
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
lineCount = render(state, topics, lineCount);
|
|
933
|
+
};
|
|
934
|
+
stdin.on('data', handleKey);
|
|
935
|
+
});
|
|
936
|
+
}
|