electric-ax 0.1.1 → 0.1.3

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.
@@ -1,4 +1,4 @@
1
- import { ElectricCliEnv } from "./index-B6gIlecl.cjs";
1
+ import { ElectricCliEnv } from "./index-CQaCUw1k.cjs";
2
2
 
3
3
  //#region src/completions.d.ts
4
4
  declare function fetchEntityTypeNames(env: ElectricCliEnv): Promise<Array<string>>;
@@ -1,4 +1,4 @@
1
- import { ElectricCliEnv } from "./index-BJvlcIKL.js";
1
+ import { ElectricCliEnv } from "./index-CrW6PmwB.js";
2
2
 
3
3
  //#region src/completions.d.ts
4
4
  declare function fetchEntityTypeNames(env: ElectricCliEnv): Promise<Array<string>>;
@@ -15,7 +15,30 @@ interface StartedBuiltinAgentsEnvironment {
15
15
  url: string;
16
16
  registeredBaseUrl: string;
17
17
  agentServerUrl: string;
18
- } //#endregion
18
+ }
19
+ interface WaitForServerOptions {
20
+ fetchImpl?: typeof globalThis.fetch;
21
+ timeoutMs?: number;
22
+ intervalMs?: number;
23
+ }
24
+ declare function readDotEnvFile(cwd?: string): Record<string, string>;
25
+ declare function resolveAnthropicApiKey(options: StartBuiltinCommandOptions, env?: NodeJS.ProcessEnv, fileEnv?: Record<string, string>): string;
26
+ declare function resolveBuiltinAgentsPort(env?: NodeJS.ProcessEnv, fileEnv?: Record<string, string>): number;
27
+ declare function resolveElectricAgentsPort(env?: NodeJS.ProcessEnv, fileEnv?: Record<string, string>): number;
28
+ declare function getStartedEnvironmentMessage(started: StartedDevEnvironment): string;
29
+ declare function getStoppedEnvironmentMessage(stopped: StoppedDevEnvironment): string;
30
+ declare function getStartedBuiltinAgentsMessage(started: StartedBuiltinAgentsEnvironment): string;
31
+ declare function resolveComposeProjectName(_cwd?: string, env?: NodeJS.ProcessEnv): string;
32
+ declare function waitForElectricAgentsServer(baseUrl: string, options?: WaitForServerOptions): Promise<void>;
33
+ declare function startElectricAgentsDevEnvironment(_options?: StartCommandOptions, env?: NodeJS.ProcessEnv, cwd?: string): Promise<StartedDevEnvironment>;
34
+ declare function stopElectricAgentsDevEnvironment(options: StopCommandOptions, env?: NodeJS.ProcessEnv, cwd?: string): Promise<StoppedDevEnvironment>;
35
+ declare function startBuiltinAgentsServer(options: StartBuiltinCommandOptions, params?: {
36
+ env?: NodeJS.ProcessEnv;
37
+ cwd?: string;
38
+ agentServerUrl?: string;
39
+ }): Promise<StartedBuiltinAgentsEnvironment>;
40
+
41
+ //#endregion
19
42
  //#region src/index.d.ts
20
43
  declare const DEFAULT_ELECTRIC_AGENTS_URL = "http://localhost:4437";
