@minzicat/pi-team 0.1.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.
package/dist/cli.js ADDED
@@ -0,0 +1,371 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * pi-team: multi-agent debate/collaboration harness built on pi RPC mode.
4
+ *
5
+ * Subcommands:
6
+ * run Start a session in the foreground (orchestrator only)
7
+ * start Create a tmux session with a 3-pane layout (orchestrator, inject, log)
8
+ * inject Connect to a running session's injection socket and forward stdin
9
+ * stop Kill a tmux session and clean up
10
+ * list List sessions under the sessions dir
11
+ *
12
+ * Agent spec format (--agent): name:provider/model[:thinking]
13
+ * Examples:
14
+ * claude:anthropic/claude-sonnet-4-5
15
+ * codex:openai-codex/gpt-5.4:xhigh
16
+ * gem:google/gemini-3-pro-preview:high
17
+ */
18
+ import { homedir } from "node:os";
19
+ import { join } from "node:path";
20
+ import { existsSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
21
+ import { Orchestra } from "./orchestra.js";
22
+ import { Observer } from "./observer.js";
23
+ import { InjectServer, runInjectClient } from "./inject-server.js";
24
+ import { createLayout, killSession, sessionExists, tmuxInstalled } from "./tmux.js";
25
+ import { startHttpInject } from "./http-inject.js";
26
+ import { listPlans } from "./usage/plans.js";
27
+ const DEFAULT_SESSIONS_DIR = join(homedir(), ".pi", "team", "sessions");
28
+ function parseArgs(argv) {
29
+ const [command = "help", ...rest] = argv;
30
+ const flags = new Map();
31
+ const positional = [];
32
+ for (let i = 0; i < rest.length; i++) {
33
+ const a = rest[i];
34
+ if (a.startsWith("--")) {
35
+ const key = a.slice(2);
36
+ const next = rest[i + 1];
37
+ if (next !== undefined && !next.startsWith("--")) {
38
+ if (!flags.has(key))
39
+ flags.set(key, []);
40
+ flags.get(key).push(next);
41
+ i++;
42
+ }
43
+ else {
44
+ if (!flags.has(key))
45
+ flags.set(key, []);
46
+ flags.get(key).push("true");
47
+ }
48
+ }
49
+ else {
50
+ positional.push(a);
51
+ }
52
+ }
53
+ return { command, flags, positional };
54
+ }
55
+ function parseAgentSpec(spec) {
56
+ // name:provider/model[:thinking][@plan]
57
+ // Examples:
58
+ // claude:anthropic/claude-sonnet-4-5
59
+ // codex:openai-codex/gpt-5.4:xhigh
60
+ // claude:anthropic/claude-sonnet-4-5@anthropic-max-20x
61
+ // codex:openai-codex/gpt-5.4:xhigh@openai-plus
62
+ let planId;
63
+ const atIdx = spec.lastIndexOf("@");
64
+ if (atIdx !== -1) {
65
+ planId = spec.slice(atIdx + 1);
66
+ spec = spec.slice(0, atIdx);
67
+ }
68
+ const firstColon = spec.indexOf(":");
69
+ if (firstColon === -1)
70
+ throw new Error(`bad agent spec: "${spec}"`);
71
+ const name = spec.slice(0, firstColon);
72
+ const rest = spec.slice(firstColon + 1);
73
+ // rest is provider/model[:thinking]
74
+ const slash = rest.indexOf("/");
75
+ if (slash === -1)
76
+ throw new Error(`bad agent spec: "${spec}" (expected name:provider/model)`);
77
+ const provider = rest.slice(0, slash);
78
+ const afterSlash = rest.slice(slash + 1);
79
+ const thinkingSplit = afterSlash.lastIndexOf(":");
80
+ const thinkingCandidates = ["off", "minimal", "low", "medium", "high", "xhigh"];
81
+ let model = afterSlash;
82
+ let thinking;
83
+ if (thinkingSplit !== -1) {
84
+ const candidate = afterSlash.slice(thinkingSplit + 1);
85
+ if (thinkingCandidates.includes(candidate)) {
86
+ model = afterSlash.slice(0, thinkingSplit);
87
+ thinking = candidate;
88
+ }
89
+ }
90
+ return { name, provider, model, thinking, planId };
91
+ }
92
+ /**
93
+ * Parse --plan name=plan-id flag values into a map and fold them into agents
94
+ * that haven't already specified a plan via the @ suffix.
95
+ */
96
+ function applyPlanFlags(agents, planFlags) {
97
+ if (!planFlags)
98
+ return agents;
99
+ const planMap = new Map();
100
+ for (const raw of planFlags) {
101
+ const eq = raw.indexOf("=");
102
+ if (eq === -1)
103
+ throw new Error(`bad --plan value: "${raw}" (expected name=plan-id)`);
104
+ planMap.set(raw.slice(0, eq), raw.slice(eq + 1));
105
+ }
106
+ return agents.map((a) => (a.planId ? a : { ...a, planId: planMap.get(a.name) ?? a.planId }));
107
+ }
108
+ function help() {
109
+ process.stdout.write(`pi-team — multi-agent debate/collaboration harness
110
+
111
+ USAGE
112
+ pi-team start --name <name> --agent <spec> --agent <spec> [--topic <text> | --topic-file <path>]
113
+ [--plan <name=plan-id>] [--max-turns N]
114
+ pi-team run (same flags as start, but foreground, no tmux)
115
+ pi-team inject --name <name>
116
+ pi-team stop --name <name>
117
+ pi-team list
118
+ pi-team plans
119
+ pi-team help
120
+
121
+ AGENT SPEC
122
+ name:provider/model[:thinking][@plan-id]
123
+ claude:anthropic/claude-sonnet-4-5
124
+ codex:openai-codex/gpt-5.4:xhigh
125
+ claude:anthropic/claude-sonnet-4-5@anthropic-max-20x
126
+ codex:openai-codex/gpt-5.4:xhigh@openai-plus
127
+
128
+ PLAN-AWARE COST TRACKING
129
+ Without --plan (or @plan suffix), pi-team shows dollar cost from pi’s
130
+ per-token pricing — which is wrong if you’re on a subscription. Declare
131
+ your plan per agent to get real 5-hour and weekly window usage instead:
132
+
133
+ pi-team start --name x \\
134
+ --agent claude:anthropic/claude-sonnet-4-5 \\
135
+ --agent codex:openai-codex/gpt-5.4:xhigh \\
136
+ --plan claude=anthropic-max-20x \\
137
+ --plan codex=openai-plus \\
138
+ --topic-file ./topic.md
139
+
140
+ Run 'pi-team plans' to list available plan ids.
141
+
142
+ EXAMPLES
143
+ # Start an emotion-concepts debate between Claude and Codex, observable via tmux
144
+ pi-team start \\
145
+ --name emotions \\
146
+ --agent claude:anthropic/claude-sonnet-4-5@anthropic-max-20x \\
147
+ --agent codex:openai-codex/gpt-5.4:xhigh@openai-plus \\
148
+ --max-turns 10 \\
149
+ --topic-file ./debate-prompt.md
150
+
151
+ tmux attach -t piteam-emotions
152
+ pi-team inject --name emotions
153
+ pi-team stop --name emotions
154
+ `);
155
+ }
156
+ function cmdPlans() {
157
+ for (const id of listPlans()) {
158
+ process.stdout.write(`${id}\n`);
159
+ }
160
+ }
161
+ function resolveTopic(flags) {
162
+ const topicFile = flags.get("topic-file")?.[0];
163
+ if (topicFile)
164
+ return readFileSync(topicFile, "utf8");
165
+ const topic = flags.get("topic")?.[0];
166
+ if (topic)
167
+ return topic;
168
+ throw new Error("missing --topic or --topic-file");
169
+ }
170
+ function buildConfig(flags) {
171
+ const name = flags.get("name")?.[0];
172
+ if (!name)
173
+ throw new Error("missing --name");
174
+ const agentSpecs = flags.get("agent") ?? [];
175
+ if (agentSpecs.length < 2)
176
+ throw new Error("need at least two --agent specs");
177
+ const parsed = agentSpecs.map(parseAgentSpec);
178
+ const agents = applyPlanFlags(parsed, flags.get("plan"));
179
+ const topic = resolveTopic(flags);
180
+ const maxTurns = Number(flags.get("max-turns")?.[0] ?? "20");
181
+ const turnDelayMs = Number(flags.get("turn-delay-ms")?.[0] ?? "0");
182
+ const sessionsDir = flags.get("sessions-dir")?.[0] ?? DEFAULT_SESSIONS_DIR;
183
+ const mode = (flags.get("mode")?.[0] ?? "round-robin");
184
+ return { name, agents, topic, maxTurns, turnDelayMs, sessionsDir, mode };
185
+ }
186
+ async function cmdRun(flags) {
187
+ const config = buildConfig(flags);
188
+ await runFromConfig(config, flags);
189
+ }
190
+ async function cmdStart(flags) {
191
+ if (!tmuxInstalled()) {
192
+ throw new Error("tmux is required for 'start'; use 'run' for foreground");
193
+ }
194
+ const config = buildConfig(flags);
195
+ if (sessionExists(`piteam-${config.name}`)) {
196
+ throw new Error(`tmux session "piteam-${config.name}" already exists. Kill with: pi-team stop --name ${config.name}`);
197
+ }
198
+ // Write config so the background `run` process can read it
199
+ const sessionDir = join(config.sessionsDir, config.name);
200
+ const { mkdirSync } = await import("node:fs");
201
+ mkdirSync(sessionDir, { recursive: true });
202
+ const configPath = join(sessionDir, "config.json");
203
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
204
+ // Resolve the path to this script for the tmux pane commands
205
+ const scriptPath = process.argv[1];
206
+ const node = process.execPath;
207
+ const httpPortFlag = flags.get("http-port")?.[0];
208
+ const httpHostFlag = flags.get("http-host")?.[0];
209
+ const httpPortArgs = httpPortFlag ? ` --http-port ${httpPortFlag}` : "";
210
+ const httpHostArgs = httpHostFlag ? ` --http-host ${httpHostFlag}` : "";
211
+ const runCmd = `${node} ${scriptPath} run --config-file ${configPath}${httpPortArgs}${httpHostArgs}`;
212
+ const injectCmd = `${node} ${scriptPath} inject --name ${config.name}`;
213
+ const logPath = join(sessionDir, "events.log");
214
+ // Ensure log file exists so tail -f doesn't fail
215
+ writeFileSync(logPath, `# pi-team session ${config.name} — started ${new Date().toISOString()}\n`);
216
+ createLayout({
217
+ sessionName: `piteam-${config.name}`,
218
+ orchestratorCmd: runCmd,
219
+ injectCmd: `sleep 1 && ${injectCmd}`,
220
+ logPath,
221
+ });
222
+ process.stdout.write(`\n\x1b[1mpi-team session "${config.name}" started in tmux.\x1b[0m\n\n` +
223
+ ` Watch: tmux attach -t piteam-${config.name}\n` +
224
+ ` Inject: pi-team inject --name ${config.name} (from any shell)\n` +
225
+ ` Stop: pi-team stop --name ${config.name}\n` +
226
+ ` Log: ${logPath}\n` +
227
+ ` Dir: ${sessionDir}\n\n`);
228
+ }
229
+ async function cmdInject(flags) {
230
+ const name = flags.get("name")?.[0];
231
+ if (!name)
232
+ throw new Error("missing --name");
233
+ const sessionsDir = flags.get("sessions-dir")?.[0] ?? DEFAULT_SESSIONS_DIR;
234
+ const socketPath = join(sessionsDir, name, "inject.sock");
235
+ // Wait briefly for socket if run just started
236
+ for (let i = 0; i < 20; i++) {
237
+ if (existsSync(socketPath))
238
+ break;
239
+ await new Promise((r) => setTimeout(r, 300));
240
+ }
241
+ if (!existsSync(socketPath)) {
242
+ throw new Error(`no injection socket at ${socketPath} — is the session running?`);
243
+ }
244
+ process.stdout.write(`\x1b[2m[connected to ${name}. Type a message and press Enter. Ctrl+D to quit.]\x1b[0m\n`);
245
+ await runInjectClient(socketPath);
246
+ }
247
+ async function cmdStop(flags) {
248
+ const name = flags.get("name")?.[0];
249
+ if (!name)
250
+ throw new Error("missing --name");
251
+ killSession(`piteam-${name}`);
252
+ process.stdout.write(`stopped piteam-${name}\n`);
253
+ }
254
+ function cmdList(flags) {
255
+ const sessionsDir = flags.get("sessions-dir")?.[0] ?? DEFAULT_SESSIONS_DIR;
256
+ if (!existsSync(sessionsDir)) {
257
+ process.stdout.write(`(no sessions at ${sessionsDir})\n`);
258
+ return;
259
+ }
260
+ const entries = readdirSync(sessionsDir);
261
+ if (entries.length === 0) {
262
+ process.stdout.write(`(no sessions)\n`);
263
+ return;
264
+ }
265
+ for (const name of entries) {
266
+ const dir = join(sessionsDir, name);
267
+ if (!statSync(dir).isDirectory())
268
+ continue;
269
+ const active = sessionExists(`piteam-${name}`);
270
+ process.stdout.write(`${active ? "● " : " "}${name} ${dir}\n`);
271
+ }
272
+ }
273
+ async function cmdRunWithConfigFile(flags) {
274
+ const cf = flags.get("config-file")?.[0];
275
+ if (!cf) {
276
+ return cmdRun(flags);
277
+ }
278
+ const config = JSON.parse(readFileSync(cf, "utf8"));
279
+ // Use the loaded config directly — it already contains AgentSpec objects
280
+ // with planId preserved. Don't round-trip through string-based flags.
281
+ await runFromConfig(config, flags);
282
+ }
283
+ async function runFromConfig(config, flags) {
284
+ const orchestra = new Orchestra(config);
285
+ const sessionDir = join(config.sessionsDir, config.name);
286
+ const logPath = join(sessionDir, "events.log");
287
+ const socketPath = join(sessionDir, "inject.sock");
288
+ new Observer(orchestra, logPath);
289
+ const injectServer = new InjectServer(orchestra, socketPath);
290
+ injectServer.start();
291
+ const httpPort = Number(flags.get("http-port")?.[0] ?? process.env.PITEAM_HTTP_PORT ?? "0");
292
+ const httpHost = flags.get("http-host")?.[0] ?? process.env.PITEAM_HTTP_HOST ?? "127.0.0.1";
293
+ let httpHandle = null;
294
+ if (httpPort > 0) {
295
+ httpHandle = startHttpInject({
296
+ orchestra,
297
+ port: httpPort,
298
+ host: httpHost,
299
+ sessionDir,
300
+ token: process.env.PITEAM_HTTP_TOKEN,
301
+ onStop: async () => {
302
+ await orchestra.stop();
303
+ },
304
+ });
305
+ process.stdout.write(`\x1b[2m· http inject on ${httpHost}:${httpPort}\x1b[0m\n`);
306
+ }
307
+ const runfile = join(sessionDir, "runfile.json");
308
+ writeFileSync(runfile, JSON.stringify({ pid: process.pid, socket: socketPath, httpPort, started: Date.now(), config }, null, 2));
309
+ const shutdown = async () => {
310
+ process.stdout.write("\n\x1b[2m· shutting down\x1b[0m\n");
311
+ injectServer.stop();
312
+ httpHandle?.stop();
313
+ await orchestra.stop();
314
+ process.exit(0);
315
+ };
316
+ process.on("SIGINT", shutdown);
317
+ process.on("SIGTERM", shutdown);
318
+ try {
319
+ await orchestra.start();
320
+ }
321
+ catch (err) {
322
+ process.stderr.write(`\n\x1b[31mfatal:\x1b[0m ${err.message}\n`);
323
+ injectServer.stop();
324
+ httpHandle?.stop();
325
+ await orchestra.stop();
326
+ process.exit(1);
327
+ }
328
+ injectServer.stop();
329
+ httpHandle?.stop();
330
+ await orchestra.stop();
331
+ process.exit(0);
332
+ }
333
+ async function main() {
334
+ const parsed = parseArgs(process.argv.slice(2));
335
+ try {
336
+ switch (parsed.command) {
337
+ case "run":
338
+ await cmdRunWithConfigFile(parsed.flags);
339
+ break;
340
+ case "start":
341
+ await cmdStart(parsed.flags);
342
+ break;
343
+ case "inject":
344
+ await cmdInject(parsed.flags);
345
+ break;
346
+ case "stop":
347
+ await cmdStop(parsed.flags);
348
+ break;
349
+ case "list":
350
+ cmdList(parsed.flags);
351
+ break;
352
+ case "plans":
353
+ cmdPlans();
354
+ break;
355
+ case "help":
356
+ case "--help":
357
+ case "-h":
358
+ help();
359
+ break;
360
+ default:
361
+ help();
362
+ process.exit(1);
363
+ }
364
+ }
365
+ catch (err) {
366
+ process.stderr.write(`\x1b[31merror:\x1b[0m ${err.message}\n`);
367
+ process.exit(1);
368
+ }
369
+ }
370
+ main();
371
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * HTTP inject endpoint: thin wrapper so external systems (ops-agent, curl,
3
+ * webhooks) can post human messages into a running team session without
4
+ * touching the Unix socket directly.
5
+ *
6
+ * Endpoints:
7
+ * POST /inject body = raw text or { "message": "..." }
8
+ * GET /state returns {agents, turn, lastMessages}
9
+ * GET /transcript returns JSONL of full transcript
10
+ * POST /stop gracefully stops the orchestra
11
+ *
12
+ * All responses JSON. Defaults to binding on 127.0.0.1 (localhost-only). Set
13
+ * host to "0.0.0.0" or another interface to expose over the network — when
14
+ * you do, you should also set PITEAM_HTTP_TOKEN so untrusted clients on the
15
+ * LAN can't POST /inject and feed arbitrary text into the agents.
16
+ */
17
+ import { createServer } from "node:http";
18
+ import { readFileSync } from "node:fs";
19
+ import { join } from "node:path";
20
+ /** Hard cap on POST /inject body to stop runaway streaming from eating memory. */
21
+ const MAX_BODY_BYTES = 1_000_000; // 1 MB
22
+ export function startHttpInject(opts) {
23
+ const server = createServer(async (req, res) => {
24
+ try {
25
+ if (opts.token) {
26
+ const auth = req.headers.authorization;
27
+ if (auth !== `Bearer ${opts.token}`) {
28
+ return json(res, 401, { error: "unauthorized" });
29
+ }
30
+ }
31
+ const url = req.url ?? "/";
32
+ if (req.method === "POST" && url === "/inject") {
33
+ const body = await readBody(req);
34
+ let message;
35
+ try {
36
+ const parsed = JSON.parse(body);
37
+ message = typeof parsed === "string" ? parsed : parsed.message;
38
+ }
39
+ catch {
40
+ message = body;
41
+ }
42
+ if (!message || !message.trim()) {
43
+ return json(res, 400, { error: "empty message" });
44
+ }
45
+ opts.orchestra.inject(message);
46
+ return json(res, 200, { ok: true, queued: message.length });
47
+ }
48
+ if (req.method === "GET" && url === "/state") {
49
+ return json(res, 200, {
50
+ session: opts.orchestra.config.name,
51
+ agents: opts.orchestra.config.agents.map((a) => ({
52
+ name: a.name,
53
+ provider: a.provider,
54
+ model: a.model,
55
+ planId: a.planId ?? "api",
56
+ })),
57
+ lastMessages: opts.orchestra.lastMessages(5),
58
+ usage: opts.orchestra.usageSnapshots(),
59
+ });
60
+ }
61
+ if (req.method === "GET" && url === "/usage") {
62
+ return json(res, 200, {
63
+ session: opts.orchestra.config.name,
64
+ snapshots: opts.orchestra.usageSnapshots(),
65
+ });
66
+ }
67
+ if (req.method === "GET" && url === "/transcript") {
68
+ const path = join(opts.sessionDir, "transcript.jsonl");
69
+ try {
70
+ const raw = readFileSync(path, "utf8");
71
+ res.writeHead(200, { "content-type": "application/x-ndjson" });
72
+ res.end(raw);
73
+ }
74
+ catch (err) {
75
+ json(res, 500, { error: err.message });
76
+ }
77
+ return;
78
+ }
79
+ if (req.method === "POST" && url === "/stop") {
80
+ if (opts.onStop)
81
+ await opts.onStop();
82
+ return json(res, 200, { ok: true });
83
+ }
84
+ if (req.method === "GET" && url === "/") {
85
+ return json(res, 200, {
86
+ service: "pi-team",
87
+ session: opts.orchestra.config.name,
88
+ endpoints: [
89
+ "POST /inject",
90
+ "GET /state",
91
+ "GET /usage",
92
+ "GET /transcript",
93
+ "POST /stop",
94
+ ],
95
+ });
96
+ }
97
+ json(res, 404, { error: "not found" });
98
+ }
99
+ catch (err) {
100
+ json(res, 500, { error: err.message });
101
+ }
102
+ });
103
+ const host = opts.host ?? "127.0.0.1";
104
+ server.on("error", (err) => {
105
+ if (err.code === "EADDRINUSE") {
106
+ console.error(`[http-inject] port ${opts.port} is already in use on ${host}`);
107
+ }
108
+ else {
109
+ console.error(`[http-inject] server error: ${err.message}`);
110
+ }
111
+ });
112
+ server.listen(opts.port, host);
113
+ return { stop: () => server.close() };
114
+ }
115
+ function readBody(req) {
116
+ return new Promise((resolve, reject) => {
117
+ const chunks = [];
118
+ let total = 0;
119
+ req.on("data", (c) => {
120
+ total += c.length;
121
+ if (total > MAX_BODY_BYTES) {
122
+ req.destroy();
123
+ reject(new Error(`request body exceeds ${MAX_BODY_BYTES} bytes`));
124
+ return;
125
+ }
126
+ chunks.push(c);
127
+ });
128
+ req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
129
+ req.on("error", reject);
130
+ });
131
+ }
132
+ function json(res, status, body) {
133
+ res.writeHead(status, { "content-type": "application/json" });
134
+ res.end(JSON.stringify(body));
135
+ }
136
+ //# sourceMappingURL=http-inject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-inject.js","sourceRoot":"","sources":["../src/http-inject.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Injection server: a Unix domain socket that accepts human messages and
3
+ * forwards them to the running Orchestra. Lets the user hop in live from a
4
+ * separate tmux pane (or remote shell) without disturbing the orchestrator's
5
+ * stdout stream.
6
+ *
7
+ * Protocol: newline-delimited text. Every line is one injection. Empty lines
8
+ * ignored. The socket file is created under the session dir.
9
+ */
10
+ import { createServer } from "node:net";
11
+ import { unlinkSync, existsSync } from "node:fs";
12
+ export class InjectServer {
13
+ orchestra;
14
+ socketPath;
15
+ server = null;
16
+ constructor(orchestra, socketPath) {
17
+ this.orchestra = orchestra;
18
+ this.socketPath = socketPath;
19
+ }
20
+ start() {
21
+ if (existsSync(this.socketPath)) {
22
+ try {
23
+ unlinkSync(this.socketPath);
24
+ }
25
+ catch {
26
+ /* ignore */
27
+ }
28
+ }
29
+ this.server = createServer((conn) => {
30
+ let buffer = "";
31
+ conn.on("data", (chunk) => {
32
+ buffer += chunk.toString("utf8");
33
+ let nl = buffer.indexOf("\n");
34
+ while (nl !== -1) {
35
+ const line = buffer.slice(0, nl).replace(/\r$/, "");
36
+ buffer = buffer.slice(nl + 1);
37
+ if (line.trim()) {
38
+ this.orchestra.inject(line);
39
+ conn.write("ok\n");
40
+ }
41
+ nl = buffer.indexOf("\n");
42
+ }
43
+ });
44
+ conn.on("end", () => {
45
+ if (buffer.trim())
46
+ this.orchestra.inject(buffer.trim());
47
+ });
48
+ conn.on("error", () => {
49
+ /* ignore */
50
+ });
51
+ });
52
+ this.server.listen(this.socketPath);
53
+ }
54
+ stop() {
55
+ if (this.server) {
56
+ this.server.close();
57
+ this.server = null;
58
+ }
59
+ if (existsSync(this.socketPath)) {
60
+ try {
61
+ unlinkSync(this.socketPath);
62
+ }
63
+ catch {
64
+ /* ignore */
65
+ }
66
+ }
67
+ }
68
+ }
69
+ /**
70
+ * Client-side: read lines from stdin (with a `team › ` prompt) and send them
71
+ * to the socket. Used by `pi-team inject <socket>`.
72
+ */
73
+ export async function runInjectClient(socketPath) {
74
+ const { createConnection } = await import("node:net");
75
+ const readline = await import("node:readline");
76
+ const conn = createConnection(socketPath);
77
+ await new Promise((resolve, reject) => {
78
+ conn.once("connect", () => resolve());
79
+ conn.once("error", reject);
80
+ });
81
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
82
+ rl.setPrompt("team › ");
83
+ rl.prompt();
84
+ rl.on("line", (line) => {
85
+ if (line.trim()) {
86
+ conn.write(`${line}\n`);
87
+ }
88
+ rl.prompt();
89
+ });
90
+ rl.on("close", () => {
91
+ conn.end();
92
+ process.exit(0);
93
+ });
94
+ conn.on("data", () => {
95
+ // server ack; don't echo
96
+ });
97
+ conn.on("end", () => {
98
+ rl.close();
99
+ });
100
+ }
101
+ //# sourceMappingURL=inject-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-server.js","sourceRoot":"","sources":["../src/inject-server.ts"],"names":[],"mappings":"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"}