phewsh 0.11.11 → 0.11.13
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/bin/phewsh.js +12 -12
- package/commands/session.js +169 -183
- package/commands/watch.js +12 -12
- package/lib/ui.js +204 -115
- package/package.json +1 -1
package/commands/watch.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Watches .intent/ for changes and auto-pushes to Supabase + regenerates CLAUDE.md.
|
|
4
4
|
// This is the backbone of cross-tool continuity:
|
|
5
|
-
// edit in terminal →
|
|
5
|
+
// edit in terminal → phewsh.com/intent updates → Claude Code knows.
|
|
6
6
|
//
|
|
7
7
|
// Usage:
|
|
8
8
|
// phewsh watch Start watching (push + CLAUDE.md)
|
|
@@ -85,8 +85,8 @@ function generateClaudeSection() {
|
|
|
85
85
|
const decisionGate = gate || projectJson?.decisionGate;
|
|
86
86
|
|
|
87
87
|
sections.push(`# PHEWSH Adaptive Context — ${projectName}`);
|
|
88
|
+
sections.push(`> **Generated file. Do not edit.** Modify .intent/ instead — this section regenerates automatically.`);
|
|
88
89
|
sections.push(`> Auto-synced by \`phewsh watch\` | ${new Date().toISOString().split('T')[0]}`);
|
|
89
|
-
sections.push(`> This section is regenerated on every .intent/ change. Do not edit manually.`);
|
|
90
90
|
sections.push('');
|
|
91
91
|
|
|
92
92
|
// Project identity
|
|
@@ -318,25 +318,25 @@ function watchIntent() {
|
|
|
318
318
|
|
|
319
319
|
function showHelp() {
|
|
320
320
|
console.log(`
|
|
321
|
-
phewsh watch —
|
|
321
|
+
phewsh watch — Keep AI tools in sync with .intent/
|
|
322
322
|
|
|
323
323
|
Usage:
|
|
324
324
|
phewsh watch Start watching
|
|
325
325
|
phewsh watch --no-claude Skip CLAUDE.md regeneration
|
|
326
|
-
phewsh watch --no-push Skip cloud push (local
|
|
326
|
+
phewsh watch --no-push Skip cloud push (local only)
|
|
327
327
|
phewsh watch --verbose Show detailed sync info
|
|
328
328
|
|
|
329
329
|
What it does:
|
|
330
330
|
Watches .intent/ for changes and automatically:
|
|
331
|
-
1.
|
|
332
|
-
2.
|
|
331
|
+
1. Regenerates CLAUDE.md so Claude Code stays current with .intent/
|
|
332
|
+
2. Pushes to phewsh.com/intent (optional — needs account)
|
|
333
333
|
|
|
334
|
-
|
|
335
|
-
edit
|
|
334
|
+
The loop:
|
|
335
|
+
edit .intent/ → CLAUDE.md updates → cloud mirror updates → every tool knows
|
|
336
336
|
|
|
337
337
|
Requirements:
|
|
338
338
|
- .intent/ directory must exist (run \`phewsh intent --init\`)
|
|
339
|
-
-
|
|
339
|
+
- Everything works without an account. Account adds cloud sync.
|
|
340
340
|
`);
|
|
341
341
|
}
|
|
342
342
|
|
|
@@ -352,8 +352,8 @@ async function main() {
|
|
|
352
352
|
const loggedIn = !!config?.supabaseUserId;
|
|
353
353
|
|
|
354
354
|
console.log('');
|
|
355
|
-
console.log(` ${b(w('
|
|
356
|
-
console.log(` ${g('
|
|
355
|
+
console.log(` ${b(w('.intent/ Watch'))} ${g('v' + require('../package.json').version)}`);
|
|
356
|
+
console.log(` ${g('Keeps your AI tools in sync with .intent/')}`);
|
|
357
357
|
console.log('');
|
|
358
358
|
|
|
359
359
|
// Show what's enabled
|
|
@@ -361,7 +361,7 @@ async function main() {
|
|
|
361
361
|
if (!flags.noClaude) features.push(`${green('●')} CLAUDE.md auto-sync`);
|
|
362
362
|
else features.push(`${g('○')} CLAUDE.md ${g('(disabled)')}`);
|
|
363
363
|
|
|
364
|
-
if (!flags.noPush && loggedIn) features.push(`${green('●')} Cloud push
|
|
364
|
+
if (!flags.noPush && loggedIn) features.push(`${green('●')} Cloud push → phewsh.com/intent`);
|
|
365
365
|
else if (!flags.noPush && !loggedIn) features.push(`${yellow('●')} Cloud push ${g('(not logged in — run phewsh login)')}`);
|
|
366
366
|
else features.push(`${g('○')} Cloud push ${g('(disabled)')}`);
|
|
367
367
|
|
package/lib/ui.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
// phewsh ui —
|
|
2
|
-
//
|
|
1
|
+
// phewsh ui — the exhale
|
|
2
|
+
// Relief. Quiet execution. Cool sweet future.
|
|
3
|
+
// Zero dependencies. Pure ANSI. The terminal breathes.
|
|
3
4
|
|
|
5
|
+
// ── PHEWSH palette ───────────────────────────────────────
|
|
6
|
+
// 24-bit color for terminals that support it (most modern ones do).
|
|
7
|
+
// Fallback-safe: if 24-bit fails, the text still renders.
|
|
8
|
+
const rgb = (r, g, b) => (s) => `\x1b[38;2;${r};${g};${b}m${s}\x1b[0m`;
|
|
9
|
+
const rgbBg = (r, g, b) => (s) => `\x1b[48;2;${r};${g};${b}m${s}\x1b[0m`;
|
|
10
|
+
|
|
11
|
+
// Brand colors — relief, quiet, future
|
|
12
|
+
const teal = rgb(100, 215, 195); // cool calm — primary
|
|
13
|
+
const peach = rgb(255, 195, 145); // warm exhale — accent
|
|
14
|
+
const sage = rgb(130, 150, 140); // quiet — secondary text
|
|
15
|
+
const slate = rgb(80, 90, 88); // whisper — dim text
|
|
16
|
+
const cream = rgb(240, 235, 225); // clarity — bright text
|
|
17
|
+
const ember = rgb(220, 140, 90); // glow — warnings/energy
|
|
18
|
+
|
|
19
|
+
// Standard ANSI fallbacks (used where 24-bit might not render)
|
|
4
20
|
const b = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
5
21
|
const d = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
6
22
|
const w = (s) => `\x1b[97m${s}\x1b[0m`;
|
|
@@ -18,30 +34,43 @@ const show = '\x1b[?25h';
|
|
|
18
34
|
const up = (n = 1) => `\x1b[${n}A`;
|
|
19
35
|
const clearLine = '\x1b[2K\r';
|
|
20
36
|
|
|
21
|
-
// ──
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
// ── Sleep helper ─────────────────────────────────────────
|
|
38
|
+
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
39
|
+
|
|
40
|
+
// ── Spinner: the exhale pulse ────────────────────────────
|
|
41
|
+
// Breathes in and out. Calm. Not frantic.
|
|
42
|
+
const EXHALE_FRAMES = [
|
|
43
|
+
' · ',
|
|
44
|
+
' · · ',
|
|
45
|
+
' · · ',
|
|
46
|
+
' · · ',
|
|
47
|
+
'· ·',
|
|
48
|
+
' · · ',
|
|
49
|
+
' · · ',
|
|
50
|
+
' · · ',
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const BREATH_DOTS = [' ·', ' · ·', '· · ·', ' · ·', ' ·', ' '];
|
|
54
|
+
|
|
55
|
+
const GENTLE_FRAMES = ['·', '•', '●', '•', '·', ' '];
|
|
56
|
+
|
|
57
|
+
function spinner(text = 'thinking', style = 'exhale') {
|
|
58
|
+
const frames = style === 'gentle' ? GENTLE_FRAMES
|
|
59
|
+
: style === 'dots' ? BREATH_DOTS
|
|
60
|
+
: EXHALE_FRAMES;
|
|
33
61
|
let i = 0;
|
|
34
62
|
let stopped = false;
|
|
63
|
+
let currentText = text;
|
|
35
64
|
process.stdout.write(hide);
|
|
36
65
|
const interval = setInterval(() => {
|
|
37
66
|
if (stopped) return;
|
|
38
67
|
const frame = frames[i % frames.length];
|
|
39
|
-
process.stdout.write(`${clearLine} ${
|
|
68
|
+
process.stdout.write(`${clearLine} ${teal(frame)} ${sage(currentText)}`);
|
|
40
69
|
i++;
|
|
41
|
-
}, style === '
|
|
70
|
+
}, style === 'gentle' ? 150 : 100);
|
|
42
71
|
|
|
43
72
|
return {
|
|
44
|
-
update(newText) {
|
|
73
|
+
update(newText) { currentText = newText; },
|
|
45
74
|
stop(finalText) {
|
|
46
75
|
stopped = true;
|
|
47
76
|
clearInterval(interval);
|
|
@@ -51,86 +80,136 @@ function spinner(text = 'thinking', style = 'braille') {
|
|
|
51
80
|
};
|
|
52
81
|
}
|
|
53
82
|
|
|
54
|
-
// ──
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
83
|
+
// ── The Exhale: signature brand animation ────────────────
|
|
84
|
+
// This is the first thing you see. It should feel like a breath.
|
|
85
|
+
// Inhale (pause) → exhale (particles expand) → settle (logo forms) → calm.
|
|
86
|
+
async function brandReveal(fast = false) {
|
|
87
|
+
if (fast) {
|
|
88
|
+
console.log('');
|
|
89
|
+
console.log(` ${d('😮\u200d💨')} ${d('🤫')}`);
|
|
90
|
+
console.log('');
|
|
91
|
+
console.log(` ${b(cream('█▀█ █░█ █▀▀ █░█ █▀ █░█'))}`);
|
|
92
|
+
console.log(` ${b(cream('█▀▀ █▀█ ██▄ ▀▄▀ ▄█ █▀█'))}`);
|
|
93
|
+
console.log('');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
process.stdout.write(hide);
|
|
98
|
+
|
|
99
|
+
// Phase 1: The inhale — brief stillness
|
|
100
|
+
console.log('');
|
|
101
|
+
await sleep(200);
|
|
102
|
+
|
|
103
|
+
// Phase 2: The exhale — particles drift outward
|
|
104
|
+
const exhaleStages = [
|
|
105
|
+
' ·',
|
|
106
|
+
' · · ·',
|
|
107
|
+
' · · · ·',
|
|
108
|
+
' · · · · ·',
|
|
109
|
+
' · · · · ·',
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
for (const stage of exhaleStages) {
|
|
113
|
+
process.stdout.write(`${clearLine} ${slate(stage)}`);
|
|
114
|
+
await sleep(70);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Phase 3: Particles converge into the emoji
|
|
118
|
+
await sleep(100);
|
|
119
|
+
process.stdout.write(`${clearLine}`);
|
|
120
|
+
console.log(` ${d('😮\u200d💨')} ${d('🤫')}`);
|
|
121
|
+
console.log('');
|
|
122
|
+
await sleep(150);
|
|
66
123
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
124
|
+
// Phase 4: Logo wave — each letter block appears left to right
|
|
125
|
+
const logoTop = ['█▀█', '█░█', '█▀▀', '█░█', '█▀', '█░█'];
|
|
126
|
+
const logoBot = ['█▀▀', '█▀█', '██▄', '▀▄▀', '▄█', '█▀█'];
|
|
127
|
+
|
|
128
|
+
let topLine = ' ';
|
|
129
|
+
let botLine = ' ';
|
|
130
|
+
|
|
131
|
+
for (let i = 0; i < logoTop.length; i++) {
|
|
132
|
+
topLine += cream(logoTop[i]) + ' ';
|
|
133
|
+
botLine += cream(logoBot[i]) + ' ';
|
|
134
|
+
|
|
135
|
+
// Overwrite both lines
|
|
136
|
+
if (i === 0) {
|
|
137
|
+
process.stdout.write(` ${b(topLine.trim())}`);
|
|
138
|
+
process.stdout.write('\n');
|
|
139
|
+
process.stdout.write(` ${b(botLine.trim())}`);
|
|
140
|
+
} else {
|
|
141
|
+
process.stdout.write(up(1));
|
|
142
|
+
process.stdout.write(`${clearLine} ${b(topLine.trim())}`);
|
|
143
|
+
process.stdout.write('\n');
|
|
144
|
+
process.stdout.write(`${clearLine} ${b(botLine.trim())}`);
|
|
71
145
|
}
|
|
146
|
+
await sleep(55);
|
|
147
|
+
}
|
|
72
148
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
149
|
+
process.stdout.write('\n');
|
|
150
|
+
await sleep(100);
|
|
151
|
+
|
|
152
|
+
// Phase 5: Tagline fades in — dim → sage → cream
|
|
153
|
+
const tagline = '.intent/ is your project\'s working memory.';
|
|
154
|
+
process.stdout.write(` ${slate(tagline)}`);
|
|
155
|
+
await sleep(200);
|
|
156
|
+
process.stdout.write(`${clearLine} ${sage(tagline)}`);
|
|
157
|
+
await sleep(200);
|
|
158
|
+
process.stdout.write(`${clearLine} ${teal(tagline)}`);
|
|
159
|
+
await sleep(300);
|
|
160
|
+
|
|
161
|
+
console.log('');
|
|
162
|
+
console.log('');
|
|
163
|
+
process.stdout.write(show);
|
|
84
164
|
}
|
|
85
165
|
|
|
86
166
|
// ── Status panel ─────────────────────────────────────────
|
|
87
|
-
// Draws a bordered status box with labeled rows.
|
|
88
167
|
function statusPanel(title, rows) {
|
|
89
168
|
const maxLabel = Math.max(...rows.map(r => r[0].length));
|
|
90
169
|
console.log('');
|
|
91
|
-
console.log(` ${b(
|
|
92
|
-
console.log(` ${
|
|
170
|
+
console.log(` ${b(cream(title))}`);
|
|
171
|
+
console.log(` ${slate('─'.repeat(48))}`);
|
|
93
172
|
for (const [label, value, color] of rows) {
|
|
94
173
|
const colorFn = color === 'green' ? green
|
|
95
|
-
: color === 'yellow' ?
|
|
96
|
-
: color === 'cyan' ?
|
|
174
|
+
: color === 'yellow' ? ember
|
|
175
|
+
: color === 'cyan' ? teal
|
|
97
176
|
: color === 'red' ? red
|
|
177
|
+
: color === 'peach' ? peach
|
|
98
178
|
: (s) => s;
|
|
99
|
-
console.log(` ${
|
|
179
|
+
console.log(` ${sage(label.padEnd(maxLabel + 2))} ${colorFn(value)}`);
|
|
100
180
|
}
|
|
101
|
-
console.log(` ${
|
|
181
|
+
console.log(` ${slate('─'.repeat(48))}`);
|
|
102
182
|
console.log('');
|
|
103
183
|
}
|
|
104
184
|
|
|
105
185
|
// ── Interop badge line ───────────────────────────────────
|
|
106
|
-
// Shows where phewsh is connected / can connect.
|
|
107
186
|
function interopLine(config, intentFiles) {
|
|
108
187
|
const parts = [];
|
|
109
|
-
if (intentFiles.length > 0) parts.push(
|
|
110
|
-
if (config?.apiKey) parts.push(
|
|
111
|
-
if (config?.supabaseUserId) parts.push(
|
|
188
|
+
if (intentFiles.length > 0) parts.push(teal('●') + sage(' .intent/'));
|
|
189
|
+
if (config?.apiKey) parts.push(teal('●') + sage(' AI'));
|
|
190
|
+
if (config?.supabaseUserId) parts.push(teal('●') + sage(' cloud'));
|
|
112
191
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
192
|
+
const available = [
|
|
193
|
+
sage('Claude Code'),
|
|
194
|
+
sage('Cursor'),
|
|
195
|
+
sage('ChatGPT'),
|
|
196
|
+
sage('MCP'),
|
|
197
|
+
];
|
|
119
198
|
|
|
120
199
|
if (parts.length > 0) {
|
|
121
|
-
console.log(` ${
|
|
200
|
+
console.log(` ${slate('active')} ${parts.join(slate(' · '))}`);
|
|
122
201
|
}
|
|
123
|
-
console.log(` ${
|
|
202
|
+
console.log(` ${slate('works in')} ${available.join(slate(' · '))}`);
|
|
124
203
|
}
|
|
125
204
|
|
|
126
205
|
// ── Divider ──────────────────────────────────────────────
|
|
127
|
-
function divider(
|
|
128
|
-
|
|
206
|
+
function divider(style = 'line', width = 48) {
|
|
207
|
+
const char = style === 'dots' ? '·' : style === 'fade' ? '░' : '─';
|
|
208
|
+
console.log(` ${slate(char.repeat(width))}`);
|
|
129
209
|
}
|
|
130
210
|
|
|
131
211
|
// ── Typewriter ───────────────────────────────────────────
|
|
132
|
-
|
|
133
|
-
function typewrite(text, speed = 20) {
|
|
212
|
+
function typewrite(text, speed = 25) {
|
|
134
213
|
return new Promise((resolve) => {
|
|
135
214
|
let i = 0;
|
|
136
215
|
const interval = setInterval(() => {
|
|
@@ -146,16 +225,16 @@ function typewrite(text, speed = 20) {
|
|
|
146
225
|
});
|
|
147
226
|
}
|
|
148
227
|
|
|
149
|
-
// ── Welcome tips
|
|
228
|
+
// ── Welcome tips ─────────────────────────────────────────
|
|
150
229
|
const TIPS = [
|
|
151
|
-
`${
|
|
152
|
-
`${
|
|
153
|
-
`${
|
|
154
|
-
`${
|
|
155
|
-
`${
|
|
156
|
-
`${
|
|
157
|
-
`${
|
|
158
|
-
`${
|
|
230
|
+
`${slate('·')} ${cream('/clarify')} ${sage('turns a messy idea into .intent/ artifacts')}`,
|
|
231
|
+
`${slate('·')} ${cream('/gate')} ${sage('sets constraints — every AI response respects your budget and time')}`,
|
|
232
|
+
`${slate('·')} ${sage('Run')} ${cream('phewsh watch')} ${sage('in another tab — keeps CLAUDE.md in sync with .intent/')}`,
|
|
233
|
+
`${slate('·')} ${cream('/export')} ${sage('exports .intent/ as portable context for any AI tool')}`,
|
|
234
|
+
`${slate('·')} ${sage('.intent/ files are plain markdown — edit them directly anytime')}`,
|
|
235
|
+
`${slate('·')} ${cream('phewsh context --copy')} ${sage('puts your .intent/ context on the clipboard')}`,
|
|
236
|
+
`${slate('·')} ${cream('/tour')} ${sage('walks through the .intent/ workflow (no key needed)')}`,
|
|
237
|
+
`${slate('·')} ${sage('Everything works without an account. Account adds sync + sharing.')}`,
|
|
159
238
|
];
|
|
160
239
|
|
|
161
240
|
function randomTip() {
|
|
@@ -165,88 +244,98 @@ function randomTip() {
|
|
|
165
244
|
// ── Tour content ─────────────────────────────────────────
|
|
166
245
|
const TOUR_PAGES = [
|
|
167
246
|
{
|
|
168
|
-
title: 'What is
|
|
247
|
+
title: 'What is .intent/?',
|
|
169
248
|
body: [
|
|
170
|
-
` PHEWSH gives your project a ${b('portable identity')}.`,
|
|
171
|
-
` Define what you're building once — every AI tool reads it.`,
|
|
172
249
|
'',
|
|
173
|
-
`
|
|
174
|
-
`
|
|
250
|
+
` ${teal('.intent/')} ${sage('is your project\'s working memory.')}`,
|
|
251
|
+
` Plain markdown files, committed with your code, read by every AI tool.`,
|
|
252
|
+
'',
|
|
253
|
+
` ${cream('phew')} ${sage('— the relief of not re-explaining.')}`,
|
|
254
|
+
` ${cream('shh')} ${sage('— it just works. No noise.')}`,
|
|
255
|
+
'',
|
|
256
|
+
` PHEWSH is the tool that ${cream('authors')} and ${cream('syncs')} .intent/.`,
|
|
257
|
+
` It works standalone, inside Claude Code, Cursor, ChatGPT, or any MCP agent.`,
|
|
175
258
|
'',
|
|
176
|
-
` ${
|
|
177
|
-
` ${
|
|
259
|
+
` ${sage('You own these files. They travel with your code.')}`,
|
|
260
|
+
` ${sage('Everything works without an account. Account adds sync + sharing.')}`,
|
|
178
261
|
]
|
|
179
262
|
},
|
|
180
263
|
{
|
|
181
264
|
title: 'The .intent/ directory',
|
|
182
265
|
body: [
|
|
183
|
-
` ${cyan('.intent/')}`,
|
|
184
|
-
` ${green('vision.md')} ${g('What this project is and why it exists')}`,
|
|
185
|
-
` ${green('plan.md')} ${g('Strategy, phases, milestones')}`,
|
|
186
|
-
` ${green('next.md')} ${g('Current tasks and what to do right now')}`,
|
|
187
|
-
` ${yellow('gate.json')} ${g('Your constraints (budget, time, skill)')}`,
|
|
188
266
|
'',
|
|
189
|
-
` ${
|
|
267
|
+
` ${teal('.intent/')}`,
|
|
268
|
+
` ${peach('vision.md')} ${sage('What this project is and why it exists')}`,
|
|
269
|
+
` ${peach('plan.md')} ${sage('Strategy, phases, milestones')}`,
|
|
270
|
+
` ${peach('next.md')} ${sage('Current tasks and what to do right now')}`,
|
|
271
|
+
` ${ember('gate.json')} ${sage('Your constraints (budget, time, skill)')}`,
|
|
272
|
+
'',
|
|
273
|
+
` ${sage('Create these with')} ${cream('/init')} ${sage('or')} ${cream('/clarify')}`,
|
|
190
274
|
]
|
|
191
275
|
},
|
|
192
276
|
{
|
|
193
277
|
title: 'Standalone mode',
|
|
194
278
|
body: [
|
|
195
|
-
` When you run ${w('phewsh')} on its own, you get an AI shell`,
|
|
196
|
-
` that knows your project inside and out.`,
|
|
197
279
|
'',
|
|
198
|
-
`
|
|
199
|
-
`
|
|
200
|
-
|
|
201
|
-
` ${
|
|
280
|
+
` Run ${cream('phewsh')} and type naturally.`,
|
|
281
|
+
` Every message carries your .intent/ context automatically.`,
|
|
282
|
+
'',
|
|
283
|
+
` ${teal('phewsh')} ${sage('>')} what should I focus on today?`,
|
|
284
|
+
` ${teal('phewsh')} ${sage('>')} is my plan realistic given my budget?`,
|
|
285
|
+
` ${teal('phewsh')} ${sage('>')} break this feature into tasks`,
|
|
202
286
|
'',
|
|
203
|
-
` ${
|
|
287
|
+
` ${sage('The AI reads .intent/ — no warmup needed.')}`,
|
|
204
288
|
]
|
|
205
289
|
},
|
|
206
290
|
{
|
|
207
|
-
title: '
|
|
291
|
+
title: '.intent/ in other tools',
|
|
208
292
|
body: [
|
|
209
|
-
` ${b('Claude Code')} ${g('phewsh watch → auto-updates CLAUDE.md')}`,
|
|
210
|
-
` ${b('Cursor')} ${g('phewsh context --file → .phewsh.context')}`,
|
|
211
|
-
` ${b('ChatGPT')} ${g('phewsh context --copy → paste into Custom Instructions')}`,
|
|
212
|
-
` ${b('MCP agents')} ${g('phewsh mcp setup → agents pull tasks automatically')}`,
|
|
213
293
|
'',
|
|
214
|
-
` ${
|
|
294
|
+
` ${b(cream('Claude Code'))} ${sage('phewsh watch → CLAUDE.md stays in sync with .intent/')}`,
|
|
295
|
+
` ${b(cream('Cursor'))} ${sage('phewsh context --file → exports .intent/ to .phewsh.context')}`,
|
|
296
|
+
` ${b(cream('ChatGPT'))} ${sage('phewsh context --copy → .intent/ on your clipboard')}`,
|
|
297
|
+
` ${b(cream('MCP agents'))} ${sage('phewsh mcp setup → agents read .intent/ automatically')}`,
|
|
298
|
+
'',
|
|
299
|
+
` ${sage('Same .intent/. Every tool. Switch mid-thought. Nothing lost.')}`,
|
|
215
300
|
]
|
|
216
301
|
},
|
|
217
302
|
{
|
|
218
303
|
title: 'The Decision Gate',
|
|
219
304
|
body: [
|
|
220
|
-
|
|
305
|
+
'',
|
|
306
|
+
` Before you build, decide ${b(cream('whether'))} to build.`,
|
|
221
307
|
` The gate captures what you can actually spend:`,
|
|
222
308
|
'',
|
|
223
|
-
` ${
|
|
224
|
-
` ${
|
|
309
|
+
` ${sage('Budget')} ${cream('$50')} ${sage('Skill')} ${cream('expert')}`,
|
|
310
|
+
` ${sage('Time')} ${cream('15 hrs/week')} ${sage('Urgency')} ${cream('high')}`,
|
|
225
311
|
'',
|
|
226
|
-
` ${
|
|
227
|
-
` ${
|
|
312
|
+
` ${sage('These constraints shape every AI response.')}`,
|
|
313
|
+
` ${sage('Run')} ${cream('/gate activate')} ${sage('to set yours.')}`,
|
|
228
314
|
]
|
|
229
315
|
},
|
|
230
316
|
{
|
|
231
317
|
title: 'You\'re ready',
|
|
232
318
|
body: [
|
|
233
|
-
` ${green('●')} Type naturally to chat with your project context`,
|
|
234
|
-
` ${green('●')} ${w('/init')} or ${w('/clarify')} to create .intent/ artifacts`,
|
|
235
|
-
` ${green('●')} ${w('/gate')} to set your constraints`,
|
|
236
|
-
` ${green('●')} ${w('/help')} for all commands`,
|
|
237
319
|
'',
|
|
238
|
-
` ${
|
|
239
|
-
` ${
|
|
320
|
+
` ${teal('●')} ${cream('/init')} or ${cream('/clarify')} to create .intent/ artifacts`,
|
|
321
|
+
` ${teal('●')} Type naturally — .intent/ context is always loaded`,
|
|
322
|
+
` ${teal('●')} ${cream('/gate')} to set your constraints`,
|
|
323
|
+
` ${teal('●')} ${cream('phewsh watch')} to keep AI tools in sync`,
|
|
324
|
+
` ${teal('●')} ${cream('/help')} for all commands`,
|
|
325
|
+
'',
|
|
326
|
+
` ${sage('.intent/ is your project\'s working memory. PHEWSH keeps it useful.')}`,
|
|
240
327
|
]
|
|
241
328
|
},
|
|
242
329
|
];
|
|
243
330
|
|
|
244
331
|
module.exports = {
|
|
245
|
-
//
|
|
332
|
+
// Brand palette
|
|
333
|
+
teal, peach, sage, slate, cream, ember,
|
|
334
|
+
// Standard ANSI
|
|
246
335
|
b, d, w, g, green, cyan, yellow, magenta, blue, red,
|
|
247
336
|
// Components
|
|
248
337
|
spinner, brandReveal, statusPanel, interopLine, divider, typewrite,
|
|
249
338
|
randomTip, TOUR_PAGES,
|
|
250
339
|
// ANSI helpers
|
|
251
|
-
hide, show, up, clearLine,
|
|
340
|
+
hide, show, up, clearLine, sleep,
|
|
252
341
|
};
|