@grackle-ai/core 0.82.2 → 0.83.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.
Files changed (103) hide show
  1. package/dist/codespace-handlers.d.ts +6 -0
  2. package/dist/codespace-handlers.d.ts.map +1 -0
  3. package/dist/codespace-handlers.js +66 -0
  4. package/dist/codespace-handlers.js.map +1 -0
  5. package/dist/cron-phase.d.ts +1 -1
  6. package/dist/cron-phase.d.ts.map +1 -1
  7. package/dist/cron-phase.js +1 -1
  8. package/dist/cron-phase.js.map +1 -1
  9. package/dist/environment-handlers.d.ts +16 -0
  10. package/dist/environment-handlers.d.ts.map +1 -0
  11. package/dist/environment-handlers.js +237 -0
  12. package/dist/environment-handlers.js.map +1 -0
  13. package/dist/event-bus.d.ts +1 -1
  14. package/dist/event-bus.d.ts.map +1 -1
  15. package/dist/event-bus.js.map +1 -1
  16. package/dist/event-hub.d.ts +29 -0
  17. package/dist/event-hub.d.ts.map +1 -0
  18. package/dist/event-hub.js +89 -0
  19. package/dist/event-hub.js.map +1 -0
  20. package/dist/finding-handlers.d.ts +6 -0
  21. package/dist/finding-handlers.d.ts.map +1 -0
  22. package/dist/finding-handlers.js +27 -0
  23. package/dist/finding-handlers.js.map +1 -0
  24. package/dist/grpc-mcp-config.d.ts +11 -0
  25. package/dist/grpc-mcp-config.d.ts.map +1 -0
  26. package/dist/grpc-mcp-config.js +29 -0
  27. package/dist/grpc-mcp-config.js.map +1 -0
  28. package/dist/grpc-proto-converters.d.ts +25 -0
  29. package/dist/grpc-proto-converters.d.ts.map +1 -0
  30. package/dist/grpc-proto-converters.js +193 -0
  31. package/dist/grpc-proto-converters.js.map +1 -0
  32. package/dist/grpc-service.d.ts +3 -19
  33. package/dist/grpc-service.d.ts.map +1 -1
  34. package/dist/grpc-service.js +28 -1989
  35. package/dist/grpc-service.js.map +1 -1
  36. package/dist/grpc-shared.d.ts +25 -0
  37. package/dist/grpc-shared.d.ts.map +1 -0
  38. package/dist/grpc-shared.js +110 -0
  39. package/dist/grpc-shared.js.map +1 -0
  40. package/dist/index.d.ts +4 -2
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +4 -3
  43. package/dist/index.js.map +1 -1
  44. package/dist/knowledge-handlers.d.ts +12 -0
  45. package/dist/knowledge-handlers.d.ts.map +1 -0
  46. package/dist/knowledge-handlers.js +85 -0
  47. package/dist/knowledge-handlers.js.map +1 -0
  48. package/dist/orphan-phase.d.ts +27 -0
  49. package/dist/orphan-phase.d.ts.map +1 -0
  50. package/dist/orphan-phase.js +69 -0
  51. package/dist/orphan-phase.js.map +1 -0
  52. package/dist/persona-handlers.d.ts +12 -0
  53. package/dist/persona-handlers.d.ts.map +1 -0
  54. package/dist/persona-handlers.js +148 -0
  55. package/dist/persona-handlers.js.map +1 -0
  56. package/dist/schedule-handlers.d.ts +12 -0
  57. package/dist/schedule-handlers.d.ts.map +1 -0
  58. package/dist/schedule-handlers.js +122 -0
  59. package/dist/schedule-handlers.js.map +1 -0
  60. package/dist/session-handlers.d.ts +34 -0
  61. package/dist/session-handlers.d.ts.map +1 -0
  62. package/dist/session-handlers.js +488 -0
  63. package/dist/session-handlers.js.map +1 -0
  64. package/dist/settings-handlers.d.ts +10 -0
  65. package/dist/settings-handlers.d.ts.map +1 -0
  66. package/dist/settings-handlers.js +68 -0
  67. package/dist/settings-handlers.js.map +1 -0
  68. package/dist/signals/orphan-reparent.d.ts +30 -0
  69. package/dist/signals/orphan-reparent.d.ts.map +1 -0
  70. package/dist/signals/orphan-reparent.js +179 -0
  71. package/dist/signals/orphan-reparent.js.map +1 -0
  72. package/dist/signals/sigchld.d.ts.map +1 -1
  73. package/dist/signals/sigchld.js +4 -8
  74. package/dist/signals/sigchld.js.map +1 -1
  75. package/dist/task-handlers.d.ts +22 -0
  76. package/dist/task-handlers.d.ts.map +1 -0
  77. package/dist/task-handlers.js +463 -0
  78. package/dist/task-handlers.js.map +1 -0
  79. package/dist/task-session.d.ts +26 -0
  80. package/dist/task-session.d.ts.map +1 -0
  81. package/dist/task-session.js +132 -0
  82. package/dist/task-session.js.map +1 -0
  83. package/dist/test-utils/mock-database.d.ts +2 -0
  84. package/dist/test-utils/mock-database.d.ts.map +1 -1
  85. package/dist/test-utils/mock-database.js +2 -0
  86. package/dist/test-utils/mock-database.js.map +1 -1
  87. package/dist/token-handlers.d.ts +12 -0
  88. package/dist/token-handlers.d.ts.map +1 -0
  89. package/dist/token-handlers.js +85 -0
  90. package/dist/token-handlers.js.map +1 -0
  91. package/dist/workspace-handlers.d.ts +12 -0
  92. package/dist/workspace-handlers.d.ts.map +1 -0
  93. package/dist/workspace-handlers.js +86 -0
  94. package/dist/workspace-handlers.js.map +1 -0
  95. package/package.json +7 -9
  96. package/dist/ws-bridge.d.ts +0 -30
  97. package/dist/ws-bridge.d.ts.map +0 -1
  98. package/dist/ws-bridge.js +0 -372
  99. package/dist/ws-bridge.js.map +0 -1
  100. package/dist/ws-broadcast.d.ts +0 -19
  101. package/dist/ws-broadcast.d.ts.map +0 -1
  102. package/dist/ws-broadcast.js +0 -60
  103. package/dist/ws-broadcast.js.map +0 -1
