volute 0.31.0 → 0.33.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 +31 -22
- package/dist/{accept-GAKQ3MEH.js → accept-D5VBM7JW.js} +5 -4
- package/dist/{activity-events-T5ZRCVAL.js → activity-events-XJO3P4RR.js} +3 -2
- package/dist/{ai-service-UWUPM4T6.js → ai-service-SBY2WG7O.js} +18 -5
- package/dist/api.d.ts +703 -1068
- package/dist/{archive-YBNSJYZZ.js → archive-INXYFVCW.js} +3 -2
- package/dist/{auth-T5AW2USD.js → auth-GKCDSO4T.js} +4 -3
- package/dist/{bridge-4AJ3EY26.js → bridge-TXWWPPOJ.js} +5 -4
- package/dist/{chat-7YLT7FI3.js → chat-U5ZOME3O.js} +8 -8
- package/dist/{chunk-NV3TYNWX.js → chunk-2NGTS5UU.js} +1 -1
- package/dist/{chunk-BWKIHH7B.js → chunk-3Z2DPESO.js} +662 -508
- package/dist/chunk-6LXAAQ43.js +22 -0
- package/dist/chunk-7J3HEVR7.js +220 -0
- package/dist/{chunk-NOWVQ7AL.js → chunk-A2A4KLFE.js} +351 -301
- package/dist/{chunk-LX6T3GKQ.js → chunk-ALEF47VT.js} +1 -1
- package/dist/{chunk-S2TZLSDH.js → chunk-C7I35G4R.js} +163 -15
- package/dist/{chunk-VGWJSNHS.js → chunk-G53F3JA4.js} +1 -35
- package/dist/{chunk-A6TUJJ3L.js → chunk-G6BSYHPK.js} +2 -2
- package/dist/{chunk-DAXJKPHZ.js → chunk-GY5HBI7A.js} +2 -2
- package/dist/{chunk-BC3P3QCK.js → chunk-I5KY25PQ.js} +1 -9
- package/dist/{chunk-BNC43CSY.js → chunk-JUKK7FPS.js} +2 -2
- package/dist/{chunk-R5QJBZZG.js → chunk-JYVGHWEJ.js} +21 -11
- package/dist/chunk-KIEPMIM5.js +59 -0
- package/dist/{chunk-EKDWA7E4.js → chunk-KVK2DLWI.js} +5 -2
- package/dist/{chunk-AAO77TZX.js → chunk-LOEJ4HPQ.js} +1 -1
- package/dist/chunk-LRCG2JLP.js +251 -0
- package/dist/{chunk-EMPFLFTG.js → chunk-M7UL5S3Q.js} +1 -1
- package/dist/{chunk-6QIUN46C.js → chunk-N432I7QH.js} +20 -3
- package/dist/{chunk-SNVPRRT7.js → chunk-NNB4WIG7.js} +2 -2
- package/dist/{chunk-HDKY4TWU.js → chunk-NPKSDYA2.js} +3 -3
- package/dist/chunk-OYAKCAVY.js +29 -0
- package/dist/chunk-PB65JZK2.js +85 -0
- package/dist/chunk-PVY5W6QN.js +41 -0
- package/dist/{chunk-PNQCXLSV.js → chunk-QTUVYI7W.js} +58 -1
- package/dist/{chunk-X62AXPR7.js → chunk-RPZZSXV3.js} +8 -196
- package/dist/{chunk-WRS3B556.js → chunk-RSX4OPZY.js} +5 -5
- package/dist/{chunk-FAHDKPEH.js → chunk-RVGLDGMI.js} +5 -3
- package/dist/chunk-SKLSMHXO.js +208 -0
- package/dist/{chunk-4OUOFS23.js → chunk-UKVWJRKN.js} +1 -1
- package/dist/{chunk-57OKQMP3.js → chunk-VH33ZWMW.js} +5 -55
- package/dist/cli.js +49 -23
- package/dist/{clock-LJCG426D.js → clock-BVH3V6E3.js} +7 -6
- package/dist/{cloud-sync-O3LXIRN6.js → cloud-sync-4NWLMFVH.js} +20 -14
- package/dist/config-H2H4UIF7.js +72 -0
- package/dist/connectors/discord-bridge.js +1 -1
- package/dist/connectors/slack-bridge.js +1 -1
- package/dist/connectors/telegram-bridge.js +1 -1
- package/dist/{conversations-RKKGP5IA.js → conversations-AWI5SZW2.js} +4 -3
- package/dist/{create-TL623TFC.js → create-2FK7Z46Y.js} +6 -2
- package/dist/{create-WUTIIRI2.js → create-YWD2TIP4.js} +6 -5
- package/dist/{daemon-client-CVGM25DM.js → daemon-client-6QXHZ7US.js} +3 -2
- package/dist/{daemon-restart-EZP7XH3V.js → daemon-restart-GOBUKLX7.js} +8 -6
- package/dist/daemon.js +1918 -1472
- package/dist/{db-SW5PL6QA.js → db-F34YLV7D.js} +2 -1
- package/dist/db-RA45JBFG.js +16 -0
- package/dist/{delete-Z6HAG35F.js → delete-QTGWEDBI.js} +1 -1
- package/dist/delivery-manager-PFAKEJTC.js +32 -0
- package/dist/delivery-router-FL45JL7N.js +21 -0
- package/dist/down-FWWTEKXM.js +15 -0
- package/dist/{env-NHESNNSP.js → env-JCOF2222.js} +5 -4
- package/dist/{export-EVMP7GWY.js → export-SUYRLI5Q.js} +4 -3
- package/dist/{extension-LR7EW3JF.js → extension-OBTGKQQD.js} +5 -3
- package/dist/{extensions-NGEJI7JH.js → extensions-KYNTVTMO.js} +10 -7
- package/dist/{files-3SM7V33S.js → files-65PMW5IK.js} +6 -5
- package/dist/{history-PQD3LXEP.js → history-DKCDI3JO.js} +9 -4
- package/dist/{import-PR2OCGQJ.js → import-DDUFE7AY.js} +4 -3
- package/dist/isolation-LLAYQYDY.js +22 -0
- package/dist/{join-R4EN5CWQ.js → join-I5QEE3LG.js} +1 -1
- package/dist/{list-B4XNUOFO.js → list-JQ463EDA.js} +5 -4
- package/dist/{login-62JVY6A2.js → login-D7ETSU4R.js} +5 -4
- package/dist/{login-URWP6S2N.js → login-RIJF2F4G.js} +3 -2
- package/dist/{logout-NXJQJDLI.js → logout-5MLHZALK.js} +3 -2
- package/dist/{logout-ZK2N62T3.js → logout-UZJRGY4Z.js} +3 -2
- package/dist/message-delivery-DFF5SJRM.js +42 -0
- package/dist/{mind-E2ZV2WRX.js → mind-IOJFLEM5.js} +25 -19
- package/dist/{mind-activity-tracker-ASNZBMLC.js → mind-activity-tracker-F6O4Q2SL.js} +4 -3
- package/dist/{mind-list-BEI7E5WY.js → mind-list-WUPMQDYQ.js} +3 -2
- package/dist/mind-manager-NBJF5D26.js +32 -0
- package/dist/mind-profile-P67FEHOY.js +47 -0
- package/dist/mind-service-2MQ6UK5N.js +38 -0
- package/dist/{mind-sleep-CANABWJI.js → mind-sleep-WW2IX7JT.js} +5 -4
- package/dist/{mind-status-6WKZVUOP.js → mind-status-L3EFFRPR.js} +3 -2
- package/dist/{mind-wake-RZKLH2IN.js → mind-wake-VSSGW465.js} +5 -4
- package/dist/{package-NU4CA7OU.js → package-U3VFO273.js} +2 -1
- package/dist/{read-THL362EI.js → read-EBY56C33.js} +5 -4
- package/dist/read-stdin-HQJ7774D.js +8 -0
- package/dist/{register-QAQELAS6.js → register-HD74C4TT.js} +5 -4
- package/dist/{registry-ASXCQCNH.js → registry-PJ4S5PHQ.js} +8 -1
- package/dist/{reject-AYPBNPNL.js → reject-UJKFBHRO.js} +5 -4
- package/dist/{restart-6SKPV3T2.js → restart-3UCMRUVC.js} +3 -2
- package/dist/{sandbox-6ZEWQDVU.js → sandbox-GJOK4QLQ.js} +4 -3
- package/dist/scheduler-ZZ7XGQG6.js +32 -0
- package/dist/schema-PA3M5ZKH.js +32 -0
- package/dist/seed-QDYVLG74.js +11 -0
- package/dist/seed-check-S2IX25RL.js +32 -0
- package/dist/seed-cmd-DKOUFEAU.js +36 -0
- package/dist/{seed-OWX2AW75.js → seed-create-4XBBOLRH.js} +27 -10
- package/dist/{sprout-FDVI2CGN.js → seed-sprout-GQEIIQRT.js} +24 -9
- package/dist/{send-ZO4BTWXK.js → send-QIV2INHB.js} +92 -101
- package/dist/{setup-7CFITEQN.js → setup-TISPCO22.js} +7 -2
- package/dist/{setup-ZXBXG7E4.js → setup-XMCBE3LF.js} +11 -7
- package/dist/{skill-YFXP67A2.js → skill-PSQGRRJX.js} +5 -4
- package/dist/skills/dreaming/SKILL.md +6 -4
- package/dist/skills/dreaming/references/INSTALL.md +2 -2
- package/dist/skills/dreaming/scripts/dream.ts +2 -2
- package/dist/skills/dreaming/scripts/wake-context-dreams.sh +1 -1
- package/dist/skills/imagegen/SKILL.md +16 -11
- package/dist/skills/imagegen/references/INSTALL.md +1 -1
- package/dist/skills/imagegen/scripts/imagegen.ts +146 -25
- package/dist/skills/orientation/SKILL.md +9 -2
- package/dist/skills/resonance/SKILL.md +4 -1
- package/dist/skills/resonance/references/INSTALL.md +2 -2
- package/dist/skills/resonance/scripts/resonance-hook.sh +2 -0
- package/dist/skills/resonance/scripts/resonance.ts +35 -5
- package/dist/skills/seed-nurture/SKILL.md +42 -0
- package/dist/skills/volute-admin/SKILL.md +83 -0
- package/dist/skills/volute-mind/SKILL.md +15 -11
- package/dist/skills-7FV7EJTE.js +62 -0
- package/dist/sleep-manager-JTXSN7NV.js +36 -0
- package/dist/spirit-VRONKFMF.js +23 -0
- package/dist/{split-MI62KJUU.js → split-STOROBYJ.js} +1 -1
- package/dist/sprout-WKLZXUIQ.js +11 -0
- package/dist/{start-D64BRKPH.js → start-K2NCUUCG.js} +3 -2
- package/dist/{status-ZZWBYFGE.js → status-3JBTFSMI.js} +6 -4
- package/dist/{stop-OP2CTXCO.js → stop-H26JZDXF.js} +3 -2
- package/dist/system-chat-JAPOJ3KE.js +36 -0
- package/dist/{systems-EQPPT4B7.js → systems-XRI52VCH.js} +6 -5
- package/dist/{tailscale-6DJKUMNF.js → tailscale-XHQBZROW.js} +2 -1
- package/dist/{template-hash-3HOR4UAJ.js → template-hash-A6VVKOXJ.js} +2 -1
- package/dist/up-M5AS6SBV.js +18 -0
- package/dist/{update-KUJXATRS.js → update-UD543CXX.js} +6 -4
- package/dist/{update-check-5WVSU37T.js → update-check-ZD6OOIYQ.js} +3 -2
- package/dist/{upgrade-KBHCWX6T.js → upgrade-O4Q7WJM3.js} +12 -14
- package/dist/{version-notify-75ELVKPV.js → version-notify-NBI2MTJO.js} +22 -16
- package/dist/volute-config-HD7WWUQC.js +10 -0
- package/dist/web-assets/assets/index-CWJrVveV.css +1 -0
- package/dist/web-assets/assets/index-DJt14FRI.js +75 -0
- package/dist/web-assets/ext-theme.css +93 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0004_spirits.sql +5 -0
- package/drizzle/meta/0004_snapshot.json +7 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +2 -1
- package/packages/extensions/notes/dist/ui/assets/index-8jWEv9SA.js +61 -0
- package/packages/extensions/notes/dist/ui/assets/index-DkaB7Ytd.css +1 -0
- package/packages/extensions/notes/dist/ui/index.html +2 -2
- package/packages/extensions/pages/skills/pages/SKILL.md +16 -46
- package/templates/_base/.init/.config/hooks/pre-prompt/session-activity.ts +40 -0
- package/templates/_base/.init/{.config → .local}/bin/volute +1 -1
- package/templates/_base/.init/.local/hooks/pre-prompt/session-activity.ts +40 -0
- package/templates/_base/.init/.local/hooks/startup-context.ts +58 -0
- package/templates/_base/home/.config/routes.json +1 -1
- package/templates/_base/src/lib/daemon-client.ts +21 -13
- package/templates/_base/src/lib/format-prefix.ts +1 -0
- package/templates/_base/src/lib/hook-loader.ts +155 -0
- package/templates/_base/src/lib/startup.ts +11 -4
- package/templates/_base/src/lib/transparency.ts +2 -2
- package/templates/claude/.init/.claude/settings.json +1 -1
- package/templates/claude/.init/.config/routes.json +2 -2
- package/templates/claude/src/agent.ts +95 -13
- package/templates/claude/src/lib/message-channel.ts +7 -2
- package/templates/claude/src/lib/stream-consumer.ts +38 -0
- package/templates/codex/.init/.config/routes.json +11 -0
- package/templates/codex/.init/AGENTS.md +29 -0
- package/templates/codex/home/.config/config.json.tmpl +7 -0
- package/templates/codex/package.json.tmpl +20 -0
- package/templates/codex/src/agent.ts +554 -0
- package/templates/codex/src/lib/content.ts +16 -0
- package/templates/codex/src/lib/session-store.ts +56 -0
- package/templates/codex/src/server.ts +59 -0
- package/templates/codex/volute-template.json +8 -0
- package/templates/pi/.init/.config/routes.json +2 -2
- package/templates/pi/src/agent.ts +62 -8
- package/templates/pi/src/lib/event-handler.ts +1 -1
- package/templates/pi/src/lib/reply-instructions-extension.ts +32 -11
- package/dist/chunk-HR5JKIDG.js +0 -222
- package/dist/down-TS4XQBA4.js +0 -13
- package/dist/message-delivery-UJHCLVU4.js +0 -30
- package/dist/mind-manager-IPA6DZXD.js +0 -26
- package/dist/pages-watcher-72OVPRMH.js +0 -22
- package/dist/skills/sessions/SKILL.md +0 -49
- package/dist/sleep-manager-TPS6OGCA.js +0 -30
- package/dist/system-chat-B43GIXQU.js +0 -30
- package/dist/up-TDXEP3VA.js +0 -16
- package/dist/web-assets/assets/index-BM1cTzBg.js +0 -72
- package/dist/web-assets/assets/index-BfJkKTPF.css +0 -1
- package/packages/extensions/notes/dist/ui/assets/index-B8GdTnXs.css +0 -1
- package/packages/extensions/notes/dist/ui/assets/index-CDpGTCWb.js +0 -2
- package/packages/extensions/pages/skills/pages/scripts/pages.mjs +0 -58
- package/templates/_base/.init/.config/hooks/startup-context.sh +0 -46
- package/templates/_base/.init/.config/scripts/session-reader.ts +0 -59
- package/templates/_base/src/lib/session-monitor.ts +0 -400
- package/templates/claude/src/lib/hooks/session-context.ts +0 -32
- package/templates/pi/src/lib/session-context-extension.ts +0 -35
- /package/templates/_base/.init/{.config → .local}/hooks/wake-context.sh +0 -0
|
@@ -5,16 +5,18 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
exec,
|
|
7
7
|
gitExec
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KIEPMIM5.js";
|
|
9
9
|
import {
|
|
10
10
|
readGlobalConfig,
|
|
11
11
|
writeGlobalConfig
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-N432I7QH.js";
|
|
13
13
|
import {
|
|
14
14
|
getDb,
|
|
15
|
-
sharedSkills,
|
|
16
15
|
voluteHome
|
|
17
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-LRCG2JLP.js";
|
|
17
|
+
import {
|
|
18
|
+
sharedSkills
|
|
19
|
+
} from "./chunk-RPZZSXV3.js";
|
|
18
20
|
|
|
19
21
|
// src/lib/skills.ts
|
|
20
22
|
import { createHash } from "crypto";
|
|
@@ -32,7 +34,7 @@ import { basename, dirname, join, resolve } from "path";
|
|
|
32
34
|
import { eq, sql } from "drizzle-orm";
|
|
33
35
|
var VALID_SKILL_ID = /^[a-zA-Z0-9_-]+$/;
|
|
34
36
|
var SEED_SKILLS = ["orientation", "memory"];
|
|
35
|
-
var STANDARD_SKILLS = ["volute-mind", "memory", "
|
|
37
|
+
var STANDARD_SKILLS = ["volute-mind", "memory", "dreaming", "shared-files"];
|
|
36
38
|
function getStandardSkillsWithExtensions() {
|
|
37
39
|
const config = readGlobalConfig();
|
|
38
40
|
if (config.defaultSkills) return [...config.defaultSkills];
|
|
@@ -42,7 +44,7 @@ async function initDefaultSkills() {
|
|
|
42
44
|
const config = readGlobalConfig();
|
|
43
45
|
let extensionSkills = [];
|
|
44
46
|
try {
|
|
45
|
-
const { getExtensionStandardSkills } = await import("./extensions-
|
|
47
|
+
const { getExtensionStandardSkills } = await import("./extensions-KYNTVTMO.js");
|
|
46
48
|
extensionSkills = getExtensionStandardSkills();
|
|
47
49
|
} catch (err) {
|
|
48
50
|
logger_default.warn("failed to load extension standard skills during init", logger_default.errorData(err));
|
|
@@ -66,15 +68,43 @@ function sharedSkillsDir() {
|
|
|
66
68
|
}
|
|
67
69
|
function parseSkillMd(content) {
|
|
68
70
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
69
|
-
if (!match) return { name: "", description: "", npmDependencies: [] };
|
|
71
|
+
if (!match) return { name: "", description: "", npmDependencies: [], hooks: {}, bin: null };
|
|
70
72
|
const frontmatter = match[1];
|
|
71
73
|
const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
|
|
72
74
|
const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
|
|
73
75
|
const depsMatch = frontmatter.match(/^\s*npm-dependencies:\s*(.+)$/m);
|
|
76
|
+
const binMatch = frontmatter.match(/^\s*bin:\s*(.+)$/m);
|
|
77
|
+
const hooks = {};
|
|
78
|
+
const lines = frontmatter.split("\n");
|
|
79
|
+
let inHooks = false;
|
|
80
|
+
let hooksIndent = -1;
|
|
81
|
+
for (const line of lines) {
|
|
82
|
+
if (!line.trim()) continue;
|
|
83
|
+
const hooksStart = line.match(/^(\s+)hooks:\s*$/);
|
|
84
|
+
if (hooksStart) {
|
|
85
|
+
inHooks = true;
|
|
86
|
+
hooksIndent = hooksStart[1].length;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (inHooks) {
|
|
90
|
+
const lineIndentMatch = line.match(/^(\s*)/);
|
|
91
|
+
const lineIndent = lineIndentMatch ? lineIndentMatch[1].length : 0;
|
|
92
|
+
if (lineIndent <= hooksIndent) {
|
|
93
|
+
inHooks = false;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const hookMatch = line.match(/^\s+([a-z0-9-]+):\s*(.+)$/);
|
|
97
|
+
if (hookMatch) {
|
|
98
|
+
hooks[hookMatch[1]] = hookMatch[2].trim();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
74
102
|
return {
|
|
75
103
|
name: nameMatch?.[1].trim() ?? "",
|
|
76
104
|
description: descMatch?.[1].trim() ?? "",
|
|
77
|
-
npmDependencies: depsMatch ? depsMatch[1].trim().split(/[\s,]+/).filter(Boolean) : []
|
|
105
|
+
npmDependencies: depsMatch ? depsMatch[1].trim().split(/[\s,]+/).filter(Boolean) : [],
|
|
106
|
+
hooks,
|
|
107
|
+
bin: binMatch?.[1].trim() ?? null
|
|
78
108
|
};
|
|
79
109
|
}
|
|
80
110
|
async function listSharedSkills() {
|
|
@@ -128,8 +158,24 @@ async function removeSharedSkill(id) {
|
|
|
128
158
|
const dir = join(sharedSkillsDir(), id);
|
|
129
159
|
if (existsSync(dir)) rmSync(dir, { recursive: true });
|
|
130
160
|
}
|
|
161
|
+
var TEMPLATE_SKILLS_DIR = {
|
|
162
|
+
claude: ".claude/skills",
|
|
163
|
+
pi: ".pi/skills",
|
|
164
|
+
codex: ".agents/skills"
|
|
165
|
+
};
|
|
131
166
|
function mindSkillsDir(dir) {
|
|
132
|
-
|
|
167
|
+
const home = resolve(dir, "home");
|
|
168
|
+
let subdir = TEMPLATE_SKILLS_DIR.claude;
|
|
169
|
+
if (existsSync(join(home, "AGENTS.md"))) {
|
|
170
|
+
subdir = TEMPLATE_SKILLS_DIR.codex;
|
|
171
|
+
} else if (existsSync(join(home, "MINDS.md"))) {
|
|
172
|
+
subdir = TEMPLATE_SKILLS_DIR.pi;
|
|
173
|
+
}
|
|
174
|
+
return resolve(home, subdir);
|
|
175
|
+
}
|
|
176
|
+
function relSkillsPath(dir) {
|
|
177
|
+
const home = resolve(dir, "home");
|
|
178
|
+
return join("home", mindSkillsDir(dir).slice(home.length + 1));
|
|
133
179
|
}
|
|
134
180
|
function readUpstream(skillDir) {
|
|
135
181
|
const upstreamPath = join(skillDir, ".upstream.json");
|
|
@@ -172,12 +218,21 @@ async function installSkill(_mindName, dir, skillId) {
|
|
|
172
218
|
}
|
|
173
219
|
}
|
|
174
220
|
}
|
|
221
|
+
if (existsSync(skillMdPath)) {
|
|
222
|
+
const { hooks, bin } = parseSkillMd(readFileSync(skillMdPath, "utf-8"));
|
|
223
|
+
installHookShims(dir, skillId, hooks);
|
|
224
|
+
if (bin) installBinShim(dir, skillId, bin);
|
|
225
|
+
}
|
|
175
226
|
let installNotes = null;
|
|
176
227
|
const installMdPath = join(destDir, "references", "INSTALL.md");
|
|
177
228
|
if (existsSync(installMdPath)) {
|
|
178
229
|
installNotes = readFileSync(installMdPath, "utf-8");
|
|
179
230
|
}
|
|
180
|
-
await gitExec(["add", join(
|
|
231
|
+
await gitExec(["add", join(relSkillsPath(dir), skillId)], { cwd: dir });
|
|
232
|
+
await gitExec(["add", join("home", ".local", "hooks")], { cwd: dir }).catch(() => {
|
|
233
|
+
});
|
|
234
|
+
await gitExec(["add", join("home", ".local", "bin")], { cwd: dir }).catch(() => {
|
|
235
|
+
});
|
|
181
236
|
if (npmInstalled.length > 0) {
|
|
182
237
|
await gitExec(["add", "package.json", "package-lock.json"], { cwd: dir });
|
|
183
238
|
}
|
|
@@ -190,7 +245,7 @@ async function installSkill(_mindName, dir, skillId) {
|
|
|
190
245
|
};
|
|
191
246
|
writeFileSync(join(destDir, ".upstream.json"), `${JSON.stringify(upstream, null, 2)}
|
|
192
247
|
`);
|
|
193
|
-
await gitExec(["add", join(
|
|
248
|
+
await gitExec(["add", join(relSkillsPath(dir), skillId, ".upstream.json")], {
|
|
194
249
|
cwd: dir
|
|
195
250
|
});
|
|
196
251
|
await gitExec(["commit", "--amend", "--no-edit"], { cwd: dir });
|
|
@@ -200,8 +255,18 @@ async function uninstallSkill(_mindName, dir, skillId) {
|
|
|
200
255
|
validateSkillId(skillId);
|
|
201
256
|
const skillDir = join(mindSkillsDir(dir), skillId);
|
|
202
257
|
if (!existsSync(skillDir)) throw new Error(`Skill not installed: ${skillId}`);
|
|
258
|
+
removeHookShims(dir, skillId);
|
|
259
|
+
const skillMdPath = join(skillDir, "SKILL.md");
|
|
260
|
+
if (existsSync(skillMdPath)) {
|
|
261
|
+
const { bin } = parseSkillMd(readFileSync(skillMdPath, "utf-8"));
|
|
262
|
+
if (bin) removeBinShim(dir, bin);
|
|
263
|
+
}
|
|
203
264
|
rmSync(skillDir, { recursive: true });
|
|
204
|
-
await gitExec(["add", join(
|
|
265
|
+
await gitExec(["add", join(relSkillsPath(dir), skillId)], { cwd: dir });
|
|
266
|
+
await gitExec(["add", join("home", ".local", "hooks")], { cwd: dir }).catch(() => {
|
|
267
|
+
});
|
|
268
|
+
await gitExec(["add", join("home", ".local", "bin")], { cwd: dir }).catch(() => {
|
|
269
|
+
});
|
|
205
270
|
await gitExec(["commit", "-m", `Uninstall skill: ${skillId}`], { cwd: dir });
|
|
206
271
|
}
|
|
207
272
|
async function updateSkill(_mindName, dir, skillId) {
|
|
@@ -217,7 +282,7 @@ async function updateSkill(_mindName, dir, skillId) {
|
|
|
217
282
|
}
|
|
218
283
|
const sourceDir = join(sharedSkillsDir(), upstream.source);
|
|
219
284
|
if (!existsSync(sourceDir)) throw new Error(`Shared skill files missing: ${upstream.source}`);
|
|
220
|
-
const relSkillPath = join(
|
|
285
|
+
const relSkillPath = join(relSkillsPath(dir), skillId);
|
|
221
286
|
const currentFiles = listFilesRecursive(skillDir).filter((f) => f !== ".upstream.json");
|
|
222
287
|
const newFiles = listFilesRecursive(sourceDir).filter((f) => f !== ".upstream.json");
|
|
223
288
|
const allFiles = [.../* @__PURE__ */ new Set([...currentFiles, ...newFiles])];
|
|
@@ -241,7 +306,9 @@ async function updateSkill(_mindName, dir, skillId) {
|
|
|
241
306
|
try {
|
|
242
307
|
baseContent2 = await gitExec(
|
|
243
308
|
["show", `${upstream.baseCommit}:${join(relSkillPath, file)}`],
|
|
244
|
-
{
|
|
309
|
+
{
|
|
310
|
+
cwd: dir
|
|
311
|
+
}
|
|
245
312
|
);
|
|
246
313
|
} catch {
|
|
247
314
|
continue;
|
|
@@ -256,7 +323,9 @@ async function updateSkill(_mindName, dir, skillId) {
|
|
|
256
323
|
try {
|
|
257
324
|
baseContent = await gitExec(
|
|
258
325
|
["show", `${upstream.baseCommit}:${join(relSkillPath, file)}`],
|
|
259
|
-
{
|
|
326
|
+
{
|
|
327
|
+
cwd: dir
|
|
328
|
+
}
|
|
260
329
|
);
|
|
261
330
|
} catch {
|
|
262
331
|
baseContent = "";
|
|
@@ -352,6 +421,77 @@ async function publishSkill(mindName, dir, skillId) {
|
|
|
352
421
|
if (!existsSync(skillMdPath)) throw new Error(`SKILL.md not found in ${skillId}`);
|
|
353
422
|
return importSkillFromDir(skillDir, mindName);
|
|
354
423
|
}
|
|
424
|
+
function shimContent(skillId, scriptPath, skillsSubdir) {
|
|
425
|
+
const ext = scriptPath.split(".").pop() ?? "sh";
|
|
426
|
+
const skillScriptPath = `${skillsSubdir}/${skillId}/${scriptPath}`;
|
|
427
|
+
if (ext === "ts") {
|
|
428
|
+
return `#!/bin/bash
|
|
429
|
+
exec node --import tsx ${skillScriptPath} "$@"
|
|
430
|
+
`;
|
|
431
|
+
}
|
|
432
|
+
if (ext === "js") {
|
|
433
|
+
return `#!/bin/bash
|
|
434
|
+
exec node ${skillScriptPath} "$@"
|
|
435
|
+
`;
|
|
436
|
+
}
|
|
437
|
+
return `#!/bin/bash
|
|
438
|
+
exec bash ${skillScriptPath} "$@"
|
|
439
|
+
`;
|
|
440
|
+
}
|
|
441
|
+
function installHookShims(dir, skillId, hooks) {
|
|
442
|
+
const home = resolve(dir, "home");
|
|
443
|
+
const skillsSubdir = mindSkillsDir(dir).slice(home.length + 1);
|
|
444
|
+
for (const [event, scriptPath] of Object.entries(hooks)) {
|
|
445
|
+
const eventDir = join(dir, "home", ".local", "hooks", event);
|
|
446
|
+
mkdirSync(eventDir, { recursive: true });
|
|
447
|
+
const shimPath = join(eventDir, `50-${skillId}.sh`);
|
|
448
|
+
const content = shimContent(skillId, scriptPath, skillsSubdir);
|
|
449
|
+
writeFileSync(shimPath, content, { mode: 493 });
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function removeHookShims(dir, skillId) {
|
|
453
|
+
const hooksBase = join(dir, "home", ".local", "hooks");
|
|
454
|
+
if (!existsSync(hooksBase)) return;
|
|
455
|
+
for (const eventDir of readdirSync(hooksBase, { withFileTypes: true })) {
|
|
456
|
+
if (!eventDir.isDirectory()) continue;
|
|
457
|
+
const shimPath = join(hooksBase, eventDir.name, `50-${skillId}.sh`);
|
|
458
|
+
if (existsSync(shimPath)) rmSync(shimPath);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
function binShimContent(skillId, scriptPath, skillsSubdir) {
|
|
462
|
+
const skillScriptPath = `${skillsSubdir}/${skillId}/${scriptPath}`;
|
|
463
|
+
const ext = scriptPath.split(".").pop() ?? "sh";
|
|
464
|
+
if (ext === "ts") {
|
|
465
|
+
return `#!/bin/bash
|
|
466
|
+
exec node --import tsx ${skillScriptPath} "$@"
|
|
467
|
+
`;
|
|
468
|
+
}
|
|
469
|
+
if (ext === "js") {
|
|
470
|
+
return `#!/bin/bash
|
|
471
|
+
exec node ${skillScriptPath} "$@"
|
|
472
|
+
`;
|
|
473
|
+
}
|
|
474
|
+
return `#!/bin/bash
|
|
475
|
+
exec bash ${skillScriptPath} "$@"
|
|
476
|
+
`;
|
|
477
|
+
}
|
|
478
|
+
function binCommandName(scriptPath) {
|
|
479
|
+
return basename(scriptPath).replace(/\.[^.]+$/, "");
|
|
480
|
+
}
|
|
481
|
+
function installBinShim(dir, skillId, scriptPath) {
|
|
482
|
+
const home = resolve(dir, "home");
|
|
483
|
+
const skillsSubdir = mindSkillsDir(dir).slice(home.length + 1);
|
|
484
|
+
const binDir = join(dir, "home", ".local", "bin");
|
|
485
|
+
mkdirSync(binDir, { recursive: true });
|
|
486
|
+
const cmdName = binCommandName(scriptPath);
|
|
487
|
+
const shimPath = join(binDir, cmdName);
|
|
488
|
+
writeFileSync(shimPath, binShimContent(skillId, scriptPath, skillsSubdir), { mode: 493 });
|
|
489
|
+
}
|
|
490
|
+
function removeBinShim(dir, scriptPath) {
|
|
491
|
+
const cmdName = binCommandName(scriptPath);
|
|
492
|
+
const shimPath = join(dir, "home", ".local", "bin", cmdName);
|
|
493
|
+
if (existsSync(shimPath)) rmSync(shimPath);
|
|
494
|
+
}
|
|
355
495
|
function listFilesRecursive(dir, prefix = "") {
|
|
356
496
|
const results = [];
|
|
357
497
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
@@ -420,16 +560,24 @@ export {
|
|
|
420
560
|
getStandardSkillsWithExtensions,
|
|
421
561
|
initDefaultSkills,
|
|
422
562
|
sharedSkillsDir,
|
|
563
|
+
parseSkillMd,
|
|
423
564
|
listSharedSkills,
|
|
424
565
|
getSharedSkill,
|
|
425
566
|
importSkillFromDir,
|
|
426
567
|
removeSharedSkill,
|
|
568
|
+
mindSkillsDir,
|
|
569
|
+
readUpstream,
|
|
427
570
|
installSkill,
|
|
428
571
|
uninstallSkill,
|
|
429
572
|
updateSkill,
|
|
430
573
|
listMindSkills,
|
|
431
574
|
publishSkill,
|
|
575
|
+
installHookShims,
|
|
576
|
+
removeHookShims,
|
|
577
|
+
installBinShim,
|
|
578
|
+
removeBinShim,
|
|
432
579
|
listFilesRecursive,
|
|
580
|
+
findSkillsRoot,
|
|
433
581
|
hashSkillDir,
|
|
434
582
|
syncBuiltinSkills
|
|
435
583
|
};
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
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
3
|
// src/lib/template.ts
|
|
9
4
|
import {
|
|
10
5
|
cpSync,
|
|
@@ -110,39 +105,10 @@ function listFiles(dir) {
|
|
|
110
105
|
return results;
|
|
111
106
|
}
|
|
112
107
|
|
|
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
108
|
export {
|
|
142
109
|
findTemplatesRoot,
|
|
143
110
|
composeTemplate,
|
|
144
111
|
copyTemplateToDir,
|
|
145
112
|
applyInitFiles,
|
|
146
|
-
listFiles
|
|
147
|
-
computeTemplateHash
|
|
113
|
+
listFiles
|
|
148
114
|
};
|
|
@@ -6,11 +6,11 @@ function slugify(text) {
|
|
|
6
6
|
}
|
|
7
7
|
function buildVoluteSlug(opts) {
|
|
8
8
|
if (opts.convType === "channel" && opts.convName) {
|
|
9
|
-
return
|
|
9
|
+
return `#${opts.convName}`;
|
|
10
10
|
}
|
|
11
11
|
const other = opts.participants.find((p) => p.username !== opts.mindUsername);
|
|
12
12
|
const otherSlug = other ? slugify(other.username) : "";
|
|
13
|
-
return otherSlug ?
|
|
13
|
+
return otherSlug ? `@${otherSlug}` : opts.conversationId;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export {
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
} from "./chunk-YUIHSKR6.js";
|
|
5
5
|
import {
|
|
6
6
|
readGlobalConfig
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-N432I7QH.js";
|
|
8
8
|
import {
|
|
9
9
|
getBaseName,
|
|
10
10
|
readRegistry,
|
|
11
11
|
voluteHome,
|
|
12
12
|
voluteSystemDir,
|
|
13
13
|
voluteUserHome
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-LRCG2JLP.js";
|
|
15
15
|
|
|
16
16
|
// src/lib/sandbox.ts
|
|
17
17
|
import { resolve } from "path";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
mindDir,
|
|
4
4
|
stateDir
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LRCG2JLP.js";
|
|
6
6
|
|
|
7
7
|
// src/lib/archive.ts
|
|
8
8
|
import { execFileSync } from "child_process";
|
|
@@ -91,12 +91,6 @@ function createExportArchive(options) {
|
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
if (existsSync(state)) {
|
|
95
|
-
const channelsPath = resolve(state, "channels.json");
|
|
96
|
-
if (existsSync(channelsPath)) {
|
|
97
|
-
zip.addFile("state/channels.json", readFileSync(channelsPath));
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
94
|
if (includeEnv && existsSync(state)) {
|
|
101
95
|
const envPath = resolve(state, "env.json");
|
|
102
96
|
if (existsSync(envPath)) {
|
|
@@ -184,14 +178,12 @@ function extractArchive(archivePath, destDir) {
|
|
|
184
178
|
mkdirSync(resolve(destPath, ".."), { recursive: true });
|
|
185
179
|
writeFileSync(destPath, entry.getData());
|
|
186
180
|
}
|
|
187
|
-
const channelsJson = resolve(extractedStateDir, "channels.json");
|
|
188
181
|
const envJson = resolve(extractedStateDir, "env.json");
|
|
189
182
|
const historyJsonl = resolve(normalizedDestDir, "history.jsonl");
|
|
190
183
|
const sessionsDir = resolve(normalizedDestDir, "sessions");
|
|
191
184
|
return {
|
|
192
185
|
manifest,
|
|
193
186
|
mindDir: extractedMindDir,
|
|
194
|
-
channelsJson: existsSync(channelsJson) ? channelsJson : null,
|
|
195
187
|
envJson: existsSync(envJson) ? envJson : null,
|
|
196
188
|
historyJsonl: existsSync(historyJsonl) ? historyJsonl : null,
|
|
197
189
|
sessionsDir: existsSync(sessionsDir) ? sessionsDir : null
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
pollHealthDown,
|
|
6
6
|
readDaemonConfig,
|
|
7
7
|
stopService
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NNB4WIG7.js";
|
|
9
9
|
import {
|
|
10
10
|
voluteSystemDir
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LRCG2JLP.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/down.ts
|
|
14
14
|
import { existsSync, readFileSync, unlinkSync } from "fs";
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
broadcast
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-KVK2DLWI.js";
|
|
5
|
+
import {
|
|
6
|
+
getDb
|
|
7
|
+
} from "./chunk-LRCG2JLP.js";
|
|
5
8
|
import {
|
|
6
|
-
getDb,
|
|
7
9
|
users
|
|
8
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-RPZZSXV3.js";
|
|
9
11
|
|
|
10
12
|
// src/lib/auth.ts
|
|
11
13
|
import { compareSync, hashSync } from "bcryptjs";
|
|
12
|
-
import { and, count, eq } from "drizzle-orm";
|
|
14
|
+
import { and, count, eq, or } from "drizzle-orm";
|
|
13
15
|
var userSelectFields = {
|
|
14
16
|
id: users.id,
|
|
15
17
|
username: users.username,
|
|
@@ -61,7 +63,12 @@ async function listUsersByType(userType) {
|
|
|
61
63
|
}
|
|
62
64
|
async function getOrCreateMindUser(mindName) {
|
|
63
65
|
const db = await getDb();
|
|
64
|
-
const existing = await db.select(userSelectFields).from(users).where(
|
|
66
|
+
const existing = await db.select(userSelectFields).from(users).where(
|
|
67
|
+
and(
|
|
68
|
+
eq(users.username, mindName),
|
|
69
|
+
or(eq(users.user_type, "mind"), eq(users.user_type, "system"))
|
|
70
|
+
)
|
|
71
|
+
).get();
|
|
65
72
|
if (existing) return existing;
|
|
66
73
|
try {
|
|
67
74
|
const [result] = await db.insert(users).values({
|
|
@@ -72,10 +79,13 @@ async function getOrCreateMindUser(mindName) {
|
|
|
72
79
|
}).returning(userSelectFields);
|
|
73
80
|
return result;
|
|
74
81
|
} catch (err) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
const retried = await db.select(userSelectFields).from(users).where(
|
|
83
|
+
and(
|
|
84
|
+
eq(users.username, mindName),
|
|
85
|
+
or(eq(users.user_type, "mind"), eq(users.user_type, "system"))
|
|
86
|
+
)
|
|
87
|
+
).get();
|
|
88
|
+
if (retried) return retried;
|
|
79
89
|
throw err;
|
|
80
90
|
}
|
|
81
91
|
}
|
|
@@ -87,9 +97,9 @@ async function getOrCreateSystemUser() {
|
|
|
87
97
|
const [result] = await db.insert(users).values({
|
|
88
98
|
username: "volute",
|
|
89
99
|
password_hash: "!system",
|
|
90
|
-
role: "
|
|
100
|
+
role: "system",
|
|
91
101
|
user_type: "system",
|
|
92
|
-
display_name: "
|
|
102
|
+
display_name: "volute"
|
|
93
103
|
}).returning(userSelectFields);
|
|
94
104
|
return result;
|
|
95
105
|
} catch (err) {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
wrapForIsolation
|
|
4
|
+
} from "./chunk-VH33ZWMW.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/exec.ts
|
|
7
|
+
import { execFile as execFileCb, execFileSync, spawn } from "child_process";
|
|
8
|
+
async function exec(cmd, args, options) {
|
|
9
|
+
const [wrappedCmd, wrappedArgs] = options?.mindName ? await wrapForIsolation(cmd, args, options.mindName) : [cmd, args];
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
execFileCb(
|
|
12
|
+
wrappedCmd,
|
|
13
|
+
wrappedArgs,
|
|
14
|
+
{ cwd: options?.cwd, env: options?.env },
|
|
15
|
+
(err, stdout, stderr) => {
|
|
16
|
+
if (err) {
|
|
17
|
+
err.stderr = stderr;
|
|
18
|
+
err.stdout = stdout;
|
|
19
|
+
reject(err);
|
|
20
|
+
} else {
|
|
21
|
+
resolve(stdout);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function gitExec(args, options) {
|
|
28
|
+
const fullArgs = process.env.VOLUTE_ISOLATION === "user" ? ["-c", "safe.directory=*", ...args] : args;
|
|
29
|
+
return exec("git", fullArgs, options);
|
|
30
|
+
}
|
|
31
|
+
function resolveVoluteBin() {
|
|
32
|
+
try {
|
|
33
|
+
return execFileSync("which", ["volute"], { encoding: "utf-8" }).trim();
|
|
34
|
+
} catch {
|
|
35
|
+
throw new Error("Could not find volute binary on PATH");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function execInherit(cmd, args, options) {
|
|
39
|
+
const [wrappedCmd, wrappedArgs] = options?.mindName ? await wrapForIsolation(cmd, args, options.mindName) : [cmd, args];
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const child = spawn(wrappedCmd, wrappedArgs, {
|
|
42
|
+
cwd: options?.cwd,
|
|
43
|
+
env: options?.env,
|
|
44
|
+
stdio: "inherit"
|
|
45
|
+
});
|
|
46
|
+
child.on("error", reject);
|
|
47
|
+
child.on("close", (code) => {
|
|
48
|
+
if (code === 0) resolve();
|
|
49
|
+
else reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code}`));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
exec,
|
|
56
|
+
gitExec,
|
|
57
|
+
resolveVoluteBin,
|
|
58
|
+
execInherit
|
|
59
|
+
};
|
|
@@ -3,9 +3,11 @@ import {
|
|
|
3
3
|
logger_default
|
|
4
4
|
} from "./chunk-YUIHSKR6.js";
|
|
5
5
|
import {
|
|
6
|
-
activity,
|
|
7
6
|
getDb
|
|
8
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-LRCG2JLP.js";
|
|
8
|
+
import {
|
|
9
|
+
activity
|
|
10
|
+
} from "./chunk-RPZZSXV3.js";
|
|
9
11
|
|
|
10
12
|
// src/lib/events/activity-events.ts
|
|
11
13
|
var subscribers = /* @__PURE__ */ new Set();
|
|
@@ -35,6 +37,7 @@ async function publish(event) {
|
|
|
35
37
|
}
|
|
36
38
|
const full = { ...event, id, created_at };
|
|
37
39
|
notify(full);
|
|
40
|
+
return id;
|
|
38
41
|
}
|
|
39
42
|
function broadcast(event) {
|
|
40
43
|
const created_at = event.created_at ?? (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|