@grackle-ai/core 0.75.4
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/README.md +30 -0
- package/dist/adapter-config.d.ts +6 -0
- package/dist/adapter-config.d.ts.map +1 -0
- package/dist/adapter-config.js +19 -0
- package/dist/adapter-config.js.map +1 -0
- package/dist/adapter-manager.d.ts +22 -0
- package/dist/adapter-manager.d.ts.map +1 -0
- package/dist/adapter-manager.js +81 -0
- package/dist/adapter-manager.js.map +1 -0
- package/dist/auto-reconnect.d.ts +23 -0
- package/dist/auto-reconnect.d.ts.map +1 -0
- package/dist/auto-reconnect.js +164 -0
- package/dist/auto-reconnect.js.map +1 -0
- package/dist/compute-task-status.d.ts +28 -0
- package/dist/compute-task-status.d.ts.map +1 -0
- package/dist/compute-task-status.js +70 -0
- package/dist/compute-task-status.js.map +1 -0
- package/dist/credential-bundle.d.ts +12 -0
- package/dist/credential-bundle.d.ts.map +1 -0
- package/dist/credential-bundle.js +183 -0
- package/dist/credential-bundle.js.map +1 -0
- package/dist/event-bus.d.ts +37 -0
- package/dist/event-bus.d.ts.map +1 -0
- package/dist/event-bus.js +65 -0
- package/dist/event-bus.js.map +1 -0
- package/dist/event-processor.d.ts +36 -0
- package/dist/event-processor.d.ts.map +1 -0
- package/dist/event-processor.js +312 -0
- package/dist/event-processor.js.map +1 -0
- package/dist/grpc-service.d.ts +22 -0
- package/dist/grpc-service.d.ts.map +1 -0
- package/dist/grpc-service.js +1724 -0
- package/dist/grpc-service.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/knowledge-init.d.ts +27 -0
- package/dist/knowledge-init.d.ts.map +1 -0
- package/dist/knowledge-init.js +212 -0
- package/dist/knowledge-init.js.map +1 -0
- package/dist/lifecycle.d.ts +36 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +112 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/log-writer.d.ts +32 -0
- package/dist/log-writer.d.ts.map +1 -0
- package/dist/log-writer.js +104 -0
- package/dist/log-writer.js.map +1 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +10 -0
- package/dist/logger.js.map +1 -0
- package/dist/pipe-delivery.d.ts +41 -0
- package/dist/pipe-delivery.d.ts.map +1 -0
- package/dist/pipe-delivery.js +186 -0
- package/dist/pipe-delivery.js.map +1 -0
- package/dist/processor-registry.d.ts +25 -0
- package/dist/processor-registry.d.ts.map +1 -0
- package/dist/processor-registry.js +58 -0
- package/dist/processor-registry.js.map +1 -0
- package/dist/reanimate-agent.d.ts +12 -0
- package/dist/reanimate-agent.d.ts.map +1 -0
- package/dist/reanimate-agent.js +76 -0
- package/dist/reanimate-agent.js.map +1 -0
- package/dist/session-recovery.d.ts +16 -0
- package/dist/session-recovery.d.ts.map +1 -0
- package/dist/session-recovery.js +129 -0
- package/dist/session-recovery.js.map +1 -0
- package/dist/signals/sigchld.d.ts +7 -0
- package/dist/signals/sigchld.d.ts.map +1 -0
- package/dist/signals/sigchld.js +167 -0
- package/dist/signals/sigchld.js.map +1 -0
- package/dist/signals/signal-delivery.d.ts +14 -0
- package/dist/signals/signal-delivery.d.ts.map +1 -0
- package/dist/signals/signal-delivery.js +166 -0
- package/dist/signals/signal-delivery.js.map +1 -0
- package/dist/stream-hub.d.ts +14 -0
- package/dist/stream-hub.d.ts.map +1 -0
- package/dist/stream-hub.js +95 -0
- package/dist/stream-hub.js.map +1 -0
- package/dist/stream-registry.d.ts +84 -0
- package/dist/stream-registry.d.ts.map +1 -0
- package/dist/stream-registry.js +363 -0
- package/dist/stream-registry.js.map +1 -0
- package/dist/test-utils/integration-setup.d.ts +11 -0
- package/dist/test-utils/integration-setup.d.ts.map +1 -0
- package/dist/test-utils/integration-setup.js +32 -0
- package/dist/test-utils/integration-setup.js.map +1 -0
- package/dist/test-utils/mock-database.d.ts +130 -0
- package/dist/test-utils/mock-database.d.ts.map +1 -0
- package/dist/test-utils/mock-database.js +147 -0
- package/dist/test-utils/mock-database.js.map +1 -0
- package/dist/token-push.d.ts +22 -0
- package/dist/token-push.d.ts.map +1 -0
- package/dist/token-push.js +78 -0
- package/dist/token-push.js.map +1 -0
- package/dist/transcript.d.ts +5 -0
- package/dist/transcript.d.ts.map +1 -0
- package/dist/transcript.js +71 -0
- package/dist/transcript.js.map +1 -0
- package/dist/utils/exec.d.ts +17 -0
- package/dist/utils/exec.d.ts.map +1 -0
- package/dist/utils/exec.js +21 -0
- package/dist/utils/exec.js.map +1 -0
- package/dist/utils/format-gh-error.d.ts +6 -0
- package/dist/utils/format-gh-error.d.ts.map +1 -0
- package/dist/utils/format-gh-error.js +30 -0
- package/dist/utils/format-gh-error.js.map +1 -0
- package/dist/utils/network.d.ts +7 -0
- package/dist/utils/network.d.ts.map +1 -0
- package/dist/utils/network.js +21 -0
- package/dist/utils/network.js.map +1 -0
- package/dist/utils/ports.d.ts +3 -0
- package/dist/utils/ports.d.ts.map +1 -0
- package/dist/utils/ports.js +19 -0
- package/dist/utils/ports.js.map +1 -0
- package/dist/utils/sleep.d.ts +3 -0
- package/dist/utils/sleep.d.ts.map +1 -0
- package/dist/utils/sleep.js +5 -0
- package/dist/utils/sleep.js.map +1 -0
- package/dist/ws-bridge.d.ts +30 -0
- package/dist/ws-bridge.d.ts.map +1 -0
- package/dist/ws-bridge.js +372 -0
- package/dist/ws-bridge.js.map +1 -0
- package/dist/ws-broadcast.d.ts +19 -0
- package/dist/ws-broadcast.d.ts.map +1 -0
- package/dist/ws-broadcast.js +60 -0
- package/dist/ws-broadcast.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
2
|
+
import { create } from "@bufbuild/protobuf";
|
|
3
|
+
import { powerline } from "@grackle-ai/common";
|
|
4
|
+
import { envRegistry, sessionStore, workspaceStore, taskStore, grackleHome } from "@grackle-ai/database";
|
|
5
|
+
import * as adapterManager from "./adapter-manager.js";
|
|
6
|
+
import { reconnectOrProvision, } from "@grackle-ai/adapter-sdk";
|
|
7
|
+
import * as streamHub from "./stream-hub.js";
|
|
8
|
+
import * as tokenPush from "./token-push.js";
|
|
9
|
+
import { v4 as uuid } from "uuid";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { LOGS_DIR, DEFAULT_MCP_PORT, ROOT_TASK_ID, eventTypeToString, } from "@grackle-ai/common";
|
|
12
|
+
import { resolvePersona, fetchOrchestratorContext, SystemPromptBuilder, buildTaskPrompt } from "@grackle-ai/prompt";
|
|
13
|
+
import { logger } from "./logger.js";
|
|
14
|
+
import { processEventStream } from "./event-processor.js";
|
|
15
|
+
import { setWssInstance } from "./ws-broadcast.js";
|
|
16
|
+
import { emit } from "./event-bus.js";
|
|
17
|
+
import { recoverSuspendedSessions } from "./session-recovery.js";
|
|
18
|
+
import { buildMcpServersJson, toDialableHost } from "./grpc-service.js";
|
|
19
|
+
import { createScopedToken, loadOrCreateApiKey } from "@grackle-ai/auth";
|
|
20
|
+
const WS_PING_INTERVAL_MS = 30_000;
|
|
21
|
+
const WS_CLOSE_UNAUTHORIZED = 4001;
|
|
22
|
+
const WS_CLOSE_FORBIDDEN_ORIGIN = 4003;
|
|
23
|
+
/** Loopback hostnames accepted as valid WebSocket origins in local mode. */
|
|
24
|
+
const LOOPBACK_HOSTNAMES = new Set([
|
|
25
|
+
"localhost",
|
|
26
|
+
"127.0.0.1",
|
|
27
|
+
"::1",
|
|
28
|
+
"[::1]",
|
|
29
|
+
]);
|
|
30
|
+
/**
|
|
31
|
+
* Check whether a WebSocket Origin header is allowed.
|
|
32
|
+
*
|
|
33
|
+
* Rules:
|
|
34
|
+
* - Missing origin (non-browser clients, extensions) → always allowed
|
|
35
|
+
* - Origin port must match the web server port
|
|
36
|
+
* - In local mode (`allowNetwork === false`), hostname must be loopback
|
|
37
|
+
* - In network mode (`allowNetwork === true`), any hostname on the right port is allowed
|
|
38
|
+
*/
|
|
39
|
+
export function isAllowedOrigin(origin, webPort, allowNetwork) {
|
|
40
|
+
if (origin === undefined) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
let parsed;
|
|
44
|
+
try {
|
|
45
|
+
parsed = new URL(origin);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const originPort = parsed.port
|
|
51
|
+
? parseInt(parsed.port, 10)
|
|
52
|
+
: (parsed.protocol === "https:" ? 443 : 80);
|
|
53
|
+
if (originPort !== webPort) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (allowNetwork) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return LOOPBACK_HOSTNAMES.has(parsed.hostname);
|
|
60
|
+
}
|
|
61
|
+
/** Create a WebSocket server on top of an HTTP server for real-time event streaming. */
|
|
62
|
+
export function createWsBridge(httpServer, options) {
|
|
63
|
+
const wss = new WebSocketServer({ server: httpServer });
|
|
64
|
+
setWssInstance(wss);
|
|
65
|
+
wss.on("connection", (ws, req) => {
|
|
66
|
+
const origin = req.headers.origin;
|
|
67
|
+
if (!isAllowedOrigin(origin, options.webPort ?? 0, options.allowNetwork ?? false)) {
|
|
68
|
+
logger.warn({ origin }, "Rejected WebSocket connection from disallowed origin");
|
|
69
|
+
ws.close(WS_CLOSE_FORBIDDEN_ORIGIN, "Forbidden origin");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const url = new URL(req.url || "/", "http://localhost");
|
|
73
|
+
const token = url.searchParams.get("token") || "";
|
|
74
|
+
const hasValidToken = token.length > 0 && options.verifyApiKey(token);
|
|
75
|
+
const hasValidCookie = options.validateCookie
|
|
76
|
+
? options.validateCookie(req.headers.cookie || "")
|
|
77
|
+
: false;
|
|
78
|
+
if (!hasValidToken && !hasValidCookie) {
|
|
79
|
+
ws.close(WS_CLOSE_UNAUTHORIZED, "Unauthorized");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const subscriptions = new Map();
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
84
|
+
ws.on("message", async (data) => {
|
|
85
|
+
try {
|
|
86
|
+
const msg = JSON.parse(data.toString());
|
|
87
|
+
await handleMessage(ws, msg, subscriptions);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
sendWs(ws, { type: "error", payload: { message: String(err) } });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
ws.on("close", () => {
|
|
94
|
+
for (const sub of subscriptions.values()) {
|
|
95
|
+
sub.cancel();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
const pingInterval = setInterval(() => {
|
|
99
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
100
|
+
ws.ping();
|
|
101
|
+
}
|
|
102
|
+
}, WS_PING_INTERVAL_MS);
|
|
103
|
+
ws.on("close", () => clearInterval(pingInterval));
|
|
104
|
+
});
|
|
105
|
+
return wss;
|
|
106
|
+
}
|
|
107
|
+
/** Safely parse an adapter config string, returning an empty object on failure. */
|
|
108
|
+
function safeParseAdapterConfig(raw, environmentId) {
|
|
109
|
+
try {
|
|
110
|
+
const parsed = JSON.parse(raw || "{}");
|
|
111
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
112
|
+
return parsed;
|
|
113
|
+
}
|
|
114
|
+
logger.warn({ environmentId, raw }, "adapterConfig is not an object, using empty config");
|
|
115
|
+
return {};
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
logger.warn({ environmentId, raw, err }, "Failed to parse adapterConfig, using empty config");
|
|
119
|
+
return {};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Auto-provisions and connects an environment if it is not already connected.
|
|
124
|
+
* Sends provision progress events over the WebSocket and updates the environment
|
|
125
|
+
* registry status. Returns the connection on success, or undefined on failure.
|
|
126
|
+
*/
|
|
127
|
+
async function autoProvisionEnvironment(ws, environmentId, env, logContext) {
|
|
128
|
+
let conn = adapterManager.getConnection(environmentId);
|
|
129
|
+
if (conn) {
|
|
130
|
+
return conn;
|
|
131
|
+
}
|
|
132
|
+
const adapter = adapterManager.getAdapter(env.adapterType);
|
|
133
|
+
if (!adapter) {
|
|
134
|
+
sendWs(ws, {
|
|
135
|
+
type: "error",
|
|
136
|
+
payload: { message: `No adapter for type: ${env.adapterType}` },
|
|
137
|
+
});
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
logger.info({ environmentId, ...logContext }, "Auto-provisioning environment");
|
|
141
|
+
envRegistry.updateEnvironmentStatus(environmentId, "connecting");
|
|
142
|
+
emit("environment.changed", {});
|
|
143
|
+
try {
|
|
144
|
+
const config = safeParseAdapterConfig(env.adapterConfig, environmentId);
|
|
145
|
+
config.defaultRuntime = env.defaultRuntime;
|
|
146
|
+
const powerlineToken = env.powerlineToken || "";
|
|
147
|
+
for await (const provEvent of reconnectOrProvision(environmentId, adapter, config, powerlineToken, !!env.bootstrapped)) {
|
|
148
|
+
logger.info({ environmentId, stage: provEvent.stage, ...logContext }, "Auto-provision progress");
|
|
149
|
+
emit("environment.provision_progress", {
|
|
150
|
+
environmentId,
|
|
151
|
+
stage: provEvent.stage,
|
|
152
|
+
message: provEvent.message,
|
|
153
|
+
progress: provEvent.progress,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
conn = await adapter.connect(environmentId, config, powerlineToken);
|
|
157
|
+
adapterManager.setConnection(environmentId, conn);
|
|
158
|
+
// Push stored tokens to newly connected environment
|
|
159
|
+
await tokenPush.pushToEnv(environmentId);
|
|
160
|
+
envRegistry.updateEnvironmentStatus(environmentId, "connected");
|
|
161
|
+
envRegistry.markBootstrapped(environmentId);
|
|
162
|
+
emit("environment.changed", {});
|
|
163
|
+
// Auto-recover suspended sessions (fire-and-forget)
|
|
164
|
+
recoverSuspendedSessions(environmentId, conn).catch((err) => {
|
|
165
|
+
logger.error({ environmentId, err }, "Session recovery failed");
|
|
166
|
+
});
|
|
167
|
+
logger.info({ environmentId, ...logContext }, "Auto-provision complete");
|
|
168
|
+
emit("environment.provision_progress", {
|
|
169
|
+
environmentId,
|
|
170
|
+
stage: "ready",
|
|
171
|
+
message: "Environment connected",
|
|
172
|
+
progress: 1,
|
|
173
|
+
});
|
|
174
|
+
return conn;
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
logger.error({ environmentId, ...logContext, err }, "Auto-provision failed");
|
|
178
|
+
envRegistry.updateEnvironmentStatus(environmentId, "error");
|
|
179
|
+
emit("environment.changed", {});
|
|
180
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
181
|
+
emit("environment.provision_progress", {
|
|
182
|
+
environmentId,
|
|
183
|
+
stage: "error",
|
|
184
|
+
message: `Auto-provision failed: ${errorMessage}`,
|
|
185
|
+
progress: 0,
|
|
186
|
+
});
|
|
187
|
+
sendWs(ws, {
|
|
188
|
+
type: "error",
|
|
189
|
+
payload: {
|
|
190
|
+
message: `Failed to auto-connect environment ${environmentId}: ${errorMessage}`,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/** Start a new agent session for a task. Returns an error message string on failure, undefined on success. */
|
|
197
|
+
export async function startTaskSession(ws, task, options) {
|
|
198
|
+
const workspace = task.workspaceId ? workspaceStore.getWorkspace(task.workspaceId) : undefined;
|
|
199
|
+
if (task.workspaceId && !workspace) {
|
|
200
|
+
logger.warn({ taskId: task.id }, "startTaskSession failed: workspace not found");
|
|
201
|
+
return `Workspace not found: ${task.workspaceId}`;
|
|
202
|
+
}
|
|
203
|
+
const environmentId = options?.environmentId || workspace?.environmentId || "";
|
|
204
|
+
const env = envRegistry.getEnvironment(environmentId);
|
|
205
|
+
if (!env) {
|
|
206
|
+
logger.warn({ taskId: task.id, environmentId }, "startTaskSession failed: environment not found");
|
|
207
|
+
return `Environment not found: ${environmentId}`;
|
|
208
|
+
}
|
|
209
|
+
let conn;
|
|
210
|
+
if (ws) {
|
|
211
|
+
conn = await autoProvisionEnvironment(ws, environmentId, env, {
|
|
212
|
+
taskId: task.id,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
conn = adapterManager.getConnection(environmentId) ?? undefined;
|
|
217
|
+
}
|
|
218
|
+
if (!conn) {
|
|
219
|
+
return ws ? undefined : `Environment not connected: ${environmentId}`;
|
|
220
|
+
}
|
|
221
|
+
// Resolve persona via cascade (request → task → workspace → app default)
|
|
222
|
+
let resolved;
|
|
223
|
+
try {
|
|
224
|
+
resolved = resolvePersona(options?.personaId || "", task.defaultPersonaId, workspace?.defaultPersonaId || "");
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
return err.message;
|
|
228
|
+
}
|
|
229
|
+
const sessionId = uuid();
|
|
230
|
+
const { runtime, model, maxTurns, systemPrompt, persona: resolvedPersonaRow } = resolved;
|
|
231
|
+
const logPath = join(grackleHome, LOGS_DIR, sessionId);
|
|
232
|
+
const freshTask = taskStore.getTask(task.id) || task;
|
|
233
|
+
// For the root/System task, use the user's chat message (passed as notes)
|
|
234
|
+
// as the initial prompt instead of the task title "System".
|
|
235
|
+
// For regular tasks, build the prompt from title + description.
|
|
236
|
+
const taskPrompt = freshTask.id === ROOT_TASK_ID
|
|
237
|
+
? (options?.notes || "")
|
|
238
|
+
: buildTaskPrompt(freshTask.title, freshTask.description, options?.notes);
|
|
239
|
+
const orchestratorCtx = freshTask.canDecompose && freshTask.depth <= 1
|
|
240
|
+
? fetchOrchestratorContext(freshTask.workspaceId || "") : undefined;
|
|
241
|
+
const systemContext = new SystemPromptBuilder({
|
|
242
|
+
task: { title: freshTask.title, description: freshTask.description, notes: options?.notes || "" },
|
|
243
|
+
taskId: freshTask.id, canDecompose: freshTask.canDecompose, personaPrompt: systemPrompt,
|
|
244
|
+
taskDepth: freshTask.depth, ...orchestratorCtx,
|
|
245
|
+
...(orchestratorCtx && { triggerMode: "fresh" }),
|
|
246
|
+
}).build();
|
|
247
|
+
sessionStore.createSession(sessionId, environmentId, runtime, freshTask.title, model, logPath, freshTask.id, resolved.personaId);
|
|
248
|
+
emit("task.started", {
|
|
249
|
+
taskId: freshTask.id,
|
|
250
|
+
sessionId,
|
|
251
|
+
workspaceId: freshTask.workspaceId || "",
|
|
252
|
+
});
|
|
253
|
+
// Re-push stored tokens + provider credentials (scoped to runtime) so they're fresh for this session.
|
|
254
|
+
// For local envs, skip file tokens — the PowerLine is on the same machine.
|
|
255
|
+
await tokenPush.refreshTokensForTask(environmentId, runtime, env.adapterType === "local" ? { excludeFileTokens: true } : undefined);
|
|
256
|
+
let mcpServersJson = "";
|
|
257
|
+
try {
|
|
258
|
+
const parsed = JSON.parse(resolvedPersonaRow.mcpServers || "[]");
|
|
259
|
+
if (Array.isArray(parsed)) {
|
|
260
|
+
const mcpServers = parsed;
|
|
261
|
+
if (mcpServers.length > 0) {
|
|
262
|
+
mcpServersJson = buildMcpServersJson(mcpServers);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
logger.warn("Failed to parse persona.mcpServers JSON; ignoring");
|
|
268
|
+
}
|
|
269
|
+
// Build MCP broker URL + scoped token so runtimes can call the MCP server.
|
|
270
|
+
const mcpPort = parseInt(process.env.GRACKLE_MCP_PORT || String(DEFAULT_MCP_PORT), 10);
|
|
271
|
+
const mcpDialHost = toDialableHost(process.env.GRACKLE_HOST || "127.0.0.1");
|
|
272
|
+
const mcpUrl = `http://${mcpDialHost}:${mcpPort}/mcp`;
|
|
273
|
+
const mcpToken = createScopedToken({ sub: freshTask.id, pid: freshTask.workspaceId || "", per: resolved.personaId, sid: sessionId }, loadOrCreateApiKey(grackleHome));
|
|
274
|
+
const useWorktrees = workspace?.useWorktrees ?? false;
|
|
275
|
+
const powerlineReq = create(powerline.SpawnRequestSchema, {
|
|
276
|
+
sessionId,
|
|
277
|
+
runtime,
|
|
278
|
+
prompt: taskPrompt,
|
|
279
|
+
model,
|
|
280
|
+
maxTurns,
|
|
281
|
+
branch: freshTask.branch,
|
|
282
|
+
worktreeBasePath: freshTask.branch
|
|
283
|
+
? (workspace?.worktreeBasePath || process.env.GRACKLE_WORKTREE_BASE || "/workspace")
|
|
284
|
+
: "",
|
|
285
|
+
useWorktrees,
|
|
286
|
+
systemContext,
|
|
287
|
+
workspaceId: freshTask.workspaceId ?? undefined,
|
|
288
|
+
taskId: freshTask.id,
|
|
289
|
+
mcpServersJson,
|
|
290
|
+
mcpUrl,
|
|
291
|
+
mcpToken,
|
|
292
|
+
});
|
|
293
|
+
processEventStream(conn.client.spawn(powerlineReq), {
|
|
294
|
+
sessionId,
|
|
295
|
+
logPath,
|
|
296
|
+
workspaceId: freshTask.workspaceId ?? undefined,
|
|
297
|
+
taskId: freshTask.id,
|
|
298
|
+
systemContext,
|
|
299
|
+
prompt: taskPrompt,
|
|
300
|
+
});
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
async function handleMessage(ws, msg, subscriptions) {
|
|
304
|
+
switch (msg.type) {
|
|
305
|
+
case "subscribe": {
|
|
306
|
+
const sessionId = msg.payload?.sessionId;
|
|
307
|
+
if (!sessionId) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
// Cancel any existing subscription for this session
|
|
311
|
+
const subKey = `session:${sessionId}`;
|
|
312
|
+
const existing = subscriptions.get(subKey);
|
|
313
|
+
if (existing) {
|
|
314
|
+
subscriptions.delete(subKey);
|
|
315
|
+
existing.cancel();
|
|
316
|
+
}
|
|
317
|
+
const stream = streamHub.createStream(sessionId);
|
|
318
|
+
subscriptions.set(subKey, stream);
|
|
319
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
320
|
+
(async () => {
|
|
321
|
+
for await (const event of stream) {
|
|
322
|
+
sendWs(ws, {
|
|
323
|
+
type: "session_event",
|
|
324
|
+
payload: {
|
|
325
|
+
sessionId: event.sessionId,
|
|
326
|
+
eventType: eventTypeToString(event.type),
|
|
327
|
+
timestamp: event.timestamp,
|
|
328
|
+
content: event.content,
|
|
329
|
+
raw: event.raw || undefined,
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
})();
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
case "subscribe_all": {
|
|
337
|
+
// Cancel any existing global subscription
|
|
338
|
+
const existingGlobal = subscriptions.get("global");
|
|
339
|
+
if (existingGlobal) {
|
|
340
|
+
subscriptions.delete("global");
|
|
341
|
+
existingGlobal.cancel();
|
|
342
|
+
}
|
|
343
|
+
const stream = streamHub.createGlobalStream();
|
|
344
|
+
subscriptions.set("global", stream);
|
|
345
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
346
|
+
(async () => {
|
|
347
|
+
for await (const event of stream) {
|
|
348
|
+
sendWs(ws, {
|
|
349
|
+
type: "session_event",
|
|
350
|
+
payload: {
|
|
351
|
+
sessionId: event.sessionId,
|
|
352
|
+
eventType: eventTypeToString(event.type),
|
|
353
|
+
timestamp: event.timestamp,
|
|
354
|
+
content: event.content,
|
|
355
|
+
raw: event.raw || undefined,
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
})();
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
default:
|
|
363
|
+
// ignore unknown messages
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function sendWs(ws, msg) {
|
|
368
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
369
|
+
ws.send(JSON.stringify(msg));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
//# sourceMappingURL=ws-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-bridge.js","sourceRoot":"","sources":["../src/ws-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { WebSocketServer } from "ws";
|
|
2
|
+
import { envRegistry } from "@grackle-ai/database";
|
|
3
|
+
/** Set the WebSocketServer instance used for broadcasting. Called once during server startup. */
|
|
4
|
+
export declare function setWssInstance(wss: WebSocketServer): void;
|
|
5
|
+
/** Broadcast a message to all connected WS clients. */
|
|
6
|
+
export declare function broadcast(msg: {
|
|
7
|
+
type: string;
|
|
8
|
+
payload?: Record<string, unknown>;
|
|
9
|
+
}): void;
|
|
10
|
+
/** Map a database environment row to the WebSocket payload shape. */
|
|
11
|
+
export declare function envRowToWs(r: ReturnType<typeof envRegistry.listEnvironments>[number]): Record<string, unknown>;
|
|
12
|
+
/** Broadcast the current environment list to all connected WebSocket clients. */
|
|
13
|
+
export declare function broadcastEnvironments(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Register a bus subscriber that forwards GrackleEvents to all WS clients.
|
|
16
|
+
* Idempotent — subsequent calls are no-ops.
|
|
17
|
+
*/
|
|
18
|
+
export declare function initWsSubscriber(): void;
|
|
19
|
+
//# sourceMappingURL=ws-broadcast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-broadcast.d.ts","sourceRoot":"","sources":["../src/ws-broadcast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKnD,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,CAEzD;AAED,uDAAuD;AACvD,wBAAgB,SAAS,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAAI,CAQxF;AAED,qEAAqE;AACrE,wBAAgB,UAAU,CACxB,CAAC,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,GACzD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,IAAI,IAAI,CAK5C;AAKD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAgBvC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { envRegistry } from "@grackle-ai/database";
|
|
2
|
+
import { subscribe } from "./event-bus.js";
|
|
3
|
+
let wssInstance = undefined;
|
|
4
|
+
/** Set the WebSocketServer instance used for broadcasting. Called once during server startup. */
|
|
5
|
+
export function setWssInstance(wss) {
|
|
6
|
+
wssInstance = wss;
|
|
7
|
+
}
|
|
8
|
+
/** Broadcast a message to all connected WS clients. */
|
|
9
|
+
export function broadcast(msg) {
|
|
10
|
+
if (!wssInstance)
|
|
11
|
+
return;
|
|
12
|
+
const data = JSON.stringify(msg);
|
|
13
|
+
for (const client of wssInstance.clients) {
|
|
14
|
+
if (client.readyState === 1 /* OPEN */) {
|
|
15
|
+
client.send(data);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Map a database environment row to the WebSocket payload shape. */
|
|
20
|
+
export function envRowToWs(r) {
|
|
21
|
+
return {
|
|
22
|
+
id: r.id,
|
|
23
|
+
displayName: r.displayName,
|
|
24
|
+
adapterType: r.adapterType,
|
|
25
|
+
adapterConfig: r.adapterConfig,
|
|
26
|
+
status: r.status,
|
|
27
|
+
bootstrapped: r.bootstrapped,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Broadcast the current environment list to all connected WebSocket clients. */
|
|
31
|
+
export function broadcastEnvironments() {
|
|
32
|
+
broadcast({
|
|
33
|
+
type: "environments",
|
|
34
|
+
payload: { environments: envRegistry.listEnvironments().map(envRowToWs) },
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/** Guard to ensure initWsSubscriber is only called once. */
|
|
38
|
+
let wsSubscriberInitialized = false;
|
|
39
|
+
/**
|
|
40
|
+
* Register a bus subscriber that forwards GrackleEvents to all WS clients.
|
|
41
|
+
* Idempotent — subsequent calls are no-ops.
|
|
42
|
+
*/
|
|
43
|
+
export function initWsSubscriber() {
|
|
44
|
+
if (wsSubscriberInitialized) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
wsSubscriberInitialized = true;
|
|
48
|
+
subscribe((event) => {
|
|
49
|
+
if (!wssInstance) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const data = JSON.stringify(event);
|
|
53
|
+
for (const client of wssInstance.clients) {
|
|
54
|
+
if (client.readyState === 1 /* OPEN */) {
|
|
55
|
+
client.send(data);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=ws-broadcast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-broadcast.js","sourceRoot":"","sources":["../src/ws-broadcast.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAqB,MAAM,gBAAgB,CAAC;AAE9D,IAAI,WAAW,GAAgC,SAAS,CAAC;AAEzD,iGAAiG;AACjG,MAAM,UAAU,cAAc,CAAC,GAAoB;IACjD,WAAW,GAAG,GAAG,CAAC;AACpB,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,SAAS,CAAC,GAAwD;IAChF,IAAI,CAAC,WAAW;QAAE,OAAO;IACzB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACjC,KAAK,MAAM,MAAM,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;QACzC,IAAI,MAAM,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;AACH,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,UAAU,CACxB,CAA0D;IAE1D,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,YAAY,EAAE,CAAC,CAAC,YAAY;KAC7B,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,qBAAqB;IACnC,SAAS,CAAC;QACR,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,EAAE,YAAY,EAAE,WAAW,CAAC,gBAAgB,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE;KAC1E,CAAC,CAAC;AACL,CAAC;AAED,4DAA4D;AAC5D,IAAI,uBAAuB,GAAY,KAAK,CAAC;AAE7C;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,uBAAuB,EAAE,CAAC;QAC5B,OAAO;IACT,CAAC;IACD,uBAAuB,GAAG,IAAI,CAAC;IAC/B,SAAS,CAAC,CAAC,KAAmB,EAAE,EAAE;QAChC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnC,KAAK,MAAM,MAAM,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;YACzC,IAAI,MAAM,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;gBACvC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@grackle-ai/core",
|
|
3
|
+
"version": "0.75.4",
|
|
4
|
+
"description": "Core gRPC business logic for Grackle — RPC handlers, event system, streaming, session lifecycle",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/nick-pape/grackle.git",
|
|
9
|
+
"directory": "packages/core"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"grackle",
|
|
13
|
+
"core",
|
|
14
|
+
"grpc",
|
|
15
|
+
"event-system",
|
|
16
|
+
"streaming"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=22.0.0"
|
|
20
|
+
},
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "dist/index.js",
|
|
23
|
+
"types": "dist/index.d.ts",
|
|
24
|
+
"files": [
|
|
25
|
+
"dist/"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@bufbuild/protobuf": "^2.5.0",
|
|
29
|
+
"@connectrpc/connect": "^2.0.0",
|
|
30
|
+
"@connectrpc/connect-node": "^2.0.0",
|
|
31
|
+
"pino": "^10.3.1",
|
|
32
|
+
"ulid": "^2.3.0",
|
|
33
|
+
"uuid": "^11.0.0",
|
|
34
|
+
"ws": "^8.0.0",
|
|
35
|
+
"@grackle-ai/adapter-sdk": "0.75.4",
|
|
36
|
+
"@grackle-ai/common": "0.75.4",
|
|
37
|
+
"@grackle-ai/knowledge": "0.75.4",
|
|
38
|
+
"@grackle-ai/database": "0.75.4",
|
|
39
|
+
"@grackle-ai/auth": "0.75.4",
|
|
40
|
+
"@grackle-ai/prompt": "0.75.4"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@rushstack/heft": "1.2.7",
|
|
44
|
+
"@types/node": "^22.0.0",
|
|
45
|
+
"@types/uuid": "^10.0.0",
|
|
46
|
+
"@types/ws": "^8.0.0",
|
|
47
|
+
"vitest": "^3.1.1",
|
|
48
|
+
"@grackle-ai/heft-rig": "0.0.1"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "heft build --clean",
|
|
52
|
+
"test": "vitest run",
|
|
53
|
+
"clean": "heft clean",
|
|
54
|
+
"_phase:build": "heft run --only build -- --clean",
|
|
55
|
+
"_phase:test": "vitest run"
|
|
56
|
+
}
|
|
57
|
+
}
|