@@ -0,0 +1,488 @@
1
+ import { ConnectError, Code } from "@connectrpc/connect";
2
+ import { create } from "@bufbuild/protobuf";
3
+ import { grackle, powerline } from "@grackle-ai/common";
4
+ import { DEFAULT_MCP_PORT, SESSION_STATUS, TERMINAL_SESSION_STATUSES, LOGS_DIR, eventTypeToEnum, } from "@grackle-ai/common";
5
+ import { envRegistry, sessionStore, taskStore, grackleHome } from "@grackle-ai/database";
6
+ import { v4 as uuid } from "uuid";
7
+ import { join } from "node:path";
8
+ import { reconnectOrProvision } from "@grackle-ai/adapter-sdk";
9
+ import * as adapterManager from "./adapter-manager.js";
10
+ import * as streamHub from "./stream-hub.js";
11
+ import * as tokenPush from "./token-push.js";
12
+ import { parseAdapterConfig } from "./adapter-config.js";
13
+ import { emit } from "./event-bus.js";
14
+ import { processEventStream } from "./event-processor.js";
15
+ import { recoverSuspendedSessions } from "./session-recovery.js";
16
+ import { logger } from "./logger.js";
17
+ import { reanimateAgent } from "./reanimate-agent.js";
18
+ import * as streamRegistry from "./stream-registry.js";
19
+ import * as pipeDelivery from "./pipe-delivery.js";
20
+ import * as logWriter from "./log-writer.js";
21
+ import { createScopedToken, loadOrCreateApiKey } from "@grackle-ai/auth";
22
+ import { resolvePersona, SystemPromptBuilder } from "@grackle-ai/prompt";
23
+ import { sendInputToSession } from "./signals/signal-delivery.js";
24
+ import { createEventStream } from "./event-hub.js";
25
+ import { sessionRowToProto } from "./grpc-proto-converters.js";
26
+ import { validatePipeInputs, toDialableHost, killSessionAndCleanup } from "./grpc-shared.js";
27
+ import { personaMcpServersToJson } from "./grpc-mcp-config.js";
28
+ /** Spawn a new agent session in the given environment. */
29
+ export async function spawnAgent(req) {
30
+ if (!req.environmentId) {
31
+ throw new ConnectError("environment_id is required", Code.InvalidArgument);
32
+ }
33
+ const env = envRegistry.getEnvironment(req.environmentId);
34
+ if (!env) {
35
+ throw new ConnectError(`Environment not found: ${req.environmentId}`, Code.NotFound);
36
+ }
37
+ let conn = adapterManager.getConnection(req.environmentId);
38
+ if (!conn) {
39
+ // Auto-provision: attempt to reconnect/provision a disconnected environment
40
+ const adapter = adapterManager.getAdapter(env.adapterType);
41
+ if (!adapter) {
42
+ throw new ConnectError(`No adapter for type: ${env.adapterType}`, Code.FailedPrecondition);
43
+ }
44
+ logger.info({ environmentId: req.environmentId }, "Auto-provisioning environment for SpawnAgent");
45
+ envRegistry.updateEnvironmentStatus(req.environmentId, "connecting");
46
+ emit("environment.changed", {});
47
+ const config = parseAdapterConfig(env.adapterConfig);
48
+ config.defaultRuntime = env.defaultRuntime;
49
+ const powerlineToken = env.powerlineToken;
50
+ try {
51
+ for await (const provEvent of reconnectOrProvision(req.environmentId, adapter, config, powerlineToken, !!env.bootstrapped)) {
52
+ logger.info({ environmentId: req.environmentId, stage: provEvent.stage }, "Auto-provision progress (SpawnAgent)");
53
+ emit("environment.provision_progress", {
54
+ environmentId: req.environmentId,
55
+ stage: provEvent.stage,
56
+ message: provEvent.message,
57
+ progress: provEvent.progress,
58
+ });
59
+ }
60
+ conn = await adapter.connect(req.environmentId, config, powerlineToken);
61
+ adapterManager.setConnection(req.environmentId, conn);
62
+ await tokenPush.pushToEnv(req.environmentId);
63
+ envRegistry.updateEnvironmentStatus(req.environmentId, "connected");
64
+ envRegistry.markBootstrapped(req.environmentId);
65
+ emit("environment.changed", {});
66
+ // Auto-recover suspended sessions (fire-and-forget)
67
+ recoverSuspendedSessions(req.environmentId, conn).catch((err) => {
68
+ logger.error({ environmentId: req.environmentId, err }, "Session recovery failed");
69
+ });
70
+ logger.info({ environmentId: req.environmentId }, "Auto-provision complete (SpawnAgent)");
71
+ emit("environment.provision_progress", {
72
+ environmentId: req.environmentId,
73
+ stage: "ready",
74
+ message: "Environment connected",
75
+ progress: 1,
76
+ });
77
+ }
78
+ catch (err) {
79
+ logger.error({ environmentId: req.environmentId, err }, "Auto-provision failed (SpawnAgent)");
80
+ envRegistry.updateEnvironmentStatus(req.environmentId, "error");
81
+ emit("environment.changed", {});
82
+ throw new ConnectError(`Failed to auto-connect environment ${req.environmentId}: ${err instanceof Error ? err.message : String(err)}`, Code.FailedPrecondition);
83
+ }
84
+ }
85
+ // Resolve persona via cascade (request → app default)
86
+ let resolved;
87
+ try {
88
+ resolved = resolvePersona(req.personaId);
89
+ }
90
+ catch (err) {
91
+ throw new ConnectError(err.message, Code.FailedPrecondition);
92
+ }
93
+ const sessionId = uuid();
94
+ const { runtime, model, systemPrompt, persona } = resolved;
95
+ const maxTurns = req.maxTurns || resolved.maxTurns;
96
+ const logPath = join(grackleHome, LOGS_DIR, sessionId);
97
+ const builderPrompt = new SystemPromptBuilder({
98
+ personaPrompt: systemPrompt,
99
+ }).build();
100
+ const systemContext = req.systemContext
101
+ ? builderPrompt + "\n\n" + req.systemContext
102
+ : builderPrompt;
103
+ // Validate pipe inputs before creating the session or spawning the child
104
+ validatePipeInputs(req.pipe, req.parentSessionId);
105
+ const pipeMode = req.pipe;
106
+ sessionStore.createSession(sessionId, req.environmentId, runtime, req.prompt, model, logPath, "", // taskId
107
+ resolved.personaId, // personaId
108
+ req.parentSessionId || "", // parentSessionId
109
+ pipeMode || "");
110
+ const mcpServersJson = personaMcpServersToJson(persona);
111
+ const mcpPort = parseInt(process.env.GRACKLE_MCP_PORT || String(DEFAULT_MCP_PORT), 10);
112
+ const mcpDialHost = toDialableHost(process.env.GRACKLE_HOST || "127.0.0.1");
113
+ const mcpUrl = `http://${mcpDialHost}:${mcpPort}/mcp`;
114
+ const mcpToken = createScopedToken({ sub: sessionId, pid: "", per: resolved.personaId, sid: sessionId }, loadOrCreateApiKey(grackleHome));
115
+ const powerlineReq = create(powerline.SpawnRequestSchema, {
116
+ sessionId,
117
+ runtime,
118
+ prompt: req.prompt,
119
+ model,
120
+ maxTurns,
121
+ branch: req.branch,
122
+ workingDirectory: req.branch
123
+ ? (req.workingDirectory.trim() || process.env.GRACKLE_WORKING_DIRECTORY || process.env.GRACKLE_WORKTREE_BASE || "/workspace")
124
+ : "",
125
+ systemContext,
126
+ mcpServersJson,
127
+ mcpUrl,
128
+ mcpToken,
129
+ scriptContent: resolved.type === "script" ? resolved.script : "",
130
+ pipe: req.pipe,
131
+ });
132
+ // Create lifecycle stream — every session gets one. The spawner holds
133
+ // a lifecycle fd; when it's closed, the session auto-stops.
134
+ const lifecycleStream = streamRegistry.createStream(`lifecycle:${sessionId}`);
135
+ const spawnerId = req.parentSessionId || "__server__";
136
+ streamRegistry.subscribe(lifecycleStream.id, spawnerId, "rw", "detach", true);
137
+ streamRegistry.subscribe(lifecycleStream.id, sessionId, "rw", "detach", false);
138
+ // Set up IPC pipe stream (optional, on top of lifecycle stream)
139
+ let pipeFd = 0;
140
+ if (pipeMode && pipeMode !== "detach" && req.parentSessionId) {
141
+ const ipcStream = streamRegistry.createStream(`pipe:${sessionId}`);
142
+ const parentSub = streamRegistry.subscribe(ipcStream.id, req.parentSessionId, "rw", pipeMode === "sync" ? "sync" : "async", true);
143
+ streamRegistry.subscribe(ipcStream.id, sessionId, "rw", "async", false);
144
+ pipeFd = parentSub.fd;
145
+ if (pipeMode === "async") {
146
+ pipeDelivery.ensureAsyncDeliveryListener(req.parentSessionId); // parent receives child messages
147
+ pipeDelivery.ensureAsyncDeliveryListener(sessionId); // child receives parent messages
148
+ }
149
+ }
150
+ // Push fresh credentials before spawning (best-effort).
151
+ // For local envs, skip file tokens — the PowerLine is on the same machine.
152
+ await tokenPush.refreshTokensForTask(req.environmentId, runtime, env.adapterType === "local" ? { excludeFileTokens: true } : undefined);
153
+ processEventStream(conn.client.spawn(powerlineReq), {
154
+ sessionId,
155
+ logPath,
156
+ systemContext,
157
+ prompt: req.prompt,
158
+ });
159
+ const row = sessionStore.getSession(sessionId);
160
+ const proto = sessionRowToProto(row);
161
+ proto.pipeFd = pipeFd;
162
+ return proto;
163
+ }
164
+ /** Resume a previously suspended agent session. */
165
+ export async function resumeAgent(req) {
166
+ const row = reanimateAgent(req.sessionId);
167
+ return sessionRowToProto(row);
168
+ }
169
+ /** Send text input to a running session. */
170
+ export async function sendInput(req) {
171
+ const session = sessionStore.getSession(req.sessionId);
172
+ if (!session) {
173
+ throw new ConnectError(`Session not found: ${req.sessionId}`, Code.NotFound);
174
+ }
175
+ if (TERMINAL_SESSION_STATUSES.has(session.status)) {
176
+ throw new ConnectError(`Session ${req.sessionId} has ended (status: ${session.status})`, Code.FailedPrecondition);
177
+ }
178
+ const conn = adapterManager.getConnection(session.environmentId);
179
+ if (!conn) {
180
+ throw new ConnectError(`Environment ${session.environmentId} not connected`, Code.FailedPrecondition);
181
+ }
182
+ // Persist and publish user input event so subscribers see the text in the event stream
183
+ const userInputEvent = create(grackle.SessionEventSchema, {
184
+ sessionId: req.sessionId,
185
+ type: grackle.EventType.USER_INPUT,
186
+ timestamp: new Date().toISOString(),
187
+ content: req.text,
188
+ raw: "",
189
+ });
190
+ if (session.logPath) {
191
+ logWriter.writeEvent(session.logPath, userInputEvent);
192
+ }
193
+ streamHub.publish(userInputEvent);
194
+ await conn.client.sendInput(create(powerline.InputMessageSchema, {
195
+ sessionId: req.sessionId,
196
+ text: req.text,
197
+ }));
198
+ return create(grackle.EmptySchema, {});
199
+ }
200
+ /** Kill (or gracefully stop) an agent session. */
201
+ export async function killAgent(req) {
202
+ const session = sessionStore.getSession(req.id);
203
+ if (!session) {
204
+ throw new ConnectError(`Session not found: ${req.id}`, Code.NotFound);
205
+ }
206
+ if (req.graceful) {
207
+ // ── SIGTERM: deliver signal message, return immediately ──
208
+ if (!TERMINAL_SESSION_STATUSES.has(session.status)) {
209
+ const message = "[SIGTERM] You have been asked to stop gracefully. " +
210
+ "Finish your current operation, save your work, close any open IPC fds " +
211
+ "(ipc_close for each owned fd), then call task_complete (if applicable) and stop.";
212
+ // Set sigtermSentAt BEFORE delivering so that if the session
213
+ // completes instantly (race), the event-processor sees the flag.
214
+ sessionStore.setSigtermSentAt(session.id);
215
+ const delivered = await sendInputToSession(session.id, session.environmentId, message, "sigterm");
216
+ if (delivered) {
217
+ return create(grackle.EmptySchema, {});
218
+ }
219
+ // Delivery failed — clear the flag since SIGTERM wasn't actually sent
220
+ sessionStore.clearSigtermSentAt(session.id);
221
+ // If delivery failed (env disconnected), fall through to hard kill
222
+ logger.warn({ sessionId: session.id }, "SIGTERM delivery failed, falling back to hard kill");
223
+ }
224
+ }
225
+ // ── SIGKILL: terminate immediately ──
226
+ // Set STOPPED + killed BEFORE closing the lifecycle FD so the orphan
227
+ // callback sees the session is already terminal and skips. Without this,
228
+ // the orphan callback would see IDLE → reason="completed", which is wrong
229
+ // for an explicit kill.
230
+ killSessionAndCleanup(session);
231
+ return create(grackle.EmptySchema, {});
232
+ }
233
+ /** Get aggregated usage stats for a session, task, task tree, workspace, or environment. */
234
+ export async function getUsage(req) {
235
+ if (!req.id) {
236
+ throw new ConnectError("id is required", Code.InvalidArgument);
237
+ }
238
+ switch (req.scope) {
239
+ case "session": {
240
+ const session = sessionStore.getSession(req.id);
241
+ if (!session) {
242
+ throw new ConnectError(`Session not found: ${req.id}`, Code.NotFound);
243
+ }
244
+ return create(grackle.UsageStatsSchema, {
245
+ inputTokens: session.inputTokens,
246
+ outputTokens: session.outputTokens,
247
+ costUsd: session.costUsd,
248
+ sessionCount: 1,
249
+ });
250
+ }
251
+ case "task": {
252
+ const usage = sessionStore.aggregateUsage({ taskId: req.id });
253
+ return create(grackle.UsageStatsSchema, usage);
254
+ }
255
+ case "task_tree": {
256
+ const descendants = taskStore.getDescendants(req.id);
257
+ const taskIds = [req.id, ...descendants.map((d) => d.id)];
258
+ const usage = sessionStore.aggregateUsage({ taskIds });
259
+ return create(grackle.UsageStatsSchema, usage);
260
+ }
261
+ case "workspace": {
262
+ const tasks = taskStore.listTasks(req.id);
263
+ const taskIds = tasks.map((t) => t.id);
264
+ const usage = taskIds.length > 0
265
+ ? sessionStore.aggregateUsage({ taskIds })
266
+ : { inputTokens: 0, outputTokens: 0, costUsd: 0, sessionCount: 0 };
267
+ return create(grackle.UsageStatsSchema, usage);
268
+ }
269
+ case "environment": {
270
+ const usage = sessionStore.aggregateUsage({ environmentId: req.id });
271
+ return create(grackle.UsageStatsSchema, usage);
272
+ }
273
+ default:
274
+ throw new ConnectError(`Invalid usage scope: ${req.scope}`, Code.InvalidArgument);
275
+ }
276
+ }
277
+ /** Wait for a message on a synchronous pipe subscription. */
278
+ export async function waitForPipe(req) {
279
+ const sub = streamRegistry.getSubscription(req.sessionId, req.fd);
280
+ if (!sub) {
281
+ throw new ConnectError(`No subscription found for session ${req.sessionId} fd ${req.fd}`, Code.NotFound);
282
+ }
283
+ if (sub.deliveryMode !== "sync") {
284
+ throw new ConnectError(`Subscription fd ${req.fd} is not a sync subscription (mode: ${sub.deliveryMode})`, Code.FailedPrecondition);
285
+ }
286
+ // Capture child session ID before blocking — the pipe stream may be
287
+ // removed by a concurrent fd close while consumeSync is awaiting.
288
+ const pipeStream = streamRegistry.getStream(sub.streamId);
289
+ const childSessionId = pipeStream?.name.startsWith("pipe:")
290
+ ? pipeStream.name.slice("pipe:".length)
291
+ : undefined;
292
+ // Use try/finally so the pipe stream (and lifecycle stream) are cleaned up
293
+ // even if consumeSync rejects (e.g., the request is cancelled or times out)
294
+ // to prevent unbounded memory growth. Lifecycle cleanup also orphans the child,
295
+ // triggering auto-stop so it doesn't linger in waiting_input (#824).
296
+ let msg;
297
+ try {
298
+ msg = await streamRegistry.consumeSync(sub.id);
299
+ }
300
+ finally {
301
+ pipeDelivery.cleanupSyncPipeAndLifecycle(sub.streamId, childSessionId);
302
+ }
303
+ return create(grackle.WaitForPipeResponseSchema, {
304
+ content: msg.content,
305
+ senderSessionId: msg.senderId,
306
+ });
307
+ }
308
+ /** Write a message to a pipe fd. */
309
+ export async function writeToFd(req) {
310
+ const sub = streamRegistry.getSubscription(req.sessionId, req.fd);
311
+ if (!sub) {
312
+ throw new ConnectError(`No subscription found for session ${req.sessionId} fd ${req.fd}`, Code.NotFound);
313
+ }
314
+ if (sub.permission !== "w" && sub.permission !== "rw") {
315
+ throw new ConnectError(`Subscription fd ${req.fd} does not have write permission (permission: ${sub.permission})`, Code.FailedPrecondition);
316
+ }
317
+ const stream = streamRegistry.getStream(sub.streamId);
318
+ if (!stream) {
319
+ throw new ConnectError("Stream no longer exists", Code.FailedPrecondition);
320
+ }
321
+ // Publish to stream — delivery is handled by async listeners registered
322
+ // at spawn time via ensureAsyncDeliveryListener. This is the same path
323
+ // used by publishChildCompletion for child→parent delivery.
324
+ const msg = streamRegistry.publish(sub.streamId, req.sessionId, req.message);
325
+ // Verify delivery to async subscribers — check if the published message
326
+ // was marked as delivered for each async target. Sync and detach subscribers
327
+ // are excluded (sync waits for consumeSync, detach buffers silently).
328
+ for (const targetSub of stream.subscriptions.values()) {
329
+ if (targetSub.sessionId === req.sessionId) {
330
+ continue;
331
+ }
332
+ if (targetSub.deliveryMode === "async" && !msg.deliveredTo.has(targetSub.id)) {
333
+ throw new ConnectError("Message delivery failed — target environment may be disconnected", Code.FailedPrecondition);
334
+ }
335
+ }
336
+ return create(grackle.EmptySchema, {});
337
+ }
338
+ /** Close a pipe file descriptor, optionally stopping child sessions. */
339
+ export async function closeFd(req) {
340
+ const sub = streamRegistry.getSubscription(req.sessionId, req.fd);
341
+ if (!sub) {
342
+ throw new ConnectError(`No subscription found for session ${req.sessionId} fd ${req.fd}`, Code.NotFound);
343
+ }
344
+ if (streamRegistry.hasUndeliveredMessages(sub.id)) {
345
+ throw new ConnectError(`Cannot close fd ${req.fd}: undelivered messages pending. Process or consume them first.`, Code.FailedPrecondition);
346
+ }
347
+ const streamId = sub.streamId;
348
+ const stream = streamRegistry.getStream(streamId);
349
+ // Collect child sessions (inherited subscriptions, not the caller's)
350
+ const childSubs = [];
351
+ if (stream) {
352
+ for (const s of stream.subscriptions.values()) {
353
+ if (s.sessionId !== req.sessionId) {
354
+ childSubs.push({ sessionId: s.sessionId, subId: s.id });
355
+ }
356
+ }
357
+ }
358
+ // Unsubscribe the caller
359
+ streamRegistry.unsubscribe(sub.id);
360
+ // Also unsubscribe children — when their last subscription is removed,
361
+ // the lifecycle manager's orphan callback auto-stops them.
362
+ let stopped = false;
363
+ for (const child of childSubs) {
364
+ streamRegistry.unsubscribe(child.subId);
365
+ // Check if the child was orphaned (auto-stopped)
366
+ const childSession = sessionStore.getSession(child.sessionId);
367
+ if (childSession?.status === SESSION_STATUS.STOPPED) {
368
+ stopped = true;
369
+ }
370
+ }
371
+ // Clean up async listeners for caller and any unsubscribed children
372
+ pipeDelivery.cleanupAsyncListenerIfEmpty(req.sessionId);
373
+ for (const child of childSubs) {
374
+ pipeDelivery.cleanupAsyncListenerIfEmpty(child.sessionId);
375
+ }
376
+ return create(grackle.CloseFdResponseSchema, { stopped });
377
+ }
378
+ /** Get all open file descriptors for a session. */
379
+ export function getSessionFds(req) {
380
+ const subs = streamRegistry.getSubscriptionsForSession(req.id);
381
+ const fds = subs.map((sub) => {
382
+ const stream = streamRegistry.getStream(sub.streamId);
383
+ let targetSessionId = "";
384
+ if (stream) {
385
+ for (const s of stream.subscriptions.values()) {
386
+ if (s.sessionId !== req.id) {
387
+ targetSessionId = s.sessionId;
388
+ break;
389
+ }
390
+ }
391
+ }
392
+ return create(grackle.FdInfoSchema, {
393
+ fd: sub.fd,
394
+ streamName: stream?.name || "",
395
+ permission: sub.permission,
396
+ deliveryMode: sub.deliveryMode,
397
+ owned: sub.createdBySpawn,
398
+ targetSessionId,
399
+ });
400
+ });
401
+ return create(grackle.SessionFdsSchema, { fds });
402
+ }
403
+ /** List sessions with optional filters. */
404
+ export async function listSessions(req) {
405
+ const rows = sessionStore.listSessions(req.environmentId, req.status);
406
+ return create(grackle.SessionListSchema, {
407
+ sessions: rows.map(sessionRowToProto),
408
+ });
409
+ }
410
+ /** Get a session by ID. */
411
+ export async function getSession(req) {
412
+ const row = sessionStore.getSession(req.id);
413
+ if (!row) {
414
+ throw new ConnectError(`Session not found: ${req.id}`, Code.NotFound);
415
+ }
416
+ return sessionRowToProto(row);
417
+ }
418
+ /** Get all events recorded for a session. */
419
+ export async function getSessionEvents(req) {
420
+ const session = sessionStore.getSession(req.id);
421
+ if (!session) {
422
+ throw new ConnectError(`Session not found: ${req.id}`, Code.NotFound);
423
+ }
424
+ if (!session.logPath) {
425
+ return create(grackle.SessionEventListSchema, {
426
+ sessionId: req.id,
427
+ events: [],
428
+ });
429
+ }
430
+ const entries = logWriter.readLog(session.logPath);
431
+ return create(grackle.SessionEventListSchema, {
432
+ sessionId: req.id,
433
+ events: entries.map((e) => create(grackle.SessionEventSchema, {
434
+ sessionId: e.session_id,
435
+ type: eventTypeToEnum(e.type),
436
+ timestamp: e.timestamp,
437
+ content: e.content,
438
+ raw: e.raw || "",
439
+ })),
440
+ });
441
+ }
442
+ /** Get all sessions for a task. */
443
+ export async function getTaskSessions(req) {
444
+ if (!req.id) {
445
+ throw new ConnectError("task id is required", Code.InvalidArgument);
446
+ }
447
+ const rows = sessionStore.listSessionsForTask(req.id);
448
+ return create(grackle.SessionListSchema, {
449
+ sessions: rows.map(sessionRowToProto),
450
+ });
451
+ }
452
+ /** Stream session events as they occur. */
453
+ export async function* streamSession(req) {
454
+ const stream = streamHub.createStream(req.id);
455
+ try {
456
+ for await (const event of stream) {
457
+ yield event;
458
+ }
459
+ }
460
+ finally {
461
+ stream.cancel();
462
+ }
463
+ }
464
+ /** Stream all session events across all sessions. */
465
+ export async function* streamAll() {
466
+ const stream = streamHub.createGlobalStream();
467
+ try {
468
+ for await (const event of stream) {
469
+ yield event;
470
+ }
471
+ }
472
+ finally {
473
+ stream.cancel();
474
+ }
475
+ }
476
+ /** Stream domain events (replaces WebSocket event broadcasting). */
477
+ export async function* streamEvents() {
478
+ const stream = createEventStream();
479
+ try {
480
+ for await (const event of stream) {
481
+ yield event;
482
+ }
483
+ }
484
+ finally {
485
+ stream.cancel();
486
+ }
487
+ }
488
+ //# sourceMappingURL=session-handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-handlers.js","sourceRoot":"","sources":["../src/session-handlers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { grackle } from "@grackle-ai/common";
2
+ /** Get the value of a setting by key. */
3
+ export declare function getSetting(req: grackle.GetSettingRequest): Promise<grackle.SettingResponse>;
4
+ /** Set the value of a setting. */
5
+ export declare function setSetting(req: grackle.SetSettingRequest): Promise<grackle.SettingResponse>;
6
+ /** Generate a new pairing code for web UI access. */
7
+ export declare function generatePairingCode(): Promise<grackle.PairingCodeResponse>;
8
+ /** Get the current version status (update available, current/latest versions). */
9
+ export declare function getVersionStatus(): Promise<grackle.VersionStatus>;
10
+ //# sourceMappingURL=settings-handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-handlers.d.ts","sourceRoot":"","sources":["../src/settings-handlers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAQ7C,yCAAyC;AACzC,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CASjG;AAED,kCAAkC;AAClC,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAuBjG;AAED,qDAAqD;AACrD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAiBhF;AAED,kFAAkF;AAClF,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAQvE"}
@@ -0,0 +1,68 @@
1
+ import { ConnectError, Code } from "@connectrpc/connect";
2
+ import { create } from "@bufbuild/protobuf";
3
+ import { grackle } from "@grackle-ai/common";
4
+ import { DEFAULT_WEB_PORT } from "@grackle-ai/common";
5
+ import { settingsStore, personaStore, isAllowedSettingKey } from "@grackle-ai/database";
6
+ import { generatePairingCode as authGeneratePairingCode } from "@grackle-ai/auth";
7
+ import { checkVersionStatus } from "./version-check.js";
8
+ import { detectLanIp } from "./utils/network.js";
9
+ import { emit } from "./event-bus.js";
10
+ /** Get the value of a setting by key. */
11
+ export async function getSetting(req) {
12
+ if (!isAllowedSettingKey(req.key)) {
13
+ throw new ConnectError(`Setting key not allowed: ${req.key}`, Code.InvalidArgument);
14
+ }
15
+ const value = settingsStore.getSetting(req.key);
16
+ return create(grackle.SettingResponseSchema, {
17
+ key: req.key,
18
+ value: value ?? "",
19
+ });
20
+ }
21
+ /** Set the value of a setting. */
22
+ export async function setSetting(req) {
23
+ if (!isAllowedSettingKey(req.key)) {
24
+ throw new ConnectError(`Setting key not allowed: ${req.key}`, Code.InvalidArgument);
25
+ }
26
+ // Validate persona exists and has required fields when setting default_persona_id
27
+ if (req.key === "default_persona_id" && req.value) {
28
+ const persona = personaStore.getPersona(req.value);
29
+ if (!persona) {
30
+ throw new ConnectError(`Persona not found: ${req.value}`, Code.NotFound);
31
+ }
32
+ if (!persona.runtime || !persona.model) {
33
+ throw new ConnectError(`Persona "${persona.name}" must have runtime and model configured`, Code.FailedPrecondition);
34
+ }
35
+ }
36
+ settingsStore.setSetting(req.key, req.value);
37
+ emit("setting.changed", { key: req.key, value: req.value });
38
+ return create(grackle.SettingResponseSchema, {
39
+ key: req.key,
40
+ value: req.value,
41
+ });
42
+ }
43
+ /** Generate a new pairing code for web UI access. */
44
+ export async function generatePairingCode() {
45
+ const code = authGeneratePairingCode();
46
+ if (!code) {
47
+ throw new ConnectError("Maximum active pairing codes reached. Wait for existing codes to expire.", Code.ResourceExhausted);
48
+ }
49
+ const webPort = parseInt(process.env.GRACKLE_WEB_PORT || String(DEFAULT_WEB_PORT), 10);
50
+ const bindHost = process.env.GRACKLE_HOST || "127.0.0.1";
51
+ const WILDCARD_ADDRESSES = new Set(["0.0.0.0", "::", "0:0:0:0:0:0:0:0"]);
52
+ const pairingHost = WILDCARD_ADDRESSES.has(bindHost)
53
+ ? (detectLanIp() || "localhost")
54
+ : (bindHost === "127.0.0.1" || bindHost === "::1" ? "localhost" : bindHost);
55
+ const url = `http://${pairingHost}:${webPort}/pair?code=${code}`;
56
+ return create(grackle.PairingCodeResponseSchema, { code, url });
57
+ }
58
+ /** Get the current version status (update available, current/latest versions). */
59
+ export async function getVersionStatus() {
60
+ const status = await checkVersionStatus();
61
+ return create(grackle.VersionStatusSchema, {
62
+ currentVersion: status.currentVersion,
63
+ latestVersion: status.latestVersion,
64
+ updateAvailable: status.updateAvailable,
65
+ isDocker: status.isDocker,
66
+ });
67
+ }
68
+ //# sourceMappingURL=settings-handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-handlers.js","sourceRoot":"","sources":["../src/settings-handlers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Orphan reparenting — automatically reparent non-terminal children when
3
+ * a parent task reaches terminal state (complete/failed).
4
+ *
5
+ * Follows the SIGCHLD subscriber pattern: subscribes to domain events,
6
+ * detects orphan conditions, and reparents children to the grandparent.
7
+ * The root task (PID 1) is the ultimate adopter.
8
+ */
9
+ /**
10
+ * Initialize the orphan reparenting event-bus subscriber.
11
+ * Idempotent — safe to call multiple times.
12
+ */
13
+ export declare function initOrphanReparentSubscriber(): void;
14
+ /**
15
+ * Transfer ALL pipe subscriptions from a dead parent's sessions to the
16
+ * grandparent's active session. Called once per parent death (not per child).
17
+ *
18
+ * When a parent dies, all its pipe connections should move to the grandparent —
19
+ * like fd inheritance when a Unix process dies and init takes over.
20
+ *
21
+ * Exported so it can be called synchronously from completeTask() /
22
+ * killSessionAndCleanup() before sessions are cleaned up.
23
+ */
24
+ export declare function transferAllPipeSubscriptions(deadParentTaskId: string, grandparentTaskId: string): void;
25
+ /**
26
+ * Reset module state. For testing only.
27
+ * @internal
28
+ */
29
+ export declare function _resetForTesting(): void;
30
+ //# sourceMappingURL=orphan-reparent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orphan-reparent.d.ts","sourceRoot":"","sources":["../../src/signals/orphan-reparent.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAyBH;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CA8BnD;AA2FD;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,gBAAgB,EAAE,MAAM,EACxB,iBAAiB,EAAE,MAAM,GACxB,IAAI,CAsDN;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}