@rk0429/agentic-relay 19.2.0 → 19.2.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/dist/interfaces/cli/relay-shell.js +89 -55
- package/dist/interfaces/cli/relay-shell.js.map +1 -1
- package/dist/interfaces/cli/text-input-utils.d.ts +40 -0
- package/dist/interfaces/cli/text-input-utils.js +90 -0
- package/dist/interfaces/cli/text-input-utils.js.map +1 -0
- package/dist/interfaces/mcp/relay-mcp-server.js +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { Box, render, useApp,
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { Box, render, useApp, useStdin } from "ink";
|
|
4
4
|
import { Header } from "./components/Header.js";
|
|
5
5
|
import { MessageList } from "./components/MessageList.js";
|
|
6
6
|
import { InputBar } from "./components/InputBar.js";
|
|
7
7
|
import { StatusBar } from "./components/StatusBar.js";
|
|
8
|
+
import { classifyInput, deleteLastGrapheme, ENABLE_BRACKETED_PASTE, DISABLE_BRACKETED_PASTE, } from "./text-input-utils.js";
|
|
8
9
|
export async function runRelayInteractiveShell(options) {
|
|
9
10
|
const instance = render(_jsx(RelayShellApp, { service: options.service, initialSession: options.initialSession }));
|
|
10
11
|
await instance.waitUntilExit();
|
|
@@ -12,65 +13,98 @@ export async function runRelayInteractiveShell(options) {
|
|
|
12
13
|
}
|
|
13
14
|
function RelayShellApp(props) {
|
|
14
15
|
const { exit } = useApp();
|
|
16
|
+
// ink's internal_eventEmitter provides decoded stdin chunks without
|
|
17
|
+
// conflicting with ink's readable-mode pipeline. This is an internal
|
|
18
|
+
// API (ink 6.x); if ink is upgraded, verify the emitter still exists.
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
20
|
+
const { setRawMode, internal_eventEmitter } = useStdin();
|
|
15
21
|
const [session, setSession] = useState(props.initialSession);
|
|
16
22
|
const [input, setInput] = useState("");
|
|
17
23
|
const [busy, setBusy] = useState(false);
|
|
18
24
|
const [notice, setNotice] = useState();
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
// Refs to avoid re-registering the stdin listener on every state change.
|
|
26
|
+
const inputRef = useRef(input);
|
|
27
|
+
const sessionRef = useRef(session);
|
|
28
|
+
const busyRef = useRef(busy);
|
|
29
|
+
inputRef.current = input;
|
|
30
|
+
sessionRef.current = session;
|
|
31
|
+
busyRef.current = busy;
|
|
32
|
+
// Enable raw mode + bracketed paste on mount; clean up on unmount.
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
setRawMode(true);
|
|
35
|
+
process.stdout.write(ENABLE_BRACKETED_PASTE);
|
|
36
|
+
return () => {
|
|
37
|
+
setRawMode(false);
|
|
38
|
+
process.stdout.write(DISABLE_BRACKETED_PASTE);
|
|
39
|
+
};
|
|
40
|
+
}, [setRawMode]);
|
|
41
|
+
// Custom stdin handler — replaces ink's useInput so that multi-byte
|
|
42
|
+
// CJK characters and bracketed-paste sequences are kept intact.
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const handleData = (data) => {
|
|
45
|
+
const action = classifyInput(data);
|
|
46
|
+
if (action.kind === "control" && action.name === "ctrl-c") {
|
|
47
|
+
exit();
|
|
38
48
|
return;
|
|
39
49
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
50
|
+
if (busyRef.current)
|
|
51
|
+
return;
|
|
52
|
+
if (action.kind === "control") {
|
|
53
|
+
switch (action.name) {
|
|
54
|
+
case "ctrl-b": {
|
|
55
|
+
const current = sessionRef.current;
|
|
56
|
+
const nextSession = props.service.cycleInteractiveBackend(current);
|
|
57
|
+
setSession(nextSession);
|
|
58
|
+
setNotice(nextSession.currentBackend === current.currentBackend
|
|
59
|
+
? "No alternative backend is available."
|
|
60
|
+
: `Switched to ${nextSession.currentBackend}.`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
case "return": {
|
|
64
|
+
const prompt = inputRef.current.trim();
|
|
65
|
+
if (!prompt)
|
|
66
|
+
return;
|
|
67
|
+
setBusy(true);
|
|
68
|
+
setNotice(undefined);
|
|
69
|
+
setInput("");
|
|
70
|
+
void props.service
|
|
71
|
+
.submitInteractivePrompt(sessionRef.current, prompt)
|
|
72
|
+
.then((result) => {
|
|
73
|
+
setSession(result.session);
|
|
74
|
+
setNotice(result.handoff
|
|
75
|
+
? `Started ${result.session.currentBackend} with handoff from ${result.handoff.source_backend}.`
|
|
76
|
+
: undefined);
|
|
77
|
+
})
|
|
78
|
+
.catch((error) => {
|
|
79
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80
|
+
setSession((previous) => props.service.appendInteractiveMessage(previous, {
|
|
81
|
+
role: "error",
|
|
82
|
+
backend: previous.currentBackend,
|
|
83
|
+
content: message,
|
|
84
|
+
}));
|
|
85
|
+
setNotice(message);
|
|
86
|
+
})
|
|
87
|
+
.finally(() => {
|
|
88
|
+
setBusy(false);
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
case "backspace":
|
|
93
|
+
setInput((previous) => deleteLastGrapheme(previous));
|
|
94
|
+
return;
|
|
95
|
+
default:
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (action.kind === "text") {
|
|
100
|
+
setInput((previous) => previous + action.value);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
internal_eventEmitter?.on("input", handleData);
|
|
104
|
+
return () => {
|
|
105
|
+
internal_eventEmitter?.removeListener("input", handleData);
|
|
106
|
+
};
|
|
107
|
+
}, [internal_eventEmitter, exit, props.service]);
|
|
74
108
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, { session: session }), _jsx(MessageList, { session: session }), _jsx(InputBar, { input: input, busy: busy }), _jsx(StatusBar, { notice: notice, busy: busy })] }));
|
|
75
109
|
}
|
|
76
110
|
//# sourceMappingURL=relay-shell.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-shell.js","sourceRoot":"","sources":["../../../src/interfaces/cli/relay-shell.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"relay-shell.js","sourceRoot":"","sources":["../../../src/interfaces/cli/relay-shell.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delete the last grapheme cluster from a string.
|
|
3
|
+
* Unlike `str.slice(0, -1)` which operates on UTF-16 code units,
|
|
4
|
+
* this correctly handles CJK characters, emoji, surrogate pairs,
|
|
5
|
+
* and combining characters.
|
|
6
|
+
*/
|
|
7
|
+
export declare function deleteLastGrapheme(str: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Bracketed paste mode escape sequences.
|
|
10
|
+
* When enabled, the terminal wraps pasted text in these markers,
|
|
11
|
+
* allowing the application to distinguish pasted text from typed input.
|
|
12
|
+
* Some terminals also use this for IME-committed text.
|
|
13
|
+
*/
|
|
14
|
+
export declare const BRACKETED_PASTE_START = "\u001B[200~";
|
|
15
|
+
export declare const BRACKETED_PASTE_END = "\u001B[201~";
|
|
16
|
+
export declare const ENABLE_BRACKETED_PASTE = "\u001B[?2004h";
|
|
17
|
+
export declare const DISABLE_BRACKETED_PASTE = "\u001B[?2004l";
|
|
18
|
+
/**
|
|
19
|
+
* Extract text from a bracketed paste sequence.
|
|
20
|
+
* Returns the inner text if the string contains bracketed paste markers,
|
|
21
|
+
* or undefined if no markers are found.
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractBracketedPaste(data: string): string | undefined;
|
|
24
|
+
export type InputAction = {
|
|
25
|
+
kind: "text";
|
|
26
|
+
value: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "control";
|
|
29
|
+
name: string;
|
|
30
|
+
} | {
|
|
31
|
+
kind: "ignore";
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Classify a raw stdin chunk into an action.
|
|
35
|
+
*
|
|
36
|
+
* Unlike ink's `parseKeypress`, this treats multi-byte CJK characters,
|
|
37
|
+
* emoji, and bracketed-paste sequences as indivisible text rather than
|
|
38
|
+
* trying to classify them as key combinations.
|
|
39
|
+
*/
|
|
40
|
+
export declare function classifyInput(data: string): InputAction;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
2
|
+
/**
|
|
3
|
+
* Delete the last grapheme cluster from a string.
|
|
4
|
+
* Unlike `str.slice(0, -1)` which operates on UTF-16 code units,
|
|
5
|
+
* this correctly handles CJK characters, emoji, surrogate pairs,
|
|
6
|
+
* and combining characters.
|
|
7
|
+
*/
|
|
8
|
+
export function deleteLastGrapheme(str) {
|
|
9
|
+
if (str.length === 0) {
|
|
10
|
+
return str;
|
|
11
|
+
}
|
|
12
|
+
const segments = [...segmenter.segment(str)];
|
|
13
|
+
if (segments.length === 0) {
|
|
14
|
+
return str;
|
|
15
|
+
}
|
|
16
|
+
const last = segments[segments.length - 1];
|
|
17
|
+
return str.slice(0, last.index);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Bracketed paste mode escape sequences.
|
|
21
|
+
* When enabled, the terminal wraps pasted text in these markers,
|
|
22
|
+
* allowing the application to distinguish pasted text from typed input.
|
|
23
|
+
* Some terminals also use this for IME-committed text.
|
|
24
|
+
*/
|
|
25
|
+
export const BRACKETED_PASTE_START = "\x1b[200~";
|
|
26
|
+
export const BRACKETED_PASTE_END = "\x1b[201~";
|
|
27
|
+
export const ENABLE_BRACKETED_PASTE = "\x1b[?2004h";
|
|
28
|
+
export const DISABLE_BRACKETED_PASTE = "\x1b[?2004l";
|
|
29
|
+
/**
|
|
30
|
+
* Extract text from a bracketed paste sequence.
|
|
31
|
+
* Returns the inner text if the string contains bracketed paste markers,
|
|
32
|
+
* or undefined if no markers are found.
|
|
33
|
+
*/
|
|
34
|
+
export function extractBracketedPaste(data) {
|
|
35
|
+
const startIdx = data.indexOf(BRACKETED_PASTE_START);
|
|
36
|
+
if (startIdx === -1) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const contentStart = startIdx + BRACKETED_PASTE_START.length;
|
|
40
|
+
const endIdx = data.indexOf(BRACKETED_PASTE_END, contentStart);
|
|
41
|
+
if (endIdx === -1) {
|
|
42
|
+
// Paste end marker not found; treat everything after start as pasted text
|
|
43
|
+
return data.slice(contentStart);
|
|
44
|
+
}
|
|
45
|
+
return data.slice(contentStart, endIdx);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Classify a raw stdin chunk into an action.
|
|
49
|
+
*
|
|
50
|
+
* Unlike ink's `parseKeypress`, this treats multi-byte CJK characters,
|
|
51
|
+
* emoji, and bracketed-paste sequences as indivisible text rather than
|
|
52
|
+
* trying to classify them as key combinations.
|
|
53
|
+
*/
|
|
54
|
+
export function classifyInput(data) {
|
|
55
|
+
// --- bracketed paste -------------------------------------------------
|
|
56
|
+
const pasted = extractBracketedPaste(data);
|
|
57
|
+
if (pasted !== undefined) {
|
|
58
|
+
// Strip newlines from pasted text (single-line input bar)
|
|
59
|
+
const cleaned = pasted.replace(/[\r\n]+/g, " ").trim();
|
|
60
|
+
return cleaned ? { kind: "text", value: cleaned } : { kind: "ignore" };
|
|
61
|
+
}
|
|
62
|
+
// --- ctrl+key --------------------------------------------------------
|
|
63
|
+
if (data === "\x03")
|
|
64
|
+
return { kind: "control", name: "ctrl-c" };
|
|
65
|
+
if (data === "\x02")
|
|
66
|
+
return { kind: "control", name: "ctrl-b" };
|
|
67
|
+
// --- enter / return --------------------------------------------------
|
|
68
|
+
if (data === "\r" || data === "\n")
|
|
69
|
+
return { kind: "control", name: "return" };
|
|
70
|
+
// --- backspace / delete ----------------------------------------------
|
|
71
|
+
if (data === "\x7f" || data === "\b" || data === "\x1b\x7f" || data === "\x1b\b") {
|
|
72
|
+
return { kind: "control", name: "backspace" };
|
|
73
|
+
}
|
|
74
|
+
// --- escape / escape sequences (arrows, function keys, etc.) ---------
|
|
75
|
+
if (data === "\x1b" || data === "\x1b\x1b")
|
|
76
|
+
return { kind: "control", name: "escape" };
|
|
77
|
+
if (data.startsWith("\x1b[") || data.startsWith("\x1bO"))
|
|
78
|
+
return { kind: "ignore" };
|
|
79
|
+
if (/^\x1b[a-zA-Z0-9]$/.test(data))
|
|
80
|
+
return { kind: "ignore" };
|
|
81
|
+
// --- tab -------------------------------------------------------------
|
|
82
|
+
if (data === "\t")
|
|
83
|
+
return { kind: "ignore" };
|
|
84
|
+
// --- remaining ctrl characters (0x01–0x1a except the ones above) -----
|
|
85
|
+
if (data.length === 1 && data <= "\x1a")
|
|
86
|
+
return { kind: "ignore" };
|
|
87
|
+
// --- printable text (ASCII, CJK, emoji, etc.) ------------------------
|
|
88
|
+
return { kind: "text", value: data };
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=text-input-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-input-utils.js","sourceRoot":"","sources":["../../../src/interfaces/cli/text-input-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -701,7 +701,7 @@ const TOOL_DESCRIPTIONS = {
|
|
|
701
701
|
export function createRelayMcpServer(options) {
|
|
702
702
|
const server = new McpServer({
|
|
703
703
|
name: "agentic-relay",
|
|
704
|
-
version: "19.2.
|
|
704
|
+
version: "19.2.1",
|
|
705
705
|
});
|
|
706
706
|
if (options.allowSpawnAgents) {
|
|
707
707
|
server.registerTool("spawn_agents", {
|