@tritard/waterbrother 0.6.0 → 0.6.2
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/package.json +1 -1
- package/src/prompt.js +31 -0
- package/src/router.js +12 -6
package/package.json
CHANGED
package/src/prompt.js
CHANGED
|
@@ -8,10 +8,15 @@ export async function promptLine(label, { input = process.stdin, output = proces
|
|
|
8
8
|
let buf = "";
|
|
9
9
|
let resolved = false;
|
|
10
10
|
const shouldPauseOnCleanup = typeof input.pause === "function";
|
|
11
|
+
const isTTY = input.isTTY && typeof input.setRawMode === "function";
|
|
12
|
+
|
|
11
13
|
function cleanup() {
|
|
12
14
|
resolved = true;
|
|
13
15
|
input.removeListener("data", onData);
|
|
14
16
|
if (signal) signal.removeEventListener("abort", onAbort);
|
|
17
|
+
if (isTTY) {
|
|
18
|
+
try { input.setRawMode(false); } catch {}
|
|
19
|
+
}
|
|
15
20
|
if (shouldPauseOnCleanup) {
|
|
16
21
|
try {
|
|
17
22
|
input.pause();
|
|
@@ -25,10 +30,27 @@ export async function promptLine(label, { input = process.stdin, output = proces
|
|
|
25
30
|
if (ch === "\r") continue;
|
|
26
31
|
if (ch === "\n") {
|
|
27
32
|
cleanup();
|
|
33
|
+
output.write("\n");
|
|
28
34
|
resolve(buf);
|
|
29
35
|
return;
|
|
30
36
|
}
|
|
37
|
+
if (ch === "\u0003") {
|
|
38
|
+
cleanup();
|
|
39
|
+
reject(new DOMException("The operation was aborted.", "AbortError"));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Backspace
|
|
43
|
+
if (ch === "\u007f" || ch === "\b") {
|
|
44
|
+
if (buf.length > 0) {
|
|
45
|
+
buf = buf.slice(0, -1);
|
|
46
|
+
output.write("\b \b");
|
|
47
|
+
}
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Skip non-printable control chars
|
|
51
|
+
if (ch.charCodeAt(0) < 32) continue;
|
|
31
52
|
buf += ch;
|
|
53
|
+
output.write(ch);
|
|
32
54
|
}
|
|
33
55
|
}
|
|
34
56
|
function onAbort() {
|
|
@@ -36,6 +58,15 @@ export async function promptLine(label, { input = process.stdin, output = proces
|
|
|
36
58
|
cleanup();
|
|
37
59
|
reject(signal.reason || new DOMException("The operation was aborted.", "AbortError"));
|
|
38
60
|
}
|
|
61
|
+
|
|
62
|
+
// Ensure clean stdin state before listening
|
|
63
|
+
if (isTTY) {
|
|
64
|
+
try { input.setRawMode(false); } catch {}
|
|
65
|
+
}
|
|
66
|
+
input.pause();
|
|
67
|
+
if (isTTY) {
|
|
68
|
+
input.setRawMode(true);
|
|
69
|
+
}
|
|
39
70
|
input.on("data", onData);
|
|
40
71
|
input.resume();
|
|
41
72
|
if (signal) signal.addEventListener("abort", onAbort, { once: true });
|
package/src/router.js
CHANGED
|
@@ -22,14 +22,15 @@ function looksLikeWorkRequest(text) {
|
|
|
22
22
|
function inferPassFromText(text) {
|
|
23
23
|
const l = lower(text);
|
|
24
24
|
if (!l) return null;
|
|
25
|
-
|
|
26
|
-
if (/^(fix these|fix that|address those|redo|rebuild|try again|patch it|build it|go ahead|go$|implement it)\b/.test(l)) return { intent: "build", confidence: "high" };
|
|
27
|
-
if (/^(check it|what'?s wrong|what is wrong|review it|challenge( harder)?|find bugs|poke holes|stress test it)\b/.test(l)) return { intent: "challenge", confidence: "high" };
|
|
28
|
-
if (/^(what am i not thinking of|what else|what if|surprise me|invent|give me alternatives|think wider|out of the box)\b/.test(l)) return { intent: "invent", confidence: "high" };
|
|
29
|
-
if (/^(should we|which should|which option|what should we|think deeper|tell me more about|compare |tradeoff|jwt or |sessions or |oauth|oauth2)\b/.test(l)) return { intent: "decide", confidence: "medium" };
|
|
25
|
+
// Decision detail must be checked before generic "decide" — "tell me more about 2" is detail, not decide
|
|
30
26
|
if (/^[1-9]\d*$/.test(l)) return { intent: "choose", confidence: "high", optionIndex: Number.parseInt(l, 10) };
|
|
31
27
|
const moreMatch = l.match(/^(tell me more about|more on|details on|expand)\s+(\d+)\b/);
|
|
32
28
|
if (moreMatch) return { intent: "decision-detail", confidence: "high", optionIndex: Number.parseInt(moreMatch[2], 10) };
|
|
29
|
+
if (/^(ship it|accept|merge it|looks good ship it)\b/.test(l)) return { intent: "accept", confidence: "high" };
|
|
30
|
+
if (/^(rebuild|try again|patch it|build it|go ahead|implement it)\b/.test(l)) return { intent: "build", confidence: "high" };
|
|
31
|
+
if (/^(check it|what'?s wrong|what is wrong|review it|challenge( harder)?|find bugs|poke holes|stress test it)\b/.test(l)) return { intent: "challenge", confidence: "high" };
|
|
32
|
+
if (/^(what am i not thinking of|what else|what if|surprise me|invent|give me alternatives|think wider|out of the box)\b/.test(l)) return { intent: "invent", confidence: "high" };
|
|
33
|
+
if (/^(should we|which should|which option|what should we|think deeper|compare |tradeoff|jwt or |sessions or |oauth|oauth2)\b/.test(l)) return { intent: "decide", confidence: "medium" };
|
|
33
34
|
if (/^ignore\b/.test(l)) return { intent: "ignore", confidence: "medium" };
|
|
34
35
|
return null;
|
|
35
36
|
}
|
|
@@ -62,8 +63,13 @@ export function routeNaturalInput(text, { task = null } = {}) {
|
|
|
62
63
|
return { kind: "choose-recommended-and-build", confidence: "high", raw };
|
|
63
64
|
}
|
|
64
65
|
}
|
|
66
|
+
if (task.state === "build-ready") {
|
|
67
|
+
if (/^(go|go ahead|do it|build it)\b/i.test(raw)) {
|
|
68
|
+
return { kind: "build", confidence: "high", raw };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
65
71
|
if (task.state === "review-ready") {
|
|
66
|
-
if (/^(fix these|fix them|address those|redo)\b/i.test(raw)) {
|
|
72
|
+
if (/^(fix these|fix them|fix that|address those|redo)\b/i.test(raw)) {
|
|
67
73
|
return { kind: "fix-review-findings", confidence: "high", raw };
|
|
68
74
|
}
|
|
69
75
|
if (/^(think deeper|re-think|rethink|step back)\b/i.test(raw)) {
|