agent-coord-mcp 0.4.8 → 0.4.9
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/scripts/coord-chat.mjs +42 -5
package/package.json
CHANGED
package/scripts/coord-chat.mjs
CHANGED
|
@@ -54,6 +54,11 @@ const ROOT = args.dir ?? process.env.AGENT_COORD_DIR ?? path.join(homedir(), "ag
|
|
|
54
54
|
const GROUP_WINDOW = 2 * 60 * 1000;
|
|
55
55
|
let lastBlock = { who: null, ts: 0, kind: null };
|
|
56
56
|
|
|
57
|
+
// Whether the ephemeral suggestion hint is currently occupying the slot above
|
|
58
|
+
// the prompt (see drawHint/clearHint). Declared early so say(), called during
|
|
59
|
+
// startup replay, can reference it without tripping the const/let TDZ.
|
|
60
|
+
let hintActive = false;
|
|
61
|
+
|
|
57
62
|
// Matches "@<this agent>" not followed by a name char, so we can flag messages
|
|
58
63
|
// that ping the current user. ID may contain regex metachars — escape it.
|
|
59
64
|
const SELF_MENTION_RE = new RegExp(
|
|
@@ -173,9 +178,14 @@ function completer(line) {
|
|
|
173
178
|
} else if (line.startsWith("/")) {
|
|
174
179
|
hits = SLASH_COMMANDS.filter((c) => c.startsWith(line));
|
|
175
180
|
}
|
|
176
|
-
if (hits.length > 1
|
|
181
|
+
if (hits.length > 1) {
|
|
182
|
+
// Show the options as an ephemeral hint and hand readline only the common
|
|
183
|
+
// prefix — a single-element completion means its native multi-column dump
|
|
184
|
+
// never lands in scrollback. Tab still advances to the shared prefix.
|
|
177
185
|
const display = hits.map((h) => h.trim()).join(" ");
|
|
178
|
-
|
|
186
|
+
drawHint(A.dim(" ┄ " + display));
|
|
187
|
+
const cp = commonPrefix(hits);
|
|
188
|
+
return [[cp.length >= substr.length ? cp : substr], substr];
|
|
179
189
|
}
|
|
180
190
|
return [hits, substr];
|
|
181
191
|
}
|
|
@@ -202,8 +212,14 @@ const rl = readline.createInterface({
|
|
|
202
212
|
// the "@" into its line buffer before we inspect it.
|
|
203
213
|
if (process.stdin.isTTY) {
|
|
204
214
|
readline.emitKeypressEvents(process.stdin);
|
|
205
|
-
process.stdin.on("keypress", (str) => {
|
|
206
|
-
|
|
215
|
+
process.stdin.on("keypress", (str, key) => {
|
|
216
|
+
// setImmediate lets readline mutate its line buffer first, then we inspect
|
|
217
|
+
// it / redraw the slot above the prompt.
|
|
218
|
+
if (str === "@") { setImmediate(showMentionPicker); return; }
|
|
219
|
+
// Tab is the completer's — it draws/keeps the hint itself. Every other key
|
|
220
|
+
// dismisses a showing hint so the view snaps back to a clean separator.
|
|
221
|
+
if (key && key.name === "tab") return;
|
|
222
|
+
if (hintActive) setImmediate(clearHint);
|
|
207
223
|
});
|
|
208
224
|
}
|
|
209
225
|
|
|
@@ -358,7 +374,28 @@ function agentColor(id) {
|
|
|
358
374
|
return AGENT_COLORS[idx];
|
|
359
375
|
}
|
|
360
376
|
|
|
377
|
+
// Ephemeral suggestion line (the @mention / completion picker). It borrows the
|
|
378
|
+
// separator slot directly above the prompt: drawn there, then wiped back to a
|
|
379
|
+
// real separator on the next keystroke — so it never piles up in scrollback.
|
|
380
|
+
function drawHint(content) {
|
|
381
|
+
if (typeof rl === "undefined" || !lastLineWasSep) return;
|
|
382
|
+
process.stdout.write("\x1b[1A\r\x1b[2K"); // up to the slot, clear it
|
|
383
|
+
process.stdout.write(content + "\n"); // draw the hint in place of the sep
|
|
384
|
+
rl.prompt(true); // redraw prompt + preserved input
|
|
385
|
+
hintActive = true;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function clearHint() {
|
|
389
|
+
if (typeof rl === "undefined" || !lastLineWasSep) { hintActive = false; return; }
|
|
390
|
+
if (!hintActive) return;
|
|
391
|
+
process.stdout.write("\x1b[1A\r\x1b[2K"); // up to the hint slot, clear it
|
|
392
|
+
process.stdout.write(sepLine() + "\n"); // restore the separator
|
|
393
|
+
rl.prompt(true);
|
|
394
|
+
hintActive = false;
|
|
395
|
+
}
|
|
396
|
+
|
|
361
397
|
function say(line) {
|
|
398
|
+
hintActive = false; // any real output reclaims the slot the hint borrowed
|
|
362
399
|
if (lastLineWasSep) {
|
|
363
400
|
// Async path: a separator we own sits directly above the prompt; we own
|
|
364
401
|
// that line. Replace it with the incoming message, drop a new sep, and
|
|
@@ -878,7 +915,7 @@ function showMentionPicker() {
|
|
|
878
915
|
const ids = onlineAgentIds().filter((id) => id !== ID);
|
|
879
916
|
if (!ids.length) return;
|
|
880
917
|
const list = ids.map((id) => A.green("●") + agentColor(id)(`@${id}`)).join(" ");
|
|
881
|
-
|
|
918
|
+
drawHint(A.dim(" ┄ ") + list + A.dim(" · Tab to complete"));
|
|
882
919
|
}
|
|
883
920
|
|
|
884
921
|
function readJsonl(file) {
|