phewsh 0.15.33 → 0.15.35
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/commands/hook.js +22 -0
- package/commands/session.js +34 -2
- package/package.json +1 -1
package/commands/hook.js
CHANGED
|
@@ -111,6 +111,28 @@ function sessionStart() {
|
|
|
111
111
|
const cont = continuityBrief(path.basename(process.cwd()));
|
|
112
112
|
if (cont) parts.push(`\n## Continuity (across your tools)\n${cont}`);
|
|
113
113
|
|
|
114
|
+
// Drift nudge (read-only): if code moved ahead of .intent/, say so — right
|
|
115
|
+
// here, where the agent will see it — so the human knows *when* to reconcile.
|
|
116
|
+
// We never auto-rewrite their source of truth; we just make the gap visible.
|
|
117
|
+
try {
|
|
118
|
+
const { statusDrift } = require('../lib/truth');
|
|
119
|
+
const drift = statusDrift(process.cwd());
|
|
120
|
+
if (drift && drift.tracked && drift.commitsSince > 0) {
|
|
121
|
+
parts.push(`\n## ⚠ phewsh drift\n.intent/ is ${drift.commitsSince} commit(s) behind the code (since ${drift.lastCommit}) — its current-state claims may be stale. Good moment to reconcile so every tool inherits today's reality.`);
|
|
122
|
+
}
|
|
123
|
+
} catch { /* drift is a nicety; never break the host */ }
|
|
124
|
+
|
|
125
|
+
// Ambient operating guidance: make phewsh *felt*, not invoked. The human may
|
|
126
|
+
// not know a single slash command — translate intent into phewsh actions for
|
|
127
|
+
// them, nudge gently, and leave a quiet signature so they feel the layer.
|
|
128
|
+
parts.push(`\n## Working with phewsh installed (ambient guidance)
|
|
129
|
+
phewsh keeps this project's intent, decisions, and outcomes aligned across every AI tool — so nothing is lost when the human switches tools. Help it work *for* them without making them learn it:
|
|
130
|
+
- Do their actual request first, and well.
|
|
131
|
+
- When you make a real decision, ship something, or change direction, offer in plain language to keep the shared record current — e.g. "want me to reconcile this into phewsh so your other tools inherit it?" Never make them memorize slash commands; map their intent to phewsh actions yourself.
|
|
132
|
+
- If the drift note above is present, mention it once, gently.
|
|
133
|
+
- Keep nudges subtle and occasional — never nag, never block the work.
|
|
134
|
+
- When phewsh context shaped your reply, sign off quietly with 😮💨🤫 (e.g. "— 😮💨🤫") so the human feels the continuity layer working in the background.`);
|
|
135
|
+
|
|
114
136
|
parts.push(`\n(Brief injected by PHEWSH ambient from .intent/. Honor the constraints above. The human can run \`phewsh\` for mission control — council, outcomes, the decision record.)`);
|
|
115
137
|
|
|
116
138
|
process.stdout.write(parts.join('\n') + '\n');
|
package/commands/session.js
CHANGED
|
@@ -383,6 +383,7 @@ async function main() {
|
|
|
383
383
|
let route = resolveRoute(config, harnesses);
|
|
384
384
|
let sessionMode = null; // INTENT_MODES id once picked
|
|
385
385
|
let awaitingOutcome = null; // decision id eligible for 1-4 labeling
|
|
386
|
+
let provisionalOutcome = null; // verdict phewsh inferred from the diff — Enter ↵ confirms it
|
|
386
387
|
let awaitingWhy = null; // { id, outcome } — next line is the reason
|
|
387
388
|
let awaitingReconcile = null; // exact proposed append, applied only after y
|
|
388
389
|
let lastTransitionReport = null; // latest native preflight -> postflight comparison
|
|
@@ -1154,6 +1155,25 @@ async function main() {
|
|
|
1154
1155
|
// anything else: drop the offer and treat it as fresh input
|
|
1155
1156
|
}
|
|
1156
1157
|
|
|
1158
|
+
// Enter ↵ confirms the provisional verdict phewsh inferred from the diff —
|
|
1159
|
+
// ambient capture so you never have to remember to run /outcomes.
|
|
1160
|
+
if (awaitingOutcome && provisionalOutcome && input.trim() === '') {
|
|
1161
|
+
const outcome = provisionalOutcome;
|
|
1162
|
+
try {
|
|
1163
|
+
labelOutcome(awaitingOutcome, outcome);
|
|
1164
|
+
console.log(` ${teal('●')} ${sage('outcome:')} ${green(outcome)} ${slate('· confirmed')}`);
|
|
1165
|
+
} catch { /* decision vanished */ }
|
|
1166
|
+
awaitingOutcome = null; provisionalOutcome = null;
|
|
1167
|
+
console.log('');
|
|
1168
|
+
rl.prompt();
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
// Typed something other than a verdict? They've moved on — drop the
|
|
1172
|
+
// provisional so a later stray Enter can't auto-confirm it.
|
|
1173
|
+
if (awaitingOutcome && provisionalOutcome && input.trim() !== '' && !/^[1-4]$/.test(input.trim())) {
|
|
1174
|
+
provisionalOutcome = null;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1157
1177
|
// A bare 1-4 right after a routed action labels its outcome
|
|
1158
1178
|
if (awaitingOutcome && /^[1-4]$/.test(input)) {
|
|
1159
1179
|
const outcome = OUTCOMES[parseInt(input, 10) - 1];
|
|
@@ -1165,6 +1185,7 @@ async function main() {
|
|
|
1165
1185
|
} catch { /* decision vanished — nothing to do */ }
|
|
1166
1186
|
const id = awaitingOutcome;
|
|
1167
1187
|
awaitingOutcome = null;
|
|
1188
|
+
provisionalOutcome = null;
|
|
1168
1189
|
// For a regret, the reason is the gold — capture one line so /recall can
|
|
1169
1190
|
// tell you *why* next time. Kept/superseded stay frictionless.
|
|
1170
1191
|
if (labeled && (outcome === 'reverted' || outcome === 'failed')) {
|
|
@@ -2401,7 +2422,7 @@ async function main() {
|
|
|
2401
2422
|
const preflightTruth = await auditTruth();
|
|
2402
2423
|
const before = captureSnapshot(preflightTruth);
|
|
2403
2424
|
const generatedBrief = await generateBrief({ report: preflightTruth });
|
|
2404
|
-
const launchBrief = `${generatedBrief.content}\n\nYou are receiving a PHEWSH handoff brief — acknowledge in one short line that you've loaded it, then proceed. Use it as project context, preserve native tool behavior, and verify claims against the repository before acting. When you finish, exit this tool — PHEWSH resumes, runs an automatic postflight comparing what changed against this brief, and offers reconciliation.`;
|
|
2425
|
+
const launchBrief = `${generatedBrief.content}\n\nYou are receiving a PHEWSH handoff brief — acknowledge in one short line that you've loaded it, then proceed. Use it as project context, preserve native tool behavior, and verify claims against the repository before acting. When you finish, exit this tool — PHEWSH resumes, runs an automatic postflight comparing what changed against this brief, and offers reconciliation.\n\nAmbient guidance: the human may not know any phewsh commands — make the layer felt, not invoked. Do their request first; when you make a real decision, ship something, or change direction, offer in plain language to keep the shared record current ("want me to reconcile this into phewsh so your other tools inherit it?"). Keep it subtle, never nag. When phewsh context shaped your reply, sign off quietly with 😮💨🤫 so they feel the continuity layer working.`;
|
|
2405
2426
|
const savedBrief = persistBrief(generatedBrief.content, { project: projectName, route: target });
|
|
2406
2427
|
const launch = interactiveLaunchArgs(target, launchBrief, { model: harnessModel });
|
|
2407
2428
|
// Foolproof fallback: the brief on the clipboard survives the native
|
|
@@ -2460,10 +2481,21 @@ async function main() {
|
|
|
2460
2481
|
briefingHash: savedBrief.hash,
|
|
2461
2482
|
});
|
|
2462
2483
|
awaitingOutcome = decisionId;
|
|
2484
|
+
// Ambient outcome capture: infer a provisional verdict from what the
|
|
2485
|
+
// session actually did, so the human confirms with one keystroke
|
|
2486
|
+
// instead of recalling. Honest — it's a confirmed default, not a
|
|
2487
|
+
// silent label; the human can always correct it with 1-4.
|
|
2488
|
+
provisionalOutcome = (postflight.headChanged || postflight.files.length > 0) ? 'kept' : null;
|
|
2463
2489
|
console.log('');
|
|
2464
2490
|
console.log(formatObservedReport(postflight, { title: `${h.label} session ended — postflight` }));
|
|
2465
2491
|
console.log('');
|
|
2466
|
-
|
|
2492
|
+
if (provisionalOutcome) {
|
|
2493
|
+
const why = postflight.headChanged ? 'committed work is in your repo' : 'changes are in your working tree';
|
|
2494
|
+
console.log(` ${teal('●')} ${sage('Back in phewsh.')} ${sage('Looks ')}${green('kept')} ${slate('(' + why + ') — enter ↵ to confirm')}`);
|
|
2495
|
+
console.log(` ${slate('or correct it: 1 kept · 2 undid · 3 redid · 4 flopped · /reconcile · /switch <tool>')}`);
|
|
2496
|
+
} else {
|
|
2497
|
+
console.log(` ${teal('●')} ${sage('Back in phewsh.')} ${slate('No changes detected. 1 kept · 2 undid · 3 redid · 4 flopped · /reconcile · /switch <tool>')}`);
|
|
2498
|
+
}
|
|
2467
2499
|
console.log('');
|
|
2468
2500
|
rl.prompt();
|
|
2469
2501
|
return;
|