21
44
  interface ElectricCliEnv {
@@ -80,4 +103,4 @@ declare function createElectricProgram({
80
103
  declare function run(argv?: Array<string>): Promise<void>;
81
104
 
82
105
  //#endregion
83
- export { DEFAULT_ELECTRIC_AGENTS_URL, ElectricCliEnv, ElectricCliHandlers, ObserveCommandOptions, PsCommandOptions, SendCommandOptions, SpawnCommandOptions, StartBuiltinCommandOptions, StartCommandOptions, StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StopCommandOptions, StoppedDevEnvironment, createElectricCliHandlers, createElectricProgram, getElectricCliEnv, resolveCommandPrefix, run };
106
+ export { DEFAULT_ELECTRIC_AGENTS_URL, ElectricCliEnv, ElectricCliHandlers, ObserveCommandOptions, PsCommandOptions, SendCommandOptions, SpawnCommandOptions, StartBuiltinCommandOptions, StartCommandOptions, StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StopCommandOptions, StoppedDevEnvironment, createElectricCliHandlers, createElectricProgram, getElectricCliEnv, getStartedBuiltinAgentsMessage, getStartedEnvironmentMessage, getStoppedEnvironmentMessage, readDotEnvFile, resolveAnthropicApiKey, resolveBuiltinAgentsPort, resolveCommandPrefix, resolveComposeProjectName, resolveElectricAgentsPort, run, startBuiltinAgentsServer, startElectricAgentsDevEnvironment, stopElectricAgentsDevEnvironment, waitForElectricAgentsServer };
@@ -15,7 +15,30 @@ interface StartedBuiltinAgentsEnvironment {
15
15
  url: string;
16
16
  registeredBaseUrl: string;
17
17
  agentServerUrl: string;
18
- } //#endregion
18
+ }
19
+ interface WaitForServerOptions {
20
+ fetchImpl?: typeof globalThis.fetch;
21
+ timeoutMs?: number;
22
+ intervalMs?: number;
23
+ }
24
+ declare function readDotEnvFile(cwd?: string): Record<string, string>;
25
+ declare function resolveAnthropicApiKey(options: StartBuiltinCommandOptions, env?: NodeJS.ProcessEnv, fileEnv?: Record<string, string>): string;
26
+ declare function resolveBuiltinAgentsPort(env?: NodeJS.ProcessEnv, fileEnv?: Record<string, string>): number;
27
+ declare function resolveElectricAgentsPort(env?: NodeJS.ProcessEnv, fileEnv?: Record<string, string>): number;
28
+ declare function getStartedEnvironmentMessage(started: StartedDevEnvironment): string;
29
+ declare function getStoppedEnvironmentMessage(stopped: StoppedDevEnvironment): string;
30
+ declare function getStartedBuiltinAgentsMessage(started: StartedBuiltinAgentsEnvironment): string;
31
+ declare function resolveComposeProjectName(_cwd?: string, env?: NodeJS.ProcessEnv): string;
32
+ declare function waitForElectricAgentsServer(baseUrl: string, options?: WaitForServerOptions): Promise<void>;
33
+ declare function startElectricAgentsDevEnvironment(_options?: StartCommandOptions, env?: NodeJS.ProcessEnv, cwd?: string): Promise<StartedDevEnvironment>;
34
+ declare function stopElectricAgentsDevEnvironment(options: StopCommandOptions, env?: NodeJS.ProcessEnv, cwd?: string): Promise<StoppedDevEnvironment>;
35
+ declare function startBuiltinAgentsServer(options: StartBuiltinCommandOptions, params?: {
36
+ env?: NodeJS.ProcessEnv;
37
+ cwd?: string;
38
+ agentServerUrl?: string;
39
+ }): Promise<StartedBuiltinAgentsEnvironment>;
40
+
41
+ //#endregion
19
42
  //#region src/index.d.ts
20
43
  declare const DEFAULT_ELECTRIC_AGENTS_URL = "http://localhost:4437";
21
44
  interface ElectricCliEnv {
@@ -80,4 +103,4 @@ declare function createElectricProgram({
80
103
  declare function run(argv?: Array<string>): Promise<void>;
81
104
 
82
105
  //#endregion
83
- export { DEFAULT_ELECTRIC_AGENTS_URL, ElectricCliEnv, ElectricCliHandlers, ObserveCommandOptions, PsCommandOptions, SendCommandOptions, SpawnCommandOptions, StartBuiltinCommandOptions, StartCommandOptions, StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StopCommandOptions, StoppedDevEnvironment, createElectricCliHandlers, createElectricProgram, getElectricCliEnv, resolveCommandPrefix, run };
106
+ export { DEFAULT_ELECTRIC_AGENTS_URL, ElectricCliEnv, ElectricCliHandlers, ObserveCommandOptions, PsCommandOptions, SendCommandOptions, SpawnCommandOptions, StartBuiltinCommandOptions, StartCommandOptions, StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StopCommandOptions, StoppedDevEnvironment, createElectricCliHandlers, createElectricProgram, getElectricCliEnv, getStartedBuiltinAgentsMessage, getStartedEnvironmentMessage, getStoppedEnvironmentMessage, readDotEnvFile, resolveAnthropicApiKey, resolveBuiltinAgentsPort, resolveCommandPrefix, resolveComposeProjectName, resolveElectricAgentsPort, run, startBuiltinAgentsServer, startElectricAgentsDevEnvironment, stopElectricAgentsDevEnvironment, waitForElectricAgentsServer };
package/dist/index.d.cts CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_ELECTRIC_AGENTS_URL, ElectricCliEnv, ElectricCliHandlers, ObserveCommandOptions, PsCommandOptions, SendCommandOptions, SpawnCommandOptions, StartBuiltinCommandOptions, StartCommandOptions, StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StopCommandOptions, StoppedDevEnvironment, createElectricCliHandlers, createElectricProgram, getElectricCliEnv, resolveCommandPrefix, run } from "./index-B6gIlecl.cjs";
2
+ import { DEFAULT_ELECTRIC_AGENTS_URL, ElectricCliEnv, ElectricCliHandlers, ObserveCommandOptions, PsCommandOptions, SendCommandOptions, SpawnCommandOptions, StartBuiltinCommandOptions, StartCommandOptions, StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StopCommandOptions, StoppedDevEnvironment, createElectricCliHandlers, createElectricProgram, getElectricCliEnv, resolveCommandPrefix, run } from "./index-CQaCUw1k.cjs";
3
3
  export { DEFAULT_ELECTRIC_AGENTS_URL, ElectricCliEnv, ElectricCliHandlers, ObserveCommandOptions, PsCommandOptions, SendCommandOptions, SpawnCommandOptions, StartBuiltinCommandOptions, StartCommandOptions, StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StopCommandOptions, StoppedDevEnvironment, createElectricCliHandlers, createElectricProgram, getElectricCliEnv, resolveCommandPrefix, run };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_ELECTRIC_AGENTS_URL, ElectricCliEnv, ElectricCliHandlers, ObserveCommandOptions, PsCommandOptions, SendCommandOptions, SpawnCommandOptions, StartBuiltinCommandOptions, StartCommandOptions, StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StopCommandOptions, StoppedDevEnvironment, createElectricCliHandlers, createElectricProgram, getElectricCliEnv, resolveCommandPrefix, run } from "./index-BJvlcIKL.js";
2
+ import { DEFAULT_ELECTRIC_AGENTS_URL, ElectricCliEnv, ElectricCliHandlers, ObserveCommandOptions, PsCommandOptions, SendCommandOptions, SpawnCommandOptions, StartBuiltinCommandOptions, StartCommandOptions, StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StopCommandOptions, StoppedDevEnvironment, createElectricCliHandlers, createElectricProgram, getElectricCliEnv, resolveCommandPrefix, run } from "./index-CrW6PmwB.js";
3
3
  export { DEFAULT_ELECTRIC_AGENTS_URL, ElectricCliEnv, ElectricCliHandlers, ObserveCommandOptions, PsCommandOptions, SendCommandOptions, SpawnCommandOptions, StartBuiltinCommandOptions, StartCommandOptions, StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StopCommandOptions, StoppedDevEnvironment, createElectricCliHandlers, createElectricProgram, getElectricCliEnv, resolveCommandPrefix, run };
package/dist/start.cjs ADDED
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ const require_chunk = require('./chunk-BCwAaXi7.cjs');
3
+ const node_fs = require_chunk.__toESM(require("node:fs"));
4
+ const node_path = require_chunk.__toESM(require("node:path"));
5
+ const node_url = require_chunk.__toESM(require("node:url"));
6
+ const node_child_process = require_chunk.__toESM(require("node:child_process"));
7
+ const __electric_ax_agents = require_chunk.__toESM(require("@electric-ax/agents"));
8
+
9
+ //#region src/start.ts
10
+ const DEFAULT_ELECTRIC_AGENTS_PORT = 4437;
11
+ const DEFAULT_BUILTIN_AGENTS_PORT = 4448;
12
+ const DEFAULT_COMPOSE_PROJECT_NAME = `electric-agents`;
13
+ const DOCKER_COMPOSE_FILE = (0, node_url.fileURLToPath)(new URL(`../docker-compose.full.yml`, require("url").pathToFileURL(__filename).href));
14
+ function parseDotEnvValue(raw) {
15
+ const trimmed = raw.trim();
16
+ if (trimmed.startsWith(`"`) && trimmed.endsWith(`"`) || trimmed.startsWith(`'`) && trimmed.endsWith(`'`)) return trimmed.slice(1, -1);
17
+ const hashIndex = trimmed.indexOf(`#`);
18
+ return hashIndex === -1 ? trimmed : trimmed.slice(0, hashIndex).trim();
19
+ }
20
+ function readDotEnvFile(cwd = process.cwd()) {
21
+ const envPath = (0, node_path.resolve)(cwd, `.env`);
22
+ try {
23
+ const content = (0, node_fs.readFileSync)(envPath, `utf8`);
24
+ const values = {};
25
+ for (const line of content.split(/\r?\n/)) {
26
+ const trimmed = line.trim();
27
+ if (!trimmed || trimmed.startsWith(`#`)) continue;
28
+ const equalsIndex = trimmed.indexOf(`=`);
29
+ if (equalsIndex <= 0) continue;
30
+ const key = trimmed.slice(0, equalsIndex).trim();
31
+ const value = parseDotEnvValue(trimmed.slice(equalsIndex + 1));
32
+ values[key] = value;
33
+ }
34
+ return values;
35
+ } catch (error) {
36
+ if (error.code === `ENOENT`) return {};
37
+ throw error;
38
+ }
39
+ }
40
+ function resolveAnthropicApiKey(options, env = process.env, fileEnv = readDotEnvFile()) {
41
+ const candidate = options.anthropicApiKey?.trim() || env.ANTHROPIC_API_KEY?.trim() || fileEnv.ANTHROPIC_API_KEY?.trim();
42
+ if (!candidate) throw new Error(`ANTHROPIC_API_KEY is required. Pass --anthropic-api-key, export it in your shell, or set it in .env.`);
43
+ return candidate;
44
+ }
45
+ function resolveBuiltinAgentsPort(env = process.env, fileEnv = readDotEnvFile()) {
46
+ const raw = env.ELECTRIC_AGENTS_BUILTIN_PORT?.trim() || fileEnv.ELECTRIC_AGENTS_BUILTIN_PORT?.trim();
47
+ const parsed = raw ? Number(raw) : DEFAULT_BUILTIN_AGENTS_PORT;
48
+ if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`ELECTRIC_AGENTS_BUILTIN_PORT must be a positive integer`);
49
+ return parsed;
50
+ }
51
+ function resolveElectricAgentsPort(env = process.env, fileEnv = readDotEnvFile()) {
52
+ const raw = env.ELECTRIC_AGENTS_PORT?.trim() || fileEnv.ELECTRIC_AGENTS_PORT?.trim();
53
+ const parsed = raw ? Number(raw) : DEFAULT_ELECTRIC_AGENTS_PORT;
54
+ if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`ELECTRIC_AGENTS_PORT must be a positive integer`);
55
+ return parsed;
56
+ }
57
+ function getStartedEnvironmentMessage(started) {
58
+ return [
59
+ `Electric Agents dev environment is up.`,
60
+ `Server + UI: ${started.uiUrl}`,
61
+ `Docker project: ${started.composeProjectName}`
62
+ ].join(`\n`);
63
+ }
64
+ function getStoppedEnvironmentMessage(stopped) {
65
+ return [
66
+ `Electric Agents dev environment is down.`,
67
+ `Docker project: ${stopped.composeProjectName}`,
68
+ stopped.removedVolumes ? `Volumes removed: yes` : `Volumes removed: no`
69
+ ].join(`\n`);
70
+ }
71
+ function getStartedBuiltinAgentsMessage(started) {
72
+ return [
73
+ `Builtin Horton server is up.`,
74
+ `Webhook server: ${started.url}`,
75
+ `Registers with: ${started.agentServerUrl}`,
76
+ `Press Ctrl-C to stop.`
77
+ ].join(`\n`);
78
+ }
79
+ function resolveComposeProjectName(_cwd = process.cwd(), env = process.env) {
80
+ const explicit = env.ELECTRIC_AGENTS_COMPOSE_PROJECT?.trim();
81
+ if (explicit) return explicit;
82
+ return DEFAULT_COMPOSE_PROJECT_NAME;
83
+ }
84
+ async function runDockerCompose(args, env) {
85
+ await new Promise((resolve, reject) => {
86
+ const child = (0, node_child_process.spawn)(`docker`, args, {
87
+ cwd: process.cwd(),
88
+ env,
89
+ stdio: `inherit`
90
+ });
91
+ child.on(`error`, (error) => {
92
+ reject(new Error(`Failed to run docker compose: ${error instanceof Error ? error.message : String(error)}`));
93
+ });
94
+ child.on(`exit`, (code) => {
95
+ if (code === 0) {
96
+ resolve();
97
+ return;
98
+ }
99
+ reject(new Error(`docker compose exited with code ${code ?? `unknown`}`));
100
+ });
101
+ });
102
+ }
103
+ function delay(ms) {
104
+ return new Promise((resolve) => {
105
+ setTimeout(resolve, ms);
106
+ });
107
+ }
108
+ async function waitForElectricAgentsServer(baseUrl, options = {}) {
109
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
110
+ const timeoutMs = options.timeoutMs ?? 6e4;
111
+ const intervalMs = options.intervalMs ?? 1e3;
112
+ const deadline = Date.now() + timeoutMs;
113
+ const healthUrl = `${baseUrl.replace(/\/$/, ``)}/_electric/health`;
114
+ let lastError = null;
115
+ while (Date.now() < deadline) {
116
+ try {
117
+ const response = await fetchImpl(healthUrl, { signal: AbortSignal.timeout(5e3) });
118
+ if (response.ok) return;
119
+ lastError = `healthcheck returned ${response.status}`;
120
+ } catch (error) {
121
+ lastError = error instanceof Error ? error.message : String(error);
122
+ }
123
+ await delay(intervalMs);
124
+ }
125
+ throw new Error(`Timed out waiting for Electric Agents server at ${healthUrl}${lastError ? `: ${lastError}` : ``}`);
126
+ }
127
+ async function startElectricAgentsDevEnvironment(_options = {}, env = process.env, cwd = process.cwd()) {
128
+ const fileEnv = readDotEnvFile(cwd);
129
+ const port = resolveElectricAgentsPort(env, fileEnv);
130
+ const composeProjectName = resolveComposeProjectName(cwd, env);
131
+ await runDockerCompose([
132
+ `compose`,
133
+ `-f`,
134
+ DOCKER_COMPOSE_FILE,
135
+ `up`,
136
+ `-d`
137
+ ], {
138
+ ...env,
139
+ COMPOSE_PROJECT_NAME: composeProjectName,
140
+ ELECTRIC_AGENTS_PORT: String(port)
141
+ });
142
+ const uiUrl = `http://localhost:${port}`;
143
+ await waitForElectricAgentsServer(uiUrl);
144
+ return {
145
+ port,
146
+ uiUrl,
147
+ composeProjectName
148
+ };
149
+ }
150
+ async function stopElectricAgentsDevEnvironment(options, env = process.env, cwd = process.cwd()) {
151
+ const composeProjectName = resolveComposeProjectName(cwd, env);
152
+ const args = [
153
+ `compose`,
154
+ `-f`,
155
+ DOCKER_COMPOSE_FILE,
156
+ `down`
157
+ ];
158
+ if (options.removeVolumes) args.push(`--volumes`);
159
+ await runDockerCompose(args, {
160
+ ...env,
161
+ COMPOSE_PROJECT_NAME: composeProjectName
162
+ });
163
+ return {
164
+ composeProjectName,
165
+ removedVolumes: options.removeVolumes ?? false
166
+ };
167
+ }
168
+ function waitForShutdown(stop, signalSource = process) {
169
+ return new Promise((resolve, reject) => {
170
+ let stopping = false;
171
+ const cleanup = () => {
172
+ signalSource.off(`SIGINT`, onSigint);
173
+ signalSource.off(`SIGTERM`, onSigterm);
174
+ };
175
+ const shutdown = (signal) => {
176
+ if (stopping) return;
177
+ stopping = true;
178
+ cleanup();
179
+ stop().then(resolve).catch((error) => {
180
+ reject(new Error(`Failed to stop builtin agents server after ${signal}: ${error instanceof Error ? error.message : String(error)}`));
181
+ });
182
+ };
183
+ const onSigint = () => {
184
+ shutdown(`SIGINT`);
185
+ };
186
+ const onSigterm = () => {
187
+ shutdown(`SIGTERM`);
188
+ };
189
+ signalSource.on(`SIGINT`, onSigint);
190
+ signalSource.on(`SIGTERM`, onSigterm);
191
+ });
192
+ }
193
+ async function startBuiltinAgentsServer(options, params = {}) {
194
+ const env = params.env ?? process.env;
195
+ const cwd = params.cwd ?? process.cwd();
196
+ const fileEnv = readDotEnvFile(cwd);
197
+ const anthropicApiKey = resolveAnthropicApiKey(options, env, fileEnv);
198
+ const port = resolveBuiltinAgentsPort(env, fileEnv);
199
+ const agentServerUrl = params.agentServerUrl ?? env.ELECTRIC_AGENTS_URL?.trim() ?? `http://localhost:${resolveElectricAgentsPort(env, fileEnv)}`;
200
+ process.env.ANTHROPIC_API_KEY = anthropicApiKey;
201
+ await waitForElectricAgentsServer(agentServerUrl);
202
+ const server = new __electric_ax_agents.BuiltinAgentsServer({
203
+ agentServerUrl,
204
+ port,
205
+ workingDirectory: cwd
206
+ });
207
+ await server.start();
208
+ const started = {
209
+ port,
210
+ url: server.url,
211
+ registeredBaseUrl: server.registeredBaseUrl,
212
+ agentServerUrl
213
+ };
214
+ console.log(getStartedBuiltinAgentsMessage(started));
215
+ await waitForShutdown(() => server.stop());
216
+ return started;
217
+ }
218
+
219
+ //#endregion
220
+ exports.getStartedBuiltinAgentsMessage = getStartedBuiltinAgentsMessage
221
+ exports.getStartedEnvironmentMessage = getStartedEnvironmentMessage
222
+ exports.getStoppedEnvironmentMessage = getStoppedEnvironmentMessage
223
+ exports.readDotEnvFile = readDotEnvFile
224
+ exports.resolveAnthropicApiKey = resolveAnthropicApiKey
225
+ exports.resolveBuiltinAgentsPort = resolveBuiltinAgentsPort
226
+ exports.resolveComposeProjectName = resolveComposeProjectName
227
+ exports.resolveElectricAgentsPort = resolveElectricAgentsPort
228
+ exports.startBuiltinAgentsServer = startBuiltinAgentsServer
229
+ exports.startElectricAgentsDevEnvironment = startElectricAgentsDevEnvironment
230
+ exports.stopElectricAgentsDevEnvironment = stopElectricAgentsDevEnvironment
231
+ exports.waitForElectricAgentsServer = waitForElectricAgentsServer
@@ -0,0 +1,2 @@
1
+ import { StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StoppedDevEnvironment, getStartedBuiltinAgentsMessage, getStartedEnvironmentMessage, getStoppedEnvironmentMessage, readDotEnvFile, resolveAnthropicApiKey, resolveBuiltinAgentsPort, resolveComposeProjectName, resolveElectricAgentsPort, startBuiltinAgentsServer, startElectricAgentsDevEnvironment, stopElectricAgentsDevEnvironment, waitForElectricAgentsServer } from "./index-CQaCUw1k.cjs";
2
+ export { StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StoppedDevEnvironment, getStartedBuiltinAgentsMessage, getStartedEnvironmentMessage, getStoppedEnvironmentMessage, readDotEnvFile, resolveAnthropicApiKey, resolveBuiltinAgentsPort, resolveComposeProjectName, resolveElectricAgentsPort, startBuiltinAgentsServer, startElectricAgentsDevEnvironment, stopElectricAgentsDevEnvironment, waitForElectricAgentsServer };
@@ -0,0 +1,2 @@
1
+ import { StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StoppedDevEnvironment, getStartedBuiltinAgentsMessage, getStartedEnvironmentMessage, getStoppedEnvironmentMessage, readDotEnvFile, resolveAnthropicApiKey, resolveBuiltinAgentsPort, resolveComposeProjectName, resolveElectricAgentsPort, startBuiltinAgentsServer, startElectricAgentsDevEnvironment, stopElectricAgentsDevEnvironment, waitForElectricAgentsServer } from "./index-CrW6PmwB.js";
2
+ export { StartedBuiltinAgentsEnvironment, StartedDevEnvironment, StoppedDevEnvironment, getStartedBuiltinAgentsMessage, getStartedEnvironmentMessage, getStoppedEnvironmentMessage, readDotEnvFile, resolveAnthropicApiKey, resolveBuiltinAgentsPort, resolveComposeProjectName, resolveElectricAgentsPort, startBuiltinAgentsServer, startElectricAgentsDevEnvironment, stopElectricAgentsDevEnvironment, waitForElectricAgentsServer };
package/dist/start.js ADDED
@@ -0,0 +1,218 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { spawn } from "node:child_process";
5
+ import { BuiltinAgentsServer } from "@electric-ax/agents";
6
+
7
+ //#region src/start.ts
8
+ const DEFAULT_ELECTRIC_AGENTS_PORT = 4437;
9
+ const DEFAULT_BUILTIN_AGENTS_PORT = 4448;
10
+ const DEFAULT_COMPOSE_PROJECT_NAME = `electric-agents`;
11
+ const DOCKER_COMPOSE_FILE = fileURLToPath(new URL(`../docker-compose.full.yml`, import.meta.url));
12
+ function parseDotEnvValue(raw) {
13
+ const trimmed = raw.trim();
14
+ if (trimmed.startsWith(`"`) && trimmed.endsWith(`"`) || trimmed.startsWith(`'`) && trimmed.endsWith(`'`)) return trimmed.slice(1, -1);
15
+ const hashIndex = trimmed.indexOf(`#`);
16
+ return hashIndex === -1 ? trimmed : trimmed.slice(0, hashIndex).trim();
17
+ }
18
+ function readDotEnvFile(cwd = process.cwd()) {
19
+ const envPath = resolve(cwd, `.env`);
20
+ try {
21
+ const content = readFileSync(envPath, `utf8`);
22
+ const values = {};
23
+ for (const line of content.split(/\r?\n/)) {
24
+ const trimmed = line.trim();
25
+ if (!trimmed || trimmed.startsWith(`#`)) continue;
26
+ const equalsIndex = trimmed.indexOf(`=`);
27
+ if (equalsIndex <= 0) continue;
28
+ const key = trimmed.slice(0, equalsIndex).trim();
29
+ const value = parseDotEnvValue(trimmed.slice(equalsIndex + 1));
30
+ values[key] = value;
31
+ }
32
+ return values;
33
+ } catch (error) {
34
+ if (error.code === `ENOENT`) return {};
35
+ throw error;
36
+ }
37
+ }
38
+ function resolveAnthropicApiKey(options, env = process.env, fileEnv = readDotEnvFile()) {
39
+ const candidate = options.anthropicApiKey?.trim() || env.ANTHROPIC_API_KEY?.trim() || fileEnv.ANTHROPIC_API_KEY?.trim();
40
+ if (!candidate) throw new Error(`ANTHROPIC_API_KEY is required. Pass --anthropic-api-key, export it in your shell, or set it in .env.`);
41
+ return candidate;
42
+ }
43
+ function resolveBuiltinAgentsPort(env = process.env, fileEnv = readDotEnvFile()) {
44
+ const raw = env.ELECTRIC_AGENTS_BUILTIN_PORT?.trim() || fileEnv.ELECTRIC_AGENTS_BUILTIN_PORT?.trim();
45
+ const parsed = raw ? Number(raw) : DEFAULT_BUILTIN_AGENTS_PORT;
46
+ if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`ELECTRIC_AGENTS_BUILTIN_PORT must be a positive integer`);
47
+ return parsed;
48
+ }
49
+ function resolveElectricAgentsPort(env = process.env, fileEnv = readDotEnvFile()) {
50
+ const raw = env.ELECTRIC_AGENTS_PORT?.trim() || fileEnv.ELECTRIC_AGENTS_PORT?.trim();
51
+ const parsed = raw ? Number(raw) : DEFAULT_ELECTRIC_AGENTS_PORT;
52
+ if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`ELECTRIC_AGENTS_PORT must be a positive integer`);
53
+ return parsed;
54
+ }
55
+ function getStartedEnvironmentMessage(started) {
56
+ return [
57
+ `Electric Agents dev environment is up.`,
58
+ `Server + UI: ${started.uiUrl}`,
59
+ `Docker project: ${started.composeProjectName}`
60
+ ].join(`\n`);
61
+ }
62
+ function getStoppedEnvironmentMessage(stopped) {
63
+ return [
64
+ `Electric Agents dev environment is down.`,
65
+ `Docker project: ${stopped.composeProjectName}`,
66
+ stopped.removedVolumes ? `Volumes removed: yes` : `Volumes removed: no`
67
+ ].join(`\n`);
68
+ }
69
+ function getStartedBuiltinAgentsMessage(started) {
70
+ return [
71
+ `Builtin Horton server is up.`,
72
+ `Webhook server: ${started.url}`,
73
+ `Registers with: ${started.agentServerUrl}`,
74
+ `Press Ctrl-C to stop.`
75
+ ].join(`\n`);
76
+ }
77
+ function resolveComposeProjectName(_cwd = process.cwd(), env = process.env) {
78
+ const explicit = env.ELECTRIC_AGENTS_COMPOSE_PROJECT?.trim();
79
+ if (explicit) return explicit;
80
+ return DEFAULT_COMPOSE_PROJECT_NAME;
81
+ }
82
+ async function runDockerCompose(args, env) {
83
+ await new Promise((resolve$1, reject) => {
84
+ const child = spawn(`docker`, args, {
85
+ cwd: process.cwd(),
86
+ env,
87
+ stdio: `inherit`
88
+ });
89
+ child.on(`error`, (error) => {
90
+ reject(new Error(`Failed to run docker compose: ${error instanceof Error ? error.message : String(error)}`));
91
+ });
92
+ child.on(`exit`, (code) => {
93
+ if (code === 0) {
94
+ resolve$1();
95
+ return;
96
+ }
97
+ reject(new Error(`docker compose exited with code ${code ?? `unknown`}`));
98
+ });
99
+ });
100
+ }
101
+ function delay(ms) {
102
+ return new Promise((resolve$1) => {
103
+ setTimeout(resolve$1, ms);
104
+ });
105
+ }
106
+ async function waitForElectricAgentsServer(baseUrl, options = {}) {
107
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
108
+ const timeoutMs = options.timeoutMs ?? 6e4;
109
+ const intervalMs = options.intervalMs ?? 1e3;
110
+ const deadline = Date.now() + timeoutMs;
111
+ const healthUrl = `${baseUrl.replace(/\/$/, ``)}/_electric/health`;
112
+ let lastError = null;
113
+ while (Date.now() < deadline) {
114
+ try {
115
+ const response = await fetchImpl(healthUrl, { signal: AbortSignal.timeout(5e3) });
116
+ if (response.ok) return;
117
+ lastError = `healthcheck returned ${response.status}`;
118
+ } catch (error) {
119
+ lastError = error instanceof Error ? error.message : String(error);
120
+ }
121
+ await delay(intervalMs);
122
+ }
123
+ throw new Error(`Timed out waiting for Electric Agents server at ${healthUrl}${lastError ? `: ${lastError}` : ``}`);
124
+ }
125
+ async function startElectricAgentsDevEnvironment(_options = {}, env = process.env, cwd = process.cwd()) {
126
+ const fileEnv = readDotEnvFile(cwd);
127
+ const port = resolveElectricAgentsPort(env, fileEnv);
128
+ const composeProjectName = resolveComposeProjectName(cwd, env);
129
+ await runDockerCompose([
130
+ `compose`,
131
+ `-f`,
132
+ DOCKER_COMPOSE_FILE,
133
+ `up`,
134
+ `-d`
135
+ ], {
136
+ ...env,
137
+ COMPOSE_PROJECT_NAME: composeProjectName,
138
+ ELECTRIC_AGENTS_PORT: String(port)
139
+ });
140
+ const uiUrl = `http://localhost:${port}`;
141
+ await waitForElectricAgentsServer(uiUrl);
142
+ return {
143
+ port,
144
+ uiUrl,
145
+ composeProjectName
146
+ };
147
+ }
148
+ async function stopElectricAgentsDevEnvironment(options, env = process.env, cwd = process.cwd()) {
149
+ const composeProjectName = resolveComposeProjectName(cwd, env);
150
+ const args = [
151
+ `compose`,
152
+ `-f`,
153
+ DOCKER_COMPOSE_FILE,
154
+ `down`
155
+ ];
156
+ if (options.removeVolumes) args.push(`--volumes`);
157
+ await runDockerCompose(args, {
158
+ ...env,
159
+ COMPOSE_PROJECT_NAME: composeProjectName
160
+ });
161
+ return {
162
+ composeProjectName,
163
+ removedVolumes: options.removeVolumes ?? false
164
+ };
165
+ }
166
+ function waitForShutdown(stop, signalSource = process) {
167
+ return new Promise((resolve$1, reject) => {
168
+ let stopping = false;
169
+ const cleanup = () => {
170
+ signalSource.off(`SIGINT`, onSigint);
171
+ signalSource.off(`SIGTERM`, onSigterm);
172
+ };
173
+ const shutdown = (signal) => {
174
+ if (stopping) return;
175
+ stopping = true;
176
+ cleanup();
177
+ stop().then(resolve$1).catch((error) => {
178
+ reject(new Error(`Failed to stop builtin agents server after ${signal}: ${error instanceof Error ? error.message : String(error)}`));
179
+ });
180
+ };
181
+ const onSigint = () => {
182
+ shutdown(`SIGINT`);
183
+ };
184
+ const onSigterm = () => {
185
+ shutdown(`SIGTERM`);
186
+ };
187
+ signalSource.on(`SIGINT`, onSigint);
188
+ signalSource.on(`SIGTERM`, onSigterm);
189
+ });
190
+ }
191
+ async function startBuiltinAgentsServer(options, params = {}) {
192
+ const env = params.env ?? process.env;
193
+ const cwd = params.cwd ?? process.cwd();
194
+ const fileEnv = readDotEnvFile(cwd);
195
+ const anthropicApiKey = resolveAnthropicApiKey(options, env, fileEnv);
196
+ const port = resolveBuiltinAgentsPort(env, fileEnv);
197
+ const agentServerUrl = params.agentServerUrl ?? env.ELECTRIC_AGENTS_URL?.trim() ?? `http://localhost:${resolveElectricAgentsPort(env, fileEnv)}`;
198
+ process.env.ANTHROPIC_API_KEY = anthropicApiKey;
199
+ await waitForElectricAgentsServer(agentServerUrl);
200
+ const server = new BuiltinAgentsServer({
201
+ agentServerUrl,
202
+ port,
203
+ workingDirectory: cwd
204
+ });
205
+ await server.start();
206
+ const started = {
207
+ port,
208
+ url: server.url,
209
+ registeredBaseUrl: server.registeredBaseUrl,
210
+ agentServerUrl
211
+ };
212
+ console.log(getStartedBuiltinAgentsMessage(started));
213
+ await waitForShutdown(() => server.stop());
214
+ return started;
215
+ }
216
+
217
+ //#endregion
218
+ export { getStartedBuiltinAgentsMessage, getStartedEnvironmentMessage, getStoppedEnvironmentMessage, readDotEnvFile, resolveAnthropicApiKey, resolveBuiltinAgentsPort, resolveComposeProjectName, resolveElectricAgentsPort, startBuiltinAgentsServer, startElectricAgentsDevEnvironment, stopElectricAgentsDevEnvironment, waitForElectricAgentsServer };
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ const require_chunk = require('./chunk-BCwAaXi7.cjs');
3
+ const react = require_chunk.__toESM(require("react"));
4
+ const ink = require_chunk.__toESM(require("ink"));
5
+ const react_jsx_runtime = require_chunk.__toESM(require("react/jsx-runtime"));
6
+
7
+ //#region src/types-table.tsx
8
+ function TypesTable({ types }) {
9
+ const groups = new Map();
10
+ for (const t of types) {
11
+ const server = t.serve_endpoint ?? `built-in`;
12
+ if (!groups.has(server)) groups.set(server, []);
13
+ groups.get(server).push(t);
14
+ }
15
+ const entries = Array.from(groups.entries());
16
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Box, {
17
+ flexDirection: "column",
18
+ children: entries.map(([server, serverTypes], i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ink.Box, {
19
+ flexDirection: "column",
20
+ marginTop: i > 0 ? 1 : 0,
21
+ children: [
22
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Text, {
23
+ bold: true,
24
+ dimColor: true,
25
+ children: server === `built-in` ? `Built-in agents` : server
26
+ }),
27
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ink.Box, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Box, {
28
+ width: 25,
29
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Text, {
30
+ bold: true,
31
+ children: "NAME"
32
+ })
33
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Text, {
34
+ bold: true,
35
+ children: "DESCRIPTION"
36
+ })] }),
37
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ink.Box, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Box, {
38
+ width: 25,
39
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Text, {
40
+ dimColor: true,
41
+ children: `─`.repeat(23)
42
+ })
43
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Text, {
44
+ dimColor: true,
45
+ children: `─`.repeat(40)
46
+ })] }),
47
+ serverTypes.map((t) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ink.Box, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Box, {
48
+ width: 25,
49
+ flexShrink: 0,
50
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Text, { children: t.name })
51
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Box, {
52
+ flexGrow: 1,
53
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ink.Text, {
54
+ wrap: "wrap",
55
+ children: t.description
56
+ })
57
+ })] }, t.name))
58
+ ]
59
+ }, server))
60
+ });
61
+ }
62
+ function renderTypesTable(types) {
63
+ console.log((0, ink.renderToString)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TypesTable, { types })));
64
+ }
65
+
66
+ //#endregion
67
+ exports.renderTypesTable = renderTypesTable
@@ -0,0 +1,10 @@
1
+ //#region src/types-table.d.ts
2
+ interface EntityType {
3
+ name: string;
4
+ description: string;
5
+ serve_endpoint?: string;
6
+ }
7
+ declare function renderTypesTable(types: Array<EntityType>): void;
8
+
9
+ //#endregion
10
+ export { renderTypesTable };
@@ -0,0 +1,10 @@
1
+ //#region src/types-table.d.ts
2
+ interface EntityType {
3
+ name: string;
4
+ description: string;
5
+ serve_endpoint?: string;
6
+ }
7
+ declare function renderTypesTable(types: Array<EntityType>): void;
8
+
9
+ //#endregion
10
+ export { renderTypesTable };
@@ -0,0 +1,65 @@
1
+ import React from "react";
2
+ import { Box, Text, renderToString } from "ink";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+
5
+ //#region src/types-table.tsx
6
+ function TypesTable({ types }) {
7
+ const groups = new Map();
8
+ for (const t of types) {
9
+ const server = t.serve_endpoint ?? `built-in`;
10
+ if (!groups.has(server)) groups.set(server, []);
11
+ groups.get(server).push(t);
12
+ }
13
+ const entries = Array.from(groups.entries());
14
+ return /* @__PURE__ */ jsx(Box, {
15
+ flexDirection: "column",
16
+ children: entries.map(([server, serverTypes], i) => /* @__PURE__ */ jsxs(Box, {
17
+ flexDirection: "column",
18
+ marginTop: i > 0 ? 1 : 0,
19
+ children: [
20
+ /* @__PURE__ */ jsx(Text, {
21
+ bold: true,
22
+ dimColor: true,
23
+ children: server === `built-in` ? `Built-in agents` : server
24
+ }),
25
+ /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Box, {
26
+ width: 25,
27
+ children: /* @__PURE__ */ jsx(Text, {
28
+ bold: true,
29
+ children: "NAME"
30
+ })
31
+ }), /* @__PURE__ */ jsx(Text, {
32
+ bold: true,
33
+ children: "DESCRIPTION"
34
+ })] }),
35
+ /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Box, {
36
+ width: 25,
37
+ children: /* @__PURE__ */ jsx(Text, {
38
+ dimColor: true,
39
+ children: `─`.repeat(23)
40
+ })
41
+ }), /* @__PURE__ */ jsx(Text, {
42
+ dimColor: true,
43
+ children: `─`.repeat(40)
44
+ })] }),
45
+ serverTypes.map((t) => /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Box, {
46
+ width: 25,
47
+ flexShrink: 0,
48
+ children: /* @__PURE__ */ jsx(Text, { children: t.name })
49
+ }), /* @__PURE__ */ jsx(Box, {
50
+ flexGrow: 1,
51
+ children: /* @__PURE__ */ jsx(Text, {
52
+ wrap: "wrap",
53
+ children: t.description
54
+ })
55
+ })] }, t.name))
56
+ ]
57
+ }, server))
58
+ });
59
+ }
60
+ function renderTypesTable(types) {
61
+ console.log(renderToString(/* @__PURE__ */ jsx(TypesTable, { types })));
62
+ }
63
+
64
+ //#endregion
65
+ export { renderTypesTable };
@@ -24,7 +24,7 @@ services:
24
24
  timeout: 5s
25
25
  retries: 30
26
26
  volumes:
27
- - electric-agents-postgres-data:/var/lib/postgresql/data
27
+ - electric-agents-postgres-data:/var/lib/postgresql
28
28
 
29
29
  electric:
30
30
  image: electricsql/electric:latest
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electric-ax",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "CLI for Electric Agents",
5
5
  "author": "ElectricSQL team and contributors",
6
6
  "license": "Apache-2.0",