volute 0.4.0 → 0.6.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.
- package/README.md +22 -22
- package/dist/agent-X7GJLBLW.js +79 -0
- package/dist/{agent-manager-AUCKMGPR.js → agent-manager-JDVXU3ON.js} +4 -4
- package/dist/channel-SMCNOIVQ.js +262 -0
- package/dist/chunk-AOKAQGO4.js +107 -0
- package/dist/{chunk-VRVVQIYY.js → chunk-AZEL2IEK.js} +1 -1
- package/dist/chunk-B3R6L2GW.js +24 -0
- package/dist/{chunk-MXUCNIBG.js → chunk-BX7KI4S3.js} +68 -3
- package/dist/{chunk-I6OHXCMV.js → chunk-G6ZNGLUX.js} +47 -9
- package/dist/{chunk-DNOXHLE5.js → chunk-H7AMDUIA.js} +1 -1
- package/dist/{chunk-YGFIWIOF.js → chunk-JR4UXCTO.js} +1 -1
- package/dist/{chunk-3C2XR4IY.js → chunk-UWHWAPGO.js} +120 -107
- package/dist/{chunk-SOZA2TLP.js → chunk-W76KWE23.js} +1 -1
- package/dist/{chunk-GSPKUPKU.js → chunk-XUA3JUFK.js} +2 -1
- package/dist/chunk-ZYGKG6VC.js +22 -0
- package/dist/chunk-ZZOOTYXK.js +583 -0
- package/dist/cli.js +83 -74
- package/dist/{connector-DKDJTLYZ.js → connector-Y7JPNROO.js} +11 -6
- package/dist/connectors/discord.js +34 -5
- package/dist/connectors/slack.js +36 -8
- package/dist/connectors/telegram.js +55 -6
- package/dist/create-G525LWEA.js +91 -0
- package/dist/{daemon-client-XR24PUJF.js → daemon-client-442IV43D.js} +2 -2
- package/dist/daemon.js +1273 -384
- package/dist/{delete-55MXCEY5.js → delete-2PH2CGDY.js} +7 -8
- package/dist/{down-3OB6UVAJ.js → down-FXWAN66A.js} +1 -1
- package/dist/{env-JB27UAC3.js → env-7GLUJCWS.js} +8 -5
- package/dist/{history-BKG74I43.js → history-H72ZUIBN.js} +3 -3
- package/dist/{import-4CI2ZUTJ.js → import-AVKQJDYC.js} +8 -8
- package/dist/{logs-NXFFGUKY.js → logs-EDGK26AK.js} +2 -2
- package/dist/message-SCOQDR3P.js +32 -0
- package/dist/{package-Z2SFO2SV.js → package-4DP4Y4UO.js} +1 -1
- package/dist/restart-O4ETYLJF.js +29 -0
- package/dist/{schedule-A35SH4HT.js → schedule-S6QVC5ON.js} +10 -5
- package/dist/send-G7PE4DOJ.js +72 -0
- package/dist/{setup-2FDVN7OF.js → setup-F4TCWVSP.js} +5 -5
- package/dist/{start-LDPMCMYT.js → start-VHQ7LNWM.js} +3 -3
- package/dist/{status-MVSQG54T.js → status-QAJWXKMZ.js} +3 -3
- package/dist/{stop-5PZTZCLL.js → stop-CAGCT5NI.js} +6 -7
- package/dist/{up-F7TMTLRE.js → up-CSX3ZUIU.js} +16 -4
- package/dist/update-XSIX3GGP.js +140 -0
- package/dist/update-check-5ZADDHCK.js +17 -0
- package/dist/{upgrade-6ZW2RD64.js → upgrade-YXKPWDRU.js} +16 -15
- package/dist/{variant-T64BKARF.js → variant-4Z6W3PP6.js} +15 -10
- package/dist/web-assets/assets/index-D5PzIndO.js +308 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0003_clean_ego.sql +12 -0
- package/drizzle/meta/0003_snapshot.json +417 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/templates/_base/.init/.config/hooks/startup-context.sh +19 -1
- package/templates/_base/.init/.config/scripts/session-reader.ts +59 -0
- package/templates/_base/_skills/sessions/SKILL.md +49 -0
- package/templates/_base/_skills/volute-agent/SKILL.md +114 -14
- package/templates/_base/home/.config/routes.json +10 -0
- package/templates/_base/home/VOLUTE.md +14 -35
- package/templates/_base/src/lib/format-prefix.ts +7 -1
- package/templates/_base/src/lib/router.ts +193 -19
- package/templates/_base/src/lib/routing.ts +55 -18
- package/templates/_base/src/lib/session-monitor.ts +400 -0
- package/templates/_base/src/lib/types.ts +5 -1
- package/templates/agent-sdk/.init/.config/routes.json +5 -0
- package/templates/agent-sdk/.init/CLAUDE.md +2 -2
- package/templates/agent-sdk/src/agent.ts +18 -1
- package/templates/agent-sdk/src/lib/hooks/session-context.ts +32 -0
- package/templates/agent-sdk/src/server.ts +8 -2
- package/templates/agent-sdk/volute-template.json +1 -1
- package/templates/pi/.init/.config/routes.json +5 -0
- package/templates/pi/.init/AGENTS.md +1 -1
- package/templates/pi/src/agent.ts +12 -4
- package/templates/pi/src/lib/session-context-extension.ts +33 -0
- package/templates/pi/src/server.ts +1 -1
- package/templates/pi/volute-template.json +1 -1
- package/dist/channel-DQ6UY7QB.js +0 -67
- package/dist/chunk-5OCWMTVS.js +0 -152
- package/dist/chunk-ZHCE4DPY.js +0 -110
- package/dist/create-ILVOG75A.js +0 -79
- package/dist/send-3U6OTKG7.js +0 -57
- package/dist/web-assets/assets/index-NS621maO.js +0 -296
- package/templates/agent-sdk/.init/.config/sessions.json +0 -4
- package/templates/pi/.init/.config/sessions.json +0 -1
- package/dist/{service-SA4TTMDU.js → service-HZNIDNJF.js} +3 -3
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadMergedEnv
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-H7AMDUIA.js";
|
|
5
5
|
import {
|
|
6
6
|
applyIsolation
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-W76KWE23.js";
|
|
8
8
|
import {
|
|
9
9
|
agentDir,
|
|
10
10
|
findAgent,
|
|
@@ -13,11 +13,11 @@ import {
|
|
|
13
13
|
setVariantRunning,
|
|
14
14
|
validateBranchName,
|
|
15
15
|
voluteHome
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-UWHWAPGO.js";
|
|
17
17
|
|
|
18
18
|
// src/lib/agent-manager.ts
|
|
19
19
|
import { execFile, spawn } from "child_process";
|
|
20
|
-
import {
|
|
20
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
21
21
|
import { resolve } from "path";
|
|
22
22
|
import { promisify } from "util";
|
|
23
23
|
|
|
@@ -58,6 +58,45 @@ function clearJsonMap(path, map) {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// src/lib/rotating-log.ts
|
|
62
|
+
import { createWriteStream, existsSync as existsSync2, renameSync, statSync } from "fs";
|
|
63
|
+
import { Writable } from "stream";
|
|
64
|
+
var MAX_SIZE = 10 * 1024 * 1024;
|
|
65
|
+
var RotatingLog = class extends Writable {
|
|
66
|
+
constructor(path, maxSize = MAX_SIZE) {
|
|
67
|
+
super();
|
|
68
|
+
this.path = path;
|
|
69
|
+
this.maxSize = maxSize;
|
|
70
|
+
this.on("error", () => {
|
|
71
|
+
});
|
|
72
|
+
try {
|
|
73
|
+
this.size = existsSync2(path) ? statSync(path).size : 0;
|
|
74
|
+
} catch {
|
|
75
|
+
this.size = 0;
|
|
76
|
+
}
|
|
77
|
+
this.stream = createWriteStream(path, { flags: "a" });
|
|
78
|
+
}
|
|
79
|
+
stream;
|
|
80
|
+
size;
|
|
81
|
+
_write(chunk, _encoding, callback) {
|
|
82
|
+
this.size += chunk.length;
|
|
83
|
+
if (this.size > this.maxSize) {
|
|
84
|
+
try {
|
|
85
|
+
renameSync(this.path, `${this.path}.1`);
|
|
86
|
+
const oldStream = this.stream;
|
|
87
|
+
this.stream = createWriteStream(this.path);
|
|
88
|
+
this.size = chunk.length;
|
|
89
|
+
oldStream.end();
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
this.stream.write(chunk, callback);
|
|
94
|
+
}
|
|
95
|
+
_final(callback) {
|
|
96
|
+
this.stream.end(callback);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
61
100
|
// src/lib/agent-manager.ts
|
|
62
101
|
var execFileAsync = promisify(execFile);
|
|
63
102
|
var MAX_RESTART_ATTEMPTS = 5;
|
|
@@ -78,7 +117,7 @@ var AgentManager = class {
|
|
|
78
117
|
return { dir: variant.path, port: variant.port, isVariant: true, baseName, variantName };
|
|
79
118
|
}
|
|
80
119
|
const dir = agentDir(baseName);
|
|
81
|
-
if (!
|
|
120
|
+
if (!existsSync3(dir)) throw new Error(`Agent directory missing: ${dir}`);
|
|
82
121
|
return { dir, port: entry.port, isVariant: false, baseName };
|
|
83
122
|
}
|
|
84
123
|
async startAgent(name) {
|
|
@@ -100,9 +139,7 @@ var AgentManager = class {
|
|
|
100
139
|
const voluteDir = resolve(dir, ".volute");
|
|
101
140
|
const logsDir = resolve(voluteDir, "logs");
|
|
102
141
|
mkdirSync(logsDir, { recursive: true });
|
|
103
|
-
const logStream =
|
|
104
|
-
flags: "a"
|
|
105
|
-
});
|
|
142
|
+
const logStream = new RotatingLog(resolve(logsDir, "agent.log"));
|
|
106
143
|
const agentEnv = loadMergedEnv(dir);
|
|
107
144
|
const { VOLUTE_DAEMON_TOKEN: _, ...parentEnv } = process.env;
|
|
108
145
|
const env = { ...parentEnv, ...agentEnv, VOLUTE_AGENT: name };
|
|
@@ -198,7 +235,7 @@ var AgentManager = class {
|
|
|
198
235
|
}
|
|
199
236
|
async handleRestart(name, dir) {
|
|
200
237
|
const restartPath = resolve(dir, ".volute", "restart.json");
|
|
201
|
-
if (!
|
|
238
|
+
if (!existsSync3(restartPath)) return false;
|
|
202
239
|
try {
|
|
203
240
|
const signal = JSON.parse(readFileSync2(restartPath, "utf-8"));
|
|
204
241
|
unlinkSync2(restartPath);
|
|
@@ -326,6 +363,7 @@ export {
|
|
|
326
363
|
loadJsonMap,
|
|
327
364
|
saveJsonMap,
|
|
328
365
|
clearJsonMap,
|
|
366
|
+
RotatingLog,
|
|
329
367
|
AgentManager,
|
|
330
368
|
initAgentManager,
|
|
331
369
|
getAgentManager
|
|
@@ -1,27 +1,137 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/lib/variants.ts
|
|
4
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
5
|
+
import { resolve as resolve2 } from "path";
|
|
6
|
+
|
|
7
|
+
// src/lib/registry.ts
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
5
9
|
import { homedir } from "os";
|
|
6
|
-
import { resolve } from "path";
|
|
10
|
+
import { dirname, resolve } from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
7
12
|
function voluteHome() {
|
|
8
|
-
|
|
13
|
+
if (process.env.VOLUTE_HOME) return process.env.VOLUTE_HOME;
|
|
14
|
+
const dir = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
if (dir.endsWith("/src/lib")) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
'VOLUTE_HOME must be set when running from source. For tests, run via "npm test" or add "--import ./test/setup.ts".'
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
return resolve(homedir(), ".volute");
|
|
21
|
+
}
|
|
22
|
+
function ensureVoluteHome() {
|
|
23
|
+
mkdirSync(resolve(voluteHome(), "agents"), { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
function readRegistry() {
|
|
26
|
+
const registryPath = resolve(voluteHome(), "agents.json");
|
|
27
|
+
if (!existsSync(registryPath)) return [];
|
|
28
|
+
try {
|
|
29
|
+
const entries = JSON.parse(readFileSync(registryPath, "utf-8"));
|
|
30
|
+
return entries.map((e) => ({ ...e, running: e.running ?? false }));
|
|
31
|
+
} catch {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function writeRegistry(entries) {
|
|
36
|
+
ensureVoluteHome();
|
|
37
|
+
const registryPath = resolve(voluteHome(), "agents.json");
|
|
38
|
+
const tmpPath = `${registryPath}.tmp`;
|
|
39
|
+
writeFileSync(tmpPath, `${JSON.stringify(entries, null, 2)}
|
|
40
|
+
`);
|
|
41
|
+
renameSync(tmpPath, registryPath);
|
|
42
|
+
}
|
|
43
|
+
var AGENT_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
44
|
+
var AGENT_NAME_MAX = 64;
|
|
45
|
+
function validateAgentName(name) {
|
|
46
|
+
if (!name) return "Agent name is required";
|
|
47
|
+
if (name.length > AGENT_NAME_MAX)
|
|
48
|
+
return `Agent name must be at most ${AGENT_NAME_MAX} characters`;
|
|
49
|
+
if (!AGENT_NAME_RE.test(name)) {
|
|
50
|
+
return "Agent name must start with alphanumeric and contain only alphanumeric, dots, dashes, or underscores";
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
function addAgent(name, port) {
|
|
55
|
+
const err = validateAgentName(name);
|
|
56
|
+
if (err) throw new Error(err);
|
|
57
|
+
const entries = readRegistry();
|
|
58
|
+
const filtered = entries.filter((e) => e.name !== name);
|
|
59
|
+
filtered.push({ name, port, created: (/* @__PURE__ */ new Date()).toISOString(), running: false });
|
|
60
|
+
writeRegistry(filtered);
|
|
61
|
+
}
|
|
62
|
+
function removeAgent(name) {
|
|
63
|
+
const entries = readRegistry();
|
|
64
|
+
writeRegistry(entries.filter((e) => e.name !== name));
|
|
65
|
+
}
|
|
66
|
+
function setAgentRunning(name, running) {
|
|
67
|
+
const entries = readRegistry();
|
|
68
|
+
const entry = entries.find((e) => e.name === name);
|
|
69
|
+
if (entry) {
|
|
70
|
+
entry.running = running;
|
|
71
|
+
writeRegistry(entries);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function findAgent(name) {
|
|
75
|
+
return readRegistry().find((e) => e.name === name);
|
|
76
|
+
}
|
|
77
|
+
function agentDir(name) {
|
|
78
|
+
return resolve(voluteHome(), "agents", name);
|
|
79
|
+
}
|
|
80
|
+
function nextPort() {
|
|
81
|
+
const entries = readRegistry();
|
|
82
|
+
const usedPorts = new Set(entries.map((e) => e.port));
|
|
83
|
+
for (const entry of entries) {
|
|
84
|
+
for (const v of readVariants(entry.name)) {
|
|
85
|
+
if (v.port) usedPorts.add(v.port);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
let port = 4100;
|
|
89
|
+
while (usedPorts.has(port)) port++;
|
|
90
|
+
if (port > 65535) throw new Error("No available ports \u2014 all ports 4100-65535 are allocated");
|
|
91
|
+
return port;
|
|
92
|
+
}
|
|
93
|
+
function daemonLoopback() {
|
|
94
|
+
const host = process.env.VOLUTE_DAEMON_HOSTNAME || "127.0.0.1";
|
|
95
|
+
if (host === "0.0.0.0") return "127.0.0.1";
|
|
96
|
+
if (host === "::") return "[::1]";
|
|
97
|
+
return host;
|
|
98
|
+
}
|
|
99
|
+
function resolveAgent(name) {
|
|
100
|
+
const [baseName, variantName] = name.split("@", 2);
|
|
101
|
+
const entry = findAgent(baseName);
|
|
102
|
+
if (!entry) {
|
|
103
|
+
throw new Error(`Unknown agent: ${baseName}`);
|
|
104
|
+
}
|
|
105
|
+
const dir = agentDir(baseName);
|
|
106
|
+
if (!existsSync(dir)) {
|
|
107
|
+
throw new Error(`Agent directory missing: ${dir}`);
|
|
108
|
+
}
|
|
109
|
+
if (variantName) {
|
|
110
|
+
const variant = findVariant(baseName, variantName);
|
|
111
|
+
if (!variant) {
|
|
112
|
+
throw new Error(`Unknown variant: ${variantName} (agent: ${baseName})`);
|
|
113
|
+
}
|
|
114
|
+
return { entry: { ...entry, port: variant.port }, dir: variant.path };
|
|
115
|
+
}
|
|
116
|
+
return { entry, dir };
|
|
9
117
|
}
|
|
118
|
+
|
|
119
|
+
// src/lib/variants.ts
|
|
10
120
|
function variantsPath() {
|
|
11
|
-
return
|
|
121
|
+
return resolve2(voluteHome(), "variants.json");
|
|
12
122
|
}
|
|
13
123
|
function readAllVariants() {
|
|
14
124
|
const path = variantsPath();
|
|
15
|
-
if (!
|
|
125
|
+
if (!existsSync2(path)) return {};
|
|
16
126
|
try {
|
|
17
|
-
return JSON.parse(
|
|
127
|
+
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
18
128
|
} catch {
|
|
19
129
|
return {};
|
|
20
130
|
}
|
|
21
131
|
}
|
|
22
132
|
function writeAllVariants(all) {
|
|
23
|
-
|
|
24
|
-
|
|
133
|
+
mkdirSync2(voluteHome(), { recursive: true });
|
|
134
|
+
writeFileSync2(variantsPath(), `${JSON.stringify(all, null, 2)}
|
|
25
135
|
`);
|
|
26
136
|
}
|
|
27
137
|
function readVariants(agentName) {
|
|
@@ -102,104 +212,6 @@ function validateBranchName(branch) {
|
|
|
102
212
|
return null;
|
|
103
213
|
}
|
|
104
214
|
|
|
105
|
-
// src/lib/registry.ts
|
|
106
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "fs";
|
|
107
|
-
import { homedir as homedir2 } from "os";
|
|
108
|
-
import { resolve as resolve2 } from "path";
|
|
109
|
-
function voluteHome2() {
|
|
110
|
-
return process.env.VOLUTE_HOME || resolve2(homedir2(), ".volute");
|
|
111
|
-
}
|
|
112
|
-
function ensureVoluteHome() {
|
|
113
|
-
mkdirSync2(resolve2(voluteHome2(), "agents"), { recursive: true });
|
|
114
|
-
}
|
|
115
|
-
function readRegistry() {
|
|
116
|
-
const registryPath = resolve2(voluteHome2(), "agents.json");
|
|
117
|
-
if (!existsSync2(registryPath)) return [];
|
|
118
|
-
try {
|
|
119
|
-
const entries = JSON.parse(readFileSync2(registryPath, "utf-8"));
|
|
120
|
-
return entries.map((e) => ({ ...e, running: e.running ?? false }));
|
|
121
|
-
} catch {
|
|
122
|
-
return [];
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
function writeRegistry(entries) {
|
|
126
|
-
ensureVoluteHome();
|
|
127
|
-
const registryPath = resolve2(voluteHome2(), "agents.json");
|
|
128
|
-
const tmpPath = `${registryPath}.tmp`;
|
|
129
|
-
writeFileSync2(tmpPath, `${JSON.stringify(entries, null, 2)}
|
|
130
|
-
`);
|
|
131
|
-
renameSync(tmpPath, registryPath);
|
|
132
|
-
}
|
|
133
|
-
var AGENT_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
134
|
-
var AGENT_NAME_MAX = 64;
|
|
135
|
-
function validateAgentName(name) {
|
|
136
|
-
if (!name) return "Agent name is required";
|
|
137
|
-
if (name.length > AGENT_NAME_MAX)
|
|
138
|
-
return `Agent name must be at most ${AGENT_NAME_MAX} characters`;
|
|
139
|
-
if (!AGENT_NAME_RE.test(name)) {
|
|
140
|
-
return "Agent name must start with alphanumeric and contain only alphanumeric, dots, dashes, or underscores";
|
|
141
|
-
}
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
function addAgent(name, port) {
|
|
145
|
-
const err = validateAgentName(name);
|
|
146
|
-
if (err) throw new Error(err);
|
|
147
|
-
const entries = readRegistry();
|
|
148
|
-
const filtered = entries.filter((e) => e.name !== name);
|
|
149
|
-
filtered.push({ name, port, created: (/* @__PURE__ */ new Date()).toISOString(), running: false });
|
|
150
|
-
writeRegistry(filtered);
|
|
151
|
-
}
|
|
152
|
-
function removeAgent(name) {
|
|
153
|
-
const entries = readRegistry();
|
|
154
|
-
writeRegistry(entries.filter((e) => e.name !== name));
|
|
155
|
-
}
|
|
156
|
-
function setAgentRunning(name, running) {
|
|
157
|
-
const entries = readRegistry();
|
|
158
|
-
const entry = entries.find((e) => e.name === name);
|
|
159
|
-
if (entry) {
|
|
160
|
-
entry.running = running;
|
|
161
|
-
writeRegistry(entries);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
function findAgent(name) {
|
|
165
|
-
return readRegistry().find((e) => e.name === name);
|
|
166
|
-
}
|
|
167
|
-
function agentDir(name) {
|
|
168
|
-
return resolve2(voluteHome2(), "agents", name);
|
|
169
|
-
}
|
|
170
|
-
function nextPort() {
|
|
171
|
-
const entries = readRegistry();
|
|
172
|
-
const usedPorts = new Set(entries.map((e) => e.port));
|
|
173
|
-
for (const entry of entries) {
|
|
174
|
-
for (const v of readVariants(entry.name)) {
|
|
175
|
-
if (v.port) usedPorts.add(v.port);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
let port = 4100;
|
|
179
|
-
while (usedPorts.has(port)) port++;
|
|
180
|
-
if (port > 65535) throw new Error("No available ports \u2014 all ports 4100-65535 are allocated");
|
|
181
|
-
return port;
|
|
182
|
-
}
|
|
183
|
-
function resolveAgent(name) {
|
|
184
|
-
const [baseName, variantName] = name.split("@", 2);
|
|
185
|
-
const entry = findAgent(baseName);
|
|
186
|
-
if (!entry) {
|
|
187
|
-
throw new Error(`Unknown agent: ${baseName}`);
|
|
188
|
-
}
|
|
189
|
-
const dir = agentDir(baseName);
|
|
190
|
-
if (!existsSync2(dir)) {
|
|
191
|
-
throw new Error(`Agent directory missing: ${dir}`);
|
|
192
|
-
}
|
|
193
|
-
if (variantName) {
|
|
194
|
-
const variant = findVariant(baseName, variantName);
|
|
195
|
-
if (!variant) {
|
|
196
|
-
throw new Error(`Unknown variant: ${variantName} (agent: ${baseName})`);
|
|
197
|
-
}
|
|
198
|
-
return { entry: { ...entry, port: variant.port }, dir: variant.path };
|
|
199
|
-
}
|
|
200
|
-
return { entry, dir };
|
|
201
|
-
}
|
|
202
|
-
|
|
203
215
|
export {
|
|
204
216
|
readVariants,
|
|
205
217
|
writeVariants,
|
|
@@ -211,7 +223,7 @@ export {
|
|
|
211
223
|
removeAllVariants,
|
|
212
224
|
checkHealth,
|
|
213
225
|
validateBranchName,
|
|
214
|
-
|
|
226
|
+
voluteHome,
|
|
215
227
|
ensureVoluteHome,
|
|
216
228
|
readRegistry,
|
|
217
229
|
validateAgentName,
|
|
@@ -221,5 +233,6 @@ export {
|
|
|
221
233
|
findAgent,
|
|
222
234
|
agentDir,
|
|
223
235
|
nextPort,
|
|
236
|
+
daemonLoopback,
|
|
224
237
|
resolveAgent
|
|
225
238
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/read-stdin.ts
|
|
4
|
+
import { isatty } from "tty";
|
|
5
|
+
async function readStdin() {
|
|
6
|
+
if (isatty(0)) return void 0;
|
|
7
|
+
const chunks = [];
|
|
8
|
+
try {
|
|
9
|
+
for await (const chunk of process.stdin) {
|
|
10
|
+
chunks.push(chunk);
|
|
11
|
+
}
|
|
12
|
+
} catch (err) {
|
|
13
|
+
console.error(`Failed to read from stdin: ${err instanceof Error ? err.message : String(err)}`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const text = Buffer.concat(chunks).toString().replace(/\r?\n$/, "");
|
|
17
|
+
return text || void 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
readStdin
|
|
22
|
+
};
|