@grackle-ai/server 0.67.0 → 0.68.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.
@@ -11,8 +11,12 @@ export declare function getConnection(environmentId: string): PowerLineConnectio
11
11
  export declare function removeConnection(environmentId: string): void;
12
12
  /** Return the map of all active environment connections. */
13
13
  export declare function listConnections(): Map<string, PowerLineConnection>;
14
- /** Start a periodic health-check loop that calls `onDisconnect` when a PowerLine becomes unreachable. */
15
- export declare function startHeartbeat(onDisconnect: (environmentId: string) => void): void;
14
+ /**
15
+ * Start a periodic health-check loop that calls `onDisconnect` when a
16
+ * PowerLine becomes unreachable. Optionally calls `onHeartbeatComplete`
17
+ * after each tick (used for auto-reconnect of disconnected environments).
18
+ */
19
+ export declare function startHeartbeat(onDisconnect: (environmentId: string) => void, onHeartbeatComplete?: () => Promise<void>): void;
16
20
  /** Stop the periodic health-check loop. */
17
21
  export declare function stopHeartbeat(): void;
18
22
  //# sourceMappingURL=adapter-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"adapter-manager.d.ts","sourceRoot":"","sources":["../src/adapter-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAUvF,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAEjE;AAED,sDAAsD;AACtD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEvE;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAEpF;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAEpF;AAED,uDAAuD;AACvD,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAElE;AAED,yGAAyG;AACzG,wBAAgB,cAAc,CAAC,YAAY,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CA6BlF;AAED,2CAA2C;AAC3C,wBAAgB,aAAa,IAAI,IAAI,CAKpC"}
1
+ {"version":3,"file":"adapter-manager.d.ts","sourceRoot":"","sources":["../src/adapter-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAUvF,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAEjE;AAED,sDAAsD;AACtD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEvE;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAEpF;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAEpF;AAED,uDAAuD;AACvD,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAElE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,EAC7C,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACxC,IAAI,CAsCN;AAED,2CAA2C;AAC3C,wBAAgB,aAAa,IAAI,IAAI,CAKpC"}
@@ -28,8 +28,12 @@ export function removeConnection(environmentId) {
28
28
  export function listConnections() {
29
29
  return connections;
30
30
  }
31
- /** Start a periodic health-check loop that calls `onDisconnect` when a PowerLine becomes unreachable. */
32
- export function startHeartbeat(onDisconnect) {
31
+ /**
32
+ * Start a periodic health-check loop that calls `onDisconnect` when a
33
+ * PowerLine becomes unreachable. Optionally calls `onHeartbeatComplete`
34
+ * after each tick (used for auto-reconnect of disconnected environments).
35
+ */
36
+ export function startHeartbeat(onDisconnect, onHeartbeatComplete) {
33
37
  if (heartbeatInterval !== undefined) {
34
38
  return;
35
39
  }
@@ -56,6 +60,15 @@ export function startHeartbeat(onDisconnect) {
56
60
  onDisconnect(environmentId);
57
61
  }
58
62
  }
63
+ // After health checks, attempt reconnection of disconnected environments
64
+ if (onHeartbeatComplete) {
65
+ try {
66
+ await onHeartbeatComplete();
67
+ }
68
+ catch (err) {
69
+ logger.error({ err }, "onHeartbeatComplete callback failed");
70
+ }
71
+ }
59
72
  }, HEARTBEAT_INTERVAL_MS);
60
73
  }
61
74
  /** Stop the periodic health-check loop. */
