phewsh 0.15.73 → 0.15.75
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 +2 -0
- package/commands/clarify.js +27 -3
- package/commands/feedback.js +62 -0
- package/commands/intent.js +6 -1
- package/commands/session.js +4 -4
- package/lib/packs.js +4 -4
- package/package.json +1 -1
package/bin/phewsh.js
CHANGED
|
@@ -115,6 +115,7 @@ const COMMANDS = {
|
|
|
115
115
|
dispatch: () => require('../commands/task')(),
|
|
116
116
|
pack: () => require('../commands/pack')(),
|
|
117
117
|
hook: () => require('../commands/hook')(),
|
|
118
|
+
feedback: () => require('../commands/feedback')(),
|
|
118
119
|
welcome: () => require('../commands/welcome')(),
|
|
119
120
|
intro: () => require('../commands/welcome')(),
|
|
120
121
|
help: showHelp,
|
|
@@ -171,6 +172,7 @@ function showHelp() {
|
|
|
171
172
|
console.log(` ${cyan('bypass')} ${g('Went around phewsh? Record why — 10 seconds, no guilt')}`);
|
|
172
173
|
console.log('');
|
|
173
174
|
console.log(` ${b(w('configure'))}`);
|
|
175
|
+
console.log(` ${cyan('feedback')} ${g('Tell us where it breaks — prefilled GitHub issue, nothing hidden')}`);
|
|
174
176
|
console.log(` ${cyan('login')} ${g('Identity + API key + cloud sync')}`);
|
|
175
177
|
console.log(` ${cyan('link')} ${g('Link local .intent/ to cloud project')}`);
|
|
176
178
|
console.log(` ${cyan('update')} ${g('Update phewsh — or `phewsh update auto on` to stay current automatically')}`);
|
package/commands/clarify.js
CHANGED
|
@@ -81,6 +81,26 @@ function assembleRaw(answers) {
|
|
|
81
81
|
return answers.map((a) => `${a.title} (${a.directive}): ${a.answer}`).join('\n');
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
// No-AI spec from the user's own words: the first answer line becomes the
|
|
85
|
+
// goal (node label stripped), the raw text survives verbatim in pps.intent.raw,
|
|
86
|
+
// and the first task points back at the AI compile.
|
|
87
|
+
function fallbackSpec(raw) {
|
|
88
|
+
const first = String(raw).split('\n').find(l => l.trim()) || "Capture this project's intent";
|
|
89
|
+
const goal = first.replace(/^[A-Za-z]+ \([^)]*\):\s*/, '').trim().slice(0, 200);
|
|
90
|
+
return {
|
|
91
|
+
goal,
|
|
92
|
+
success_criteria: [],
|
|
93
|
+
constraints: [],
|
|
94
|
+
inputs: [],
|
|
95
|
+
outputs: [],
|
|
96
|
+
tasks: [
|
|
97
|
+
{ text: 'Re-run `phewsh clarify --update` to compile this spec with AI', type: 'copy' },
|
|
98
|
+
{ text: 'Refine the vision — complete vision.md', type: 'do' },
|
|
99
|
+
{ text: 'Define Phase 1 — what is the smallest thing to ship?', type: 'do' },
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
84
104
|
function buildClarifySystemPrompt(existing) {
|
|
85
105
|
const isRefine = !!(existing?.intent?.goal);
|
|
86
106
|
return `You are a project compiler. Your job is to extract clean, structured intent from messy human input.
|
|
@@ -264,8 +284,12 @@ async function main() {
|
|
|
264
284
|
? await callClarifyViaHarness(harnessId, raw, existing)
|
|
265
285
|
: await callClarifyAPI(config.apiKey, raw, existing);
|
|
266
286
|
} catch (err) {
|
|
267
|
-
|
|
268
|
-
|
|
287
|
+
// A failed compile must NEVER eat the user's answers. They just walked
|
|
288
|
+
// the compass — write a plain no-AI spec from what they typed, and let
|
|
289
|
+
// `clarify --update` enrich it when a route works again.
|
|
290
|
+
console.log(`\n AI compile unavailable (${err.message}).`);
|
|
291
|
+
console.log(' Saving your answers as a plain spec instead — nothing you typed is lost.');
|
|
292
|
+
extracted = fallbackSpec(raw);
|
|
269
293
|
}
|
|
270
294
|
|
|
271
295
|
const entity = getProjectName();
|
|
@@ -333,4 +357,4 @@ if (require.main === module) {
|
|
|
333
357
|
});
|
|
334
358
|
}
|
|
335
359
|
|
|
336
|
-
module.exports = { run: main, GUIDE_NODES, INTENT_NODES, assembleRaw, askGuided, extractJson };
|
|
360
|
+
module.exports = { run: main, GUIDE_NODES, INTENT_NODES, assembleRaw, askGuided, extractJson, fallbackSpec };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// phewsh feedback — the door the launch post points at.
|
|
2
|
+
//
|
|
3
|
+
// phewsh feedback open a prefilled GitHub issue in the browser
|
|
4
|
+
// phewsh feedback "it broke..." same, with your words already in the body
|
|
5
|
+
//
|
|
6
|
+
// Deliberately no hidden telemetry: everything sent is shown first, travels
|
|
7
|
+
// as a URL you can read, and lands in the public issue tracker. Email stays
|
|
8
|
+
// the quiet alternative for anything private.
|
|
9
|
+
|
|
10
|
+
const os = require('os');
|
|
11
|
+
const { execFileSync } = require('child_process');
|
|
12
|
+
|
|
13
|
+
const REPO_ISSUES = 'https://github.com/cleverIdeaz/phewsh-cli/issues/new';
|
|
14
|
+
const EMAIL = 'hello@phewsh.com';
|
|
15
|
+
|
|
16
|
+
const b = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
17
|
+
const g = (s) => `\x1b[38;5;247m${s}\x1b[0m`;
|
|
18
|
+
const w = (s) => `\x1b[97m${s}\x1b[0m`;
|
|
19
|
+
const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
|
|
20
|
+
|
|
21
|
+
function buildUrl(text) {
|
|
22
|
+
const version = require('../package.json').version;
|
|
23
|
+
const body = [
|
|
24
|
+
text ? text.trim() : '<!-- What happened? What did you expect? -->',
|
|
25
|
+
'',
|
|
26
|
+
'---',
|
|
27
|
+
`phewsh ${version} · ${process.platform} ${os.release()} · node ${process.version}`,
|
|
28
|
+
].join('\n');
|
|
29
|
+
const params = new URLSearchParams({ title: text ? text.trim().slice(0, 72) : '', body });
|
|
30
|
+
return `${REPO_ISSUES}?${params.toString()}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Arg-array spawn only — the URL carries user text; it must never touch a shell.
|
|
34
|
+
function openBrowser(url) {
|
|
35
|
+
try {
|
|
36
|
+
if (process.platform === 'darwin') execFileSync('open', [url]);
|
|
37
|
+
else if (process.platform === 'win32') execFileSync('cmd', ['/c', 'start', '', url]);
|
|
38
|
+
else execFileSync('xdg-open', [url]);
|
|
39
|
+
return true;
|
|
40
|
+
} catch { return false; }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function main() {
|
|
44
|
+
const text = process.argv.slice(3).filter(a => !a.startsWith('--')).join(' ');
|
|
45
|
+
const url = buildUrl(text);
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log(` ${b(w('phewsh feedback'))} ${g('— where it breaks is exactly what we want to hear')}`);
|
|
48
|
+
console.log(` ${g('Includes only what you see: your words + version/OS/node. Nothing else.')}`);
|
|
49
|
+
console.log('');
|
|
50
|
+
const opened = openBrowser(url);
|
|
51
|
+
if (opened) {
|
|
52
|
+
console.log(` ${cyan('●')} ${g('Opened a prefilled GitHub issue in your browser.')}`);
|
|
53
|
+
} else {
|
|
54
|
+
console.log(` ${g('Open this to file it:')}`);
|
|
55
|
+
console.log(` ${w(url)}`);
|
|
56
|
+
}
|
|
57
|
+
console.log(` ${g('Prefer email?')} ${w(EMAIL)}`);
|
|
58
|
+
console.log('');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = main;
|
|
62
|
+
module.exports.buildUrl = buildUrl;
|
package/commands/intent.js
CHANGED
|
@@ -6,7 +6,12 @@ const { createPPS, writeGuardedViews } = require('../lib/pps');
|
|
|
6
6
|
|
|
7
7
|
const os = require('os');
|
|
8
8
|
const configFile = require('../lib/config-file');
|
|
9
|
-
|
|
9
|
+
// Flags may arrive as `phewsh intent --init` / `phewsh init --init` (flag at
|
|
10
|
+
// argv[3]) or as a direct `node intent.js --init` (flag at argv[2]) — the
|
|
11
|
+
// session used the direct form and every flag was silently missed, so /init
|
|
12
|
+
// printed help instead of initializing. Accept both shapes.
|
|
13
|
+
const rawArgs = process.argv.slice(2);
|
|
14
|
+
const args = (rawArgs[0] === 'intent' || rawArgs[0] === 'init') ? rawArgs.slice(1) : rawArgs;
|
|
10
15
|
const INTENT_DIR = path.join(process.cwd(), '.intent');
|
|
11
16
|
const CONFIG_PATH = path.join(os.homedir(), '.phewsh', 'config.json');
|
|
12
17
|
const WEB_URL = 'https://phewsh.com/intent';
|
package/commands/session.js
CHANGED
|
@@ -1329,8 +1329,8 @@ async function main() {
|
|
|
1329
1329
|
if (choice.kind === 'init') {
|
|
1330
1330
|
bootstrapChoices = null;
|
|
1331
1331
|
try {
|
|
1332
|
-
const {
|
|
1333
|
-
|
|
1332
|
+
const { execFileSync } = require('child_process');
|
|
1333
|
+
execFileSync(process.execPath, [path.join(__dirname, '..', 'bin', 'phewsh.js'), 'intent', '--init'], { stdio: 'inherit' });
|
|
1334
1334
|
intentFiles = loadIntentContext();
|
|
1335
1335
|
systemPrompt = buildSystemPrompt(intentFiles);
|
|
1336
1336
|
if (intentFiles.length > 0) {
|
|
@@ -1916,8 +1916,8 @@ async function main() {
|
|
|
1916
1916
|
console.log(` ${sage('Use /reload to refresh context')}\n`);
|
|
1917
1917
|
} else {
|
|
1918
1918
|
try {
|
|
1919
|
-
const {
|
|
1920
|
-
|
|
1919
|
+
const { execFileSync } = require('child_process');
|
|
1920
|
+
execFileSync(process.execPath, [path.join(__dirname, '..', 'bin', 'phewsh.js'), 'intent', '--init'], { stdio: 'inherit' });
|
|
1921
1921
|
intentFiles = loadIntentContext();
|
|
1922
1922
|
systemPrompt = buildSystemPrompt(intentFiles);
|
|
1923
1923
|
if (intentFiles.length > 0) {
|
package/lib/packs.js
CHANGED
|
@@ -54,11 +54,11 @@ const PACKS = {
|
|
|
54
54
|
},
|
|
55
55
|
'loop-library': {
|
|
56
56
|
kind: 'linked',
|
|
57
|
-
title: 'Loop Library',
|
|
58
|
-
desc: '
|
|
59
|
-
source: '
|
|
57
|
+
title: 'Loop Library / Loopy',
|
|
58
|
+
desc: 'Forward Future\'s practical agent-loop library and Loopy skill, with checks and stopping conditions. Good Work-layer inspiration; phewsh links to it without becoming a scheduler or runner.',
|
|
59
|
+
source: 'signals.forwardfuture.com/loop-library · github.com/Forward-Future/loop-library',
|
|
60
60
|
license: 'MIT',
|
|
61
|
-
install: 'npx skills add Forward-Future/loop-library --skill
|
|
61
|
+
install: 'npx skills add Forward-Future/loop-library --skill loopy -g # install Loopy through upstream skills tooling',
|
|
62
62
|
},
|
|
63
63
|
'matt-skills': {
|
|
64
64
|
kind: 'linked',
|