chivgent 0.11.0 → 0.12.0

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.
@@ -0,0 +1,173 @@
1
+ import { createConnection } from "node:net";
2
+ import { encodeMessage, FramingError, LineDecoder, parseLine } from "./framing.js";
3
+ import { parseServerMessage, PROTOCOL_VERSION, } from "./protocol.js";
4
+ export class RemoteError extends Error {
5
+ code;
6
+ constructor(message, code) {
7
+ super(message);
8
+ this.code = code;
9
+ this.name = "RemoteError";
10
+ }
11
+ }
12
+ /**
13
+ * A client attached to a session running in another process.
14
+ *
15
+ * It holds no state of its own: it sends prompts and renders what comes back.
16
+ * That is what keeps a second client honest — two attached clients see one
17
+ * stream because there is only one session.
18
+ */
19
+ export class RemoteSession {
20
+ options;
21
+ socket;
22
+ decoder = new LineDecoder();
23
+ hello;
24
+ pending;
25
+ closedReason;
26
+ constructor(options) {
27
+ this.options = options;
28
+ }
29
+ get session() {
30
+ if (this.hello === undefined) {
31
+ throw new RemoteError("Not connected.");
32
+ }
33
+ return this.hello.session;
34
+ }
35
+ get toolNames() {
36
+ return this.hello?.tools ?? [];
37
+ }
38
+ async connect() {
39
+ const socket = await new Promise((resolve, reject) => {
40
+ const candidate = createConnection(this.options.socketPath);
41
+ candidate.once("connect", () => {
42
+ candidate.off("error", reject);
43
+ resolve(candidate);
44
+ });
45
+ candidate.once("error", (error) => {
46
+ reject(new RemoteError(error.code === "ENOENT" || error.code === "ECONNREFUSED"
47
+ ? `No chivgent server is listening on ${this.options.socketPath}.`
48
+ : `Could not connect to ${this.options.socketPath}: ${error.message}`));
49
+ });
50
+ });
51
+ this.socket = socket;
52
+ socket.setNoDelay(true);
53
+ socket.on("data", (chunk) => this.receive(chunk));
54
+ socket.on("close", () => this.handleClose());
55
+ socket.on("error", () => this.handleClose());
56
+ return new Promise((resolve, reject) => {
57
+ const timer = setTimeout(() => {
58
+ reject(new RemoteError("The server did not answer the handshake."));
59
+ }, 5_000);
60
+ this.onHello = (hello) => {
61
+ clearTimeout(timer);
62
+ resolve(hello);
63
+ };
64
+ this.onHelloError = (error) => {
65
+ clearTimeout(timer);
66
+ reject(error);
67
+ };
68
+ this.write({ type: "hello", version: PROTOCOL_VERSION });
69
+ });
70
+ }
71
+ onHello;
72
+ onHelloError;
73
+ /** Sends a prompt and resolves when the run it started finishes. */
74
+ prompt(text) {
75
+ if (this.socket === undefined) {
76
+ return Promise.reject(new RemoteError("Not connected."));
77
+ }
78
+ if (this.pending !== undefined) {
79
+ return Promise.reject(new RemoteError("A prompt is already in flight."));
80
+ }
81
+ return new Promise((resolve, reject) => {
82
+ this.pending = { resolve, reject };
83
+ this.write({ type: "prompt", text });
84
+ });
85
+ }
86
+ interrupt() {
87
+ if (this.socket !== undefined && !this.socket.destroyed) {
88
+ this.write({ type: "interrupt" });
89
+ }
90
+ }
91
+ close() {
92
+ this.socket?.end();
93
+ this.socket?.destroy();
94
+ this.socket = undefined;
95
+ }
96
+ write(message) {
97
+ this.socket?.write(encodeMessage(message));
98
+ }
99
+ receive(chunk) {
100
+ let lines;
101
+ try {
102
+ lines = this.decoder.push(chunk);
103
+ }
104
+ catch (error) {
105
+ const message = error instanceof FramingError ? error.message : "Framing error.";
106
+ this.failAll(new RemoteError(message));
107
+ return;
108
+ }
109
+ for (const line of lines) {
110
+ const parsed = parseLine(line);
111
+ if ("error" in parsed) {
112
+ this.options.onError?.("bad_message", parsed.error);
113
+ continue;
114
+ }
115
+ const message = parseServerMessage(parsed.value);
116
+ if ("error" in message) {
117
+ this.options.onError?.("bad_message", message.error);
118
+ continue;
119
+ }
120
+ switch (message.message.type) {
121
+ case "hello":
122
+ this.hello = message.message;
123
+ this.onHello?.(message.message);
124
+ this.onHello = undefined;
125
+ this.onHelloError = undefined;
126
+ break;
127
+ case "event":
128
+ this.options.onEvent?.(message.message.event);
129
+ break;
130
+ case "result": {
131
+ const pending = this.pending;
132
+ this.pending = undefined;
133
+ pending?.resolve(message.message);
134
+ break;
135
+ }
136
+ case "error": {
137
+ const error = new RemoteError(message.message.message, message.message.code);
138
+ this.options.onError?.(message.message.code, message.message.message);
139
+ if (this.onHelloError !== undefined) {
140
+ this.onHelloError(error);
141
+ this.onHello = undefined;
142
+ this.onHelloError = undefined;
143
+ break;
144
+ }
145
+ // A busy or agent error ends the prompt that caused it; the
146
+ // connection itself stays usable.
147
+ const pending = this.pending;
148
+ this.pending = undefined;
149
+ pending?.reject(error);
150
+ break;
151
+ }
152
+ case "bye":
153
+ this.closedReason = message.message.reason;
154
+ break;
155
+ }
156
+ }
157
+ }
158
+ handleClose() {
159
+ this.socket = undefined;
160
+ this.failAll(new RemoteError(this.closedReason === undefined
161
+ ? "The chivgent server closed the connection."
162
+ : `The chivgent server closed the connection: ${this.closedReason}`));
163
+ }
164
+ failAll(error) {
165
+ const pending = this.pending;
166
+ this.pending = undefined;
167
+ pending?.reject(error);
168
+ this.onHelloError?.(error);
169
+ this.onHello = undefined;
170
+ this.onHelloError = undefined;
171
+ }
172
+ }
173
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/remote/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * JSON Lines framing.
3
+ *
4
+ * One JSON object per line, the same shape the session log and `--json` mode
5
+ * already use. A length-prefixed binary frame would be needed to carry
6
+ * attachments; every message here is required to be JSON-serialisable, so the
7
+ * simpler framing is enough and stays inspectable with `nc`.
8
+ */
9
+ export declare const MAX_LINE_BYTES: number;
10
+ export declare class FramingError extends Error {
11
+ constructor(message: string);
12
+ }
13
+ export declare function encodeMessage(value: unknown): string;
14
+ /**
15
+ * Splits a byte stream into lines without unbounded buffering.
16
+ *
17
+ * A peer that never sends a newline must not be able to exhaust memory, so the
18
+ * buffer is capped and overflow is a protocol error rather than a slow death.
19
+ */
20
+ export declare class LineDecoder {
21
+ private readonly maxLineBytes;
22
+ private buffer;
23
+ private readonly decoder;
24
+ constructor(maxLineBytes?: number);
25
+ push(chunk: Buffer): string[];
26
+ }
27
+ /** Parses one line, or returns why it could not be parsed. */
28
+ export declare function parseLine(line: string): {
29
+ readonly value: unknown;
30
+ } | {
31
+ readonly error: string;
32
+ };
33
+ //# sourceMappingURL=framing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framing.d.ts","sourceRoot":"","sources":["../../src/remote/framing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,cAAc,QAAc,CAAC;AAE1C,qBAAa,YAAa,SAAQ,KAAK;IACrC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMpD;AAED;;;;;GAKG;AACH,qBAAa,WAAW;IAIV,OAAO,CAAC,QAAQ,CAAC,YAAY;IAHzC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IAEpD,YAA6B,YAAY,GAAE,MAAuB,EAAI;IAEtE,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAuB5B;CACF;AAED,8DAA8D;AAC9D,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,GACX;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAQ1D"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * JSON Lines framing.
3
+ *
4
+ * One JSON object per line, the same shape the session log and `--json` mode
5
+ * already use. A length-prefixed binary frame would be needed to carry
6
+ * attachments; every message here is required to be JSON-serialisable, so the
7
+ * simpler framing is enough and stays inspectable with `nc`.
8
+ */
9
+ export const MAX_LINE_BYTES = 1024 * 1024;
10
+ export class FramingError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = "FramingError";
14
+ }
15
+ }
16
+ export function encodeMessage(value) {
17
+ const line = JSON.stringify(value);
18
+ if (line === undefined) {
19
+ throw new FramingError("Message is not JSON-serialisable.");
20
+ }
21
+ return `${line}\n`;
22
+ }
23
+ /**
24
+ * Splits a byte stream into lines without unbounded buffering.
25
+ *
26
+ * A peer that never sends a newline must not be able to exhaust memory, so the
27
+ * buffer is capped and overflow is a protocol error rather than a slow death.
28
+ */
29
+ export class LineDecoder {
30
+ maxLineBytes;
31
+ buffer = "";
32
+ decoder = new TextDecoder("utf-8");
33
+ constructor(maxLineBytes = MAX_LINE_BYTES) {
34
+ this.maxLineBytes = maxLineBytes;
35
+ }
36
+ push(chunk) {
37
+ this.buffer += this.decoder.decode(chunk, { stream: true });
38
+ const lines = [];
39
+ for (;;) {
40
+ const index = this.buffer.indexOf("\n");
41
+ if (index === -1) {
42
+ break;
43
+ }
44
+ const line = this.buffer.slice(0, index);
45
+ this.buffer = this.buffer.slice(index + 1);
46
+ const trimmed = line.trim();
47
+ if (trimmed.length > 0) {
48
+ lines.push(trimmed);
49
+ }
50
+ }
51
+ if (Buffer.byteLength(this.buffer, "utf8") > this.maxLineBytes) {
52
+ throw new FramingError(`A single line exceeded the ${this.maxLineBytes}-byte limit.`);
53
+ }
54
+ return lines;
55
+ }
56
+ }
57
+ /** Parses one line, or returns why it could not be parsed. */
58
+ export function parseLine(line) {
59
+ try {
60
+ return { value: JSON.parse(line) };
61
+ }
62
+ catch (error) {
63
+ return {
64
+ error: error instanceof Error ? error.message : "Invalid JSON.",
65
+ };
66
+ }
67
+ }
68
+ //# sourceMappingURL=framing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framing.js","sourceRoot":"","sources":["../../src/remote/framing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;AAE1C,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,IAAI,YAAY,CAAC,mCAAmC,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,GAAG,IAAI,IAAI,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,WAAW;IAIO,YAAY;IAHjC,MAAM,GAAG,EAAE,CAAC;IACH,OAAO,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;IAEpD,YAA6B,YAAY,GAAW,cAAc;4BAArC,YAAY;IAA4B,CAAC;IAEtE,IAAI,CAAC,KAAa;QAChB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,SAAS,CAAC;YACR,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjB,MAAM;YACR,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YAC/D,MAAM,IAAI,YAAY,CACpB,8BAA8B,IAAI,CAAC,YAAY,cAAc,CAC9D,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,8DAA8D;AAC9D,MAAM,UAAU,SAAS,CACvB,IAAY;IAEZ,IAAI,CAAC;QACH,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;IACrC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO;YACL,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;SAChE,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,81 @@
1
+ import type { AgentEvent } from "../events.js";
2
+ import type { Message } from "../messages.js";
3
+ /**
4
+ * Bumped whenever the shape below changes in a way an older peer would
5
+ * misread. A mismatch is refused with both versions named, which costs one
6
+ * release note and saves a baffling debugging session later.
7
+ */
8
+ export declare const PROTOCOL_VERSION = 1;
9
+ export type ProtocolErrorCode = "version_mismatch" | "busy" | "bad_message" | "too_large" | "agent_error";
10
+ export interface SessionSummary {
11
+ readonly id: string;
12
+ readonly cwd: string;
13
+ readonly turns: number;
14
+ readonly messages: number;
15
+ /** Capabilities the server was started with, so an attaching client can see them. */
16
+ readonly capabilities: readonly string[];
17
+ }
18
+ export interface ClientHello {
19
+ readonly type: "hello";
20
+ readonly version: number;
21
+ }
22
+ export interface ClientPrompt {
23
+ readonly type: "prompt";
24
+ readonly text: string;
25
+ }
26
+ export interface ClientInterrupt {
27
+ readonly type: "interrupt";
28
+ }
29
+ export type ClientMessage = ClientHello | ClientPrompt | ClientInterrupt;
30
+ export interface ServerHello {
31
+ readonly type: "hello";
32
+ readonly version: number;
33
+ readonly session: SessionSummary;
34
+ readonly tools: readonly string[];
35
+ }
36
+ export interface ServerError {
37
+ readonly type: "error";
38
+ readonly code: ProtocolErrorCode;
39
+ readonly message: string;
40
+ }
41
+ /**
42
+ * An AgentEvent, wrapped rather than sent bare.
43
+ *
44
+ * Without the wrapper the protocol's own messages share a namespace with the
45
+ * agent's events, and the day an event type called "error" is added the two
46
+ * collide silently.
47
+ */
48
+ export interface ServerEvent {
49
+ readonly type: "event";
50
+ readonly event: AgentEvent;
51
+ }
52
+ export interface ServerBye {
53
+ readonly type: "bye";
54
+ readonly reason: string;
55
+ }
56
+ /** Sent when a run finishes, so a one-shot client knows when to leave. */
57
+ export interface ServerResult {
58
+ readonly type: "result";
59
+ readonly status: "completed" | "max_turns" | "aborted" | "error";
60
+ readonly messages: number;
61
+ }
62
+ export type ServerMessage = ServerHello | ServerError | ServerEvent | ServerBye | ServerResult;
63
+ /** Parses one client message, or returns why it is not one. */
64
+ export declare function parseClientMessage(value: unknown): {
65
+ readonly message: ClientMessage;
66
+ } | {
67
+ readonly error: string;
68
+ };
69
+ export declare function parseServerMessage(value: unknown): {
70
+ readonly message: ServerMessage;
71
+ } | {
72
+ readonly error: string;
73
+ };
74
+ export declare function summariseSession(options: {
75
+ readonly id: string;
76
+ readonly cwd: string;
77
+ readonly turns: number;
78
+ readonly messages: readonly Message[];
79
+ readonly capabilities: readonly string[];
80
+ }): SessionSummary;
81
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/remote/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Bumped whenever the shape below changes in a way an older peer would
3
+ * misread. A mismatch is refused with both versions named, which costs one
4
+ * release note and saves a baffling debugging session later.
5
+ */
6
+ export const PROTOCOL_VERSION = 1;
7
+ function isRecord(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ }
10
+ /** Parses one client message, or returns why it is not one. */
11
+ export function parseClientMessage(value) {
12
+ if (!isRecord(value)) {
13
+ return { error: "A message must be a JSON object." };
14
+ }
15
+ switch (value.type) {
16
+ case "hello":
17
+ if (typeof value.version !== "number" || !Number.isInteger(value.version)) {
18
+ return { error: "hello needs an integer version." };
19
+ }
20
+ return { message: { type: "hello", version: value.version } };
21
+ case "prompt":
22
+ if (typeof value.text !== "string" || value.text.trim().length === 0) {
23
+ return { error: "prompt needs a non-empty text." };
24
+ }
25
+ return { message: { type: "prompt", text: value.text } };
26
+ case "interrupt":
27
+ return { message: { type: "interrupt" } };
28
+ default:
29
+ return { error: `Unknown message type: ${String(value.type)}` };
30
+ }
31
+ }
32
+ export function parseServerMessage(value) {
33
+ if (!isRecord(value)) {
34
+ return { error: "A message must be a JSON object." };
35
+ }
36
+ switch (value.type) {
37
+ case "hello":
38
+ if (typeof value.version !== "number" ||
39
+ !isRecord(value.session) ||
40
+ !Array.isArray(value.tools)) {
41
+ return { error: "hello is missing version, session or tools." };
42
+ }
43
+ return { message: value };
44
+ case "error":
45
+ if (typeof value.message !== "string" || typeof value.code !== "string") {
46
+ return { error: "error needs a code and a message." };
47
+ }
48
+ return { message: value };
49
+ case "event":
50
+ if (!isRecord(value.event) || typeof value.event.type !== "string") {
51
+ return { error: "event needs an event object." };
52
+ }
53
+ return { message: value };
54
+ case "result":
55
+ if (typeof value.status !== "string") {
56
+ return { error: "result needs a status." };
57
+ }
58
+ return { message: value };
59
+ case "bye":
60
+ return {
61
+ message: {
62
+ type: "bye",
63
+ reason: typeof value.reason === "string" ? value.reason : "",
64
+ },
65
+ };
66
+ default:
67
+ return { error: `Unknown message type: ${String(value.type)}` };
68
+ }
69
+ }
70
+ export function summariseSession(options) {
71
+ return {
72
+ id: options.id,
73
+ cwd: options.cwd,
74
+ turns: options.turns,
75
+ messages: options.messages.length,
76
+ capabilities: options.capabilities,
77
+ };
78
+ }
79
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/remote/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { OutputStream } from "../render.js";
2
+ import type { RemoteSession } from "./client.js";
3
+ export interface RemoteReplOptions {
4
+ readonly remote: RemoteSession;
5
+ readonly input: NodeJS.ReadableStream;
6
+ readonly output: NodeJS.WritableStream;
7
+ readonly stderr: OutputStream;
8
+ readonly socketPath: string;
9
+ }
10
+ /**
11
+ * The interactive loop for an attached client.
12
+ *
13
+ * It deliberately offers fewer commands than the local REPL: /clear would
14
+ * change a transcript this process does not own, and other clients would see
15
+ * it happen without asking.
16
+ */
17
+ export declare function runRemoteRepl(options: RemoteReplOptions): Promise<number>;
18
+ //# sourceMappingURL=repl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/remote/repl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAWD;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,MAAM,CAAC,CAsFjB"}
@@ -0,0 +1,100 @@
1
+ import { createInterface } from "node:readline";
2
+ import { REPL_PROMPT } from "../repl.js";
3
+ const HELP = `Commands:
4
+ /help Show this help
5
+ /session Show the served session's id, workspace and capabilities
6
+ /tools List the tools the server offers
7
+ /exit Leave this client (the server keeps running)
8
+
9
+ Anything else is sent to the server. Ctrl+C interrupts the answer in progress.
10
+ `;
11
+ /**
12
+ * The interactive loop for an attached client.
13
+ *
14
+ * It deliberately offers fewer commands than the local REPL: /clear would
15
+ * change a transcript this process does not own, and other clients would see
16
+ * it happen without asking.
17
+ */
18
+ export async function runRemoteRepl(options) {
19
+ const write = (text) => {
20
+ options.stderr.write(text);
21
+ };
22
+ const readline = createInterface({
23
+ input: options.input,
24
+ output: options.output,
25
+ terminal: true,
26
+ prompt: REPL_PROMPT,
27
+ });
28
+ let running = false;
29
+ readline.on("SIGINT", () => {
30
+ if (!running) {
31
+ write("Press Ctrl+D or /exit to leave.\n");
32
+ readline.prompt();
33
+ return;
34
+ }
35
+ options.remote.interrupt();
36
+ });
37
+ const summary = options.remote.session;
38
+ write([
39
+ `attached to ${summary.id}`,
40
+ `workspace: ${summary.cwd}`,
41
+ `capabilities: ${summary.capabilities.length === 0 ? "read-only" : summary.capabilities.join(" ")}`,
42
+ "Type /help for commands, Ctrl+D to detach.",
43
+ "",
44
+ "",
45
+ ].join("\n"));
46
+ readline.prompt();
47
+ for await (const line of readline) {
48
+ const trimmed = line.trim();
49
+ if (trimmed.length === 0) {
50
+ readline.prompt();
51
+ continue;
52
+ }
53
+ if (trimmed.startsWith("/")) {
54
+ const command = trimmed.split(/\s+/, 1)[0];
55
+ if (command === "/exit" || command === "/quit") {
56
+ break;
57
+ }
58
+ if (command === "/help" || command === "/?") {
59
+ write(HELP);
60
+ }
61
+ else if (command === "/session") {
62
+ write([
63
+ `id: ${summary.id}`,
64
+ `workspace: ${summary.cwd}`,
65
+ `socket: ${options.socketPath}`,
66
+ `capabilities: ${summary.capabilities.length === 0 ? "read-only" : summary.capabilities.join(" ")}`,
67
+ "",
68
+ ].join("\n"));
69
+ }
70
+ else if (command === "/tools") {
71
+ write(`${options.remote.toolNames.map((name) => ` ${name}`).join("\n")}\n`);
72
+ }
73
+ else {
74
+ write(`Unknown command: ${trimmed}. Try /help.\n`);
75
+ }
76
+ readline.prompt();
77
+ continue;
78
+ }
79
+ running = true;
80
+ try {
81
+ await options.remote.prompt(trimmed);
82
+ }
83
+ catch (error) {
84
+ const message = error instanceof Error ? error.message : "Unknown error";
85
+ write(`${message}\n`);
86
+ // A dead server ends the client; a busy or agent error does not.
87
+ if (message.includes("closed the connection")) {
88
+ readline.close();
89
+ return 1;
90
+ }
91
+ }
92
+ finally {
93
+ running = false;
94
+ }
95
+ readline.prompt();
96
+ }
97
+ readline.close();
98
+ return 0;
99
+ }
100
+ //# sourceMappingURL=repl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repl.js","sourceRoot":"","sources":["../../src/remote/repl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { AgentEvent } from "../events.js";
2
+ import type { AgentSession } from "../session.js";
3
+ export declare class SocketInUseError extends Error {
4
+ readonly socketPath: string;
5
+ constructor(socketPath: string);
6
+ }
7
+ export interface SessionServerOptions {
8
+ readonly session: AgentSession;
9
+ readonly socketPath: string;
10
+ /** Named in the handshake so an attaching client can see what it gets. */
11
+ readonly capabilities: readonly string[];
12
+ readonly onWarning?: (message: string) => void;
13
+ }
14
+ /**
15
+ * Exposes one session on a Unix socket.
16
+ *
17
+ * A client is just another subscriber that lives in another process, which is
18
+ * why this is thin: the session already fans events out and already runs one
19
+ * prompt at a time.
20
+ */
21
+ export declare class SessionServer {
22
+ private readonly options;
23
+ private readonly connections;
24
+ private server;
25
+ private running;
26
+ private controller;
27
+ private unsubscribe;
28
+ constructor(options: SessionServerOptions);
29
+ get socketPath(): string;
30
+ listen(): Promise<void>;
31
+ close(): Promise<void>;
32
+ private accept;
33
+ private drop;
34
+ private handleLine;
35
+ private runPrompt;
36
+ private fail;
37
+ private broadcast;
38
+ private send;
39
+ }
40
+ export type { AgentEvent };
41
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/remote/server.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAelD,qBAAa,gBAAiB,SAAQ,KAAK;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM;IAAvC,YAAqB,UAAU,EAAE,MAAM,EAKtC;CACF;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAChD;AAQD;;;;;;GAMG;AACH,qBAAa,aAAa;IAOZ,OAAO,CAAC,QAAQ,CAAC,OAAO;IANpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyB;IACrD,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,WAAW,CAA2B;IAE9C,YAA6B,OAAO,EAAE,oBAAoB,EAAI;IAE9D,IAAI,UAAU,IAAI,MAAM,CAEvB;IAEK,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAkC5B;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAe3B;IAED,OAAO,CAAC,MAAM;IA8Bd,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,UAAU;YAsDJ,SAAS;IA+BvB,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,IAAI;CAYb;AAED,YAAY,EAAE,UAAU,EAAE,CAAC"}