@@ -1 +1 @@
1
- {"version":3,"file":"adapter-manager.js","sourceRoot":"","sources":["../src/adapter-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,qBAAqB,GAAW,MAAM,CAAC;AAE7C,MAAM,QAAQ,GAAoC,IAAI,GAAG,EAA8B,CAAC;AACxF,MAAM,WAAW,GAAqC,IAAI,GAAG,EAA+B,CAAC;AAC7F,IAAI,iBAAiB,GAA+C,SAAS,CAAC;AAE9E,sEAAsE;AACtE,MAAM,UAAU,eAAe,CAAC,OAA2B;IACzD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,aAAa,CAAC,aAAqB,EAAE,IAAyB;IAC5E,WAAW,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,aAAqB;IACjD,OAAO,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AACxC,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,gBAAgB,CAAC,aAAqB;IACpD,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AACpC,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,eAAe;IAC7B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,yGAAyG;AACzG,MAAM,UAAU,cAAc,CAAC,YAA6C;IAC1E,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO;IACT,CAAC;IAED,kEAAkE;IAClE,iBAAiB,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACzC,KAAK,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC;YAChD,MAAM,GAAG,GAAG,WAAW,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YACtD,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,SAAS;YACX,CAAC;YACD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;gBAC3C,IAAI,CAAC,EAAE,EAAE,CAAC;oBACR,MAAM,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,EAAE,qBAAqB,CAAC,CAAC;oBACtD,YAAY,CAAC,aAAa,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,EAAE,iBAAiB,CAAC,CAAC;gBAClD,YAAY,CAAC,aAAa,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC,EAAE,qBAAqB,CAAC,CAAC;AAC5B,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,aAAa;IAC3B,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QACpC,aAAa,CAAC,iBAAiB,CAAC,CAAC;QACjC,iBAAiB,GAAG,SAAS,CAAC;IAChC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"adapter-manager.js","sourceRoot":"","sources":["../src/adapter-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Scan for disconnected environments and attempt to reconnect eligible ones.
3
+ * Called after each heartbeat tick. Uses exponential backoff per environment
4
+ * and a concurrency lock to prevent overlapping attempts.
5
+ *
6
+ * Fire-and-forget for each environment — logs errors but does not throw.
7
+ */
8
+ export declare function attemptReconnects(): Promise<void>;
9
+ /**
10
+ * Clear reconnect state for an environment. Call when the environment is
11
+ * manually provisioned, removed, or otherwise taken out of the reconnect cycle.
12
+ */
13
+ export declare function clearReconnectState(environmentId: string): void;
14
+ /** @internal Reset all reconnect state for testing. */
15
+ export declare function _resetForTesting(): void;
16
+ //# sourceMappingURL=auto-reconnect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-reconnect.d.ts","sourceRoot":"","sources":["../src/auto-reconnect.ts"],"names":[],"mappings":"AAwCA;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4CvD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAK/D;AAED,uDAAuD;AACvD,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
@@ -0,0 +1,154 @@
1
+ import { reconnectOrProvision } from "@grackle-ai/adapter-sdk";
2
+ import * as envRegistry from "./env-registry.js";
3
+ import * as adapterManager from "./adapter-manager.js";
4
+ import * as tokenBroker from "./token-broker.js";
5
+ import { recoverSuspendedSessions } from "./session-recovery.js";
6
+ import { emit } from "./event-bus.js";
7
+ import { logger } from "./logger.js";
8
+ // ─── Constants ──────────────────────────────────────────────
9
+ /** Initial delay before first reconnect attempt (milliseconds). */
10
+ const RECONNECT_INITIAL_DELAY_MS = 10_000;
11
+ /** Maximum number of reconnect attempts before giving up. */
12
+ const RECONNECT_MAX_RETRIES = 5;
13
+ /** Maximum delay between reconnect attempts (milliseconds). */
14
+ const RECONNECT_MAX_DELAY_MS = 120_000;
15
+ /** Multiplier for exponential backoff. */
16
+ const RECONNECT_BACKOFF_MULTIPLIER = 2;
17
+ /** Tracks reconnect backoff state per environment. */
18
+ const reconnectStates = new Map();
19
+ /** Prevents concurrent reconnect attempts for the same environment. */
20
+ const reconnecting = new Set();
21
+ // ─── Public API ─────────────────────────────────────────────
22
+ /**
23
+ * Scan for disconnected environments and attempt to reconnect eligible ones.
24
+ * Called after each heartbeat tick. Uses exponential backoff per environment
25
+ * and a concurrency lock to prevent overlapping attempts.
26
+ *
27
+ * Fire-and-forget for each environment — logs errors but does not throw.
28
+ */
29
+ export async function attemptReconnects() {
30
+ const environments = envRegistry.listEnvironments();
31
+ const disconnected = environments.filter((env) => env.status === "disconnected");
32
+ for (const env of disconnected) {
33
+ const state = reconnectStates.get(env.id);
34
+ // First time seeing this environment disconnected — initialize state with delay
35
+ if (!state) {
36
+ reconnectStates.set(env.id, {
37
+ attempts: 0,
38
+ nextRetryAt: Date.now() + RECONNECT_INITIAL_DELAY_MS,
39
+ });
40
+ continue;
41
+ }
42
+ // Backoff not elapsed yet
43
+ if (Date.now() < state.nextRetryAt) {
44
+ continue;
45
+ }
46
+ // Max retries exhausted
47
+ if (state.attempts >= RECONNECT_MAX_RETRIES) {
48
+ continue;
49
+ }
50
+ // Already reconnecting
51
+ if (reconnecting.has(env.id)) {
52
+ continue;
53
+ }
54
+ // Attempt reconnect (fire-and-forget)
55
+ tryReconnect(env.id).catch((err) => {
56
+ logger.error({ environmentId: env.id, err }, "Unhandled error during auto-reconnect");
57
+ });
58
+ }
59
+ // Clean up state for environments that are no longer disconnected
60
+ for (const [envId] of reconnectStates) {
61
+ const env = environments.find((e) => e.id === envId);
62
+ if (env?.status !== "disconnected") {
63
+ reconnectStates.delete(envId);
64
+ }
65
+ }
66
+ }
67
+ /**
68
+ * Clear reconnect state for an environment. Call when the environment is
69
+ * manually provisioned, removed, or otherwise taken out of the reconnect cycle.
70
+ */
71
+ export function clearReconnectState(environmentId) {
72
+ reconnectStates.delete(environmentId);
73
+ // Note: does not cancel an in-flight tryReconnect — the lock will
74
+ // prevent a new attempt from starting, and the in-flight one will
75
+ // complete or fail on its own.
76
+ }
77
+ /** @internal Reset all reconnect state for testing. */
78
+ export function _resetForTesting() {
79
+ reconnectStates.clear();
80
+ reconnecting.clear();
81
+ }
82
+ // ─── Internal ───────────────────────────────────────────────
83
+ /**
84
+ * Attempt to reconnect a single disconnected environment.
85
+ * Uses the existing `reconnectOrProvision` flow from adapter-sdk.
86
+ */
87
+ async function tryReconnect(environmentId) {
88
+ reconnecting.add(environmentId);
89
+ try {
90
+ // Re-fetch environment in case it was removed while waiting
91
+ const env = envRegistry.getEnvironment(environmentId);
92
+ if (!env) {
93
+ reconnectStates.delete(environmentId);
94
+ return;
95
+ }
96
+ const adapter = adapterManager.getAdapter(env.adapterType);
97
+ if (!adapter) {
98
+ logger.warn({ environmentId, adapterType: env.adapterType }, "No adapter registered — skipping reconnect");
99
+ return;
100
+ }
101
+ logger.info({ environmentId, adapterType: env.adapterType }, "Attempting auto-reconnect");
102
+ envRegistry.updateEnvironmentStatus(environmentId, "connecting");
103
+ emit("environment.changed", {});
104
+ const config = JSON.parse(env.adapterConfig);
105
+ config.defaultRuntime = env.defaultRuntime;
106
+ const powerlineToken = env.powerlineToken;
107
+ // Run reconnectOrProvision — tries fast reconnect if supported, falls back to provision
108
+ for await (const event of reconnectOrProvision(environmentId, adapter, config, powerlineToken, !!env.bootstrapped)) {
109
+ logger.debug({ environmentId, stage: event.stage, message: event.message }, "Reconnect progress");
110
+ }
111
+ // Establish gRPC connection
112
+ const conn = await adapter.connect(environmentId, config, powerlineToken);
113
+ adapterManager.setConnection(environmentId, conn);
114
+ // Push tokens (local environments exclude file tokens)
115
+ if (env.adapterType === "local") {
116
+ await tokenBroker.pushToEnv(environmentId, { excludeFileTokens: true });
117
+ }
118
+ else {
119
+ await tokenBroker.pushToEnv(environmentId);
120
+ }
121
+ envRegistry.updateEnvironmentStatus(environmentId, "connected");
122
+ envRegistry.markBootstrapped(environmentId);
123
+ emit("environment.changed", {});
124
+ // Auto-recover suspended sessions (fire-and-forget)
125
+ recoverSuspendedSessions(environmentId, conn).catch((err) => {
126
+ logger.error({ environmentId, err }, "Session recovery failed after auto-reconnect");
127
+ });
128
+ logger.info({ environmentId }, "Auto-reconnect successful");
129
+ reconnectStates.delete(environmentId);
130
+ }
131
+ catch (err) {
132
+ // Clean up any partially-established connection to avoid leaking state
133
+ adapterManager.removeConnection(environmentId);
134
+ const state = reconnectStates.get(environmentId) ?? { attempts: 0, nextRetryAt: 0 };
135
+ state.attempts++;
136
+ if (state.attempts >= RECONNECT_MAX_RETRIES) {
137
+ logger.error({ environmentId, attempts: state.attempts, err }, "Auto-reconnect exhausted all retries — giving up");
138
+ envRegistry.updateEnvironmentStatus(environmentId, "error");
139
+ emit("environment.changed", {});
140
+ }
141
+ else {
142
+ const delay = Math.min(RECONNECT_INITIAL_DELAY_MS * Math.pow(RECONNECT_BACKOFF_MULTIPLIER, state.attempts), RECONNECT_MAX_DELAY_MS);
143
+ state.nextRetryAt = Date.now() + delay;
144
+ reconnectStates.set(environmentId, state);
145
+ logger.info({ environmentId, attempts: state.attempts, nextRetryInMs: delay, err }, "Auto-reconnect failed — will retry");
146
+ envRegistry.updateEnvironmentStatus(environmentId, "disconnected");
147
+ emit("environment.changed", {});
148
+ }
149
+ }
150
+ finally {
151
+ reconnecting.delete(environmentId);
152
+ }
153
+ }
154
+ //# sourceMappingURL=auto-reconnect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-reconnect.js","sourceRoot":"","sources":["../src/auto-reconnect.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"grpc-service.d.ts","sourceRoot":"","sources":["../src/grpc-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA+E7E;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAYvD;AAqLD,gFAAgF;AAChF,wBAAgB,mBAAmB,CACjC,UAAU,EAAE;IACV,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB,EAAE,GACF,MAAM,CAUR;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAczE;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CA46CjE"}
1
+ {"version":3,"file":"grpc-service.d.ts","sourceRoot":"","sources":["../src/grpc-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA+F7E;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAYvD;AAqLD,gFAAgF;AAChF,wBAAgB,mBAAmB,CACjC,UAAU,EAAE;IACV,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB,EAAE,GACF,MAAM,CAUR;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAczE;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAghDjE"}
@@ -16,6 +16,7 @@ import { emit } from "./event-bus.js";
16
16
  import { processEventStream } from "./event-processor.js";
17
17
  import * as processorRegistry from "./processor-registry.js";
18
18
  import { recoverSuspendedSessions } from "./session-recovery.js";
19
+ import { clearReconnectState } from "./auto-reconnect.js";
19
20
  import { join } from "node:path";
20
21
  import { LOGS_DIR, DEFAULT_WEB_PORT, DEFAULT_MCP_PORT, MAX_TASK_DEPTH, SESSION_STATUS, TERMINAL_SESSION_STATUSES, TASK_STATUS, ROOT_TASK_ID, taskStatusToEnum, taskStatusToString, workspaceStatusToEnum, claudeProviderModeToEnum, providerToggleToEnum, } from "@grackle-ai/common";
21
22
  import { resolvePersona } from "./resolve-persona.js";
@@ -29,6 +30,8 @@ import { computeTaskStatus } from "./compute-task-status.js";
29
30
  import { loadOrCreateApiKey } from "./api-key.js";
30
31
  import { logger } from "./logger.js";
31
32
  import { reanimateAgent } from "./reanimate-agent.js";
33
+ import { getKnowledgeEmbedder, isKnowledgeEnabled } from "./knowledge-init.js";
34
+ import { knowledgeSearch, getNode as getKnowledgeNodeById, expandNode, createNativeNode, ingest, createPassThroughChunker, listRecentNodes, } from "@grackle-ai/knowledge";
32
35
  import { slugify } from "./utils/slugify.js";
33
36
  import { SystemPromptBuilder, buildTaskPrompt } from "./system-prompt-builder.js";
34
37
  import { importGitHubIssues as executeGitHubImport } from "./github-import.js";
@@ -269,6 +272,8 @@ export function registerGrackleRoutes(router) {
269
272
  if (wsCount > 0) {
270
273
  throw new ConnectError(`Cannot remove environment: ${wsCount} active workspace(s) still reference it. Archive or reparent them first.`, Code.FailedPrecondition);
271
274
  }
275
+ // Stop auto-reconnect attempts for this environment
276
+ clearReconnectState(req.id);
272
277
  // Disconnect the adapter if currently connected
273
278
  const env = envRegistry.getEnvironment(req.id);
274
279
  if (env) {
@@ -291,6 +296,8 @@ export function registerGrackleRoutes(router) {
291
296
  return create(grackle.EmptySchema, {});
292
297
  },
293
298
  async *provisionEnvironment(req) {
299
+ // Manual provision overrides auto-reconnect
300
+ clearReconnectState(req.id);
294
301
  const env = envRegistry.getEnvironment(req.id);
295
302
  if (!env) {
296
303
  yield create(grackle.ProvisionEventSchema, {
@@ -1360,6 +1367,110 @@ export function registerGrackleRoutes(router) {
1360
1367
  const url = `http://${pairingHost}:${webPort}/pair?code=${code}`;
1361
1368
  return create(grackle.PairingCodeResponseSchema, { code, url });
1362
1369
  },
1370
+ // ── Knowledge Graph ────────────────────────────────────────
1371
+ async searchKnowledge(req) {
1372
+ const embedder = getKnowledgeEmbedder();
1373
+ if (!embedder) {
1374
+ throw new ConnectError("Knowledge graph not available", Code.Unavailable);
1375
+ }
1376
+ const results = await knowledgeSearch(req.query, embedder, {
1377
+ limit: req.limit || 10,
1378
+ workspaceId: req.workspaceId || undefined,
1379
+ });
1380
+ return create(grackle.SearchKnowledgeResponseSchema, {
1381
+ results: results.map((r) => create(grackle.SearchKnowledgeResultSchema, {
1382
+ score: r.score,
1383
+ node: knowledgeNodeToProto(r.node),
1384
+ edges: r.edges.map(knowledgeEdgeToProto),
1385
+ })),
1386
+ });
1387
+ },
1388
+ async getKnowledgeNode(req) {
1389
+ if (!isKnowledgeEnabled()) {
1390
+ throw new ConnectError("Knowledge graph not available", Code.Unavailable);
1391
+ }
1392
+ const result = await getKnowledgeNodeById(req.id);
1393
+ if (!result) {
1394
+ throw new ConnectError(`Knowledge node not found: ${req.id}`, Code.NotFound);
1395
+ }
1396
+ return create(grackle.GetKnowledgeNodeResponseSchema, {
1397
+ node: knowledgeNodeToProto(result.node),
1398
+ edges: result.edges.map(knowledgeEdgeToProto),
1399
+ });
1400
+ },
1401
+ async expandKnowledgeNode(req) {
1402
+ if (!isKnowledgeEnabled()) {
1403
+ throw new ConnectError("Knowledge graph not available", Code.Unavailable);
1404
+ }
1405
+ const result = await expandNode(req.id, {
1406
+ depth: req.depth || 1,
1407
+ edgeTypes: req.edgeTypes.length > 0 ? req.edgeTypes : undefined,
1408
+ });
1409
+ return create(grackle.ExpandKnowledgeNodeResponseSchema, {
1410
+ nodes: result.nodes.map(knowledgeNodeToProto),
1411
+ edges: result.edges.map(knowledgeEdgeToProto),
1412
+ });
1413
+ },
1414
+ async listRecentKnowledgeNodes(req) {
1415
+ if (!isKnowledgeEnabled()) {
1416
+ throw new ConnectError("Knowledge graph not available", Code.Unavailable);
1417
+ }
1418
+ const result = await listRecentNodes(req.limit || 20, req.workspaceId || undefined);
1419
+ return create(grackle.ListRecentKnowledgeNodesResponseSchema, {
1420
+ nodes: result.nodes.map(knowledgeNodeToProto),
1421
+ edges: result.edges.map(knowledgeEdgeToProto),
1422
+ });
1423
+ },
1424
+ async createKnowledgeNode(req) {
1425
+ const embedder = getKnowledgeEmbedder();
1426
+ if (!embedder) {
1427
+ throw new ConnectError("Knowledge graph not available", Code.Unavailable);
1428
+ }
1429
+ const chunker = createPassThroughChunker();
1430
+ const embedded = await ingest(req.content, chunker, embedder);
1431
+ if (embedded.length === 0) {
1432
+ throw new ConnectError("Content produced no embeddings", Code.InvalidArgument);
1433
+ }
1434
+ const id = await createNativeNode({
1435
+ category: (req.category || "insight"),
1436
+ title: req.title,
1437
+ content: req.content,
1438
+ tags: [...req.tags],
1439
+ embedding: embedded[0].vector,
1440
+ workspaceId: req.workspaceId || "",
1441
+ });
1442
+ return create(grackle.CreateKnowledgeNodeResponseSchema, { id });
1443
+ },
1444
+ });
1445
+ }
1446
+ // ---------------------------------------------------------------------------
1447
+ // Knowledge graph proto converters
1448
+ // ---------------------------------------------------------------------------
1449
+ /** Convert a KnowledgeNode to its proto representation. */
1450
+ function knowledgeNodeToProto(node) {
1451
+ return create(grackle.KnowledgeNodeProtoSchema, {
1452
+ id: node.id,
1453
+ kind: node.kind,
1454
+ workspaceId: node.workspaceId,
1455
+ createdAt: node.createdAt,
1456
+ updatedAt: node.updatedAt,
1457
+ sourceType: node.kind === "reference" ? node.sourceType : "",
1458
+ sourceId: node.kind === "reference" ? node.sourceId : "",
1459
+ label: node.kind === "reference" ? node.label : "",
1460
+ category: node.kind === "native" ? node.category : "",
1461
+ title: node.kind === "native" ? node.title : "",
1462
+ content: node.kind === "native" ? node.content : "",
1463
+ tags: node.kind === "native" ? node.tags : [],
1464
+ });
1465
+ }
1466
+ /** Convert a KnowledgeEdge to its proto representation. */
1467
+ function knowledgeEdgeToProto(edge) {
1468
+ return create(grackle.KnowledgeEdgeProtoSchema, {
1469
+ fromId: edge.fromId,
1470
+ toId: edge.toId,
1471
+ type: edge.type,
1472
+ metadataJson: edge.metadata ? JSON.stringify(edge.metadata) : "",
1473
+ createdAt: edge.createdAt,
1363
1474
  });
1364
1475
  }
1365
1476
  //# sourceMappingURL=grpc-service.js.map