phewsh 0.15.25 → 0.15.26
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/session.js +25 -1
- package/lib/outcomes.js +4 -1
- package/package.json +1 -1
package/commands/session.js
CHANGED
|
@@ -334,6 +334,7 @@ async function main() {
|
|
|
334
334
|
let route = resolveRoute(config, harnesses);
|
|
335
335
|
let sessionMode = null; // INTENT_MODES id once picked
|
|
336
336
|
let awaitingOutcome = null; // decision id eligible for 1-4 labeling
|
|
337
|
+
let awaitingWhy = null; // { id, outcome } — next line is the reason
|
|
337
338
|
let awaitingFallback = null; // { input, fullSystem, options } after a route failure
|
|
338
339
|
let bootstrapChoices = null; // root-bootstrap menu entries when no project here
|
|
339
340
|
let nextChoices = null; // ranked /next suggestions awaiting a numeric pick
|
|
@@ -597,6 +598,7 @@ async function main() {
|
|
|
597
598
|
if (s.length > 50) s = s.slice(0, 49).trimEnd() + '…';
|
|
598
599
|
const verb = hit.outcome === 'failed' ? 'failed' : 'reverted';
|
|
599
600
|
console.log(` ${peach('↩')} ${sage(`You ${verb} something close before:`)} ${slate('“' + s + '” · via ' + continuity.labelFor(hit.route) + ' · ' + continuity.agoText(hit.ts))}`);
|
|
601
|
+
if (hit.why) console.log(` ${slate(' why it didn\'t hold: ')}${sage(hit.why)}`);
|
|
600
602
|
console.log(` ${slate(' not a block — just so the record doesn\'t let you repeat it blind.')}`);
|
|
601
603
|
} catch { /* recall is advisory, never blocks a turn */ }
|
|
602
604
|
}
|
|
@@ -955,6 +957,16 @@ async function main() {
|
|
|
955
957
|
async function handleInput(input) {
|
|
956
958
|
input = expandPastes(input);
|
|
957
959
|
|
|
960
|
+
// Answering the "why?" prompt — the whole line is the reason, not a command.
|
|
961
|
+
if (awaitingWhy) {
|
|
962
|
+
const { id, outcome } = awaitingWhy;
|
|
963
|
+
awaitingWhy = null;
|
|
964
|
+
try { labelOutcome(id, outcome, input); console.log(` ${slate('noted — the record will remember why.')}`); } catch { /* gone */ }
|
|
965
|
+
console.log('');
|
|
966
|
+
rl.prompt();
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
969
|
+
|
|
958
970
|
// Any typed input supersedes a pending "did you mean" offer.
|
|
959
971
|
if (pendingDidYouMean) pendingDidYouMean = null;
|
|
960
972
|
|
|
@@ -979,12 +991,22 @@ async function main() {
|
|
|
979
991
|
// A bare 1-4 right after a routed action labels its outcome
|
|
980
992
|
if (awaitingOutcome && /^[1-4]$/.test(input)) {
|
|
981
993
|
const outcome = OUTCOMES[parseInt(input, 10) - 1];
|
|
994
|
+
let labeled = null;
|
|
982
995
|
try {
|
|
983
|
-
labelOutcome(awaitingOutcome, outcome);
|
|
996
|
+
labeled = labelOutcome(awaitingOutcome, outcome);
|
|
984
997
|
const color = outcome === 'kept' ? green : outcome === 'superseded' ? peach : ember;
|
|
985
998
|
console.log(` ${teal('●')} ${sage('outcome:')} ${color(outcome)}`);
|
|
986
999
|
} catch { /* decision vanished — nothing to do */ }
|
|
1000
|
+
const id = awaitingOutcome;
|
|
987
1001
|
awaitingOutcome = null;
|
|
1002
|
+
// For a regret, the reason is the gold — capture one line so /recall can
|
|
1003
|
+
// tell you *why* next time. Kept/superseded stay frictionless.
|
|
1004
|
+
if (labeled && (outcome === 'reverted' || outcome === 'failed')) {
|
|
1005
|
+
awaitingWhy = { id, outcome };
|
|
1006
|
+
console.log(` ${slate('why? one line — feeds /recall next time · enter to skip')}`);
|
|
1007
|
+
rl.prompt();
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
988
1010
|
console.log('');
|
|
989
1011
|
rl.prompt();
|
|
990
1012
|
return;
|
|
@@ -2268,6 +2290,8 @@ async function main() {
|
|
|
2268
2290
|
const lineDispatcher = createLineDispatcher(handleInput, {
|
|
2269
2291
|
onBatch: ({ input, lines }) => { collapsePastedEcho(lines, input); cmdHistory.append(input); },
|
|
2270
2292
|
onNoop: () => {
|
|
2293
|
+
// Bare Enter skips the "why?" prompt — the label still stands.
|
|
2294
|
+
if (awaitingWhy) { awaitingWhy = null; console.log(''); rl.prompt(); return; }
|
|
2271
2295
|
// Bare Enter accepts a pending "did you mean" suggestion.
|
|
2272
2296
|
if (pendingDidYouMean) {
|
|
2273
2297
|
const cmd = pendingDidYouMean;
|
package/lib/outcomes.js
CHANGED
|
@@ -51,7 +51,7 @@ function recordDecision({ project, route, mode, summary }) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/** Label a decision by id (or unambiguous id prefix). Returns the decision or null. */
|
|
54
|
-
function labelOutcome(idOrPrefix, outcome) {
|
|
54
|
+
function labelOutcome(idOrPrefix, outcome, why = null) {
|
|
55
55
|
if (!OUTCOMES.includes(outcome)) {
|
|
56
56
|
throw new Error(`Outcome must be one of: ${OUTCOMES.join(', ')}`);
|
|
57
57
|
}
|
|
@@ -60,6 +60,9 @@ function labelOutcome(idOrPrefix, outcome) {
|
|
|
60
60
|
if (matches.length !== 1) return null;
|
|
61
61
|
matches[0].outcome = outcome;
|
|
62
62
|
matches[0].labeledAt = new Date().toISOString();
|
|
63
|
+
// One-line reason — the most valuable thing about a reverted/failed call.
|
|
64
|
+
// Feeds /recall ("you reverted this before — because …") and /learn.
|
|
65
|
+
if (why && String(why).trim()) matches[0].why = String(why).trim().slice(0, 200);
|
|
63
66
|
save(decisions);
|
|
64
67
|
return matches[0];
|
|
65
68
|
}
|