naiad-cli 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.
Files changed (50) hide show
  1. package/dist/api/client.d.ts +81 -0
  2. package/dist/api/client.js +130 -0
  3. package/dist/api/client.js.map +1 -0
  4. package/dist/callback/server.d.ts +11 -0
  5. package/dist/callback/server.js +53 -0
  6. package/dist/callback/server.js.map +1 -0
  7. package/dist/callback/server.test.d.ts +1 -0
  8. package/dist/callback/server.test.js +79 -0
  9. package/dist/callback/server.test.js.map +1 -0
  10. package/dist/commands/exec.d.ts +10 -0
  11. package/dist/commands/exec.js +94 -0
  12. package/dist/commands/exec.js.map +1 -0
  13. package/dist/commands/interactive.d.ts +6 -0
  14. package/dist/commands/interactive.js +137 -0
  15. package/dist/commands/interactive.js.map +1 -0
  16. package/dist/config/config.d.ts +5 -0
  17. package/dist/config/config.js +21 -0
  18. package/dist/config/config.js.map +1 -0
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.js +137 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/lifecycle/setup.d.ts +11 -0
  23. package/dist/lifecycle/setup.js +49 -0
  24. package/dist/lifecycle/setup.js.map +1 -0
  25. package/dist/lifecycle/teardown.d.ts +6 -0
  26. package/dist/lifecycle/teardown.js +34 -0
  27. package/dist/lifecycle/teardown.js.map +1 -0
  28. package/dist/lifecycle/types.d.ts +21 -0
  29. package/dist/lifecycle/types.js +2 -0
  30. package/dist/lifecycle/types.js.map +1 -0
  31. package/dist/lifecycle/workers.d.ts +2 -0
  32. package/dist/lifecycle/workers.js +22 -0
  33. package/dist/lifecycle/workers.js.map +1 -0
  34. package/dist/pi/launcher.d.ts +26 -0
  35. package/dist/pi/launcher.js +109 -0
  36. package/dist/pi/launcher.js.map +1 -0
  37. package/dist/sync/events.d.ts +14 -0
  38. package/dist/sync/events.js +44 -0
  39. package/dist/sync/events.js.map +1 -0
  40. package/dist/sync/heartbeat.d.ts +12 -0
  41. package/dist/sync/heartbeat.js +33 -0
  42. package/dist/sync/heartbeat.js.map +1 -0
  43. package/dist/sync/session-upload.d.ts +12 -0
  44. package/dist/sync/session-upload.js +69 -0
  45. package/dist/sync/session-upload.js.map +1 -0
  46. package/dist/utils/package-root.d.ts +1 -0
  47. package/dist/utils/package-root.js +13 -0
  48. package/dist/utils/package-root.js.map +1 -0
  49. package/extensions/naiad-extension.ts +330 -0
  50. package/package.json +31 -0
