@polycode-projects/the-mechanical-code-talker 0.7.1 → 0.8.1
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/ROADMAP.md +120 -11
- package/bin/tmct.mjs +45 -0
- package/package.json +3 -1
- package/src/ask-vocab.mjs +1 -1
- package/src/ask.mjs +123 -3
- package/src/chat.mjs +79 -7
- package/src/concept.mjs +5 -0
- package/src/conformance.mjs +1 -1
- package/src/corpus/templates.mjs +1 -1
- package/src/finish.mjs +1 -1
- package/src/hash.mjs +1 -1
- package/src/interpret/normalize.mjs +65 -1
- package/src/interpret/pipeline.mjs +18 -3
- package/src/interpret/strategies/ace.mjs +49 -0
- package/src/interpret/strategies/keywords.mjs +2 -2
- package/src/providers/bootstrap.mjs +1 -1
- package/src/providers/fixture.mjs +1 -1
- package/src/providers/graph-service.mjs +1 -1
- package/src/repository-interface.mjs +1 -1
- package/src/router/goal-reasoner.mjs +266 -0
- package/src/router/guardrail.mjs +120 -0
- package/src/router/planner.mjs +168 -0
- package/src/router/registry.mjs +271 -0
- package/src/router/resolver.mjs +331 -0
- package/src/server-http.mjs +296 -0
- package/src/syllogise.mjs +0 -0
- package/src/tui/app.mjs +63 -14
package/src/tui/app.mjs
CHANGED
|
@@ -69,6 +69,40 @@ export function wrapLines(lines, width) {
|
|
|
69
69
|
return out;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// ---- line editor (pure, cursor-aware — readline-style in-line editing) ----
|
|
73
|
+
// The input line is a (value, cursor) pair: `cursor` is an index in [0, value.length]
|
|
74
|
+
// naming the gap BEFORE which the next character lands. Left/right move it; typing and
|
|
75
|
+
// backspace act AT it, so a message can be edited mid-line and resubmitted. Pure so
|
|
76
|
+
// node:test exercises the editing without a terminal.
|
|
77
|
+
|
|
78
|
+
/** Insert `str` at the cursor; the cursor advances past it. */
|
|
79
|
+
export function insertAt(value, cursor, str) {
|
|
80
|
+
const c = clampCursor(value, cursor);
|
|
81
|
+
return { value: value.slice(0, c) + str + value.slice(c), cursor: c + str.length };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Delete the character BEFORE the cursor (Backspace); the cursor steps left. A no-op
|
|
85
|
+
* at column 0. (This shell treats Backspace and Delete alike — delete-before-cursor.) */
|
|
86
|
+
export function backspaceAt(value, cursor) {
|
|
87
|
+
const c = clampCursor(value, cursor);
|
|
88
|
+
if (c <= 0) return { value, cursor: 0 };
|
|
89
|
+
return { value: value.slice(0, c - 1) + value.slice(c), cursor: c - 1 };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Clamp a cursor index into [0, value.length]. */
|
|
93
|
+
export function clampCursor(value, cursor) {
|
|
94
|
+
return Math.max(0, Math.min(String(value).length, Number(cursor) || 0));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Split the value around the cursor for rendering: the text before it, the single
|
|
98
|
+
* character UNDER it (a space when the cursor sits past the end), and the text after
|
|
99
|
+
* that character — so the caret block can highlight `at` in place. */
|
|
100
|
+
export function inputCells(value, cursor) {
|
|
101
|
+
const c = clampCursor(value, cursor);
|
|
102
|
+
const s = String(value);
|
|
103
|
+
return { before: s.slice(0, c), at: s.slice(c, c + 1) || " ", after: s.slice(c + 1) };
|
|
104
|
+
}
|
|
105
|
+
|
|
72
106
|
/** Terminal size, live across resizes (falls back to 80×24 off-TTY). */
|
|
73
107
|
function useTerminalSize() {
|
|
74
108
|
const { stdout } = useStdout();
|
|
@@ -90,6 +124,7 @@ export function App({ session }) {
|
|
|
90
124
|
const { columns, rows } = useTerminalSize();
|
|
91
125
|
const [items, setItems] = useState([]);
|
|
92
126
|
const [input, setInput] = useState("");
|
|
127
|
+
const [cursor, setCursor] = useState(0); // caret position within `input` (readline-style)
|
|
93
128
|
const [prompt, setPrompt] = useState(session.promptFor());
|
|
94
129
|
const [busy, setBusy] = useState(false);
|
|
95
130
|
// Command history (up/down arrow recall, readline-style). `history` is oldest→newest;
|
|
@@ -111,10 +146,14 @@ export function App({ session }) {
|
|
|
111
146
|
}
|
|
112
147
|
};
|
|
113
148
|
|
|
149
|
+
// Set the editable line to a whole string with the caret at its end (history recall,
|
|
150
|
+
// submit-reset) — one place so `input` and `cursor` never drift apart.
|
|
151
|
+
const setLine = (value) => { setInput(value); setCursor(value.length); };
|
|
152
|
+
|
|
114
153
|
const trySubmit = (raw) => {
|
|
115
154
|
if (busy) return; // one turn at a time — the engine is deterministic and fast
|
|
116
155
|
const line = String(raw).trim();
|
|
117
|
-
|
|
156
|
+
setLine("");
|
|
118
157
|
setHistCursor(-1); // any submit resets history navigation to the live input
|
|
119
158
|
if (line) {
|
|
120
159
|
// record for up-arrow recall; collapse an immediate duplicate of the last line
|
|
@@ -125,30 +164,36 @@ export function App({ session }) {
|
|
|
125
164
|
|
|
126
165
|
useInput((ch, key) => {
|
|
127
166
|
if (key.return) { trySubmit(input); return; }
|
|
128
|
-
|
|
129
|
-
|
|
167
|
+
// Left/right arrow + Ctrl-A/E: move the caret so a typed line can be edited mid-string
|
|
168
|
+
// and resubmitted (not just appended to / backspaced from the end).
|
|
169
|
+
if (key.leftArrow) { setCursor((c) => clampCursor(input, c - 1)); return; }
|
|
170
|
+
if (key.rightArrow) { setCursor((c) => clampCursor(input, c + 1)); return; }
|
|
171
|
+
if (key.ctrl && ch === "a") { setCursor(0); return; } // home
|
|
172
|
+
if (key.ctrl && ch === "e") { setCursor(input.length); return; } // end
|
|
173
|
+
if (key.backspace || key.delete) { const r = backspaceAt(input, cursor); setInput(r.value); setCursor(r.cursor); return; }
|
|
174
|
+
if (key.ctrl && ch === "u") { setLine(""); return; }
|
|
130
175
|
// Up/down arrow: recall previous prompts (readline-style), oldest→newest history.
|
|
131
176
|
if (key.upArrow) {
|
|
132
177
|
if (!history.length) return;
|
|
133
178
|
const nc = Math.min(histCursor + 1, history.length - 1);
|
|
134
179
|
setHistCursor(nc);
|
|
135
|
-
|
|
180
|
+
setLine(history[history.length - 1 - nc]);
|
|
136
181
|
return;
|
|
137
182
|
}
|
|
138
183
|
if (key.downArrow) {
|
|
139
|
-
if (histCursor <= 0) { setHistCursor(-1);
|
|
184
|
+
if (histCursor <= 0) { setHistCursor(-1); setLine(""); return; } // back to a fresh line
|
|
140
185
|
const nc = histCursor - 1;
|
|
141
186
|
setHistCursor(nc);
|
|
142
|
-
|
|
187
|
+
setLine(history[history.length - 1 - nc]);
|
|
143
188
|
return;
|
|
144
189
|
}
|
|
145
|
-
if (key.ctrl || key.meta || key.escape || key.tab
|
|
190
|
+
if (key.ctrl || key.meta || key.escape || key.tab) return;
|
|
146
191
|
if (!ch) return;
|
|
147
192
|
// A PASTED chunk arrives as one multi-char event; a newline inside it means
|
|
148
193
|
// "submit this line" (one line per turn — the readline shell's per-line read).
|
|
149
194
|
const nl = ch.search(/[\r\n]/);
|
|
150
|
-
if (nl === -1) {
|
|
151
|
-
trySubmit(input + ch.slice(0, nl));
|
|
195
|
+
if (nl === -1) { const r = insertAt(input, cursor, ch); setInput(r.value); setCursor(r.cursor); return; }
|
|
196
|
+
trySubmit(input.slice(0, cursor) + ch.slice(0, nl) + input.slice(cursor));
|
|
152
197
|
});
|
|
153
198
|
|
|
154
199
|
// The pane's line budget: full height minus the input line and the status bar.
|
|
@@ -163,11 +208,15 @@ export function App({ session }) {
|
|
|
163
208
|
h(Text, { key: `l${i}`, wrap: "truncate-end" }, line === "" ? " " : line)),
|
|
164
209
|
),
|
|
165
210
|
h(Box, { height: 1 },
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
211
|
+
(() => {
|
|
212
|
+
const { before, at, after } = inputCells(input, cursor);
|
|
213
|
+
return h(Text, { wrap: "truncate-end" },
|
|
214
|
+
h(Text, { bold: true }, prompt),
|
|
215
|
+
before,
|
|
216
|
+
busy ? h(Text, { dimColor: true }, "…") : h(Text, { inverse: true }, at), // caret block over the char at the cursor
|
|
217
|
+
busy ? null : after,
|
|
218
|
+
);
|
|
219
|
+
})(),
|
|
171
220
|
),
|
|
172
221
|
h(Box, { height: 1 },
|
|
173
222
|
h(Text, { dimColor: true, wrap: "truncate-end" },
|