@ritualai/cli 0.7.15 → 0.8.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/dist/commands/doctor.js +66 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +468 -108
- package/dist/commands/init.js.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/agents/providers.js +33 -5
- package/dist/lib/agents/providers.js.map +1 -1
- package/dist/lib/build-flow-explainer.js +226 -0
- package/dist/lib/build-flow-explainer.js.map +1 -0
- package/dist/lib/final-cta-box.js +224 -0
- package/dist/lib/final-cta-box.js.map +1 -0
- package/dist/lib/gitignore-update.js +13 -4
- package/dist/lib/gitignore-update.js.map +1 -1
- package/dist/lib/onboarding-state.js +140 -0
- package/dist/lib/onboarding-state.js.map +1 -0
- package/dist/lib/persona-picker.js +171 -0
- package/dist/lib/persona-picker.js.map +1 -0
- package/dist/lib/persona-samples.js +245 -0
- package/dist/lib/persona-samples.js.map +1 -0
- package/dist/lib/project-config.js.map +1 -1
- package/dist/lib/skill-bundles.js +4 -0
- package/dist/lib/skill-bundles.js.map +1 -1
- package/dist/lib/skill-copy.js +62 -10
- package/dist/lib/skill-copy.js.map +1 -1
- package/dist/lib/workspace-explainer.js +193 -0
- package/dist/lib/workspace-explainer.js.map +1 -0
- package/dist/lib/workspace-flow.js +8 -7
- package/dist/lib/workspace-flow.js.map +1 -1
- package/package.json +73 -73
- package/skills/claude-code/ritual/.ritual-bundle.json +2 -2
- package/skills/claude-code/ritual/references/build-flow.md +51 -14
- package/skills/codex/ritual/.ritual-bundle.json +2 -2
- package/skills/codex/ritual/references/build-flow.md +51 -14
- package/skills/cursor/ritual/.ritual-bundle.json +2 -2
- package/skills/cursor/ritual/references/build-flow.md +51 -14
- package/skills/gemini/ritual/.ritual-bundle.json +2 -2
- package/skills/gemini/ritual/references/build-flow.md +51 -14
- package/skills/kiro/ritual/.ritual-bundle.json +2 -2
- package/skills/kiro/ritual/references/build-flow.md +51 -14
- package/skills/vscode/ritual/.ritual-bundle.json +2 -2
- package/skills/vscode/ritual/references/build-flow.md +51 -14
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Final CTA box — last screen of `ritual init` in compact mode.
|
|
4
|
+
*
|
|
5
|
+
* Two-column "Ready to ship" panel that lands RIGHT after the
|
|
6
|
+
* build-flow explainer (which is the "here's what /ritual build
|
|
7
|
+
* does" payoff). Its job: turn the FTUE into action.
|
|
8
|
+
*
|
|
9
|
+
* LEFT column — primary CTA. Per-agent restart instructions
|
|
10
|
+
* (only the agents we actually wired this run),
|
|
11
|
+
* then the literal command to ask their coding
|
|
12
|
+
* agent next: `/ritual build "<your feature>"`.
|
|
13
|
+
*
|
|
14
|
+
* RIGHT column — "more info — invoke when you want it" menu of
|
|
15
|
+
* secondary commands. By NOT printing the details
|
|
16
|
+
* by default, we keep the CTA scannable; the user
|
|
17
|
+
* knows what to type if they want depth.
|
|
18
|
+
*
|
|
19
|
+
* Why a separate file: the box helpers (top/padded/bottom) +
|
|
20
|
+
* stripAnsi + column-padding math are ~50 lines and they recur
|
|
21
|
+
* across the FTUE panels. Better to factor here so each new panel
|
|
22
|
+
* can `import { boxTop, boxPadded, boxBottom }` rather than copy-
|
|
23
|
+
* pasting. Composable. If we add more panels we lift these into
|
|
24
|
+
* `box.ts`.
|
|
25
|
+
*
|
|
26
|
+
* Width: 110 chars. Deliberately matches `welcome-banner.ts` so
|
|
27
|
+
* the FTUE is visually bookended — same frame at the open as the
|
|
28
|
+
* close. The two FTUE-middle explainers (workspace + build-flow)
|
|
29
|
+
* use the narrower 78-char frame because their bodies need to
|
|
30
|
+
* breathe vertically rather than horizontally.
|
|
31
|
+
*
|
|
32
|
+
* Non-TTY / narrow terminal fallback: caller is expected to choose
|
|
33
|
+
* `printFinalCtaBoxTerse` instead — same content, no chrome.
|
|
34
|
+
*/
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.printFinalCtaBox = printFinalCtaBox;
|
|
37
|
+
exports.printFinalCtaBoxTerse = printFinalCtaBoxTerse;
|
|
38
|
+
exports.boxTop = boxTop;
|
|
39
|
+
exports.boxBottom = boxBottom;
|
|
40
|
+
const colors_1 = require("./colors");
|
|
41
|
+
/** Width target. Matches welcome-banner.ts so FTUE is bookended. */
|
|
42
|
+
const W = 110;
|
|
43
|
+
/** Left column width (CTA). Sized for the longest restart bullet
|
|
44
|
+
* ("VS Code: Cmd+Shift+P → \"Developer: Reload Window\"" = ~50 chars
|
|
45
|
+
* after the bullet indent) PLUS the 4-char `⚠ ` warning marker
|
|
46
|
+
* + warning text. Sized once here so the whole frame doesn't shift
|
|
47
|
+
* if we add an agent later — easier than per-row truncation. */
|
|
48
|
+
const LEFT_W = 64;
|
|
49
|
+
/**
|
|
50
|
+
* Render the final CTA box to stdout. Caller chooses whether to
|
|
51
|
+
* invoke this (compact mode) or the verbose-mode 3 print blocks.
|
|
52
|
+
*/
|
|
53
|
+
function printFinalCtaBox(opts) {
|
|
54
|
+
const titleBar = (0, colors_1.color)(colors_1.RITUAL_TEAL, '─ ready to ship ');
|
|
55
|
+
const top = boxTop(W, titleBar);
|
|
56
|
+
const bottom = boxBottom(W);
|
|
57
|
+
const leftLines = renderLeftColumn(opts);
|
|
58
|
+
const rightLines = renderRightColumn();
|
|
59
|
+
// Pad both columns to the same row count so the inner divider
|
|
60
|
+
// reads cleanly top-to-bottom.
|
|
61
|
+
const rows = Math.max(leftLines.length, rightLines.length);
|
|
62
|
+
while (leftLines.length < rows)
|
|
63
|
+
leftLines.push('');
|
|
64
|
+
while (rightLines.length < rows)
|
|
65
|
+
rightLines.push('');
|
|
66
|
+
const divider = (0, colors_1.color)(colors_1.RITUAL_TEAL, '│');
|
|
67
|
+
const rightW = W - LEFT_W - 3; // minus 3 dividers (outer + inner + outer)
|
|
68
|
+
const lines = [];
|
|
69
|
+
lines.push(top);
|
|
70
|
+
lines.push(twoColRow('', '', divider));
|
|
71
|
+
for (let i = 0; i < rows; i++) {
|
|
72
|
+
const l = padDisplay(leftLines[i], LEFT_W);
|
|
73
|
+
const r = padDisplay(rightLines[i], rightW);
|
|
74
|
+
lines.push(`${divider}${l}${divider}${r}${divider}`);
|
|
75
|
+
}
|
|
76
|
+
lines.push(twoColRow('', '', divider));
|
|
77
|
+
lines.push(bottom);
|
|
78
|
+
for (const ln of lines)
|
|
79
|
+
process.stdout.write(ln + '\n');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Narrow-terminal fallback (TTY-styled). Renders the same content
|
|
83
|
+
* as the rich 110-wide box but stacked vertically with a single
|
|
84
|
+
* accent-color rule between sections instead of split columns —
|
|
85
|
+
* fits at any width ≥ 78 cols. Honors NO_COLOR / non-TTY via the
|
|
86
|
+
* `color/dim/boldColor` helpers (they auto-degrade to plain text).
|
|
87
|
+
*
|
|
88
|
+
* Fires when stdout columns are between 78 and 99, OR when stdout
|
|
89
|
+
* isn't a TTY (CI / piped output) — the colors collapse to plain
|
|
90
|
+
* text in that path.
|
|
91
|
+
*/
|
|
92
|
+
function printFinalCtaBoxTerse(opts) {
|
|
93
|
+
const out = process.stdout.write.bind(process.stdout);
|
|
94
|
+
const rule = (label) => ` ${(0, colors_1.color)(colors_1.RITUAL_TEAL, '─')} ${(0, colors_1.boldColor)(colors_1.RITUAL_TEAL, label)}`;
|
|
95
|
+
const amber = [0xe0, 0xa8, 0x4f];
|
|
96
|
+
out('\n');
|
|
97
|
+
out(` ${(0, colors_1.boldColor)(colors_1.RITUAL_TEAL, 'ready to ship')}\n`);
|
|
98
|
+
out('\n');
|
|
99
|
+
if (opts.insideClaudeWarning) {
|
|
100
|
+
out(` ${(0, colors_1.boldColor)(amber, '⚠ ' + opts.insideClaudeWarning)}\n`);
|
|
101
|
+
out('\n');
|
|
102
|
+
}
|
|
103
|
+
out(`${rule('1. restart your coding agents')}\n`);
|
|
104
|
+
for (const line of restartLinesFor(opts.wiredAgentNames)) {
|
|
105
|
+
out(` ${(0, colors_1.dim)('•')} ${line}\n`);
|
|
106
|
+
}
|
|
107
|
+
out('\n');
|
|
108
|
+
out(`${rule('2. ask your coding agent')}\n`);
|
|
109
|
+
out(` ${(0, colors_1.color)(colors_1.RITUAL_TEAL, '›')} /ritual build "<your feature>"\n`);
|
|
110
|
+
out('\n');
|
|
111
|
+
out(` ${(0, colors_1.dim)('more info — invoke when you want it:')}\n`);
|
|
112
|
+
const pairs = [
|
|
113
|
+
['ritual init --verbose', 'what was wired up · paths · key info'],
|
|
114
|
+
['ritual doctor', 'verify the MCP connection · diagnose'],
|
|
115
|
+
['ritual graph status', 'see what\'s in this workspace'],
|
|
116
|
+
];
|
|
117
|
+
const colW = Math.max(...pairs.map(([c]) => c.length));
|
|
118
|
+
for (const [cmd, desc] of pairs) {
|
|
119
|
+
out(` ${(0, colors_1.color)(colors_1.RITUAL_TEAL, cmd.padEnd(colW))} ${(0, colors_1.dim)('— ' + desc)}\n`);
|
|
120
|
+
}
|
|
121
|
+
out('\n');
|
|
122
|
+
}
|
|
123
|
+
// ─── column content ──────────────────────────────────────────────────────────
|
|
124
|
+
function renderLeftColumn(opts) {
|
|
125
|
+
const lines = [];
|
|
126
|
+
if (opts.insideClaudeWarning) {
|
|
127
|
+
// ⚠ warning belongs on the LEFT (CTA side) because the user
|
|
128
|
+
// has to act on it before the CTA below it works. Bold so it
|
|
129
|
+
// doesn't get lost in the chrome.
|
|
130
|
+
lines.push(` ${(0, colors_1.boldColor)([0xe0, 0xa8, 0x4f], '⚠ ' + opts.insideClaudeWarning)}`);
|
|
131
|
+
lines.push('');
|
|
132
|
+
}
|
|
133
|
+
lines.push(` ${(0, colors_1.boldColor)(colors_1.RITUAL_TEAL, '1. restart your coding agents')}`);
|
|
134
|
+
for (const r of restartLinesFor(opts.wiredAgentNames)) {
|
|
135
|
+
lines.push(` ${(0, colors_1.dim)('•')} ${r}`);
|
|
136
|
+
}
|
|
137
|
+
lines.push('');
|
|
138
|
+
lines.push(` ${(0, colors_1.boldColor)(colors_1.RITUAL_TEAL, '2. ask your coding agent')}`);
|
|
139
|
+
lines.push('');
|
|
140
|
+
lines.push(` ${(0, colors_1.color)(colors_1.RITUAL_TEAL, '›')} /ritual build "<your feature>"`);
|
|
141
|
+
return lines;
|
|
142
|
+
}
|
|
143
|
+
function renderRightColumn() {
|
|
144
|
+
// Each secondary command is a 2-row pair: command name (cyan
|
|
145
|
+
// accent) + one-line description (dim). Blank rows between pairs
|
|
146
|
+
// so the eye groups them; matches the rhythm of `gh help` output.
|
|
147
|
+
const pairs = [
|
|
148
|
+
['ritual init --verbose', 'what was wired up · paths · key info'],
|
|
149
|
+
['ritual doctor', 'verify the MCP connection · diagnose'],
|
|
150
|
+
['ritual graph status', 'see what\'s in this workspace'],
|
|
151
|
+
];
|
|
152
|
+
const lines = [
|
|
153
|
+
` ${(0, colors_1.dim)('more info — invoke when you want it:')}`,
|
|
154
|
+
'',
|
|
155
|
+
];
|
|
156
|
+
for (let i = 0; i < pairs.length; i++) {
|
|
157
|
+
const [cmd, desc] = pairs[i];
|
|
158
|
+
lines.push(` ${(0, colors_1.color)(colors_1.RITUAL_TEAL, cmd)}`);
|
|
159
|
+
lines.push(` ${(0, colors_1.dim)(desc)}`);
|
|
160
|
+
if (i < pairs.length - 1)
|
|
161
|
+
lines.push('');
|
|
162
|
+
}
|
|
163
|
+
return lines;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Build the per-agent restart bullets. Recognizes the agent names
|
|
167
|
+
* we actually ship for (Claude Code, Cursor, Windsurf, Kiro, etc.)
|
|
168
|
+
* and uses the documented one-keystroke restart action for each;
|
|
169
|
+
* falls through to a generic "restart Agent X" for anything we
|
|
170
|
+
* don't have a specific gesture for.
|
|
171
|
+
*/
|
|
172
|
+
function restartLinesFor(agentNames) {
|
|
173
|
+
if (agentNames.length === 0) {
|
|
174
|
+
return ['restart your coding agent so it loads the MCP server'];
|
|
175
|
+
}
|
|
176
|
+
return agentNames.map((name) => {
|
|
177
|
+
switch (name) {
|
|
178
|
+
case 'Claude Code':
|
|
179
|
+
return 'Claude Code: exit any session, then run `claude` again';
|
|
180
|
+
case 'Cursor':
|
|
181
|
+
return 'Cursor: Cmd-Q, then reopen';
|
|
182
|
+
case 'Windsurf':
|
|
183
|
+
return 'Windsurf: restart the app';
|
|
184
|
+
case 'Kiro':
|
|
185
|
+
return 'Kiro: restart the app';
|
|
186
|
+
case 'Gemini CLI':
|
|
187
|
+
return 'Gemini CLI: start a fresh `gemini` session';
|
|
188
|
+
case 'VS Code (Copilot)':
|
|
189
|
+
return 'VS Code: Cmd+Shift+P → "Developer: Reload Window"';
|
|
190
|
+
case 'Codex':
|
|
191
|
+
return 'Codex: start a fresh `codex` session';
|
|
192
|
+
default:
|
|
193
|
+
return `${name}: restart so it loads the MCP server`;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// ─── shared box / padding helpers ───────────────────────────────────────────
|
|
198
|
+
function boxTop(width, title) {
|
|
199
|
+
const stripped = stripAnsi(title);
|
|
200
|
+
const fillWidth = width - stripped.length - 4;
|
|
201
|
+
return (0, colors_1.color)(colors_1.RITUAL_TEAL, '╭') + ' ' + title + ' ' + (0, colors_1.color)(colors_1.RITUAL_TEAL, '─'.repeat(Math.max(0, fillWidth)) + '╮');
|
|
202
|
+
}
|
|
203
|
+
function boxBottom(width) {
|
|
204
|
+
// Inner ┴ where the column divider was — same shape as
|
|
205
|
+
// welcome-banner so the two frames look related.
|
|
206
|
+
const left = '─'.repeat(LEFT_W);
|
|
207
|
+
const right = '─'.repeat(Math.max(0, width - LEFT_W - 3));
|
|
208
|
+
return (0, colors_1.color)(colors_1.RITUAL_TEAL, `╰${left}┴${right}╯`);
|
|
209
|
+
}
|
|
210
|
+
function twoColRow(left, right, divider) {
|
|
211
|
+
const rightW = W - LEFT_W - 3;
|
|
212
|
+
return `${divider}${padDisplay(left, LEFT_W)}${divider}${padDisplay(right, rightW)}${divider}`;
|
|
213
|
+
}
|
|
214
|
+
function padDisplay(s, width) {
|
|
215
|
+
const visLen = stripAnsi(s).length;
|
|
216
|
+
if (visLen >= width)
|
|
217
|
+
return s;
|
|
218
|
+
return s + ' '.repeat(width - visLen);
|
|
219
|
+
}
|
|
220
|
+
function stripAnsi(s) {
|
|
221
|
+
// eslint-disable-next-line no-control-regex
|
|
222
|
+
return s.replace(/\x1b\[[0-9;]*m/g, '');
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=final-cta-box.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"final-cta-box.js","sourceRoot":"","sources":["../../src/lib/final-cta-box.ts"],"names":[],"mappings":"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"}
|
|
@@ -42,12 +42,15 @@ const END_MARKER = '# End: ritual init';
|
|
|
42
42
|
/**
|
|
43
43
|
* Returns the gitignore entry for a single provider — the project
|
|
44
44
|
* skill dir with a trailing slash so git treats it as a directory
|
|
45
|
-
* match.
|
|
45
|
+
* match. Returns null for MCP-only agents (no projectSkillDir),
|
|
46
|
+
* which the caller should filter out before assembling the block.
|
|
46
47
|
*/
|
|
47
48
|
function entryForProvider(provider) {
|
|
48
49
|
// projectSkillDir is e.g. `.claude/skills` or `.cursor/rules`.
|
|
49
50
|
// We ignore only the `ritual/` SKILL package under it — the
|
|
50
51
|
// user's own custom rules/skills siblings stay tracked.
|
|
52
|
+
if (!provider.projectSkillDir)
|
|
53
|
+
return null;
|
|
51
54
|
return `${provider.projectSkillDir}/ritual/`;
|
|
52
55
|
}
|
|
53
56
|
/**
|
|
@@ -58,6 +61,7 @@ function entryForProvider(provider) {
|
|
|
58
61
|
function buildBlock(scaffoldedProviders) {
|
|
59
62
|
const entries = scaffoldedProviders
|
|
60
63
|
.map(entryForProvider)
|
|
64
|
+
.filter((e) => e !== null)
|
|
61
65
|
// Sort so the block's contents are deterministic regardless of
|
|
62
66
|
// detect()-order changes between releases. Makes diffs in
|
|
63
67
|
// people's `.gitignore` files signal-not-noise.
|
|
@@ -103,9 +107,14 @@ function replaceOrAppendBlock(body, newBlock) {
|
|
|
103
107
|
function updateProjectGitignore(projectRoot, scaffoldedProviders) {
|
|
104
108
|
const gitignorePath = (0, node_path_1.join)(projectRoot, '.gitignore');
|
|
105
109
|
const preExisting = (0, node_fs_1.existsSync)(gitignorePath);
|
|
106
|
-
const entries = scaffoldedProviders
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
const entries = scaffoldedProviders
|
|
111
|
+
.map(entryForProvider)
|
|
112
|
+
.filter((e) => e !== null)
|
|
113
|
+
.sort();
|
|
114
|
+
// No-op fast path: nothing to ignore (either no providers
|
|
115
|
+
// scaffolded at all, or all of them are MCP-only with no
|
|
116
|
+
// project-local skill dir).
|
|
117
|
+
if (entries.length === 0) {
|
|
109
118
|
return { gitignorePath, preExisting, entries, changed: false };
|
|
110
119
|
}
|
|
111
120
|
const currentBody = preExisting ? (0, node_fs_1.readFileSync)(gitignorePath, 'utf8') : '';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitignore-update.js","sourceRoot":"","sources":["../../src/lib/gitignore-update.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"gitignore-update.js","sourceRoot":"","sources":["../../src/lib/gitignore-update.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Per-machine onboarding state.
|
|
4
|
+
*
|
|
5
|
+
* Tracks whether the three FTUE screens (persona picker, workspace
|
|
6
|
+
* explainer, build-flow explainer) have been shown on this machine.
|
|
7
|
+
* We want the explainers to teach the mental model ONCE per machine,
|
|
8
|
+
* not every time someone runs `ritual init` in a new repo — by the
|
|
9
|
+
* time you're cloning your second project we'd just be in your way.
|
|
10
|
+
*
|
|
11
|
+
* Storage shape (`~/.config/ritual/onboarding.json`):
|
|
12
|
+
* {
|
|
13
|
+
* "version": 1,
|
|
14
|
+
* "personaPickedAt": "2026-05-19T20:01:00Z",
|
|
15
|
+
* "personaSlug": "backend-services",
|
|
16
|
+
* "workspaceExplainerSeenAt": "2026-05-19T20:01:12Z",
|
|
17
|
+
* "buildFlowExplainerSeenAt": "2026-05-19T20:01:25Z"
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* Each field is optional and additive — we only set it once that
|
|
21
|
+
* screen has been shown (and, for the picker, confirmed). Missing
|
|
22
|
+
* fields are treated as "not yet seen". This makes the schema
|
|
23
|
+
* forward-compatible: adding a screen #4 in a later release just
|
|
24
|
+
* means a new field that's missing on existing installs.
|
|
25
|
+
*
|
|
26
|
+
* Why a separate file from `credentials.json`:
|
|
27
|
+
* - We want to be able to reset onboarding (`ritual init
|
|
28
|
+
* --re-onboard`) without nuking the user's auth tokens.
|
|
29
|
+
* - This file is non-secret — losing it just means we re-onboard
|
|
30
|
+
* once, never a security issue. Different blast radius from
|
|
31
|
+
* credentials, so different file.
|
|
32
|
+
*
|
|
33
|
+
* Why per-MACHINE not per-PROJECT:
|
|
34
|
+
* - The persona is a "what kind of work do you do" question, not
|
|
35
|
+
* "what kind of work does this repo support". You're the same
|
|
36
|
+
* dev across all your repos.
|
|
37
|
+
* - The explainers are mental-model teaching — once you've seen
|
|
38
|
+
* them, you've seen them.
|
|
39
|
+
* - Project-level overrides still work via `.ritual/config.json`
|
|
40
|
+
* (the per-project persona override picks up here as fallback
|
|
41
|
+
* when the project file doesn't set one explicitly).
|
|
42
|
+
*/
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.readOnboardingState = readOnboardingState;
|
|
45
|
+
exports.updateOnboardingState = updateOnboardingState;
|
|
46
|
+
exports.shouldShowPersonaPicker = shouldShowPersonaPicker;
|
|
47
|
+
exports.shouldShowWorkspaceExplainer = shouldShowWorkspaceExplainer;
|
|
48
|
+
exports.shouldShowBuildFlowExplainer = shouldShowBuildFlowExplainer;
|
|
49
|
+
exports.resetOnboardingState = resetOnboardingState;
|
|
50
|
+
const node_os_1 = require("node:os");
|
|
51
|
+
const node_path_1 = require("node:path");
|
|
52
|
+
const node_fs_1 = require("node:fs");
|
|
53
|
+
/** Bump if the on-disk schema changes incompatibly. */
|
|
54
|
+
const CURRENT_VERSION = 1;
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the onboarding-state file path. Honors `XDG_CONFIG_HOME`
|
|
57
|
+
* for the same reasons as `config.ts` — Linux dotfile convention +
|
|
58
|
+
* clean override seam for tests.
|
|
59
|
+
*
|
|
60
|
+
* Evaluated lazily on each call so tests can mutate env between
|
|
61
|
+
* sub-tests without needing to reset the module cache.
|
|
62
|
+
*/
|
|
63
|
+
function onboardingPath() {
|
|
64
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
65
|
+
const base = xdg && xdg.length > 0 ? xdg : (0, node_path_1.join)((0, node_os_1.homedir)(), '.config');
|
|
66
|
+
return (0, node_path_1.join)(base, 'ritual', 'onboarding.json');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Read the current state. Returns an empty object (with the right
|
|
70
|
+
* version) when the file doesn't exist or is corrupt — corruption
|
|
71
|
+
* here is a "show the screens again" outcome, never a hard error,
|
|
72
|
+
* because the worst case is we onboard the user a second time.
|
|
73
|
+
*/
|
|
74
|
+
function readOnboardingState() {
|
|
75
|
+
const path = onboardingPath();
|
|
76
|
+
if (!(0, node_fs_1.existsSync)(path))
|
|
77
|
+
return { version: CURRENT_VERSION };
|
|
78
|
+
try {
|
|
79
|
+
const raw = (0, node_fs_1.readFileSync)(path, 'utf-8');
|
|
80
|
+
const parsed = JSON.parse(raw);
|
|
81
|
+
if (parsed.version !== CURRENT_VERSION) {
|
|
82
|
+
// Future schema bumps land here — for now we treat any
|
|
83
|
+
// mismatch as "fresh state" rather than try to migrate.
|
|
84
|
+
return { version: CURRENT_VERSION };
|
|
85
|
+
}
|
|
86
|
+
return { ...parsed, version: CURRENT_VERSION };
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return { version: CURRENT_VERSION };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Merge `patch` into the existing on-disk state and persist. We
|
|
94
|
+
* always read-then-write rather than blind-overwrite so a partial
|
|
95
|
+
* patch (e.g. "mark workspace explainer seen") doesn't blow away
|
|
96
|
+
* unrelated fields (persona pick) written by an earlier screen.
|
|
97
|
+
*/
|
|
98
|
+
function updateOnboardingState(patch) {
|
|
99
|
+
const current = readOnboardingState();
|
|
100
|
+
const next = { ...current, ...patch, version: CURRENT_VERSION };
|
|
101
|
+
persist(next);
|
|
102
|
+
return next;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Convenience predicates the init flow uses to decide whether to
|
|
106
|
+
* render each screen. Centralized here so the gating policy lives
|
|
107
|
+
* in one place — if we later decide the workspace explainer should
|
|
108
|
+
* re-show after a year or after a major version bump, we change
|
|
109
|
+
* the predicate, not every call site.
|
|
110
|
+
*/
|
|
111
|
+
function shouldShowPersonaPicker(state) {
|
|
112
|
+
return !state.personaPickedAt;
|
|
113
|
+
}
|
|
114
|
+
function shouldShowWorkspaceExplainer(state) {
|
|
115
|
+
return !state.workspaceExplainerSeenAt;
|
|
116
|
+
}
|
|
117
|
+
function shouldShowBuildFlowExplainer(state) {
|
|
118
|
+
return !state.buildFlowExplainerSeenAt;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Wipe the on-disk state. Used by `ritual init --re-onboard` (a
|
|
122
|
+
* support escape hatch for "I want to see the intro again"). We
|
|
123
|
+
* write `{}` instead of unlinking so file permissions / SELinux
|
|
124
|
+
* contexts / Windows ACLs aren't disturbed.
|
|
125
|
+
*/
|
|
126
|
+
function resetOnboardingState() {
|
|
127
|
+
persist({ version: CURRENT_VERSION });
|
|
128
|
+
}
|
|
129
|
+
// ─── internal ──────────────────────────────────────────────────────────────
|
|
130
|
+
function persist(state) {
|
|
131
|
+
const path = onboardingPath();
|
|
132
|
+
const dir = (0, node_path_1.join)(path, '..');
|
|
133
|
+
if (!(0, node_fs_1.existsSync)(dir))
|
|
134
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
135
|
+
// 0600 on the file so we don't widen access just because the
|
|
136
|
+
// parent dir is group-readable. Onboarding state isn't secret
|
|
137
|
+
// but there's no reason to make it world-visible either.
|
|
138
|
+
(0, node_fs_1.writeFileSync)(path, JSON.stringify(state, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=onboarding-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboarding-state.js","sourceRoot":"","sources":["../../src/lib/onboarding-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Persona picker — onboarding screen #1 of 3.
|
|
4
|
+
*
|
|
5
|
+
* Shown once per machine on first `ritual init` (gated by
|
|
6
|
+
* onboarding-state.ts). Determines two downstream things:
|
|
7
|
+
*
|
|
8
|
+
* 1. The default template `/ritual build` will reach for. Persona
|
|
9
|
+
* slug equals the template's schema.id, so a user who picks
|
|
10
|
+
* "Backend Services" gets the backend-services Engineering
|
|
11
|
+
* template by default — they can still override per build.
|
|
12
|
+
* 2. The accent + framing used in screens #2 and #3 so the whole
|
|
13
|
+
* onboarding cohort feels personal.
|
|
14
|
+
*
|
|
15
|
+
* UI version (this file): numbered-list with color accents, chip
|
|
16
|
+
* tags ("APIs · workers · idempotency"), and a "see more" gate so
|
|
17
|
+
* we surface the 5 most-common personas first and the long tail
|
|
18
|
+
* only when asked. This is the pragmatic version; an Ink-based
|
|
19
|
+
* card UI is a polish pass we can layer on later without changing
|
|
20
|
+
* the contract here.
|
|
21
|
+
*
|
|
22
|
+
* Non-TTY fallback: returns `null` immediately. Callers must check
|
|
23
|
+
* `process.stdin.isTTY` before invoking the interactive version —
|
|
24
|
+
* see init.ts for the pattern. The seed value can also be supplied
|
|
25
|
+
* via `--persona <slug>` on the command line for CI bootstrapping.
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.__test = void 0;
|
|
29
|
+
exports.pickPersona = pickPersona;
|
|
30
|
+
const colors_1 = require("./colors");
|
|
31
|
+
const prompt_1 = require("./prompt");
|
|
32
|
+
const persona_samples_1 = require("./persona-samples");
|
|
33
|
+
/**
|
|
34
|
+
* Run the persona picker. Returns the picked persona, or `null` if
|
|
35
|
+
* the user skipped explicitly (entered empty / "skip" / etc).
|
|
36
|
+
*
|
|
37
|
+
* Throws on non-TTY stdin (Node's readline doesn't support it). The
|
|
38
|
+
* caller must gate on `process.stdin.isTTY` first.
|
|
39
|
+
*/
|
|
40
|
+
async function pickPersona(opts = {}) {
|
|
41
|
+
const featured = orderByFeatured(persona_samples_1.PERSONA_SAMPLES, persona_samples_1.FEATURED_PERSONA_SLUGS);
|
|
42
|
+
let showingAll = opts.showAll ?? false;
|
|
43
|
+
let visibleCount = showingAll ? featured.length : Math.min(persona_samples_1.FEATURED_PERSONA_SLUGS.length, featured.length);
|
|
44
|
+
printHeader();
|
|
45
|
+
printPersonaList(featured.slice(0, visibleCount));
|
|
46
|
+
// Initial prompt: number, "more", or skip
|
|
47
|
+
while (true) {
|
|
48
|
+
const answer = (await (0, prompt_1.prompt)(formatPickPrompt(visibleCount, showingAll))).trim();
|
|
49
|
+
if (!answer || answer.toLowerCase() === 'skip') {
|
|
50
|
+
process.stdout.write('\n' + (0, colors_1.dim)(' no persona set — /ritual build will ask you per exploration.') + '\n\n');
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
// Allow "more" to expand the list (one-way; once expanded, the
|
|
54
|
+
// long-tail personas are shown until pick / skip).
|
|
55
|
+
if (answer.toLowerCase() === 'more' && !showingAll) {
|
|
56
|
+
const tail = featured.slice(visibleCount);
|
|
57
|
+
process.stdout.write('\n');
|
|
58
|
+
printPersonaList(tail, visibleCount);
|
|
59
|
+
showingAll = true;
|
|
60
|
+
visibleCount = featured.length;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const idx = parseChoice(answer, featured.length);
|
|
64
|
+
if (idx === null) {
|
|
65
|
+
process.stdout.write((0, colors_1.dim)(` didn't recognize "${answer}" — try a number, "more", or "skip".`) + '\n');
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const picked = featured[idx];
|
|
69
|
+
process.stdout.write('\n ' +
|
|
70
|
+
(0, colors_1.boldColor)(picked.accent, `✓ ${picked.label}`) +
|
|
71
|
+
(0, colors_1.dim)(` · default template for /ritual build`) +
|
|
72
|
+
'\n\n');
|
|
73
|
+
return { slug: picked.slug, label: picked.label };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// ─── rendering ──────────────────────────────────────────────────────────────
|
|
77
|
+
function printHeader() {
|
|
78
|
+
const lines = [
|
|
79
|
+
'',
|
|
80
|
+
' ' + (0, colors_1.boldColor)(colors_1.RITUAL_TEAL, 'What kind of code do you work on most?'),
|
|
81
|
+
' ' + (0, colors_1.dim)('you can always change this later — it\'s a default, not a lock-in.'),
|
|
82
|
+
'',
|
|
83
|
+
];
|
|
84
|
+
for (const l of lines)
|
|
85
|
+
process.stdout.write(l + '\n');
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Render a list of personas as `N) Label tag · tag · tag`.
|
|
89
|
+
*
|
|
90
|
+
* `startIndex` is the 0-based index of the FIRST persona in the slice,
|
|
91
|
+
* so when we render the long-tail after "more", the numbering continues
|
|
92
|
+
* from where the featured list left off (6, 7, 8…).
|
|
93
|
+
*/
|
|
94
|
+
function printPersonaList(personas, startIndex = 0) {
|
|
95
|
+
const numWidth = String(startIndex + personas.length).length;
|
|
96
|
+
const labelWidth = Math.max(...personas.map((p) => p.label.length));
|
|
97
|
+
for (let i = 0; i < personas.length; i++) {
|
|
98
|
+
const p = personas[i];
|
|
99
|
+
const n = String(startIndex + i + 1).padStart(numWidth, ' ');
|
|
100
|
+
const label = (0, colors_1.boldColor)(p.accent, p.label.padEnd(labelWidth, ' '));
|
|
101
|
+
const tags = p.caresAbout.slice(0, 4).join(' · ');
|
|
102
|
+
process.stdout.write(` ${(0, colors_1.color)(p.accent, n + ')')} ${label} ${(0, colors_1.dim)(tags)}\n`);
|
|
103
|
+
}
|
|
104
|
+
process.stdout.write('\n');
|
|
105
|
+
}
|
|
106
|
+
function formatPickPrompt(visibleCount, showingAll) {
|
|
107
|
+
const hint = showingAll
|
|
108
|
+
? `pick a number (1-${visibleCount}), or "skip"`
|
|
109
|
+
: `pick a number (1-${visibleCount}), "more" to see the rest, or "skip"`;
|
|
110
|
+
return ` ${(0, colors_1.dim)(hint)}\n ${(0, colors_1.color)(colors_1.RITUAL_TEAL, '›')} `;
|
|
111
|
+
}
|
|
112
|
+
// ─── helpers ────────────────────────────────────────────────────────────────
|
|
113
|
+
/**
|
|
114
|
+
* Reorder `samples` so the featured slugs come first (in the order
|
|
115
|
+
* given by `featuredSlugs`) and the rest follow in their natural
|
|
116
|
+
* order. Defensive against missing slugs — if a featured slug has no
|
|
117
|
+
* matching sample, we just skip it.
|
|
118
|
+
*/
|
|
119
|
+
function orderByFeatured(samples, featuredSlugs) {
|
|
120
|
+
const bySlug = new Map(samples.map((s) => [s.slug, s]));
|
|
121
|
+
const featured = [];
|
|
122
|
+
for (const slug of featuredSlugs) {
|
|
123
|
+
const s = bySlug.get(slug);
|
|
124
|
+
if (s)
|
|
125
|
+
featured.push(s);
|
|
126
|
+
}
|
|
127
|
+
const tail = samples.filter((s) => !featuredSlugs.includes(s.slug));
|
|
128
|
+
return [...featured, ...tail];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Parse a user's text answer into a 0-based index into the full
|
|
132
|
+
* persona list. Returns null if the answer doesn't resolve. We
|
|
133
|
+
* accept 1-based numbers (matching the rendered list) and a tiny
|
|
134
|
+
* set of label aliases — "backend", "frontend" — for hand-typers.
|
|
135
|
+
*
|
|
136
|
+
* Exported (alongside `orderByFeatured`) under `__test` so the spec
|
|
137
|
+
* can exercise parsing without spinning up readline. Not part of the
|
|
138
|
+
* public API; treat the underscore prefix as the contract.
|
|
139
|
+
*/
|
|
140
|
+
function parseChoice(answer, listLength) {
|
|
141
|
+
const trimmed = answer.trim().toLowerCase();
|
|
142
|
+
// Empty input is never a match — defense-in-depth even though
|
|
143
|
+
// the caller short-circuits "" as "skip". Without this, the
|
|
144
|
+
// substring loop below would resolve "" against every label.
|
|
145
|
+
if (!trimmed)
|
|
146
|
+
return null;
|
|
147
|
+
const asNumber = Number(trimmed);
|
|
148
|
+
if (Number.isInteger(asNumber) && asNumber >= 1 && asNumber <= listLength) {
|
|
149
|
+
return asNumber - 1;
|
|
150
|
+
}
|
|
151
|
+
// Word aliases — substring match against label or shortLabel. We
|
|
152
|
+
// keep this loose because the picker isn't latency-sensitive and
|
|
153
|
+
// it's friendlier than rejecting "frontend" because the label is
|
|
154
|
+
// "Frontend Web".
|
|
155
|
+
for (let i = 0; i < persona_samples_1.PERSONA_SAMPLES.length; i++) {
|
|
156
|
+
const p = persona_samples_1.PERSONA_SAMPLES[i];
|
|
157
|
+
if (trimmed === p.slug ||
|
|
158
|
+
p.label.toLowerCase().includes(trimmed) ||
|
|
159
|
+
p.shortLabel.toLowerCase() === trimmed) {
|
|
160
|
+
return i;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Test seam — internal pure helpers exported solely for unit
|
|
167
|
+
* coverage. Do not consume from non-spec code; the underscore
|
|
168
|
+
* prefix is the contract.
|
|
169
|
+
*/
|
|
170
|
+
exports.__test = { parseChoice, orderByFeatured };
|
|
171
|
+
//# sourceMappingURL=persona-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persona-picker.js","sourceRoot":"","sources":["../../src/lib/persona-picker.ts"],"names":[],"mappings":"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"}
|