@matthias-hausberger/beige 0.2.1-beta1 → 1.0.0-beta3
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/config.schema.json +23 -83
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +185 -87
- package/dist/cli.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +9 -49
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +18 -61
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +46 -71
- package/dist/config/schema.js.map +1 -1
- package/dist/gateway/agent-manager.d.ts +76 -5
- package/dist/gateway/agent-manager.d.ts.map +1 -1
- package/dist/gateway/agent-manager.js +400 -46
- package/dist/gateway/agent-manager.js.map +1 -1
- package/dist/gateway/api.d.ts +2 -2
- package/dist/gateway/api.d.ts.map +1 -1
- package/dist/gateway/api.js +24 -2
- package/dist/gateway/api.js.map +1 -1
- package/dist/gateway/error-logger.d.ts +52 -0
- package/dist/gateway/error-logger.d.ts.map +1 -0
- package/dist/gateway/error-logger.js +213 -0
- package/dist/gateway/error-logger.js.map +1 -0
- package/dist/gateway/gateway.d.ts +4 -5
- package/dist/gateway/gateway.d.ts.map +1 -1
- package/dist/gateway/gateway.js +74 -44
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/llm-errors.d.ts +54 -0
- package/dist/gateway/llm-errors.d.ts.map +1 -0
- package/dist/gateway/llm-errors.js +208 -0
- package/dist/gateway/llm-errors.js.map +1 -0
- package/dist/gateway/policy.d.ts +2 -1
- package/dist/gateway/policy.d.ts.map +1 -1
- package/dist/gateway/policy.js +12 -3
- package/dist/gateway/policy.js.map +1 -1
- package/dist/gateway/sessions.d.ts +7 -5
- package/dist/gateway/sessions.d.ts.map +1 -1
- package/dist/gateway/sessions.js +13 -7
- package/dist/gateway/sessions.js.map +1 -1
- package/dist/gateway/system-prompt.template.md +7 -5
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +2 -3
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +14 -65
- package/dist/install.js.map +1 -1
- package/dist/plugins/context.d.ts +31 -0
- package/dist/plugins/context.d.ts.map +1 -0
- package/dist/plugins/context.js +222 -0
- package/dist/plugins/context.js.map +1 -0
- package/dist/plugins/index.d.ts +10 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +7 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/installer.d.ts +80 -0
- package/dist/plugins/installer.d.ts.map +1 -0
- package/dist/{tools → plugins}/installer.js +231 -278
- package/dist/plugins/installer.js.map +1 -0
- package/dist/plugins/loader.d.ts +41 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +136 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/registry.d.ts +40 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +171 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/types.d.ts +455 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +15 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/sandbox/manager.d.ts +5 -26
- package/dist/sandbox/manager.d.ts.map +1 -1
- package/dist/sandbox/manager.js +32 -53
- package/dist/sandbox/manager.js.map +1 -1
- package/dist/socket/protocol.d.ts +2 -0
- package/dist/socket/protocol.d.ts.map +1 -1
- package/dist/socket/protocol.js.map +1 -1
- package/dist/socket/server.d.ts +3 -1
- package/dist/socket/server.d.ts.map +1 -1
- package/dist/socket/server.js +5 -1
- package/dist/socket/server.js.map +1 -1
- package/dist/test/fixtures.d.ts +9 -7
- package/dist/test/fixtures.d.ts.map +1 -1
- package/dist/test/fixtures.js +17 -29
- package/dist/test/fixtures.js.map +1 -1
- package/dist/tools/runner.d.ts +26 -27
- package/dist/tools/runner.d.ts.map +1 -1
- package/dist/tools/runner.js +114 -11
- package/dist/tools/runner.js.map +1 -1
- package/dist/types/session.d.ts +17 -0
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js +10 -14
- package/dist/types/session.js.map +1 -1
- package/package.json +2 -4
- package/sandbox/Dockerfile +6 -0
- package/sandbox/tool-client.ts +19 -0
- package/dist/channels/registry.d.ts +0 -14
- package/dist/channels/registry.d.ts.map +0 -1
- package/dist/channels/registry.js +0 -14
- package/dist/channels/registry.js.map +0 -1
- package/dist/channels/telegram.d.ts +0 -92
- package/dist/channels/telegram.d.ts.map +0 -1
- package/dist/channels/telegram.js +0 -469
- package/dist/channels/telegram.js.map +0 -1
- package/dist/tools/installer.d.ts +0 -93
- package/dist/tools/installer.d.ts.map +0 -1
- package/dist/tools/installer.js.map +0 -1
- package/dist/tools/registry.d.ts +0 -20
- package/dist/tools/registry.d.ts.map +0 -1
- package/dist/tools/registry.js +0 -124
- package/dist/tools/registry.js.map +0 -1
- package/tools/README.md +0 -1
- package/tools/kv/README.md +0 -150
- package/tools/kv/index.ts +0 -154
- package/tools/kv/tool.json +0 -23
- package/tools/message/README.md +0 -53
- package/tools/message/index.ts +0 -183
- package/tools/message/tool.json +0 -11
package/config.schema.json
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
"type": "object",
|
|
6
6
|
"required": [
|
|
7
7
|
"llm",
|
|
8
|
-
"tools",
|
|
9
8
|
"agents"
|
|
10
9
|
],
|
|
11
10
|
"properties": {
|
|
@@ -59,37 +58,28 @@
|
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
},
|
|
62
|
-
"
|
|
63
|
-
"description": "
|
|
61
|
+
"plugins": {
|
|
62
|
+
"description": "Plugin registry. Each key becomes the plugin name. Plugins can provide tools, channels, hooks, and skills.",
|
|
64
63
|
"type": "object",
|
|
65
64
|
"patternProperties": {
|
|
66
65
|
"^(.*)$": {
|
|
67
|
-
"title": "
|
|
66
|
+
"title": "PluginConfig",
|
|
68
67
|
"type": "object",
|
|
69
68
|
"properties": {
|
|
70
69
|
"path": {
|
|
71
|
-
"description": "Path to the
|
|
70
|
+
"description": "Path to the plugin package directory. Resolved relative to the config file unless absolute.",
|
|
72
71
|
"type": "string"
|
|
73
72
|
},
|
|
74
|
-
"target": {
|
|
75
|
-
"description": "\"gateway\" runs the handler on the host process. \"sandbox\" is planned. Auto-resolved for tools installed via 'beige tools install'.",
|
|
76
|
-
"anyOf": [
|
|
77
|
-
{
|
|
78
|
-
"const": "gateway",
|
|
79
|
-
"type": "string"
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"const": "sandbox",
|
|
83
|
-
"type": "string"
|
|
84
|
-
}
|
|
85
|
-
]
|
|
86
|
-
},
|
|
87
73
|
"config": {
|
|
88
|
-
"description": "Arbitrary config object passed to
|
|
74
|
+
"description": "Arbitrary config object passed to createPlugin(config, ctx) at startup",
|
|
89
75
|
"type": "object",
|
|
90
76
|
"patternProperties": {
|
|
91
77
|
"^(.*)$": {}
|
|
92
78
|
}
|
|
79
|
+
},
|
|
80
|
+
"_source": {
|
|
81
|
+
"description": "Install source (e.g. 'npm:@scope/package'). Written by 'beige plugins install', used by 'beige plugins update'. Do not edit manually.",
|
|
82
|
+
"type": "string"
|
|
93
83
|
}
|
|
94
84
|
}
|
|
95
85
|
}
|
|
@@ -166,6 +156,11 @@
|
|
|
166
156
|
"type": "string"
|
|
167
157
|
}
|
|
168
158
|
]
|
|
159
|
+
},
|
|
160
|
+
"compactionThreshold": {
|
|
161
|
+
"description": "Context token count at which auto-compaction triggers for this model. Must be less than the model's context window. When set, compaction kicks in earlier than the default (contextWindow − 16384 tokens). Example: set to 100000 on a 200k-window model to compact at 100k tokens.",
|
|
162
|
+
"minimum": 1,
|
|
163
|
+
"type": "number"
|
|
169
164
|
}
|
|
170
165
|
}
|
|
171
166
|
},
|
|
@@ -212,19 +207,24 @@
|
|
|
212
207
|
"type": "string"
|
|
213
208
|
}
|
|
214
209
|
]
|
|
210
|
+
},
|
|
211
|
+
"compactionThreshold": {
|
|
212
|
+
"description": "Context token count at which auto-compaction triggers for this model. Must be less than the model's context window. When set, compaction kicks in earlier than the default (contextWindow − 16384 tokens). Example: set to 100000 on a 200k-window model to compact at 100k tokens.",
|
|
213
|
+
"minimum": 1,
|
|
214
|
+
"type": "number"
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
},
|
|
219
219
|
"tools": {
|
|
220
|
-
"description": "Tool names
|
|
220
|
+
"description": "Tool names registered by plugins that this agent can invoke",
|
|
221
221
|
"type": "array",
|
|
222
222
|
"items": {
|
|
223
223
|
"type": "string"
|
|
224
224
|
}
|
|
225
225
|
},
|
|
226
226
|
"skills": {
|
|
227
|
-
"description": "Skill names from
|
|
227
|
+
"description": "Skill names (from skills registry or plugin-registered) mounted into this agent's sandbox",
|
|
228
228
|
"type": "array",
|
|
229
229
|
"items": {
|
|
230
230
|
"type": "string"
|
|
@@ -262,8 +262,8 @@
|
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
264
|
},
|
|
265
|
-
"
|
|
266
|
-
"description": "Per-agent
|
|
265
|
+
"pluginConfigs": {
|
|
266
|
+
"description": "Per-agent plugin config overrides. Keys must reference plugins in the plugins registry. Values are deep-merged with the top-level plugin config from config.plugins.<name>.config.",
|
|
267
267
|
"type": "object",
|
|
268
268
|
"patternProperties": {
|
|
269
269
|
"^(.*)$": {
|
|
@@ -295,66 +295,6 @@
|
|
|
295
295
|
"type": "string"
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
|
-
},
|
|
299
|
-
"channels": {
|
|
300
|
-
"title": "ChannelsConfig",
|
|
301
|
-
"type": "object",
|
|
302
|
-
"properties": {
|
|
303
|
-
"telegram": {
|
|
304
|
-
"title": "TelegramChannelConfig",
|
|
305
|
-
"type": "object",
|
|
306
|
-
"required": [
|
|
307
|
-
"enabled",
|
|
308
|
-
"token",
|
|
309
|
-
"allowedUsers",
|
|
310
|
-
"agentMapping"
|
|
311
|
-
],
|
|
312
|
-
"properties": {
|
|
313
|
-
"enabled": {
|
|
314
|
-
"description": "Set to true to activate the Telegram bot",
|
|
315
|
-
"type": "boolean"
|
|
316
|
-
},
|
|
317
|
-
"token": {
|
|
318
|
-
"description": "Telegram bot token from @BotFather. Use \"${TELEGRAM_BOT_TOKEN}\".",
|
|
319
|
-
"type": "string"
|
|
320
|
-
},
|
|
321
|
-
"allowedUsers": {
|
|
322
|
-
"description": "Telegram user IDs permitted to interact with the bot. All others are silently ignored.",
|
|
323
|
-
"type": "array",
|
|
324
|
-
"items": {
|
|
325
|
-
"type": "number"
|
|
326
|
-
}
|
|
327
|
-
},
|
|
328
|
-
"agentMapping": {
|
|
329
|
-
"description": "Maps Telegram chats to agents",
|
|
330
|
-
"type": "object",
|
|
331
|
-
"required": [
|
|
332
|
-
"default"
|
|
333
|
-
],
|
|
334
|
-
"properties": {
|
|
335
|
-
"default": {
|
|
336
|
-
"description": "Agent name that handles all incoming messages",
|
|
337
|
-
"type": "string"
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
},
|
|
341
|
-
"defaults": {
|
|
342
|
-
"title": "ChannelDefaultSettings",
|
|
343
|
-
"type": "object",
|
|
344
|
-
"properties": {
|
|
345
|
-
"verbose": {
|
|
346
|
-
"description": "Send a notification for every tool call the agent makes (e.g. 🔧 exec: ls). Default: false",
|
|
347
|
-
"type": "boolean"
|
|
348
|
-
},
|
|
349
|
-
"streaming": {
|
|
350
|
-
"description": "Stream responses to the user in real-time. Default: true",
|
|
351
|
-
"type": "boolean"
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
298
|
}
|
|
359
299
|
}
|
|
360
300
|
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* beige gateway logs Show gateway logs
|
|
13
13
|
* beige gateway logs -f Follow gateway logs (tail -f)
|
|
14
14
|
* beige tui [agent] Connect to a running gateway via TUI
|
|
15
|
-
* beige
|
|
15
|
+
* beige plugins <command> Manage plugins (install, list, update, remove)
|
|
16
16
|
* beige --config <path> Use a specific config file
|
|
17
17
|
*
|
|
18
18
|
* Shell 1: beige ← starts gateway daemon
|
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* beige gateway logs Show gateway logs
|
|
13
13
|
* beige gateway logs -f Follow gateway logs (tail -f)
|
|
14
14
|
* beige tui [agent] Connect to a running gateway via TUI
|
|
15
|
-
* beige
|
|
15
|
+
* beige plugins <command> Manage plugins (install, list, update, remove)
|
|
16
16
|
* beige --config <path> Use a specific config file
|
|
17
17
|
*
|
|
18
18
|
* Shell 1: beige ← starts gateway daemon
|
|
@@ -24,7 +24,7 @@ import { spawn } from "child_process";
|
|
|
24
24
|
import { watch } from "fs";
|
|
25
25
|
import { runSetup } from "./install.js";
|
|
26
26
|
import { beigeDir } from "./paths.js";
|
|
27
|
-
import {
|
|
27
|
+
import { installPlugins, removePlugin, updatePlugin, updateAllPlugins, listPluginsFromConfig, } from "./plugins/installer.js";
|
|
28
28
|
// ── Timestamp helpers ────────────────────────────────────────────────
|
|
29
29
|
/** Returns a local-time HH:MM:SS prefix, e.g. "14:03:07". */
|
|
30
30
|
function timestampPrefix() {
|
|
@@ -34,6 +34,8 @@ function timestampPrefix() {
|
|
|
34
34
|
const ss = String(d.getSeconds()).padStart(2, "0");
|
|
35
35
|
return `${hh}:${mm}:${ss}`;
|
|
36
36
|
}
|
|
37
|
+
// Save original stderr.write before wrapping (for immediate flush on shutdown)
|
|
38
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
37
39
|
/**
|
|
38
40
|
* Wraps process.stdout.write / process.stderr.write so that every line
|
|
39
41
|
* written by the gateway process is prefixed with an HH:MM:SS timestamp.
|
|
@@ -300,13 +302,40 @@ async function cmdGatewayStart(configPath, foreground, timeoutMs) {
|
|
|
300
302
|
const config = loadConfig(configPath);
|
|
301
303
|
const { Gateway } = await import("./gateway/gateway.js");
|
|
302
304
|
const gateway = new Gateway(config, configPath);
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
305
|
+
let isShuttingDown = false;
|
|
306
|
+
const shutdown = async (signal) => {
|
|
307
|
+
// Prevent duplicate shutdowns
|
|
308
|
+
if (isShuttingDown)
|
|
309
|
+
return;
|
|
310
|
+
isShuttingDown = true;
|
|
311
|
+
// Use original stderr.write to bypass timestamp buffering for immediate feedback
|
|
312
|
+
originalStderrWrite(`\n[BEIGE] Received ${signal} - Shutting down...\n`);
|
|
313
|
+
// Force exit after 10 seconds if shutdown hangs
|
|
314
|
+
const timeout = setTimeout(() => {
|
|
315
|
+
originalStderrWrite("[BEIGE] Shutdown timed out, forcing exit...\n");
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}, 10000);
|
|
318
|
+
try {
|
|
319
|
+
await gateway.stop();
|
|
320
|
+
clearTimeout(timeout);
|
|
321
|
+
originalStderrWrite("[BEIGE] Shutdown complete\n");
|
|
322
|
+
process.exit(0);
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
clearTimeout(timeout);
|
|
326
|
+
originalStderrWrite(`[BEIGE] Shutdown error: ${err.message}\n`);
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|
|
307
329
|
};
|
|
308
|
-
|
|
309
|
-
|
|
330
|
+
// Log that signal handlers are being registered (helps debug signal issues)
|
|
331
|
+
originalStderrWrite("[BEIGE] Registering signal handlers...\n");
|
|
332
|
+
// Register handlers with explicit listener count check
|
|
333
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
334
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
335
|
+
// Verify handlers are registered
|
|
336
|
+
const sigintListeners = process.listenerCount("SIGINT");
|
|
337
|
+
const sigtermListeners = process.listenerCount("SIGTERM");
|
|
338
|
+
originalStderrWrite(`[BEIGE] Signal handlers registered (SIGINT: ${sigintListeners}, SIGTERM: ${sigtermListeners})\n`);
|
|
310
339
|
// SIGHUP → graceful in-place restart (reload config, recreate sandboxes)
|
|
311
340
|
process.on("SIGHUP", () => {
|
|
312
341
|
console.log("[BEIGE] Received SIGHUP — restarting gateway...");
|
|
@@ -341,27 +370,84 @@ function cmdGatewayStop() {
|
|
|
341
370
|
process.exit(1);
|
|
342
371
|
}
|
|
343
372
|
}
|
|
344
|
-
function cmdGatewayRestart() {
|
|
373
|
+
async function cmdGatewayRestart(configPath, timeoutMs) {
|
|
345
374
|
const pid = readPid();
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
console.log("[BEIGE]
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if (!isRunning(pid)) {
|
|
352
|
-
console.log(`[BEIGE] Gateway (PID ${pid}) is not running`);
|
|
353
|
-
console.log("[BEIGE] Run 'beige gateway start' to start it");
|
|
354
|
-
process.exit(1);
|
|
375
|
+
// If not running, just start it
|
|
376
|
+
if (pid === null || !isRunning(pid)) {
|
|
377
|
+
console.log("[BEIGE] Gateway is not running — starting it...");
|
|
378
|
+
await cmdGatewayStart(configPath, false, timeoutMs);
|
|
379
|
+
return;
|
|
355
380
|
}
|
|
381
|
+
// Gateway is running — perform graceful restart
|
|
382
|
+
console.log(`[BEIGE] Restarting gateway (PID ${pid})...`);
|
|
383
|
+
const { loadConfig } = await import("./config/loader.js");
|
|
384
|
+
const config = loadConfig(configPath);
|
|
385
|
+
const port = config.gateway?.port ?? 7433;
|
|
386
|
+
const host = config.gateway?.host ?? "127.0.0.1";
|
|
387
|
+
const healthUrl = `http://${host}:${port}/api/health`;
|
|
388
|
+
// Send SIGHUP to trigger restart
|
|
356
389
|
try {
|
|
357
390
|
process.kill(pid, "SIGHUP");
|
|
358
|
-
console.log(`[BEIGE] Sent SIGHUP to gateway (PID ${pid}) — graceful restart initiated`);
|
|
359
|
-
console.log(`[BEIGE] Follow progress with: beige gateway logs -f`);
|
|
360
391
|
}
|
|
361
392
|
catch (err) {
|
|
362
393
|
console.error(`[BEIGE] Failed to signal gateway (PID ${pid}):`, err);
|
|
363
394
|
process.exit(1);
|
|
364
395
|
}
|
|
396
|
+
// Wait for restart to complete
|
|
397
|
+
const success = await waitForGatewayRestart(pid, healthUrl, timeoutMs);
|
|
398
|
+
if (success) {
|
|
399
|
+
console.log(`[BEIGE] Gateway restarted successfully`);
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
console.error(`[BEIGE] Gateway restart timed out after ${timeoutMs / 1000}s`);
|
|
403
|
+
console.error(`[BEIGE] Check logs: ${getLogFile()}`);
|
|
404
|
+
process.exit(1);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Wait for gateway restart to complete.
|
|
409
|
+
*
|
|
410
|
+
* The restart cycle is: healthy → unhealthy (teardown) → healthy (startup)
|
|
411
|
+
* We need to see it go from healthy to unhealthy and back to healthy.
|
|
412
|
+
*/
|
|
413
|
+
async function waitForGatewayRestart(childPid, healthUrl, timeoutMs) {
|
|
414
|
+
const startTime = Date.now();
|
|
415
|
+
const pollIntervalMs = 500;
|
|
416
|
+
let seenHealthy = false;
|
|
417
|
+
let seenUnhealthy = false;
|
|
418
|
+
const checkHealth = async () => {
|
|
419
|
+
try {
|
|
420
|
+
const res = await fetch(healthUrl, { method: "GET", signal: AbortSignal.timeout(2000) });
|
|
421
|
+
return res.ok;
|
|
422
|
+
}
|
|
423
|
+
catch {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
428
|
+
// Check if child process exited unexpectedly
|
|
429
|
+
if (!isRunning(childPid)) {
|
|
430
|
+
console.log("[BEIGE] Gateway process exited during restart");
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
const healthy = await checkHealth();
|
|
434
|
+
if (healthy) {
|
|
435
|
+
if (seenUnhealthy) {
|
|
436
|
+
// We saw it go down and come back up - restart complete!
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
seenHealthy = true;
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
if (seenHealthy) {
|
|
443
|
+
// We saw it go down after being up - restart in progress
|
|
444
|
+
seenUnhealthy = true;
|
|
445
|
+
console.log("[BEIGE] Gateway tearing down...");
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
449
|
+
}
|
|
450
|
+
return false;
|
|
365
451
|
}
|
|
366
452
|
function cmdGatewayStatus() {
|
|
367
453
|
const pid = readPid();
|
|
@@ -419,7 +505,7 @@ Usage:
|
|
|
419
505
|
beige setup First-time setup (copies tools, writes default config)
|
|
420
506
|
beige gateway <command> Manage the gateway daemon
|
|
421
507
|
beige tui [agent] Connect TUI to running gateway
|
|
422
|
-
beige
|
|
508
|
+
beige plugins <command> Manage plugins (install, list, update, remove)
|
|
423
509
|
|
|
424
510
|
Options:
|
|
425
511
|
-c, --config <path> Config file (default: ~/.beige/config.json5)
|
|
@@ -428,26 +514,26 @@ Options:
|
|
|
428
514
|
-h, --help Show this help
|
|
429
515
|
|
|
430
516
|
Run 'beige gateway' for gateway-specific commands.
|
|
431
|
-
Run 'beige
|
|
517
|
+
Run 'beige plugins' for plugin management commands.
|
|
432
518
|
`);
|
|
433
519
|
}
|
|
434
|
-
function
|
|
520
|
+
function printPluginsHelp() {
|
|
435
521
|
console.log(`
|
|
436
|
-
Beige —
|
|
522
|
+
Beige — Plugin commands
|
|
437
523
|
|
|
438
524
|
Usage:
|
|
439
|
-
beige
|
|
440
|
-
beige
|
|
441
|
-
beige
|
|
442
|
-
beige
|
|
525
|
+
beige plugins install <source> Install plugins from a source
|
|
526
|
+
beige plugins list List installed plugins
|
|
527
|
+
beige plugins remove <name> Remove an installed plugin
|
|
528
|
+
beige plugins update [name] Update a plugin (or all plugins)
|
|
443
529
|
|
|
444
530
|
Install sources:
|
|
445
531
|
npm:@scope/package NPM package (latest)
|
|
446
532
|
npm:@scope/package@1.2.3 NPM package (specific version)
|
|
447
|
-
github:owner/repo GitHub repository (all
|
|
448
|
-
github:owner/repo/path/to/
|
|
533
|
+
github:owner/repo GitHub repository (all plugins)
|
|
534
|
+
github:owner/repo/path/to/plugin Single plugin from a GitHub subfolder
|
|
449
535
|
github:owner/repo#tag GitHub repository at a tag/branch
|
|
450
|
-
./path/to/
|
|
536
|
+
./path/to/plugin Local directory
|
|
451
537
|
|
|
452
538
|
Options:
|
|
453
539
|
--force, -f Force install even with conflicts
|
|
@@ -462,14 +548,14 @@ Usage:
|
|
|
462
548
|
beige gateway start Start the gateway daemon
|
|
463
549
|
beige gateway start --foreground Start the gateway in the foreground
|
|
464
550
|
beige gateway stop Stop the gateway daemon
|
|
465
|
-
beige gateway restart Gracefully restart the gateway (
|
|
551
|
+
beige gateway restart Gracefully restart the gateway (or start if not running)
|
|
466
552
|
beige gateway status Show gateway daemon status
|
|
467
553
|
beige gateway logs Show gateway logs
|
|
468
554
|
beige gateway logs -f Follow gateway logs
|
|
469
555
|
|
|
470
556
|
Options:
|
|
471
557
|
-c, --config <path> Config file (default: ~/.beige/config.json5)
|
|
472
|
-
--timeout <seconds> Startup wait timeout in seconds (default: 60, 0 = indefinite)
|
|
558
|
+
--timeout <seconds> Startup/restart wait timeout in seconds (default: 60, 0 = indefinite)
|
|
473
559
|
-h, --help Show this help
|
|
474
560
|
`);
|
|
475
561
|
}
|
|
@@ -527,8 +613,21 @@ function parseArgs() {
|
|
|
527
613
|
}
|
|
528
614
|
if (sub === "stop")
|
|
529
615
|
return { kind: "gateway-stop" };
|
|
530
|
-
if (sub === "restart")
|
|
531
|
-
|
|
616
|
+
if (sub === "restart") {
|
|
617
|
+
let timeoutMs = 60000;
|
|
618
|
+
const timeoutIdx = rest.findIndex((a) => a.startsWith("--timeout"));
|
|
619
|
+
if (timeoutIdx !== -1) {
|
|
620
|
+
const arg = rest[timeoutIdx];
|
|
621
|
+
const raw = arg.includes("=") ? arg.split("=")[1] : rest[timeoutIdx + 1];
|
|
622
|
+
const parsed = Number(raw);
|
|
623
|
+
if (isNaN(parsed) || parsed < 0) {
|
|
624
|
+
console.error(`[BEIGE] Invalid --timeout value: ${raw}. Must be a non-negative number (0 = indefinite).`);
|
|
625
|
+
process.exit(1);
|
|
626
|
+
}
|
|
627
|
+
timeoutMs = parsed * 1000;
|
|
628
|
+
}
|
|
629
|
+
return { kind: "gateway-restart", timeoutMs };
|
|
630
|
+
}
|
|
532
631
|
if (sub === "status")
|
|
533
632
|
return { kind: "gateway-status" };
|
|
534
633
|
if (sub === "logs") {
|
|
@@ -546,37 +645,37 @@ function parseArgs() {
|
|
|
546
645
|
const force = args.includes("--force") || args.includes("-f");
|
|
547
646
|
return { kind: "setup", force };
|
|
548
647
|
}
|
|
549
|
-
if (cmd === "
|
|
648
|
+
if (cmd === "plugins") {
|
|
550
649
|
if (!sub || sub === "--help" || sub === "-h") {
|
|
551
|
-
|
|
650
|
+
printPluginsHelp();
|
|
552
651
|
process.exit(0);
|
|
553
652
|
}
|
|
554
653
|
if (sub === "install") {
|
|
555
654
|
const source = rest[0];
|
|
556
655
|
if (!source || source === "--help" || source === "-h") {
|
|
557
|
-
|
|
656
|
+
printPluginsHelp();
|
|
558
657
|
process.exit(source === "--help" || source === "-h" ? 0 : 1);
|
|
559
658
|
}
|
|
560
659
|
const force = rest.includes("--force") || rest.includes("-f");
|
|
561
660
|
return { kind: "install", source, force };
|
|
562
661
|
}
|
|
563
662
|
if (sub === "list") {
|
|
564
|
-
return { kind: "
|
|
663
|
+
return { kind: "plugins-list" };
|
|
565
664
|
}
|
|
566
665
|
if (sub === "remove") {
|
|
567
666
|
const name = rest[0];
|
|
568
667
|
if (!name) {
|
|
569
|
-
console.error("[BEIGE] Missing
|
|
668
|
+
console.error("[BEIGE] Missing plugin name. Usage: beige plugins remove <name>");
|
|
570
669
|
process.exit(1);
|
|
571
670
|
}
|
|
572
|
-
return { kind: "
|
|
671
|
+
return { kind: "plugins-remove", name };
|
|
573
672
|
}
|
|
574
673
|
if (sub === "update") {
|
|
575
|
-
const name = rest[0];
|
|
576
|
-
return { kind: "
|
|
674
|
+
const name = rest[0];
|
|
675
|
+
return { kind: "plugins-update", name };
|
|
577
676
|
}
|
|
578
|
-
console.error(`[BEIGE] Unknown
|
|
579
|
-
|
|
677
|
+
console.error(`[BEIGE] Unknown plugins subcommand: ${sub}`);
|
|
678
|
+
printPluginsHelp();
|
|
580
679
|
process.exit(1);
|
|
581
680
|
}
|
|
582
681
|
console.error(`[BEIGE] Unknown command: ${cmd}`);
|
|
@@ -602,7 +701,7 @@ else if (mode.kind === "gateway-stop") {
|
|
|
602
701
|
cmdGatewayStop();
|
|
603
702
|
}
|
|
604
703
|
else if (mode.kind === "gateway-restart") {
|
|
605
|
-
cmdGatewayRestart();
|
|
704
|
+
await cmdGatewayRestart(configPath, mode.timeoutMs);
|
|
606
705
|
}
|
|
607
706
|
else if (mode.kind === "gateway-status") {
|
|
608
707
|
cmdGatewayStatus();
|
|
@@ -645,21 +744,21 @@ else if (mode.kind === "tui") {
|
|
|
645
744
|
else if (mode.kind === "install") {
|
|
646
745
|
await cmdInstall(mode.source, mode.force);
|
|
647
746
|
}
|
|
648
|
-
else if (mode.kind === "
|
|
649
|
-
|
|
747
|
+
else if (mode.kind === "plugins-list") {
|
|
748
|
+
cmdPluginsList();
|
|
650
749
|
}
|
|
651
|
-
else if (mode.kind === "
|
|
652
|
-
|
|
750
|
+
else if (mode.kind === "plugins-remove") {
|
|
751
|
+
cmdPluginsRemove(mode.name);
|
|
653
752
|
}
|
|
654
|
-
else if (mode.kind === "
|
|
655
|
-
await
|
|
753
|
+
else if (mode.kind === "plugins-update") {
|
|
754
|
+
await cmdPluginsUpdate(mode.name);
|
|
656
755
|
}
|
|
657
756
|
async function cmdInstall(source, force) {
|
|
658
757
|
console.log(`[BEIGE] Installing from: ${source}`);
|
|
659
|
-
const result = await
|
|
758
|
+
const result = await installPlugins(source, { force });
|
|
660
759
|
if (!result.success) {
|
|
661
760
|
if (result.conflicts && result.conflicts.length > 0) {
|
|
662
|
-
console.error("[BEIGE]
|
|
761
|
+
console.error("[BEIGE] Plugin name conflicts detected:");
|
|
663
762
|
for (const conflict of result.conflicts) {
|
|
664
763
|
console.error(` - ${conflict}`);
|
|
665
764
|
}
|
|
@@ -670,48 +769,48 @@ async function cmdInstall(source, force) {
|
|
|
670
769
|
}
|
|
671
770
|
process.exit(1);
|
|
672
771
|
}
|
|
673
|
-
if (result.
|
|
674
|
-
console.log(`[BEIGE] Installed ${result.
|
|
675
|
-
for (const
|
|
676
|
-
console.log(` - ${
|
|
772
|
+
if (result.plugins && result.plugins.length > 0) {
|
|
773
|
+
console.log(`[BEIGE] Installed ${result.plugins.length} plugin(s) and added to config.json5:`);
|
|
774
|
+
for (const plugin of result.plugins) {
|
|
775
|
+
console.log(` - ${plugin.name}: ${plugin.manifest.description}`);
|
|
677
776
|
}
|
|
678
|
-
console.log(`\n[BEIGE] Add tools to your agent's 'tools' array
|
|
777
|
+
console.log(`\n[BEIGE] Add plugin tools to your agent's 'tools' array and restart the gateway.`);
|
|
778
|
+
console.log(`[BEIGE] Review config.json5 to fill in any required config values (e.g. API keys).`);
|
|
679
779
|
}
|
|
680
780
|
}
|
|
681
|
-
function
|
|
682
|
-
const
|
|
683
|
-
if (
|
|
684
|
-
console.log("[BEIGE] No
|
|
685
|
-
console.log("\n[BEIGE] Install
|
|
781
|
+
function cmdPluginsList() {
|
|
782
|
+
const plugins = listPluginsFromConfig();
|
|
783
|
+
if (plugins.length === 0) {
|
|
784
|
+
console.log("[BEIGE] No plugins in config.");
|
|
785
|
+
console.log("\n[BEIGE] Install plugins with: beige plugins install <source>");
|
|
686
786
|
return;
|
|
687
787
|
}
|
|
688
|
-
console.log("[BEIGE]
|
|
689
|
-
for (const
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
if (
|
|
696
|
-
console.log(`
|
|
697
|
-
}
|
|
788
|
+
console.log("[BEIGE] Plugins in config.json5:\n");
|
|
789
|
+
for (const plugin of plugins) {
|
|
790
|
+
console.log(` ${plugin.name}`);
|
|
791
|
+
if (plugin.path)
|
|
792
|
+
console.log(` Path: ${plugin.path}`);
|
|
793
|
+
if (plugin.source)
|
|
794
|
+
console.log(` Source: ${plugin.source}`);
|
|
795
|
+
if (plugin.hasConfig)
|
|
796
|
+
console.log(` Config: ✓ (has config values)`);
|
|
698
797
|
console.log();
|
|
699
798
|
}
|
|
700
799
|
}
|
|
701
|
-
function
|
|
702
|
-
const result =
|
|
800
|
+
function cmdPluginsRemove(name) {
|
|
801
|
+
const result = removePlugin(name);
|
|
703
802
|
if (!result.success) {
|
|
704
803
|
console.error(`[BEIGE] ${result.error}`);
|
|
705
804
|
process.exit(1);
|
|
706
805
|
}
|
|
707
|
-
console.log(`[BEIGE] Removed
|
|
806
|
+
console.log(`[BEIGE] Removed plugin '${name}' from config.json5 and disk.`);
|
|
708
807
|
}
|
|
709
|
-
async function
|
|
808
|
+
async function cmdPluginsUpdate(name) {
|
|
710
809
|
if (name) {
|
|
711
|
-
console.log(`[BEIGE] Updating
|
|
712
|
-
const result = await
|
|
810
|
+
console.log(`[BEIGE] Updating plugin: ${name}`);
|
|
811
|
+
const result = await updatePlugin(name);
|
|
713
812
|
if (result.success) {
|
|
714
|
-
console.log(`[BEIGE] Updated ${result.
|
|
813
|
+
console.log(`[BEIGE] Updated ${result.plugins?.length ?? 0} plugin(s) from same source.`);
|
|
715
814
|
}
|
|
716
815
|
else {
|
|
717
816
|
console.error(`[BEIGE] Failed to update: ${result.error}`);
|
|
@@ -719,14 +818,13 @@ async function cmdToolsUpdate(name) {
|
|
|
719
818
|
}
|
|
720
819
|
return;
|
|
721
820
|
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
console.log("[BEIGE] No tools installed.");
|
|
821
|
+
const plugins = listPluginsFromConfig();
|
|
822
|
+
if (plugins.length === 0) {
|
|
823
|
+
console.log("[BEIGE] No plugins in config.");
|
|
726
824
|
return;
|
|
727
825
|
}
|
|
728
|
-
console.log(`[BEIGE] Updating all
|
|
729
|
-
const result = await
|
|
826
|
+
console.log(`[BEIGE] Updating all plugins with _source...\n`);
|
|
827
|
+
const result = await updateAllPlugins();
|
|
730
828
|
console.log(`\n[BEIGE] Update complete: ${result.updated.length} updated, ${result.failed.length} failed.`);
|
|
731
829
|
for (const f of result.failed) {
|
|
732
830
|
console.error(` Failed: ${f.source} — ${f.error}`);
|