phewsh 0.11.1 → 0.11.9
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 +6 -0
- package/commands/context.js +359 -0
- package/commands/gate.js +340 -0
- package/commands/intent.js +155 -6
- package/commands/mcp.js +2 -2
- package/commands/session.js +112 -11
- package/commands/sync.js +38 -0
- package/commands/watch.js +399 -0
- package/package.json +2 -3
package/bin/phewsh.js
CHANGED
|
@@ -47,7 +47,10 @@ const COMMANDS = {
|
|
|
47
47
|
ai: () => require('../commands/ai'),
|
|
48
48
|
style: () => require('../commands/style'),
|
|
49
49
|
mbhd: () => require('../commands/mbhd'),
|
|
50
|
+
context: () => require('../commands/context'),
|
|
51
|
+
gate: () => require('../commands/gate'),
|
|
50
52
|
sap: () => require('../commands/sap'),
|
|
53
|
+
watch: () => require('../commands/watch')(),
|
|
51
54
|
mcp: () => require('../commands/mcp')(),
|
|
52
55
|
serve: () => require('../commands/serve')(),
|
|
53
56
|
help: showHelp,
|
|
@@ -73,7 +76,10 @@ function showHelp() {
|
|
|
73
76
|
console.log(` ${w('link')} Link local .intent/ to a cloud project`);
|
|
74
77
|
console.log(` ${w('intent')} Manage .intent/ artifacts — status, open, evolve`);
|
|
75
78
|
console.log(` ${w('ai')} One-shot AI prompt (reads .intent/)`);
|
|
79
|
+
console.log(` ${w('gate')} Declare operational constraints (budget, time, skill)`);
|
|
80
|
+
console.log(` ${w('context')} Export portable context for any AI tool`);
|
|
76
81
|
console.log(` ${w('login')} Set up identity, API key, and cloud sync`);
|
|
82
|
+
console.log(` ${w('watch')} Live sync — .intent/ changes push to cloud + CLAUDE.md`);
|
|
77
83
|
console.log(` ${w('serve')} Start live execution bridge for the web app`);
|
|
78
84
|
console.log(` ${w('mcp')} Connect AI agents — setup, sync, status`);
|
|
79
85
|
console.log(` ${w('sap')} Sustainable AI Protocol — usage and accountability`);
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
// phewsh context
|
|
2
|
+
// Export portable adaptive context for any AI tool.
|
|
3
|
+
// Reads .intent/ artifacts + gate.json and generates an operational briefing.
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
const INTENT_DIR = path.join(process.cwd(), '.intent');
|
|
9
|
+
|
|
10
|
+
const args = process.argv.slice(3);
|
|
11
|
+
const flags = {
|
|
12
|
+
full: args.includes('--full') || args.includes('-f'),
|
|
13
|
+
claude: args.includes('--claude'),
|
|
14
|
+
clipboard: args.includes('--copy') || args.includes('-c'),
|
|
15
|
+
file: args.includes('--file') || args.includes('-o'),
|
|
16
|
+
help: args.includes('--help') || args.includes('-h'),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function loadArtifact(name) {
|
|
20
|
+
const p = path.join(INTENT_DIR, name);
|
|
21
|
+
if (!fs.existsSync(p)) return null;
|
|
22
|
+
return fs.readFileSync(p, 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function loadGate() {
|
|
26
|
+
const p = path.join(INTENT_DIR, 'gate.json');
|
|
27
|
+
if (!fs.existsSync(p)) return null;
|
|
28
|
+
try { return JSON.parse(fs.readFileSync(p, 'utf-8')); } catch { return null; }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function extractExecutionState(nextContent) {
|
|
32
|
+
const items = [];
|
|
33
|
+
const stateMap = { ' ': 'todo', '-': 'in_progress', 'x': 'done', '!': 'blocked', '~': 'skipped' };
|
|
34
|
+
|
|
35
|
+
for (const line of nextContent.split('\n')) {
|
|
36
|
+
const match = line.match(/^[-*]\s*\[([ x!\-~])\]\s*\*?\*?(.+?)\*?\*?\s*$/);
|
|
37
|
+
if (match) {
|
|
38
|
+
const char = match[1] === '-' ? '-' : match[1];
|
|
39
|
+
items.push({ title: match[2].replace(/\*\*/g, '').trim(), state: stateMap[char] || 'todo' });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
total: items.length,
|
|
45
|
+
done: items.filter(i => i.state === 'done').length,
|
|
46
|
+
doing: items.filter(i => i.state === 'in_progress').length,
|
|
47
|
+
blocked: items.filter(i => i.state === 'blocked').length,
|
|
48
|
+
skipped: items.filter(i => i.state === 'skipped').length,
|
|
49
|
+
items,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildConstraintInstructions(c) {
|
|
54
|
+
const lines = [];
|
|
55
|
+
|
|
56
|
+
if (c.budget > 0) {
|
|
57
|
+
lines.push(`- Budget: $${c.budget} total. ${
|
|
58
|
+
c.budget < 100 ? 'Extremely tight — free/open-source only.'
|
|
59
|
+
: c.budget < 500 ? 'Limited — justify any paid tool.'
|
|
60
|
+
: c.budget < 2000 ? 'Moderate — strategic spending OK.'
|
|
61
|
+
: 'Substantial — professional tools welcome.'
|
|
62
|
+
}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (c.timeHoursPerWeek > 0) {
|
|
66
|
+
lines.push(`- Time: ${c.timeHoursPerWeek} hrs/week. ${
|
|
67
|
+
c.timeHoursPerWeek <= 5 ? 'Micro-steps only. Each task < 2 hours.'
|
|
68
|
+
: c.timeHoursPerWeek <= 15 ? 'Part-time. Clear stopping points.'
|
|
69
|
+
: c.timeHoursPerWeek <= 30 ? 'Near full-time. Sustained work OK.'
|
|
70
|
+
: 'Full-time+. Ambitious scope OK.'
|
|
71
|
+
}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
lines.push(`- Skill: ${c.skillLevel}. ${
|
|
75
|
+
c.skillLevel === 'beginner' ? 'Explain everything. Simplest architecture wins.'
|
|
76
|
+
: c.skillLevel === 'intermediate' ? 'Reference docs, flag gotchas.'
|
|
77
|
+
: c.skillLevel === 'advanced' ? 'Focus on strategic decisions.'
|
|
78
|
+
: 'Deep expertise. Advanced patterns welcome.'
|
|
79
|
+
}`);
|
|
80
|
+
|
|
81
|
+
lines.push(`- Urgency: ${c.urgency}. ${
|
|
82
|
+
c.urgency === 'relaxed' ? 'Thoroughness over speed.'
|
|
83
|
+
: c.urgency === 'moderate' ? 'Weeks not months. Proven approaches.'
|
|
84
|
+
: c.urgency === 'urgent' ? 'Days matter. Cut scope aggressively.'
|
|
85
|
+
: 'BLOCKING. Strip to essentials.'
|
|
86
|
+
}`);
|
|
87
|
+
|
|
88
|
+
lines.push(`- Autonomy: ${c.autonomy}. ${
|
|
89
|
+
c.autonomy === 'hands-on' ? 'Present options, not recommendations.'
|
|
90
|
+
: c.autonomy === 'guided' ? 'Opinionated suggestions with reasoning.'
|
|
91
|
+
: c.autonomy === 'delegated' ? 'Be decisive. Only escalate irreversible decisions.'
|
|
92
|
+
: 'Maximum automation.'
|
|
93
|
+
}`);
|
|
94
|
+
|
|
95
|
+
return lines.join('\n');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function generateContext(includeArtifacts = false) {
|
|
99
|
+
const vision = loadArtifact('vision.md');
|
|
100
|
+
const plan = loadArtifact('plan.md');
|
|
101
|
+
const next = loadArtifact('next.md');
|
|
102
|
+
const gate = loadGate();
|
|
103
|
+
const projectName = path.basename(process.cwd());
|
|
104
|
+
|
|
105
|
+
if (!vision && !plan && !next) return null;
|
|
106
|
+
|
|
107
|
+
const sections = [];
|
|
108
|
+
const constraints = gate?.constraints;
|
|
109
|
+
const hasConstraints = constraints && (
|
|
110
|
+
constraints.budget > 0 ||
|
|
111
|
+
constraints.timeHoursPerWeek > 0 ||
|
|
112
|
+
constraints.skillLevel !== 'intermediate' ||
|
|
113
|
+
constraints.urgency !== 'moderate' ||
|
|
114
|
+
constraints.autonomy !== 'guided'
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// Header
|
|
118
|
+
sections.push(`# PHEWSH Adaptive Context — ${projectName}`);
|
|
119
|
+
sections.push(`> Generated ${new Date().toISOString().split('T')[0]} | phewsh.com/intent`);
|
|
120
|
+
sections.push(`> Drop this into CLAUDE.md, .cursorrules, or agent config.`);
|
|
121
|
+
sections.push('');
|
|
122
|
+
|
|
123
|
+
// Project identity
|
|
124
|
+
sections.push('## Project');
|
|
125
|
+
sections.push(`- **Name**: ${projectName}`);
|
|
126
|
+
if (gate?.archetype) sections.push(`- **Type**: ${gate.archetype}`);
|
|
127
|
+
|
|
128
|
+
// Extract TLDR from vision first line
|
|
129
|
+
if (vision) {
|
|
130
|
+
const firstMeaningful = vision.split('\n').find(l => l.trim().length > 20 && !l.startsWith('#'));
|
|
131
|
+
if (firstMeaningful) sections.push(`- **TLDR**: ${firstMeaningful.trim()}`);
|
|
132
|
+
}
|
|
133
|
+
sections.push('');
|
|
134
|
+
|
|
135
|
+
// Operational constraints
|
|
136
|
+
if (hasConstraints) {
|
|
137
|
+
sections.push('## Operational Reality');
|
|
138
|
+
sections.push('These constraints MUST shape every suggestion and implementation decision:');
|
|
139
|
+
sections.push('');
|
|
140
|
+
sections.push(buildConstraintInstructions(constraints));
|
|
141
|
+
sections.push('');
|
|
142
|
+
|
|
143
|
+
// Execution Reality Map
|
|
144
|
+
if (gate?.executionMap) {
|
|
145
|
+
const map = gate.executionMap;
|
|
146
|
+
sections.push('### Execution Assessment');
|
|
147
|
+
sections.push(`- **Feasibility**: ${gate.feasibility}`);
|
|
148
|
+
if (map.recommendedMode) sections.push(`- **Recommended mode**: ${map.recommendedMode}`);
|
|
149
|
+
if (map.primaryBottleneck) sections.push(`- **Primary bottleneck**: ${map.primaryBottleneck}`);
|
|
150
|
+
if (map.highestLeveragePath) sections.push(`- **Highest leverage move**: ${map.highestLeveragePath}`);
|
|
151
|
+
if (map.estimatedTimeline) sections.push(`- **Timeline**: ${map.estimatedTimeline}`);
|
|
152
|
+
if (map.majorRisks?.length > 0) sections.push(`- **Risks**: ${map.majorRisks.join('; ')}`);
|
|
153
|
+
sections.push('');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Execution state
|
|
158
|
+
if (next) {
|
|
159
|
+
const exec = extractExecutionState(next);
|
|
160
|
+
if (exec.total > 0) {
|
|
161
|
+
sections.push('## Current Execution State');
|
|
162
|
+
sections.push(`Progress: ${exec.done}/${exec.total} done${exec.doing ? `, ${exec.doing} in progress` : ''}${exec.blocked ? `, ${exec.blocked} blocked` : ''}`);
|
|
163
|
+
sections.push('');
|
|
164
|
+
|
|
165
|
+
const doing = exec.items.filter(i => i.state === 'in_progress');
|
|
166
|
+
if (doing.length > 0) {
|
|
167
|
+
sections.push('**Currently working on:**');
|
|
168
|
+
doing.forEach(i => sections.push(`- ${i.title}`));
|
|
169
|
+
sections.push('');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const blocked = exec.items.filter(i => i.state === 'blocked');
|
|
173
|
+
if (blocked.length > 0) {
|
|
174
|
+
sections.push('**Blocked:**');
|
|
175
|
+
blocked.forEach(i => sections.push(`- ${i.title}`));
|
|
176
|
+
sections.push('');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const todo = exec.items.filter(i => i.state === 'todo');
|
|
180
|
+
if (todo.length > 0) {
|
|
181
|
+
sections.push('**Remaining:**');
|
|
182
|
+
todo.forEach(i => sections.push(`- ${i.title}`));
|
|
183
|
+
sections.push('');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Constraint drift
|
|
189
|
+
if (gate?.constraintHistory?.length > 0) {
|
|
190
|
+
sections.push('### Constraint Drift');
|
|
191
|
+
sections.push('Reality changed during this project:');
|
|
192
|
+
sections.push('');
|
|
193
|
+
for (const ch of gate.constraintHistory.slice(-10)) {
|
|
194
|
+
const date = ch.timestamp.split('T')[0];
|
|
195
|
+
sections.push(`- **${ch.field}**: ${ch.from} → ${ch.to}${ch.reason ? ` (${ch.reason})` : ''} — ${date}`);
|
|
196
|
+
}
|
|
197
|
+
sections.push('');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Responsibility split
|
|
201
|
+
if (gate?.responsibilitySplit) {
|
|
202
|
+
sections.push('## Responsibility Split');
|
|
203
|
+
if (gate.responsibilitySplit.ai?.length > 0) {
|
|
204
|
+
sections.push('**AI/agents can handle:**');
|
|
205
|
+
gate.responsibilitySplit.ai.forEach(r => sections.push(`- ${r}`));
|
|
206
|
+
}
|
|
207
|
+
if (gate.responsibilitySplit.human?.length > 0) {
|
|
208
|
+
sections.push('**Requires human action:**');
|
|
209
|
+
gate.responsibilitySplit.human.forEach(r => sections.push(`- ${r}`));
|
|
210
|
+
}
|
|
211
|
+
sections.push('');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// AI instructions
|
|
215
|
+
sections.push('## Instructions for AI Tools');
|
|
216
|
+
sections.push('When working on this project:');
|
|
217
|
+
const instructions = [];
|
|
218
|
+
|
|
219
|
+
if (hasConstraints) {
|
|
220
|
+
instructions.push('- Adapt ALL suggestions to the operational constraints above.');
|
|
221
|
+
if (constraints.budget > 0 && constraints.budget < 500) {
|
|
222
|
+
instructions.push('- Never recommend paid services without noting cost and a free alternative.');
|
|
223
|
+
}
|
|
224
|
+
if (constraints.timeHoursPerWeek > 0 && constraints.timeHoursPerWeek <= 10) {
|
|
225
|
+
instructions.push('- Break every task into steps completable in a single sitting.');
|
|
226
|
+
}
|
|
227
|
+
if (constraints.skillLevel === 'beginner') {
|
|
228
|
+
instructions.push('- Explain every tool, concept, and command. No assumed knowledge.');
|
|
229
|
+
}
|
|
230
|
+
if (constraints.urgency === 'urgent' || constraints.urgency === 'critical') {
|
|
231
|
+
instructions.push('- Prioritize shipping over polish. Cut scope ruthlessly.');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (next) {
|
|
236
|
+
const exec = extractExecutionState(next);
|
|
237
|
+
const blockedCount = exec.items.filter(i => i.state === 'blocked').length;
|
|
238
|
+
if (blockedCount > 0) {
|
|
239
|
+
instructions.push(`- ${blockedCount} task(s) are blocked. Suggest alternative approaches if relevant.`);
|
|
240
|
+
}
|
|
241
|
+
if (exec.done > 0 && exec.total > 0) {
|
|
242
|
+
const pct = Math.round((exec.done / exec.total) * 100);
|
|
243
|
+
instructions.push(`- Project is ${pct}% complete. Focus on remaining work.`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (instructions.length === 0) {
|
|
248
|
+
instructions.push('- Follow the project vision and plan. Check execution state for current progress.');
|
|
249
|
+
}
|
|
250
|
+
sections.push(instructions.join('\n'));
|
|
251
|
+
sections.push('');
|
|
252
|
+
|
|
253
|
+
// Full artifacts (optional)
|
|
254
|
+
if (includeArtifacts) {
|
|
255
|
+
if (vision) { sections.push('## Vision'); sections.push(vision); sections.push(''); }
|
|
256
|
+
if (plan) { sections.push('## Plan'); sections.push(plan); sections.push(''); }
|
|
257
|
+
if (next) { sections.push('## Next Actions'); sections.push(next); sections.push(''); }
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
sections.push('---');
|
|
261
|
+
sections.push('*Exported from [PHEWSH Intent](https://phewsh.com/intent) — software that adapts to you.*');
|
|
262
|
+
|
|
263
|
+
return sections.join('\n');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function showHelp() {
|
|
267
|
+
console.log(`
|
|
268
|
+
phewsh context — Export portable adaptive context
|
|
269
|
+
|
|
270
|
+
Usage:
|
|
271
|
+
phewsh context Generate context to stdout
|
|
272
|
+
phewsh context --full Include full artifact text
|
|
273
|
+
phewsh context --copy Copy to clipboard
|
|
274
|
+
phewsh context --file Write to .phewsh.context in current directory
|
|
275
|
+
phewsh context --claude Write to CLAUDE.md (for Claude Code)
|
|
276
|
+
|
|
277
|
+
What it does:
|
|
278
|
+
Reads .intent/ artifacts + gate.json and produces an operational
|
|
279
|
+
briefing that makes any AI tool constraint-aware.
|
|
280
|
+
|
|
281
|
+
Drop the output into CLAUDE.md, .cursorrules, or agent config.
|
|
282
|
+
`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function main() {
|
|
286
|
+
if (flags.help) { showHelp(); return; }
|
|
287
|
+
|
|
288
|
+
if (!fs.existsSync(INTENT_DIR)) {
|
|
289
|
+
console.log('\n No .intent/ found. Run `phewsh intent --init` first.\n');
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const content = generateContext(flags.full);
|
|
294
|
+
if (!content) {
|
|
295
|
+
console.log('\n No artifacts found in .intent/\n');
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (flags.file) {
|
|
300
|
+
const outPath = path.join(process.cwd(), '.phewsh.context');
|
|
301
|
+
fs.writeFileSync(outPath, content);
|
|
302
|
+
console.log(`\n ✓ Written to ${outPath}\n`);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (flags.claude) {
|
|
307
|
+
const outPath = path.join(process.cwd(), 'CLAUDE.md');
|
|
308
|
+
const START_MARKER = '<!-- PHEWSH:START -->';
|
|
309
|
+
const END_MARKER = '<!-- PHEWSH:END -->';
|
|
310
|
+
const wrapped = `${START_MARKER}\n${content}\n${END_MARKER}`;
|
|
311
|
+
|
|
312
|
+
if (fs.existsSync(outPath)) {
|
|
313
|
+
let existing = fs.readFileSync(outPath, 'utf-8');
|
|
314
|
+
const startIdx = existing.indexOf(START_MARKER);
|
|
315
|
+
const endIdx = existing.indexOf(END_MARKER);
|
|
316
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
317
|
+
existing = existing.slice(0, startIdx) + wrapped + existing.slice(endIdx + END_MARKER.length);
|
|
318
|
+
fs.writeFileSync(outPath, existing);
|
|
319
|
+
console.log('\n ✓ Updated PHEWSH section in CLAUDE.md\n');
|
|
320
|
+
} else {
|
|
321
|
+
fs.writeFileSync(outPath, existing.trimEnd() + '\n\n' + wrapped + '\n');
|
|
322
|
+
console.log('\n ✓ Appended to CLAUDE.md\n');
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
fs.writeFileSync(outPath, wrapped + '\n');
|
|
326
|
+
console.log('\n ✓ Created CLAUDE.md\n');
|
|
327
|
+
}
|
|
328
|
+
console.log(' Tip: Run `phewsh watch` to keep this section auto-synced.\n');
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (flags.clipboard) {
|
|
333
|
+
try {
|
|
334
|
+
const { execSync } = require('child_process');
|
|
335
|
+
if (process.platform === 'darwin') {
|
|
336
|
+
execSync('pbcopy', { input: content });
|
|
337
|
+
} else if (process.platform === 'linux') {
|
|
338
|
+
execSync('xclip -selection clipboard', { input: content });
|
|
339
|
+
} else {
|
|
340
|
+
execSync('clip', { input: content });
|
|
341
|
+
}
|
|
342
|
+
console.log('\n ✓ Copied to clipboard\n');
|
|
343
|
+
} catch {
|
|
344
|
+
// Fallback: print to stdout
|
|
345
|
+
console.log(content);
|
|
346
|
+
}
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Default: print to stdout
|
|
351
|
+
console.log(content);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
module.exports = { main, generateContext };
|
|
355
|
+
|
|
356
|
+
main().catch(err => {
|
|
357
|
+
console.error('\n Error:', err.message);
|
|
358
|
+
process.exit(1);
|
|
359
|
+
});
|