@@ -0,0 +1,81 @@
1
+ import type { NaiadConfig } from "../config/config.js";
2
+ export declare class APIClient {
3
+ private baseUrl;
4
+ private apiKey;
5
+ constructor(config: NaiadConfig);
6
+ private request;
7
+ listModels(): Promise<{
8
+ models: Array<{
9
+ id: string;
10
+ display_name: string;
11
+ }>;
12
+ }>;
13
+ createThread(prompt: string, opts?: {
14
+ source?: string;
15
+ trigger?: string;
16
+ context?: Record<string, unknown>;
17
+ replyTarget?: Record<string, unknown>;
18
+ }): Promise<{
19
+ id: string;
20
+ status: string;
21
+ }>;
22
+ updateThread(threadId: string, update: {
23
+ status?: string;
24
+ error?: string;
25
+ result?: unknown;
26
+ }): Promise<{
27
+ id: string;
28
+ status: string;
29
+ }>;
30
+ createSession(threadId: string, agentId: string, runtime?: string): Promise<{
31
+ id: string;
32
+ }>;
33
+ updateSession(sessionId: string, status: string): Promise<void>;
34
+ postEvents(threadId: string, sessionId: string, events: Array<{
35
+ client_seq: number;
36
+ event_type: string;
37
+ data: unknown;
38
+ }>): Promise<{
39
+ accepted: number;
40
+ duplicates: number;
41
+ }>;
42
+ postHeartbeat(agentId: string, threadId: string, sessionId: string, status: string, metrics?: Record<string, unknown>): Promise<void>;
43
+ getUploadUrls(sessionId: string, chunks: Array<{
44
+ start: number;
45
+ end: number;
46
+ sha256_hex: string;
47
+ }>): Promise<{
48
+ urls: Array<{
49
+ start: number;
50
+ end: number;
51
+ url: string;
52
+ }>;
53
+ }>;
54
+ finalizeSession(sessionId: string, totalBytes: number, chunkCount: number, sha256: string): Promise<void>;
55
+ getSession(sessionId: string): Promise<{
56
+ id: string;
57
+ thread_id: string;
58
+ attempt: number;
59
+ status: string;
60
+ }>;
61
+ listThreadSessions(threadId: string): Promise<Array<{
62
+ id: string;
63
+ thread_id: string;
64
+ attempt: number;
65
+ status: string;
66
+ started_at: string;
67
+ }>>;
68
+ downloadSession(sessionId: string): Promise<Buffer>;
69
+ listThreads(params?: {
70
+ status?: string;
71
+ limit?: number;
72
+ offset?: number;
73
+ }): Promise<{
74
+ threads: Array<{
75
+ id: string;
76
+ status: string;
77
+ created_at: string;
78
+ }>;
79
+ total: number;
80
+ }>;
81
+ }
@@ -0,0 +1,130 @@
1
+ export class APIClient {
2
+ baseUrl;
3
+ apiKey;
4
+ constructor(config) {
5
+ this.baseUrl = config.apiUrl;
6
+ this.apiKey = config.apiKey;
7
+ }
8
+ async request(method, path, body) {
9
+ const url = `${this.baseUrl}${path}`;
10
+ const res = await fetch(url, {
11
+ method,
12
+ headers: {
13
+ "Content-Type": "application/json",
14
+ "Authorization": `Bearer ${this.apiKey}`,
15
+ },
16
+ body: body ? JSON.stringify(body) : undefined,
17
+ });
18
+ return res;
19
+ }
20
+ async listModels() {
21
+ const res = await this.request("GET", "/api/v1/models");
22
+ if (!res.ok)
23
+ throw new Error(`Failed to list models: ${res.status} ${await res.text()}`);
24
+ return res.json();
25
+ }
26
+ async createThread(prompt, opts) {
27
+ const body = {
28
+ prompt,
29
+ source: opts?.source || "cli",
30
+ trigger: opts?.trigger || "cli",
31
+ context: opts?.context || {},
32
+ };
33
+ if (opts?.replyTarget) {
34
+ body.reply_target = opts.replyTarget;
35
+ }
36
+ const res = await this.request("POST", "/api/v1/threads", body);
37
+ if (!res.ok)
38
+ throw new Error(`Failed to create thread: ${res.status} ${await res.text()}`);
39
+ return res.json();
40
+ }
41
+ async updateThread(threadId, update) {
42
+ const res = await this.request("PATCH", `/api/v1/threads/${threadId}`, update);
43
+ if (!res.ok)
44
+ throw new Error(`Failed to update thread: ${res.status} ${await res.text()}`);
45
+ return res.json();
46
+ }
47
+ async createSession(threadId, agentId, runtime = "local_cli") {
48
+ const res = await this.request("POST", `/api/v1/threads/${threadId}/sessions`, {
49
+ runtime,
50
+ agent_id: agentId,
51
+ });
52
+ if (!res.ok)
53
+ throw new Error(`Failed to create session: ${res.status} ${await res.text()}`);
54
+ return res.json();
55
+ }
56
+ async updateSession(sessionId, status) {
57
+ const res = await this.request("PATCH", `/api/v1/sessions/${sessionId}`, { status });
58
+ if (!res.ok)
59
+ throw new Error(`Failed to update session: ${res.status} ${await res.text()}`);
60
+ }
61
+ async postEvents(threadId, sessionId, events) {
62
+ const res = await this.request("POST", `/api/v1/threads/${threadId}/events`, {
63
+ session_id: sessionId,
64
+ events,
65
+ });
66
+ if (!res.ok)
67
+ throw new Error(`Failed to post events: ${res.status} ${await res.text()}`);
68
+ return res.json();
69
+ }
70
+ async postHeartbeat(agentId, threadId, sessionId, status, metrics = {}) {
71
+ const res = await this.request("POST", "/api/v1/agents/heartbeat", {
72
+ agent_id: agentId,
73
+ thread_id: threadId,
74
+ session_id: sessionId,
75
+ status,
76
+ metrics,
77
+ });
78
+ if (!res.ok)
79
+ throw new Error(`Failed to post heartbeat: ${res.status} ${await res.text()}`);
80
+ }
81
+ async getUploadUrls(sessionId, chunks) {
82
+ const res = await this.request("POST", `/api/v1/sessions/${sessionId}/upload-urls`, { chunks });
83
+ if (!res.ok)
84
+ throw new Error(`Failed to get upload urls: ${res.status} ${await res.text()}`);
85
+ return res.json();
86
+ }
87
+ async finalizeSession(sessionId, totalBytes, chunkCount, sha256) {
88
+ const res = await this.request("POST", `/api/v1/sessions/${sessionId}/finalize`, {
89
+ total_bytes: totalBytes,
90
+ chunk_count: chunkCount,
91
+ sha256,
92
+ });
93
+ if (!res.ok)
94
+ throw new Error(`Failed to finalize session: ${res.status} ${await res.text()}`);
95
+ }
96
+ async getSession(sessionId) {
97
+ const res = await this.request("GET", `/api/v1/sessions/${sessionId}`);
98
+ if (!res.ok)
99
+ throw new Error(`Failed to get session: ${res.status} ${await res.text()}`);
100
+ return res.json();
101
+ }
102
+ async listThreadSessions(threadId) {
103
+ const res = await this.request("GET", `/api/v1/threads/${threadId}/sessions`);
104
+ if (!res.ok)
105
+ throw new Error(`Failed to list sessions: ${res.status} ${await res.text()}`);
106
+ const data = await res.json();
107
+ return data.sessions;
108
+ }
109
+ async downloadSession(sessionId) {
110
+ const res = await this.request("GET", `/api/v1/sessions/${sessionId}/download`);
111
+ if (!res.ok)
112
+ throw new Error(`Failed to download session: ${res.status} ${await res.text()}`);
113
+ return Buffer.from(await res.arrayBuffer());
114
+ }
115
+ async listThreads(params) {
116
+ const searchParams = new URLSearchParams();
117
+ if (params?.status)
118
+ searchParams.set("status", params.status);
119
+ if (params?.limit)
120
+ searchParams.set("limit", String(params.limit));
121
+ if (params?.offset)
122
+ searchParams.set("offset", String(params.offset));
123
+ const qs = searchParams.toString();
124
+ const res = await this.request("GET", `/api/v1/threads${qs ? `?${qs}` : ""}`);
125
+ if (!res.ok)
126
+ throw new Error(`Failed to list threads: ${res.status} ${await res.text()}`);
127
+ return res.json();
128
+ }
129
+ }
130
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface CallbackEvent {
2
+ type: string;
3
+ data: unknown;
4
+ timestamp: number;
5
+ }
6
+ export interface CallbackServer {
7
+ url: string;
8
+ drain(): CallbackEvent[];
9
+ close(): Promise<void>;
10
+ }
11
+ export declare function startCallbackServer(): Promise<CallbackServer>;
@@ -0,0 +1,53 @@
1
+ import { createServer } from "node:http";
2
+ export async function startCallbackServer() {
3
+ const events = [];
4
+ const server = createServer((req, res) => {
5
+ if (req.method !== "POST" || req.url !== "/events") {
6
+ res.writeHead(404);
7
+ res.end();
8
+ return;
9
+ }
10
+ let body = "";
11
+ req.on("data", (chunk) => {
12
+ body += chunk.toString();
13
+ });
14
+ req.on("end", () => {
15
+ try {
16
+ const parsed = JSON.parse(body);
17
+ events.push({
18
+ type: parsed.type,
19
+ data: parsed.data,
20
+ timestamp: Date.now(),
21
+ });
22
+ res.writeHead(200, { "Content-Type": "application/json" });
23
+ res.end(JSON.stringify({ ok: true }));
24
+ }
25
+ catch {
26
+ res.writeHead(400, { "Content-Type": "application/json" });
27
+ res.end(JSON.stringify({ ok: false, error: "invalid json" }));
28
+ }
29
+ });
30
+ });
31
+ await new Promise((resolve) => {
32
+ server.listen(0, "127.0.0.1", () => resolve());
33
+ });
34
+ const addr = server.address();
35
+ const url = `http://127.0.0.1:${addr.port}/events`;
36
+ return {
37
+ url,
38
+ drain() {
39
+ return events.splice(0);
40
+ },
41
+ close() {
42
+ return new Promise((resolve, reject) => {
43
+ server.close((err) => {
44
+ if (err)
45
+ reject(err);
46
+ else
47
+ resolve();
48
+ });
49
+ });
50
+ },
51
+ };
52
+ }
53
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/callback/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA0D,MAAM,WAAW,CAAC;AAcjG,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAoB,EAAE,GAAmB,EAAE,EAAE;QACxE,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YACnD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YAC/B,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAoC,CAAC;gBACnE,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;iBACtB,CAAC,CAAC;gBACH,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;YAChE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAsB,CAAC;IAClD,MAAM,GAAG,GAAG,oBAAoB,IAAI,CAAC,IAAI,SAAS,CAAC;IAEnD,OAAO;QACL,GAAG;QACH,KAAK;YACH,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK;YACH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACrC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBACnB,IAAI,GAAG;wBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;wBAChB,OAAO,EAAE,CAAC;gBACjB,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { startCallbackServer } from "./server.js";
4
+ describe("CallbackServer", () => {
5
+ it("receives a single event and drains it", async () => {
6
+ const server = await startCallbackServer();
7
+ try {
8
+ const res = await fetch(server.url, {
9
+ method: "POST",
10
+ headers: { "Content-Type": "application/json" },
11
+ body: JSON.stringify({ type: "agent_start", data: { foo: 1 } }),
12
+ });
13
+ assert.equal(res.status, 200);
14
+ const events = server.drain();
15
+ assert.equal(events.length, 1);
16
+ assert.equal(events[0].type, "agent_start");
17
+ assert.deepEqual(events[0].data, { foo: 1 });
18
+ assert.equal(typeof events[0].timestamp, "number");
19
+ }
20
+ finally {
21
+ await server.close();
22
+ }
23
+ });
24
+ it("buffers multiple events and drain clears them", async () => {
25
+ const server = await startCallbackServer();
26
+ try {
27
+ for (let i = 0; i < 3; i++) {
28
+ await fetch(server.url, {
29
+ method: "POST",
30
+ headers: { "Content-Type": "application/json" },
31
+ body: JSON.stringify({ type: `event_${i}`, data: { i } }),
32
+ });
33
+ }
34
+ const events = server.drain();
35
+ assert.equal(events.length, 3);
36
+ assert.equal(events[0].type, "event_0");
37
+ assert.equal(events[1].type, "event_1");
38
+ assert.equal(events[2].type, "event_2");
39
+ // Drain again should be empty
40
+ const empty = server.drain();
41
+ assert.equal(empty.length, 0);
42
+ }
43
+ finally {
44
+ await server.close();
45
+ }
46
+ });
47
+ it("shuts down cleanly", async () => {
48
+ const server = await startCallbackServer();
49
+ await server.close();
50
+ // Server should no longer accept connections
51
+ try {
52
+ await fetch(server.url, {
53
+ method: "POST",
54
+ headers: { "Content-Type": "application/json" },
55
+ body: JSON.stringify({ type: "test", data: {} }),
56
+ });
57
+ assert.fail("Should have thrown on closed server");
58
+ }
59
+ catch {
60
+ // Expected — connection refused
61
+ }
62
+ });
63
+ it("returns 400 on invalid JSON", async () => {
64
+ const server = await startCallbackServer();
65
+ try {
66
+ const res = await fetch(server.url, {
67
+ method: "POST",
68
+ headers: { "Content-Type": "application/json" },
69
+ body: "not json",
70
+ });
71
+ assert.equal(res.status, 400);
72
+ assert.equal(server.drain().length, 0);
73
+ }
74
+ finally {
75
+ await server.close();
76
+ }
77
+ });
78
+ });
79
+ //# sourceMappingURL=server.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.test.js","sourceRoot":"","sources":["../../src/callback/server.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { NaiadConfig } from "../config/config.js";
2
+ export interface ExecOptions {
3
+ model?: string;
4
+ source?: string;
5
+ trigger?: string;
6
+ context?: string;
7
+ replyTarget?: string;
8
+ output?: string;
9
+ }
10
+ export declare function execCommand(config: NaiadConfig, prompt: string, opts?: ExecOptions): Promise<void>;
@@ -0,0 +1,94 @@
1
+ import { writeFileSync } from "fs";
2
+ import { launchPi } from "../pi/launcher.js";
3
+ import { setupLifecycle } from "../lifecycle/setup.js";
4
+ import { startWorkers } from "../lifecycle/workers.js";
5
+ import { teardownLifecycle } from "../lifecycle/teardown.js";
6
+ export async function execCommand(config, prompt, opts = {}) {
7
+ const ctx = await setupLifecycle({
8
+ config,
9
+ modelFlag: opts.model,
10
+ threadPrompt: prompt,
11
+ source: opts.source,
12
+ trigger: opts.trigger,
13
+ context: opts.context,
14
+ replyTarget: opts.replyTarget,
15
+ });
16
+ // Phase 1 output: write partial result immediately after thread creation
17
+ if (opts.output) {
18
+ const partial = {
19
+ thread_id: ctx.threadId,
20
+ thread_url: `${config.apiUrl}/app/threads/${ctx.threadId}`,
21
+ session_id: ctx.sessionId,
22
+ status: "RUNNING",
23
+ model: ctx.model,
24
+ };
25
+ writeFileSync(opts.output, JSON.stringify(partial, null, 2));
26
+ }
27
+ // Launch pi in RPC mode
28
+ const pi = launchPi({
29
+ model: ctx.model,
30
+ sessionDir: ctx.sessionDir,
31
+ extensionPath: ctx.extensionPath,
32
+ env: {
33
+ NAIAD_INFERENCE_URL: `${config.apiUrl}/api/v1/inference`,
34
+ NAIAD_API_KEY: config.apiKey,
35
+ NAIAD_THREAD_ID: ctx.threadId,
36
+ NAIAD_SESSION_ID: ctx.sessionId,
37
+ NAIAD_MODEL: ctx.model,
38
+ },
39
+ });
40
+ // Start background workers
41
+ const workers = startWorkers(ctx);
42
+ // Process pi events
43
+ let agentEnded = false;
44
+ pi.onEvent((event) => {
45
+ // Forward all events to the spool
46
+ workers.eventSpool.pushEvent(event.type, event);
47
+ // Print assistant message content to stdout
48
+ if (event.type === "message_update") {
49
+ const assistantEvent = event.assistantMessageEvent;
50
+ if (assistantEvent?.type === "text_delta") {
51
+ process.stdout.write(assistantEvent.delta ?? "");
52
+ }
53
+ }
54
+ if (event.type === "agent_end") {
55
+ agentEnded = true;
56
+ }
57
+ });
58
+ // Send prompt (with a small delay for pi to initialize)
59
+ await new Promise((resolve) => setTimeout(resolve, 500));
60
+ pi.sendPrompt(prompt);
61
+ // Wait for agent to finish
62
+ const exitCode = await new Promise((resolve) => {
63
+ pi.process.on("exit", (code, signal) => {
64
+ resolve(signal ? 1 : (code ?? 0));
65
+ });
66
+ // Also listen for agent_end to trigger shutdown
67
+ const checkInterval = setInterval(() => {
68
+ if (agentEnded) {
69
+ clearInterval(checkInterval);
70
+ pi.shutdown().then(() => {
71
+ // process exit event will resolve the promise
72
+ });
73
+ }
74
+ }, 100);
75
+ });
76
+ // Flush and finalize
77
+ process.stdout.write("\n");
78
+ console.error("[naiad] Agent finished, flushing...");
79
+ await workers.stop();
80
+ await teardownLifecycle({ ctx, exitCode });
81
+ // Phase 2 output: write final result before exit
82
+ if (opts.output) {
83
+ const result = {
84
+ thread_id: ctx.threadId,
85
+ thread_url: `${config.apiUrl}/app/threads/${ctx.threadId}`,
86
+ session_id: ctx.sessionId,
87
+ status: exitCode === 0 ? "COMPLETED" : "FAILED",
88
+ model: ctx.model,
89
+ };
90
+ writeFileSync(opts.output, JSON.stringify(result, null, 2));
91
+ }
92
+ process.exit(exitCode);
93
+ }
94
+ //# sourceMappingURL=exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { NaiadConfig } from "../config/config.js";
2
+ export declare function interactiveCommand(config: NaiadConfig, options: {
3
+ modelFlag?: string;
4
+ sessionId?: string;
5
+ continueRecent?: boolean;
6
+ }): Promise<void>;
@@ -0,0 +1,137 @@
1
+ import { mkdtempSync, writeFileSync } from "fs";
2
+ import { join } from "path";
3
+ import { tmpdir } from "os";
4
+ import { randomUUID } from "crypto";
5
+ import { APIClient } from "../api/client.js";
6
+ import { launchPiInteractive } from "../pi/launcher.js";
7
+ import { startCallbackServer } from "../callback/server.js";
8
+ import { startWorkers } from "../lifecycle/workers.js";
9
+ import { teardownLifecycle } from "../lifecycle/teardown.js";
10
+ import { findPackageRoot } from "../utils/package-root.js";
11
+ export async function interactiveCommand(config, options) {
12
+ const client = new APIClient(config);
13
+ // Validate API key by listing models
14
+ console.error("[naiad] Validating API key...");
15
+ const { models } = await client.listModels();
16
+ if (models.length === 0) {
17
+ console.error("[naiad] No models available");
18
+ process.exit(1);
19
+ }
20
+ const model = options.modelFlag || models[0].id;
21
+ console.error(`[naiad] Using model: ${model}`);
22
+ const sessionDir = mkdtempSync(join(tmpdir(), "naiad-session-"));
23
+ const pkgRoot = findPackageRoot();
24
+ const extensionPath = join(pkgRoot, "extensions", "naiad-extension.ts");
25
+ const agentId = randomUUID();
26
+ let threadId;
27
+ let sessionId;
28
+ let resumeSessionFile;
29
+ if (options.sessionId || options.continueRecent) {
30
+ // Resume flow
31
+ const resolved = await resolveResumeSession(client, options);
32
+ threadId = resolved.threadId;
33
+ // Download previous session JSONL
34
+ console.error(`[naiad] Downloading session ${resolved.previousSessionId}...`);
35
+ const jsonlData = await client.downloadSession(resolved.previousSessionId);
36
+ const jsonlFilename = `${new Date().toISOString().replace(/[:.]/g, "-")}_${randomUUID()}.jsonl`;
37
+ resumeSessionFile = join(sessionDir, jsonlFilename);
38
+ writeFileSync(resumeSessionFile, jsonlData);
39
+ console.error(`[naiad] Session data written to ${resumeSessionFile}`);
40
+ // Create new session on existing thread
41
+ const session = await client.createSession(threadId, agentId);
42
+ sessionId = session.id;
43
+ console.error(`[naiad] Created session: ${sessionId} (resuming thread ${threadId})`);
44
+ // Transition thread back to RUNNING
45
+ await client.updateThread(threadId, { status: "RUNNING" });
46
+ }
47
+ else {
48
+ // New session flow
49
+ const thread = await client.createThread("[interactive session]");
50
+ threadId = thread.id;
51
+ console.error(`[naiad] Created thread: ${threadId}`);
52
+ const session = await client.createSession(threadId, agentId);
53
+ sessionId = session.id;
54
+ console.error(`[naiad] Created session: ${sessionId}`);
55
+ await client.updateThread(threadId, { status: "RUNNING" });
56
+ }
57
+ const ctx = {
58
+ config,
59
+ client,
60
+ model,
61
+ agentId,
62
+ threadId,
63
+ sessionId,
64
+ sessionDir,
65
+ extensionPath,
66
+ };
67
+ // Start callback server
68
+ const callbackServer = await startCallbackServer();
69
+ console.error(`[naiad] Callback server listening at ${callbackServer.url}`);
70
+ // Guard against EIO on inherited stdin after pi exits and releases the PTY
71
+ process.stdin.on("error", () => { });
72
+ // Launch pi in interactive mode
73
+ const pi = launchPiInteractive({
74
+ model,
75
+ sessionDir,
76
+ extensionPath,
77
+ resumeSessionFile,
78
+ env: {
79
+ NAIAD_INFERENCE_URL: `${config.apiUrl}/api/v1/inference`,
80
+ NAIAD_API_KEY: config.apiKey,
81
+ NAIAD_THREAD_ID: threadId,
82
+ NAIAD_SESSION_ID: sessionId,
83
+ NAIAD_MODEL: model,
84
+ NAIAD_CALLBACK_URL: callbackServer.url,
85
+ },
86
+ });
87
+ // Start background workers
88
+ const workers = startWorkers(ctx);
89
+ // Event pump: drain callback buffer → event spool
90
+ const eventPump = setInterval(() => {
91
+ const events = callbackServer.drain();
92
+ for (const ev of events) {
93
+ workers.eventSpool.pushEvent(ev.type, ev.data);
94
+ }
95
+ }, 200);
96
+ // Wait for pi to exit
97
+ const exitCode = await new Promise((resolve) => {
98
+ pi.process.on("exit", (code, signal) => {
99
+ resolve(signal ? 1 : (code ?? 0));
100
+ });
101
+ });
102
+ // Clean up event pump
103
+ clearInterval(eventPump);
104
+ // Drain any remaining callback events
105
+ const remaining = callbackServer.drain();
106
+ for (const ev of remaining) {
107
+ workers.eventSpool.pushEvent(ev.type, ev.data);
108
+ }
109
+ console.error("[naiad] Pi exited, flushing...");
110
+ // Stop workers and callback server
111
+ await workers.stop();
112
+ await callbackServer.close();
113
+ // Teardown
114
+ await teardownLifecycle({ ctx, exitCode });
115
+ process.exit(exitCode);
116
+ }
117
+ async function resolveResumeSession(client, options) {
118
+ if (options.sessionId) {
119
+ const session = await client.getSession(options.sessionId);
120
+ return { threadId: session.thread_id, previousSessionId: session.id };
121
+ }
122
+ // -c: find most recent thread, then its most recent session
123
+ const { threads } = await client.listThreads({ limit: 1 });
124
+ if (threads.length === 0) {
125
+ console.error("[naiad] No previous sessions found. Run `naiad` first to create a session.");
126
+ process.exit(1);
127
+ }
128
+ const thread = threads[0];
129
+ const sessions = await client.listThreadSessions(thread.id);
130
+ if (sessions.length === 0) {
131
+ console.error(`[naiad] Thread ${thread.id} has no sessions. Run \`naiad\` first to create a session.`);
132
+ process.exit(1);
133
+ }
134
+ console.error(`[naiad] Continuing thread ${thread.id}, session ${sessions[0].id}`);
135
+ return { threadId: thread.id, previousSessionId: sessions[0].id };
136
+ }
137
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/commands/interactive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface NaiadConfig {
2
+ apiUrl: string;
3
+ apiKey: string;
4
+ }
5
+ export declare function loadConfig(): NaiadConfig;