volute 0.20.0 → 0.22.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 +7 -7
- package/dist/{activity-events-OMXKXD5N.js → activity-events-3WHHCOBB.js} +3 -4
- package/dist/api.d.ts +4294 -0
- package/dist/{archive-ZCFOSTKB.js → archive-4ZQYK5MN.js} +4 -2
- package/dist/auth-HM2RSPY7.js +37 -0
- package/dist/{channel-PUQKGSQM.js → channel-BOOMFULW.js} +2 -2
- package/dist/{chunk-UU7A7KLB.js → chunk-A4S7H6G6.js} +5 -7
- package/dist/chunk-AKPFNL7L.js +148 -0
- package/dist/{chunk-EBGCNDMM.js → chunk-B2CPS4QU.js} +128 -114
- package/dist/chunk-G5KRTU2F.js +76 -0
- package/dist/{chunk-FCDU5BFX.js → chunk-HFCBO2GL.js} +2 -2
- package/dist/{chunk-GZ7DW4YL.js → chunk-HGCDWKSP.js} +2 -2
- package/dist/{chunk-7UFKREVW.js → chunk-JNFRY2WU.js} +2 -2
- package/dist/{chunk-DYZGP3EW.js → chunk-JTDFJWI2.js} +2 -1
- package/dist/{chunk-WC6ZHVRL.js → chunk-KFI7TQJ6.js} +2 -2
- package/dist/{chunk-AW7P4EVV.js → chunk-KTJGZ7M7.js} +55 -7
- package/dist/{chunk-OGXOMR65.js → chunk-NWPT4ASZ.js} +1 -1
- package/dist/{chunk-SCUDS4US.js → chunk-ON3FF5JA.js} +1 -1
- package/dist/chunk-OSFGKF2T.js +2651 -0
- package/dist/{chunk-TIWH32HP.js → chunk-PHHKNGA3.js} +3 -3
- package/dist/{chunk-VDWCHYTS.js → chunk-PHU4DEAJ.js} +1 -1
- package/dist/{chunk-7NO7EV5Z.js → chunk-QIXPN3OO.js} +2 -2
- package/dist/{chunk-O6ASDHFO.js → chunk-RK627D57.js} +40 -63
- package/dist/{chunk-NSE7VJQA.js → chunk-SGPEZ32F.js} +29 -1
- package/dist/{chunk-IKMY5X76.js → chunk-TFS25FIM.js} +12 -9
- package/dist/{chunk-PUVXOZ6T.js → chunk-VNVCRVYI.js} +118 -69
- package/dist/{chunk-32VR2EOH.js → chunk-VT5QODNE.js} +2 -2
- package/dist/{chunk-RHEGSQFJ.js → chunk-WSLPZF72.js} +1 -1
- package/dist/chunk-XLC342FO.js +29 -0
- package/dist/cli.js +57 -119
- package/dist/cloud-sync-C6WRYRVR.js +96 -0
- package/dist/{connector-JBVNZ7VK.js → connector-PYT5UOTZ.js} +6 -6
- package/dist/connectors/discord.js +2 -2
- package/dist/connectors/slack.js +2 -2
- package/dist/connectors/telegram.js +2 -2
- package/dist/{create-HP4OVVHF.js → create-WIDA3M4C.js} +1 -1
- package/dist/{daemon-client-ITWUCNFO.js → daemon-client-ZHCDL4RS.js} +2 -2
- package/dist/{daemon-restart-KPSWNYTH.js → daemon-restart-TPQ2XBRZ.js} +6 -6
- package/dist/daemon.js +2250 -1985
- package/dist/{delete-BSU7K3RY.js → delete-LOIANQGD.js} +1 -1
- package/dist/down-WSUASL5E.js +14 -0
- package/dist/{env-A3LMO777.js → env-4PHIHTF4.js} +2 -2
- package/dist/{export-6QBUOQGC.js → export-XD6PJBQP.js} +19 -8
- package/dist/{file-C57SK5DK.js → file-X4L5TTOL.js} +2 -2
- package/dist/{history-WNK3DFUM.js → history-HTEKRNID.js} +2 -2
- package/dist/{import-XEC34Y4Z.js → import-EAXTHHXL.js} +4 -3
- package/dist/{log-PPPZDVEF.js → log-SRO5Q6AD.js} +2 -2
- package/dist/{login-HNH3EUQV.js → login-UO6AOVEA.js} +4 -4
- package/dist/{logout-I5CB5UZS.js → logout-UKD5LA37.js} +2 -2
- package/dist/{logs-SF2IMJN4.js → logs-HNTNNBDW.js} +2 -2
- package/dist/{merge-33C237A4.js → merge-B6SYTGI7.js} +2 -2
- package/dist/message-delivery-WUS4K4ZC.js +21 -0
- package/dist/{mind-Z7CKD6DG.js → mind-BTXR5B3C.js} +35 -11
- package/dist/{mind-activity-tracker-624QLQLC.js → mind-activity-tracker-PGC3DBJ7.js} +4 -5
- package/dist/{mind-manager-3DMYKZPB.js → mind-manager-P5OBDUKI.js} +5 -6
- package/dist/mind-sleep-FWRBIFBS.js +41 -0
- package/dist/mind-wake-LJK2YU5X.js +36 -0
- package/dist/{package-4NHAVUUI.js → package-A7PEYJI2.js} +10 -1
- package/dist/{pages-4DGQT7ZA.js → pages-YSTRWJR4.js} +6 -6
- package/dist/{publish-TAJUET4I.js → publish-BZNHKUUK.js} +6 -6
- package/dist/{pull-XAEWQJ47.js → pull-GRQAXM2E.js} +2 -2
- package/dist/{register-VSPCMHKX.js → register-U2UO6TC4.js} +5 -5
- package/dist/registry-D2BSQ2X5.js +42 -0
- package/dist/{restart-IQKMCK5M.js → restart-CIDAKGG2.js} +3 -6
- package/dist/{schedule-FFZG23IW.js → schedule-NLR3LZLY.js} +2 -2
- package/dist/{seed-J43YDKXG.js → seed-3H2MRREW.js} +2 -2
- package/dist/{send-KVIZIGCE.js → send-RP2TA7SG.js} +132 -36
- package/dist/{service-LUR7WDO7.js → service-7BFXDI6J.js} +31 -13
- package/dist/{setup-52YRV7VP.js → setup-SSIIXQMI.js} +9 -34
- package/dist/{shared-KO35ZM44.js → shared-2OGT3NSL.js} +4 -4
- package/dist/{skill-BCVNI6TV.js → skill-Q2Y6PQ3L.js} +2 -2
- package/dist/skills/orientation/SKILL.md +2 -2
- package/dist/skills/volute-mind/SKILL.md +5 -5
- package/dist/sleep-manager-3RWUX2ZR.js +27 -0
- package/dist/{sprout-QN7Y4VVO.js → sprout-UKCYBGHK.js} +34 -30
- package/dist/{start-I5JYB65M.js → start-JR6CUUWF.js} +3 -6
- package/dist/{status-D7E5HHBV.js → status-5XDGYHKP.js} +2 -2
- package/dist/{status-4ESFLGH4.js → status-H2MKDN6L.js} +5 -5
- package/dist/{status-FU2PFVVF.js → status-LV34BG6G.js} +3 -3
- package/dist/{stop-NBVKEFQQ.js → stop-VKPGK25U.js} +2 -5
- package/dist/template-hash-BIMA4ILT.js +8 -0
- package/dist/{up-FS7CKM6V.js → up-JKGC7PPF.js} +5 -5
- package/dist/{update-FJIHDJKM.js → update-ELC6MEUT.js} +5 -5
- package/dist/{update-check-MWE5AH4U.js → update-check-F5Z3ALXX.js} +2 -2
- package/dist/{upgrade-AIT24B5I.js → upgrade-GXW2EQY3.js} +12 -3
- package/dist/{variant-63ZWO2W7.js → variant-A4I7PHXS.js} +16 -24
- package/dist/version-notify-5FGUAVSF.js +181 -0
- package/dist/web-assets/assets/index-DWBxl4LO.js +69 -0
- package/dist/web-assets/assets/index-ZqMd1mx1.css +1 -0
- package/dist/web-assets/index.html +2 -2
- package/package.json +10 -1
- package/templates/_base/.init/.config/prompts.json +1 -0
- package/templates/_base/home/.config/config.json.tmpl +4 -1
- package/templates/_base/src/lib/logger.ts +68 -23
- package/templates/_base/src/lib/startup.ts +12 -3
- package/templates/claude/src/agent.ts +150 -29
- package/templates/claude/src/lib/hooks/pre-compact.ts +18 -4
- package/templates/claude/src/lib/message-channel.ts +6 -0
- package/templates/claude/src/lib/stream-consumer.ts +7 -0
- package/templates/claude/src/server.ts +3 -1
- package/templates/pi/home/.config/config.json.tmpl +4 -1
- package/templates/pi/src/agent.ts +87 -0
- package/templates/pi/src/lib/event-handler.ts +13 -1
- package/templates/pi/src/server.ts +3 -1
- package/dist/chunk-5XNT2472.js +0 -36
- package/dist/chunk-FGSYHIS3.js +0 -891
- package/dist/chunk-UJ6GHNR7.js +0 -675
- package/dist/db-C2CJ46ZU.js +0 -10
- package/dist/delivery-manager-CSG7LXA4.js +0 -16
- package/dist/down-ZY35KMHR.js +0 -14
- package/dist/schema-GFH6RV3W.js +0 -26
- package/dist/variants-JAGWGBXG.js +0 -26
- package/dist/web-assets/assets/index-CUZTZzaW.js +0 -64
- package/dist/web-assets/assets/index-adVuCkqy.css +0 -1
|
@@ -3,13 +3,15 @@ import {
|
|
|
3
3
|
addHistoryToArchive,
|
|
4
4
|
createExportArchive,
|
|
5
5
|
extractArchive,
|
|
6
|
+
isHomeOnlyArchive,
|
|
6
7
|
readManifest
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-KTJGZ7M7.js";
|
|
9
|
+
import "./chunk-B2CPS4QU.js";
|
|
9
10
|
import "./chunk-K3NQKI34.js";
|
|
10
11
|
export {
|
|
11
12
|
addHistoryToArchive,
|
|
12
13
|
createExportArchive,
|
|
13
14
|
extractArchive,
|
|
15
|
+
isHomeOnlyArchive,
|
|
14
16
|
readManifest
|
|
15
17
|
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-K3NQKI34.js";
|
|
3
|
+
|
|
4
|
+
// src/commands/auth.ts
|
|
5
|
+
async function run(args) {
|
|
6
|
+
const subcommand = args[0];
|
|
7
|
+
switch (subcommand) {
|
|
8
|
+
case "register":
|
|
9
|
+
await import("./register-U2UO6TC4.js").then((m) => m.run(args.slice(1)));
|
|
10
|
+
break;
|
|
11
|
+
case "login":
|
|
12
|
+
await import("./login-UO6AOVEA.js").then((m) => m.run(args.slice(1)));
|
|
13
|
+
break;
|
|
14
|
+
case "logout":
|
|
15
|
+
await import("./logout-UKD5LA37.js").then((m) => m.run());
|
|
16
|
+
break;
|
|
17
|
+
case "--help":
|
|
18
|
+
case "-h":
|
|
19
|
+
case void 0:
|
|
20
|
+
printUsage();
|
|
21
|
+
break;
|
|
22
|
+
default:
|
|
23
|
+
printUsage();
|
|
24
|
+
console.error(`
|
|
25
|
+
Unknown subcommand: ${subcommand}`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function printUsage() {
|
|
30
|
+
console.log(`Usage:
|
|
31
|
+
volute auth register [--name <name>] Register a system on volute.systems
|
|
32
|
+
volute auth login [--key <key>] Log in with an existing API key
|
|
33
|
+
volute auth logout Remove stored credentials`);
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
run
|
|
37
|
+
};
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
} from "./chunk-D424ZQGI.js";
|
|
12
12
|
import {
|
|
13
13
|
daemonFetch
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-KFI7TQJ6.js";
|
|
15
|
+
import "./chunk-B2CPS4QU.js";
|
|
16
16
|
import "./chunk-K3NQKI34.js";
|
|
17
17
|
|
|
18
18
|
// src/commands/channel.ts
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
} from "./chunk-YUIHSKR6.js";
|
|
5
|
-
import {
|
|
3
|
+
activity,
|
|
6
4
|
getDb
|
|
7
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SGPEZ32F.js";
|
|
8
6
|
import {
|
|
9
|
-
|
|
10
|
-
} from "./chunk-
|
|
7
|
+
logger_default
|
|
8
|
+
} from "./chunk-YUIHSKR6.js";
|
|
11
9
|
|
|
12
|
-
// src/lib/activity-events.ts
|
|
10
|
+
// src/lib/events/activity-events.ts
|
|
13
11
|
var subscribers = /* @__PURE__ */ new Set();
|
|
14
12
|
function subscribe(callback) {
|
|
15
13
|
subscribers.add(callback);
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/template-hash.ts
|
|
4
|
+
import { createHash } from "crypto";
|
|
5
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, rmSync as rmSync2 } from "fs";
|
|
6
|
+
import { resolve as resolve2 } from "path";
|
|
7
|
+
|
|
8
|
+
// src/lib/template.ts
|
|
9
|
+
import {
|
|
10
|
+
cpSync,
|
|
11
|
+
existsSync,
|
|
12
|
+
mkdirSync,
|
|
13
|
+
readdirSync,
|
|
14
|
+
readFileSync,
|
|
15
|
+
renameSync,
|
|
16
|
+
rmSync,
|
|
17
|
+
statSync,
|
|
18
|
+
writeFileSync
|
|
19
|
+
} from "fs";
|
|
20
|
+
import { tmpdir } from "os";
|
|
21
|
+
import { dirname, join, relative, resolve } from "path";
|
|
22
|
+
function findTemplatesRoot() {
|
|
23
|
+
let dir = dirname(new URL(import.meta.url).pathname);
|
|
24
|
+
for (let i = 0; i < 5; i++) {
|
|
25
|
+
const candidate = resolve(dir, "templates");
|
|
26
|
+
if (existsSync(resolve(candidate, "_base"))) return candidate;
|
|
27
|
+
dir = dirname(dir);
|
|
28
|
+
}
|
|
29
|
+
console.error(
|
|
30
|
+
"Templates directory not found. Searched up from:",
|
|
31
|
+
dirname(new URL(import.meta.url).pathname)
|
|
32
|
+
);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
function composeTemplate(templatesRoot, templateName) {
|
|
36
|
+
const baseDir = resolve(templatesRoot, "_base");
|
|
37
|
+
const templateDir = resolve(templatesRoot, templateName);
|
|
38
|
+
if (!existsSync(baseDir)) {
|
|
39
|
+
console.error("Base template not found:", baseDir);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
if (!existsSync(templateDir)) {
|
|
43
|
+
console.error(`Template not found: ${templateName}`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
const composedDir = resolve(tmpdir(), `volute-template-${Date.now()}`);
|
|
47
|
+
mkdirSync(composedDir, { recursive: true });
|
|
48
|
+
cpSync(baseDir, composedDir, { recursive: true });
|
|
49
|
+
for (const file of listFiles(templateDir)) {
|
|
50
|
+
const src = resolve(templateDir, file);
|
|
51
|
+
const dest = resolve(composedDir, file);
|
|
52
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
53
|
+
cpSync(src, dest);
|
|
54
|
+
}
|
|
55
|
+
const manifestPath = resolve(composedDir, "volute-template.json");
|
|
56
|
+
if (!existsSync(manifestPath)) {
|
|
57
|
+
rmSync(composedDir, { recursive: true, force: true });
|
|
58
|
+
console.error(`Template manifest not found: ${templateName}/volute-template.json`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
62
|
+
rmSync(manifestPath);
|
|
63
|
+
return { composedDir, manifest };
|
|
64
|
+
}
|
|
65
|
+
function copyTemplateToDir(composedDir, destDir, mindName, manifest) {
|
|
66
|
+
cpSync(composedDir, destDir, { recursive: true });
|
|
67
|
+
for (const [from, to] of Object.entries(manifest.rename)) {
|
|
68
|
+
const fromPath = resolve(destDir, from);
|
|
69
|
+
if (existsSync(fromPath)) {
|
|
70
|
+
renameSync(fromPath, resolve(destDir, to));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (const file of manifest.substitute) {
|
|
74
|
+
const path = resolve(destDir, file);
|
|
75
|
+
if (existsSync(path)) {
|
|
76
|
+
const content = readFileSync(path, "utf-8");
|
|
77
|
+
writeFileSync(path, content.replaceAll("{{name}}", mindName));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function applyInitFiles(destDir) {
|
|
82
|
+
const initDir = resolve(destDir, ".init");
|
|
83
|
+
if (!existsSync(initDir)) return;
|
|
84
|
+
const homeDir = resolve(destDir, "home");
|
|
85
|
+
for (const file of listFiles(initDir)) {
|
|
86
|
+
const src = resolve(initDir, file);
|
|
87
|
+
const dest = resolve(homeDir, file);
|
|
88
|
+
const parent = dirname(dest);
|
|
89
|
+
if (!existsSync(parent)) {
|
|
90
|
+
mkdirSync(parent, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
cpSync(src, dest);
|
|
93
|
+
}
|
|
94
|
+
rmSync(initDir, { recursive: true, force: true });
|
|
95
|
+
}
|
|
96
|
+
function listFiles(dir) {
|
|
97
|
+
const results = [];
|
|
98
|
+
function walk(current) {
|
|
99
|
+
for (const entry of readdirSync(current)) {
|
|
100
|
+
const full = join(current, entry);
|
|
101
|
+
if (statSync(full).isDirectory()) {
|
|
102
|
+
if (entry === ".git") continue;
|
|
103
|
+
walk(full);
|
|
104
|
+
} else {
|
|
105
|
+
results.push(relative(dir, full));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
walk(dir);
|
|
110
|
+
return results;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/lib/template-hash.ts
|
|
114
|
+
var hashCache = /* @__PURE__ */ new Map();
|
|
115
|
+
function computeTemplateHash(templateName) {
|
|
116
|
+
const cached = hashCache.get(templateName);
|
|
117
|
+
if (cached) return cached;
|
|
118
|
+
const templatesRoot = findTemplatesRoot();
|
|
119
|
+
const baseDir = resolve2(templatesRoot, "_base");
|
|
120
|
+
const templateDir = resolve2(templatesRoot, templateName);
|
|
121
|
+
if (!existsSync2(baseDir)) throw new Error(`Base template not found: ${baseDir}`);
|
|
122
|
+
if (!existsSync2(templateDir)) throw new Error(`Template not found: ${templateName}`);
|
|
123
|
+
const { composedDir } = composeTemplate(templatesRoot, templateName);
|
|
124
|
+
try {
|
|
125
|
+
const files = listFiles(composedDir).filter((f) => !f.startsWith(".init/") && !f.startsWith(".init\\")).sort();
|
|
126
|
+
const hash = createHash("sha256");
|
|
127
|
+
for (const file of files) {
|
|
128
|
+
const content = readFileSync2(resolve2(composedDir, file));
|
|
129
|
+
hash.update(file);
|
|
130
|
+
hash.update("\0");
|
|
131
|
+
hash.update(content);
|
|
132
|
+
}
|
|
133
|
+
const result = hash.digest("hex");
|
|
134
|
+
hashCache.set(templateName, result);
|
|
135
|
+
return result;
|
|
136
|
+
} finally {
|
|
137
|
+
rmSync2(composedDir, { recursive: true, force: true });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
findTemplatesRoot,
|
|
143
|
+
composeTemplate,
|
|
144
|
+
copyTemplateToDir,
|
|
145
|
+
applyInitFiles,
|
|
146
|
+
listFiles,
|
|
147
|
+
computeTemplateHash
|
|
148
|
+
};
|
|
@@ -1,23 +1,122 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// src/lib/variants.ts
|
|
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
3
|
// src/lib/registry.ts
|
|
8
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
4
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "fs";
|
|
9
5
|
import { homedir } from "os";
|
|
10
|
-
import { dirname, resolve } from "path";
|
|
6
|
+
import { dirname, resolve as resolve2 } from "path";
|
|
11
7
|
import { fileURLToPath } from "url";
|
|
8
|
+
|
|
9
|
+
// src/lib/variants.ts
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
11
|
+
import { resolve } from "path";
|
|
12
|
+
function variantsPath() {
|
|
13
|
+
return resolve(voluteHome(), "variants.json");
|
|
14
|
+
}
|
|
15
|
+
function readAllVariants() {
|
|
16
|
+
const path = variantsPath();
|
|
17
|
+
if (!existsSync(path)) return {};
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
20
|
+
} catch {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function writeAllVariants(all) {
|
|
25
|
+
mkdirSync(voluteHome(), { recursive: true });
|
|
26
|
+
writeFileSync(variantsPath(), `${JSON.stringify(all, null, 2)}
|
|
27
|
+
`);
|
|
28
|
+
}
|
|
29
|
+
function readVariants(mindName) {
|
|
30
|
+
return readAllVariants()[mindName] ?? [];
|
|
31
|
+
}
|
|
32
|
+
function writeVariants(mindName, variants) {
|
|
33
|
+
const all = readAllVariants();
|
|
34
|
+
if (variants.length === 0) {
|
|
35
|
+
delete all[mindName];
|
|
36
|
+
} else {
|
|
37
|
+
all[mindName] = variants;
|
|
38
|
+
}
|
|
39
|
+
writeAllVariants(all);
|
|
40
|
+
}
|
|
41
|
+
function addVariant(mindName, variant) {
|
|
42
|
+
const variants = readVariants(mindName);
|
|
43
|
+
const filtered = variants.filter((v) => v.name !== variant.name);
|
|
44
|
+
filtered.push(variant);
|
|
45
|
+
writeVariants(mindName, filtered);
|
|
46
|
+
}
|
|
47
|
+
function removeVariant(mindName, name) {
|
|
48
|
+
const variants = readVariants(mindName);
|
|
49
|
+
writeVariants(
|
|
50
|
+
mindName,
|
|
51
|
+
variants.filter((v) => v.name !== name)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
function findVariant(mindName, name) {
|
|
55
|
+
return readVariants(mindName).find((v) => v.name === name);
|
|
56
|
+
}
|
|
57
|
+
function setVariantRunning(mindName, variantName, running) {
|
|
58
|
+
const all = readAllVariants();
|
|
59
|
+
const variants = all[mindName] ?? [];
|
|
60
|
+
const variant = variants.find((v) => v.name === variantName);
|
|
61
|
+
if (variant) {
|
|
62
|
+
variant.running = running;
|
|
63
|
+
all[mindName] = variants;
|
|
64
|
+
writeAllVariants(all);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function getAllRunningVariants() {
|
|
68
|
+
const all = readAllVariants();
|
|
69
|
+
const result = [];
|
|
70
|
+
for (const [mindName, variants] of Object.entries(all)) {
|
|
71
|
+
for (const variant of variants) {
|
|
72
|
+
if (variant.running) {
|
|
73
|
+
result.push({ mindName, variant });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
function removeAllVariants(mindName) {
|
|
80
|
+
const all = readAllVariants();
|
|
81
|
+
delete all[mindName];
|
|
82
|
+
writeAllVariants(all);
|
|
83
|
+
}
|
|
84
|
+
async function checkHealth(port) {
|
|
85
|
+
try {
|
|
86
|
+
const res = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
87
|
+
signal: AbortSignal.timeout(2e3)
|
|
88
|
+
});
|
|
89
|
+
if (!res.ok) return { ok: false };
|
|
90
|
+
const data = await res.json();
|
|
91
|
+
return { ok: true, name: data.name };
|
|
92
|
+
} catch {
|
|
93
|
+
return { ok: false };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
var SAFE_BRANCH_RE = /^[a-zA-Z0-9._\-/]+$/;
|
|
97
|
+
function validateBranchName(branch) {
|
|
98
|
+
if (!SAFE_BRANCH_RE.test(branch)) {
|
|
99
|
+
return `Invalid branch name: ${branch}. Only alphanumeric, '.', '_', '-', '/' allowed.`;
|
|
100
|
+
}
|
|
101
|
+
if (branch.includes("..")) {
|
|
102
|
+
return `Invalid branch name: ${branch}. '..' not allowed.`;
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/lib/registry.ts
|
|
12
108
|
var registryCache = null;
|
|
13
109
|
function initRegistryCache() {
|
|
14
110
|
registryCache = readRegistryFromDisk();
|
|
15
111
|
}
|
|
112
|
+
function getRegistryCache() {
|
|
113
|
+
return registryCache;
|
|
114
|
+
}
|
|
16
115
|
function readRegistryFromDisk() {
|
|
17
|
-
const registryPath =
|
|
18
|
-
if (!
|
|
116
|
+
const registryPath = resolve2(voluteHome(), "minds.json");
|
|
117
|
+
if (!existsSync2(registryPath)) return [];
|
|
19
118
|
try {
|
|
20
|
-
const entries = JSON.parse(
|
|
119
|
+
const entries = JSON.parse(readFileSync2(registryPath, "utf-8"));
|
|
21
120
|
return entries.map((e) => ({
|
|
22
121
|
...e,
|
|
23
122
|
running: e.running ?? false,
|
|
@@ -35,11 +134,11 @@ function voluteHome() {
|
|
|
35
134
|
'VOLUTE_HOME must be set when running from source. For tests, run via "npm test" or add "--import ./test/setup.ts".'
|
|
36
135
|
);
|
|
37
136
|
}
|
|
38
|
-
return
|
|
137
|
+
return resolve2(homedir(), ".volute");
|
|
39
138
|
}
|
|
40
139
|
function ensureVoluteHome() {
|
|
41
|
-
const mindsBase = process.env.VOLUTE_MINDS_DIR ??
|
|
42
|
-
|
|
140
|
+
const mindsBase = process.env.VOLUTE_MINDS_DIR ?? resolve2(voluteHome(), "minds");
|
|
141
|
+
mkdirSync2(mindsBase, { recursive: true });
|
|
43
142
|
}
|
|
44
143
|
function readRegistry() {
|
|
45
144
|
if (registryCache) return registryCache;
|
|
@@ -48,9 +147,9 @@ function readRegistry() {
|
|
|
48
147
|
function writeRegistry(entries) {
|
|
49
148
|
if (registryCache) registryCache = entries;
|
|
50
149
|
ensureVoluteHome();
|
|
51
|
-
const registryPath =
|
|
150
|
+
const registryPath = resolve2(voluteHome(), "minds.json");
|
|
52
151
|
const tmpPath = `${registryPath}.tmp`;
|
|
53
|
-
|
|
152
|
+
writeFileSync2(tmpPath, `${JSON.stringify(entries, null, 2)}
|
|
54
153
|
`);
|
|
55
154
|
renameSync(tmpPath, registryPath);
|
|
56
155
|
}
|
|
@@ -92,17 +191,25 @@ function setMindStage(name, stage) {
|
|
|
92
191
|
writeRegistry(entries);
|
|
93
192
|
}
|
|
94
193
|
}
|
|
194
|
+
function setMindTemplateHash(name, hash) {
|
|
195
|
+
const entries = readRegistry();
|
|
196
|
+
const entry = entries.find((e) => e.name === name);
|
|
197
|
+
if (entry) {
|
|
198
|
+
entry.templateHash = hash;
|
|
199
|
+
writeRegistry(entries);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
95
202
|
function findMind(name) {
|
|
96
203
|
return readRegistry().find((e) => e.name === name);
|
|
97
204
|
}
|
|
98
205
|
function mindDir(name) {
|
|
99
206
|
if (process.env.VOLUTE_MINDS_DIR) {
|
|
100
|
-
return
|
|
207
|
+
return resolve2(process.env.VOLUTE_MINDS_DIR, name);
|
|
101
208
|
}
|
|
102
|
-
return
|
|
209
|
+
return resolve2(voluteHome(), "minds", name);
|
|
103
210
|
}
|
|
104
211
|
function stateDir(name) {
|
|
105
|
-
return
|
|
212
|
+
return resolve2(voluteHome(), "state", name);
|
|
106
213
|
}
|
|
107
214
|
function nextPort() {
|
|
108
215
|
const entries = readRegistry();
|
|
@@ -131,7 +238,7 @@ function resolveMind(name) {
|
|
|
131
238
|
throw new Error(`Unknown mind: ${baseName}`);
|
|
132
239
|
}
|
|
133
240
|
const dir = mindDir(baseName);
|
|
134
|
-
if (!
|
|
241
|
+
if (!existsSync2(dir)) {
|
|
135
242
|
throw new Error(`Mind directory missing: ${dir}`);
|
|
136
243
|
}
|
|
137
244
|
if (variantName) {
|
|
@@ -144,102 +251,6 @@ function resolveMind(name) {
|
|
|
144
251
|
return { entry, dir };
|
|
145
252
|
}
|
|
146
253
|
|
|
147
|
-
// src/lib/variants.ts
|
|
148
|
-
function variantsPath() {
|
|
149
|
-
return resolve2(voluteHome(), "variants.json");
|
|
150
|
-
}
|
|
151
|
-
function readAllVariants() {
|
|
152
|
-
const path = variantsPath();
|
|
153
|
-
if (!existsSync2(path)) return {};
|
|
154
|
-
try {
|
|
155
|
-
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
156
|
-
} catch {
|
|
157
|
-
return {};
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
function writeAllVariants(all) {
|
|
161
|
-
mkdirSync2(voluteHome(), { recursive: true });
|
|
162
|
-
writeFileSync2(variantsPath(), `${JSON.stringify(all, null, 2)}
|
|
163
|
-
`);
|
|
164
|
-
}
|
|
165
|
-
function readVariants(mindName) {
|
|
166
|
-
return readAllVariants()[mindName] ?? [];
|
|
167
|
-
}
|
|
168
|
-
function writeVariants(mindName, variants) {
|
|
169
|
-
const all = readAllVariants();
|
|
170
|
-
if (variants.length === 0) {
|
|
171
|
-
delete all[mindName];
|
|
172
|
-
} else {
|
|
173
|
-
all[mindName] = variants;
|
|
174
|
-
}
|
|
175
|
-
writeAllVariants(all);
|
|
176
|
-
}
|
|
177
|
-
function addVariant(mindName, variant) {
|
|
178
|
-
const variants = readVariants(mindName);
|
|
179
|
-
const filtered = variants.filter((v) => v.name !== variant.name);
|
|
180
|
-
filtered.push(variant);
|
|
181
|
-
writeVariants(mindName, filtered);
|
|
182
|
-
}
|
|
183
|
-
function removeVariant(mindName, name) {
|
|
184
|
-
const variants = readVariants(mindName);
|
|
185
|
-
writeVariants(
|
|
186
|
-
mindName,
|
|
187
|
-
variants.filter((v) => v.name !== name)
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
function findVariant(mindName, name) {
|
|
191
|
-
return readVariants(mindName).find((v) => v.name === name);
|
|
192
|
-
}
|
|
193
|
-
function setVariantRunning(mindName, variantName, running) {
|
|
194
|
-
const all = readAllVariants();
|
|
195
|
-
const variants = all[mindName] ?? [];
|
|
196
|
-
const variant = variants.find((v) => v.name === variantName);
|
|
197
|
-
if (variant) {
|
|
198
|
-
variant.running = running;
|
|
199
|
-
all[mindName] = variants;
|
|
200
|
-
writeAllVariants(all);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
function getAllRunningVariants() {
|
|
204
|
-
const all = readAllVariants();
|
|
205
|
-
const result = [];
|
|
206
|
-
for (const [mindName, variants] of Object.entries(all)) {
|
|
207
|
-
for (const variant of variants) {
|
|
208
|
-
if (variant.running) {
|
|
209
|
-
result.push({ mindName, variant });
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return result;
|
|
214
|
-
}
|
|
215
|
-
function removeAllVariants(mindName) {
|
|
216
|
-
const all = readAllVariants();
|
|
217
|
-
delete all[mindName];
|
|
218
|
-
writeAllVariants(all);
|
|
219
|
-
}
|
|
220
|
-
async function checkHealth(port) {
|
|
221
|
-
try {
|
|
222
|
-
const res = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
223
|
-
signal: AbortSignal.timeout(2e3)
|
|
224
|
-
});
|
|
225
|
-
if (!res.ok) return { ok: false };
|
|
226
|
-
const data = await res.json();
|
|
227
|
-
return { ok: true, name: data.name };
|
|
228
|
-
} catch {
|
|
229
|
-
return { ok: false };
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
var SAFE_BRANCH_RE = /^[a-zA-Z0-9._\-/]+$/;
|
|
233
|
-
function validateBranchName(branch) {
|
|
234
|
-
if (!SAFE_BRANCH_RE.test(branch)) {
|
|
235
|
-
return `Invalid branch name: ${branch}. Only alphanumeric, '.', '_', '-', '/' allowed.`;
|
|
236
|
-
}
|
|
237
|
-
if (branch.includes("..")) {
|
|
238
|
-
return `Invalid branch name: ${branch}. '..' not allowed.`;
|
|
239
|
-
}
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
254
|
export {
|
|
244
255
|
readVariants,
|
|
245
256
|
writeVariants,
|
|
@@ -252,14 +263,17 @@ export {
|
|
|
252
263
|
checkHealth,
|
|
253
264
|
validateBranchName,
|
|
254
265
|
initRegistryCache,
|
|
266
|
+
getRegistryCache,
|
|
255
267
|
voluteHome,
|
|
256
268
|
ensureVoluteHome,
|
|
257
269
|
readRegistry,
|
|
270
|
+
writeRegistry,
|
|
258
271
|
validateMindName,
|
|
259
272
|
addMind,
|
|
260
273
|
removeMind,
|
|
261
274
|
setMindRunning,
|
|
262
275
|
setMindStage,
|
|
276
|
+
setMindTemplateHash,
|
|
263
277
|
findMind,
|
|
264
278
|
mindDir,
|
|
265
279
|
stateDir,
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
subscribe
|
|
4
|
+
} from "./chunk-A4S7H6G6.js";
|
|
5
|
+
import {
|
|
6
|
+
logger_default
|
|
7
|
+
} from "./chunk-YUIHSKR6.js";
|
|
8
|
+
|
|
9
|
+
// src/lib/webhook.ts
|
|
10
|
+
var slog = logger_default.child("webhook");
|
|
11
|
+
function getWebhookUrl() {
|
|
12
|
+
return process.env.VOLUTE_WEBHOOK_URL;
|
|
13
|
+
}
|
|
14
|
+
function getAuthHeaders() {
|
|
15
|
+
const headers = { "Content-Type": "application/json" };
|
|
16
|
+
const secret = process.env.VOLUTE_WEBHOOK_SECRET;
|
|
17
|
+
if (secret) headers.Authorization = `Bearer ${secret}`;
|
|
18
|
+
return headers;
|
|
19
|
+
}
|
|
20
|
+
function fireWebhook(event) {
|
|
21
|
+
try {
|
|
22
|
+
const url = getWebhookUrl();
|
|
23
|
+
if (!url) return;
|
|
24
|
+
const payload = { ...event, timestamp: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString() };
|
|
25
|
+
fetch(url, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: getAuthHeaders(),
|
|
28
|
+
body: JSON.stringify(payload)
|
|
29
|
+
}).then((res) => {
|
|
30
|
+
if (!res.ok) {
|
|
31
|
+
slog.warn(`webhook ${event.event} returned HTTP ${res.status}`);
|
|
32
|
+
}
|
|
33
|
+
}).catch((err) => {
|
|
34
|
+
slog.warn(`webhook delivery failed for ${event.event}`, logger_default.errorData(err));
|
|
35
|
+
});
|
|
36
|
+
} catch (err) {
|
|
37
|
+
slog.error(`webhook ${event.event} failed to serialize`, logger_default.errorData(err));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function initWebhook() {
|
|
41
|
+
const url = getWebhookUrl();
|
|
42
|
+
if (!url) return () => {
|
|
43
|
+
};
|
|
44
|
+
try {
|
|
45
|
+
const parsed = new URL(url);
|
|
46
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
47
|
+
slog.error(`VOLUTE_WEBHOOK_URL has unsupported protocol: ${parsed.protocol}`);
|
|
48
|
+
return () => {
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
slog.error(`VOLUTE_WEBHOOK_URL is not a valid URL`);
|
|
53
|
+
return () => {
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
slog.info("webhook enabled");
|
|
57
|
+
return subscribe((event) => {
|
|
58
|
+
try {
|
|
59
|
+
fireWebhook({
|
|
60
|
+
event: event.type,
|
|
61
|
+
mind: event.mind,
|
|
62
|
+
data: { summary: event.summary, ...event.metadata },
|
|
63
|
+
timestamp: event.created_at
|
|
64
|
+
});
|
|
65
|
+
} catch (err) {
|
|
66
|
+
slog.error(`failed to fire webhook for ${event.type}`, logger_default.errorData(err));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
getWebhookUrl,
|
|
73
|
+
getAuthHeaders,
|
|
74
|
+
fireWebhook,
|
|
75
|
+
initWebhook
|
|
76
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
voluteHome
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-B2CPS4QU.js";
|
|
5
5
|
|
|
6
6
|
// src/lib/systems-config.ts
|
|
7
7
|
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
@@ -18,7 +18,7 @@ function readSystemsConfig() {
|
|
|
18
18
|
try {
|
|
19
19
|
data = JSON.parse(raw);
|
|
20
20
|
} catch {
|
|
21
|
-
console.error(`Warning: ${path} contains invalid JSON. Run "volute logout" and re-login.`);
|
|
21
|
+
console.error(`Warning: ${path} contains invalid JSON. Run "volute auth logout" and re-login.`);
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
24
|
if (!data.apiKey || !data.system) return null;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
publish
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-A4S7H6G6.js";
|
|
5
5
|
import {
|
|
6
6
|
logger_default
|
|
7
7
|
} from "./chunk-YUIHSKR6.js";
|
|
8
8
|
|
|
9
|
-
// src/lib/mind-activity-tracker.ts
|
|
9
|
+
// src/lib/events/mind-activity-tracker.ts
|
|
10
10
|
var IDLE_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
11
11
|
var minds = /* @__PURE__ */ new Map();
|
|
12
12
|
function getState(mind) {
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
modeLabel,
|
|
5
5
|
pollHealth,
|
|
6
6
|
startService
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-VT5QODNE.js";
|
|
8
8
|
import {
|
|
9
9
|
parseArgs
|
|
10
10
|
} from "./chunk-D424ZQGI.js";
|
|
11
11
|
import {
|
|
12
12
|
voluteHome
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-B2CPS4QU.js";
|
|
14
14
|
|
|
15
15
|
// src/commands/up.ts
|
|
16
16
|
import { spawn } from "child_process";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
wrapForIsolation
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-NWPT4ASZ.js";
|
|
5
5
|
|
|
6
6
|
// src/lib/exec.ts
|
|
7
7
|
import { execFile as execFileCb, execFileSync, spawn } from "child_process";
|
|
@@ -15,6 +15,7 @@ function exec(cmd, args, options) {
|
|
|
15
15
|
(err, stdout, stderr) => {
|
|
16
16
|
if (err) {
|
|
17
17
|
err.stderr = stderr;
|
|
18
|
+
err.stdout = stdout;
|
|
18
19
|
reject(err);
|
|
19
20
|
} else {
|
|
20
21
|
resolve(stdout);
|