volute 0.43.1 → 0.45.1

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.
Files changed (132) hide show
  1. package/dist/{activity-events-UISXY4Y5.js → activity-events-OMCSM7XW.js} +3 -3
  2. package/dist/{ai-service-FBCCEYF5.js → ai-service-534WUSDL.js} +4 -4
  3. package/dist/{archive-I32WHCJB.js → archive-6R4TZMYI.js} +3 -3
  4. package/dist/{auth-3RIG6GKN.js → auth-FRZJVQCS.js} +4 -4
  5. package/dist/avatar-image-BNWEXSA2.js +16 -0
  6. package/dist/backup-OZXHL3JS.js +381 -0
  7. package/dist/{chat-SDSX5TVV.js → chat-I4EDDIQC.js} +2 -2
  8. package/dist/{chunk-AD46AYZQ.js → chunk-2BONPXAF.js} +1 -1
  9. package/dist/{chunk-ONM2AZFL.js → chunk-322KE457.js} +14 -2
  10. package/dist/{chunk-PGPLCJPK.js → chunk-3ERIL673.js} +1 -1
  11. package/dist/{chunk-QQ2MVQU3.js → chunk-5AUKCNPE.js} +10 -10
  12. package/dist/{chunk-XDTKJNW5.js → chunk-5GT7URXJ.js} +1 -1
  13. package/dist/{chunk-DMUPZQWP.js → chunk-77BVGCTZ.js} +8 -8
  14. package/dist/{chunk-EFL5UOY4.js → chunk-CYI534DJ.js} +3 -3
  15. package/dist/{chunk-57LBQ7JX.js → chunk-FHWUQZXE.js} +1 -1
  16. package/dist/{chunk-YAMO2U3N.js → chunk-H7IYFRAL.js} +1 -1
  17. package/dist/{chunk-M3PGGSBH.js → chunk-HVU45COX.js} +1 -1
  18. package/dist/{chunk-O3DXAR44.js → chunk-IEWZ7VD7.js} +2 -2
  19. package/dist/{chunk-DE4EKQFH.js → chunk-IUXTYXFI.js} +3 -3
  20. package/dist/{chunk-K4EHBHPE.js → chunk-JSRMEY52.js} +7 -5
  21. package/dist/{chunk-QHG4OMZL.js → chunk-KDLYIECM.js} +37 -32
  22. package/dist/{chunk-EE7SZJON.js → chunk-KP3KWNG6.js} +2 -2
  23. package/dist/chunk-KVKP6VQ5.js +318 -0
  24. package/dist/{chunk-JVK6QQIC.js → chunk-LAXUUY7O.js} +2 -2
  25. package/dist/{chunk-C6ESRQZ7.js → chunk-OXXTPILE.js} +1 -1
  26. package/dist/{chunk-ATEX3ZPG.js → chunk-Q2XBKQ2D.js} +2 -2
  27. package/dist/{chunk-GZJFC76M.js → chunk-QMJJWTNL.js} +1 -1
  28. package/dist/chunk-SQL7M4HJ.js +120 -0
  29. package/dist/{chunk-YSV3VJQK.js → chunk-TSK5PI4L.js} +1 -1
  30. package/dist/{chunk-4SVONUTC.js → chunk-U4FNXDEJ.js} +350 -207
  31. package/dist/{chunk-2HIVYZDB.js → chunk-UMI4UIJG.js} +1 -1
  32. package/dist/{chunk-Y6O35D7K.js → chunk-V4GYPD5L.js} +41 -16
  33. package/dist/{chunk-KINGVQSR.js → chunk-Y6OPHHGM.js} +5 -5
  34. package/dist/{chunk-SPLPKBES.js → chunk-ZIR7HSAX.js} +6 -9
  35. package/dist/{chunk-7G2EEYXX.js → chunk-ZMIMSIIT.js} +2 -2
  36. package/dist/{chunk-L3IV23ZG.js → chunk-ZV7MFISX.js} +2 -0
  37. package/dist/cli.js +53 -22
  38. package/dist/{cloud-sync-KOEBUFW5.js → cloud-sync-Y7LQPRE3.js} +16 -16
  39. package/dist/{conversations-67WWW25C.js → conversations-G4LYMHAA.js} +4 -4
  40. package/dist/{create-7W3LV3J7.js → create-2YY7IPMS.js} +1 -1
  41. package/dist/{daemon-restart-EZXB73W7.js → daemon-restart-ABP54YN6.js} +7 -7
  42. package/dist/daemon.js +679 -478
  43. package/dist/{db-CZV62BOQ.js → db-JFLCJCUG.js} +2 -2
  44. package/dist/{db-IJL6B26S.js → db-LZTLA7XC.js} +1 -1
  45. package/dist/delivery-manager-R5STGLXB.js +32 -0
  46. package/dist/{delivery-router-HXBHYHJM.js → delivery-router-6DE3BPHO.js} +3 -3
  47. package/dist/{down-RRNYIGCU.js → down-XCAZXWLB.js} +5 -5
  48. package/dist/echo-text-NQXYYYCU.js +32 -0
  49. package/dist/{exec-SJK7VUTC.js → exec-4GWHAHS3.js} +3 -3
  50. package/dist/{export-7LPCIB5J.js → export-ID7YUSLZ.js} +3 -3
  51. package/dist/{extensions-PQPZT6LS.js → extensions-AYSPKE33.js} +16 -16
  52. package/dist/{files-LV7VAKPC.js → files-BQ2WB5KC.js} +3 -3
  53. package/dist/{import-XPECCRQ7.js → import-SKID37QX.js} +6 -6
  54. package/dist/{isolation-5AYEY55P.js → isolation-5MB3J73F.js} +3 -3
  55. package/dist/{login-KJSN4JDA.js → login-LM4NF4ZB.js} +2 -2
  56. package/dist/{logout-TMJGUQV2.js → logout-CTJVIZGA.js} +2 -2
  57. package/dist/message-delivery-IUAXRPFE.js +34 -0
  58. package/dist/{mind-G3WEWDM4.js → mind-KLHC7XYR.js} +6 -6
  59. package/dist/{mind-activity-tracker-JHAT6456.js → mind-activity-tracker-BGHJE7XA.js} +4 -4
  60. package/dist/mind-service-BF2LUQMH.js +36 -0
  61. package/dist/{package-24TL6DTF.js → package-BMHV7UHN.js} +1 -1
  62. package/dist/{registry-7LQHTRUX.js → registry-NUJAGLQJ.js} +2 -2
  63. package/dist/{sandbox-SJH3XOPZ.js → sandbox-72MWV4JL.js} +4 -4
  64. package/dist/scheduler-YHJRRV6E.js +30 -0
  65. package/dist/{schema-LRUTFOER.js → schema-PVNG3PQM.js} +1 -1
  66. package/dist/{seed-HHSJTM6O.js → seed-4MKQ5QKG.js} +1 -1
  67. package/dist/{seed-cmd-UPQY35RG.js → seed-cmd-LCXMR7VV.js} +2 -2
  68. package/dist/{seed-create-MDRMXMSB.js → seed-create-N2BF5LQX.js} +3 -3
  69. package/dist/{seed-sprout-4M7IQWMH.js → seed-sprout-6ZDP23YI.js} +7 -7
  70. package/dist/{send-ZBZWIH5V.js → send-O6W53VBM.js} +37 -42
  71. package/dist/{service-4EVZKGSA.js → service-AQVPUANO.js} +4 -4
  72. package/dist/{service-install-SHRM6NHK.js → service-install-4QNUDKLM.js} +5 -5
  73. package/dist/{setup-ZD2LMBR3.js → setup-3O6O2JZ7.js} +7 -7
  74. package/dist/{setup-25MMJ3J4.js → setup-73YBJZQL.js} +3 -3
  75. package/dist/skills/memory/SKILL.md +2 -1
  76. package/dist/skills/orientation/SKILL.md +1 -1
  77. package/dist/skills/plan-coordinator/SKILL.md +2 -2
  78. package/dist/skills/volute-admin/SKILL.md +9 -6
  79. package/dist/skills/volute-mind/SKILL.md +15 -16
  80. package/dist/skills/volute-mind/references/extensions.md +5 -3
  81. package/dist/skills/volute-mind/references/integrations.md +2 -2
  82. package/dist/skills/volute-mind/references/routing.md +19 -23
  83. package/dist/skills/volute-mind/references/variants.md +10 -8
  84. package/dist/{skills-4KQ377GN.js → skills-ND4ZFYUW.js} +5 -5
  85. package/dist/sleep-manager-YAHDOIU5.js +34 -0
  86. package/dist/{spirit-53DQPRNR.js → spirit-II3HOERM.js} +7 -7
  87. package/dist/{sprout-YKM2M6D6.js → sprout-4KUG76AQ.js} +1 -1
  88. package/dist/{src-O4PRLMKM.js → src-JAOVXO5W.js} +1 -0
  89. package/dist/{src-3EGHHKZK.js → src-XFY3XDD6.js} +16 -11
  90. package/dist/{src-L2Z7X5UT.js → src-YH6PQ7LJ.js} +264 -52
  91. package/dist/{status-WTU2WHXY.js → status-E5DQNCAO.js} +5 -5
  92. package/dist/system-chat-E65T2HSW.js +34 -0
  93. package/dist/{tailscale-Q7ZJL7S7.js → tailscale-QAWVKQKU.js} +2 -2
  94. package/dist/{turn-tracker-JZYERJ76.js → turn-tracker-QQIVVXBI.js} +7 -5
  95. package/dist/{up-LFZA4GI5.js → up-LG56MPBI.js} +6 -6
  96. package/dist/{update-EJ7Q77ZX.js → update-7TYVH5FM.js} +5 -5
  97. package/dist/{update-check-ACYYNKTW.js → update-check-VSCSJ7KX.js} +3 -3
  98. package/dist/{upgrade-37DAGF6H.js → upgrade-NWAZ7MLD.js} +1 -1
  99. package/dist/{version-notify-SRQJCQEK.js → version-notify-CODJOUW2.js} +17 -17
  100. package/dist/web-assets/assets/index-B1JBQv2m.css +1 -0
  101. package/dist/web-assets/assets/index-Dac11sKB.js +86 -0
  102. package/dist/web-assets/ext-theme.css +5 -0
  103. package/dist/web-assets/index.html +2 -2
  104. package/package.json +1 -1
  105. package/packages/extensions/notes/dist/ui/assets/{index-BbgANhFm.js → index-D0-DgYyj.js} +1 -1
  106. package/packages/extensions/notes/dist/ui/index.html +1 -1
  107. package/packages/extensions/notes/skills/notes/SKILL.md +31 -3
  108. package/packages/extensions/pages/dist/ui/assets/{index-Dxk-DYrf.js → index-CQjEQg1r.js} +1 -1
  109. package/packages/extensions/pages/dist/ui/index.html +1 -1
  110. package/packages/extensions/plan/skills/plan/SKILL.md +1 -1
  111. package/templates/_base/.init/.config/prompts.json +1 -1
  112. package/templates/_base/.init/.local/hooks/startup-context.ts +21 -4
  113. package/templates/_base/.init/MEMORY.md +2 -1
  114. package/templates/_base/home/VOLUTE.md +6 -9
  115. package/templates/_base/src/lib/startup.ts +1 -1
  116. package/templates/claude/.init/CLAUDE.md +1 -1
  117. package/templates/claude/src/agent.ts +30 -3
  118. package/templates/claude/src/lib/stream-consumer.ts +7 -4
  119. package/templates/codex/.init/AGENTS.md +4 -2
  120. package/templates/codex/src/agent.ts +13 -7
  121. package/templates/pi/.init/MINDS.md +4 -2
  122. package/templates/pi/src/lib/event-handler.ts +6 -2
  123. package/dist/delivery-manager-OMCCJEVP.js +0 -32
  124. package/dist/echo-text-KFSUCZXL.js +0 -32
  125. package/dist/message-delivery-HRGFNWO7.js +0 -34
  126. package/dist/mind-service-2C7AINBO.js +0 -36
  127. package/dist/scheduler-VON2TB52.js +0 -30
  128. package/dist/sleep-manager-AG5SQDDI.js +0 -34
  129. package/dist/system-chat-54RN3K67.js +0 -34
  130. package/dist/web-assets/assets/index-D7udpBCx.css +0 -1
  131. package/dist/web-assets/assets/index-DTDmEfPU.js +0 -79
  132. package/templates/_base/.init/.config/hooks/pre-prompt/session-activity.ts +0 -40
@@ -3,10 +3,10 @@ import {
3
3
  broadcast,
4
4
  publish,
5
5
  subscribe
6
- } from "./chunk-7G2EEYXX.js";
6
+ } from "./chunk-ZMIMSIIT.js";
7
7
  import "./chunk-T2TP6ZC6.js";
8
- import "./chunk-YAMO2U3N.js";
9
- import "./chunk-L3IV23ZG.js";
8
+ import "./chunk-H7IYFRAL.js";
9
+ import "./chunk-ZV7MFISX.js";
10
10
  import "./chunk-K3NQKI34.js";
11
11
  export {
12
12
  broadcast,
@@ -25,11 +25,11 @@ import {
25
25
  setProviderRefreshHook,
26
26
  setUtilityModel,
27
27
  unqualifyModelId
28
- } from "./chunk-YSV3VJQK.js";
29
- import "./chunk-ONM2AZFL.js";
28
+ } from "./chunk-TSK5PI4L.js";
29
+ import "./chunk-322KE457.js";
30
30
  import "./chunk-T2TP6ZC6.js";
31
- import "./chunk-YAMO2U3N.js";
32
- import "./chunk-L3IV23ZG.js";
31
+ import "./chunk-H7IYFRAL.js";
32
+ import "./chunk-ZV7MFISX.js";
33
33
  import "./chunk-K3NQKI34.js";
34
34
  export {
35
35
  addCustomModel,
@@ -5,9 +5,9 @@ import {
5
5
  extractArchive,
6
6
  isHomeOnlyArchive,
7
7
  readManifest
8
- } from "./chunk-GZJFC76M.js";
9
- import "./chunk-YAMO2U3N.js";
10
- import "./chunk-L3IV23ZG.js";
8
+ } from "./chunk-QMJJWTNL.js";
9
+ import "./chunk-H7IYFRAL.js";
10
+ import "./chunk-ZV7MFISX.js";
11
11
  import "./chunk-K3NQKI34.js";
12
12
  export {
13
13
  addHistoryToArchive,
@@ -17,11 +17,11 @@ import {
17
17
  syncMindProfile,
18
18
  updateUserProfile,
19
19
  verifyUser
20
- } from "./chunk-EFL5UOY4.js";
21
- import "./chunk-7G2EEYXX.js";
20
+ } from "./chunk-CYI534DJ.js";
21
+ import "./chunk-ZMIMSIIT.js";
22
22
  import "./chunk-T2TP6ZC6.js";
23
- import "./chunk-YAMO2U3N.js";
24
- import "./chunk-L3IV23ZG.js";
23
+ import "./chunk-H7IYFRAL.js";
24
+ import "./chunk-ZV7MFISX.js";
25
25
  import "./chunk-K3NQKI34.js";
26
26
  export {
27
27
  approveUser,
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ AVATAR_DIM,
4
+ migrateAvatarSizes,
5
+ normalizeAvatar
6
+ } from "./chunk-SQL7M4HJ.js";
7
+ import "./chunk-CU6OFXMM.js";
8
+ import "./chunk-T2TP6ZC6.js";
9
+ import "./chunk-H7IYFRAL.js";
10
+ import "./chunk-ZV7MFISX.js";
11
+ import "./chunk-K3NQKI34.js";
12
+ export {
13
+ AVATAR_DIM,
14
+ migrateAvatarSizes,
15
+ normalizeAvatar
16
+ };
@@ -0,0 +1,381 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ stopDaemon
4
+ } from "./chunk-IEWZ7VD7.js";
5
+ import {
6
+ promptLine,
7
+ promptPassword
8
+ } from "./chunk-VHWGEJ4V.js";
9
+ import {
10
+ daemonFetch
11
+ } from "./chunk-RBNMDAKB.js";
12
+ import {
13
+ getClient,
14
+ urlOf
15
+ } from "./chunk-LOPXTW6H.js";
16
+ import {
17
+ command,
18
+ subcommands
19
+ } from "./chunk-TXSA4Q3V.js";
20
+ import "./chunk-O7IGP7ZW.js";
21
+ import {
22
+ RESTIC_INSTALL_HINT,
23
+ resticVersion,
24
+ restoreStagedDb
25
+ } from "./chunk-KVKP6VQ5.js";
26
+ import {
27
+ getServiceMode,
28
+ modeLabel,
29
+ stopService
30
+ } from "./chunk-Q2XBKQ2D.js";
31
+ import {
32
+ chownMindDir,
33
+ exec,
34
+ execInherit,
35
+ wrapForIsolation
36
+ } from "./chunk-3ERIL673.js";
37
+ import {
38
+ _resetConfigCache,
39
+ readGlobalConfig
40
+ } from "./chunk-322KE457.js";
41
+ import "./chunk-T2TP6ZC6.js";
42
+ import {
43
+ voluteHome,
44
+ voluteSystemDir
45
+ } from "./chunk-H7IYFRAL.js";
46
+ import "./chunk-ZV7MFISX.js";
47
+ import "./chunk-K3NQKI34.js";
48
+
49
+ // src/commands/backup.ts
50
+ import { existsSync, readdirSync, rmSync } from "fs";
51
+ import { resolve } from "path";
52
+ function printPassphrase(password) {
53
+ console.log("\n\u250C\u2500 BACKUP PASSPHRASE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
54
+ console.log(` ${password}`);
55
+ console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
56
+ console.log("Store this somewhere OFF this machine (password manager, paper).");
57
+ console.log("Without it your backups are unreadable \u2014 this is the exact");
58
+ console.log("scenario (lost machine) that backups exist for.\n");
59
+ console.log(`It is also stored in ${resolve(voluteSystemDir(), "secrets.json")}`);
60
+ }
61
+ async function apiError(res, fallback) {
62
+ const data = await res.json().catch(() => ({}));
63
+ console.error(data.error ?? `${fallback}: HTTP ${res.status}`);
64
+ process.exit(1);
65
+ }
66
+ var initCmd = command({
67
+ name: "volute backup init",
68
+ description: "Configure the backup repository and initialize it",
69
+ flags: {
70
+ repo: { type: "string", description: "Restic repository (path, s3:..., b2:..., sftp:...)" },
71
+ password: { type: "string", description: "Repository passphrase (generated if omitted)" }
72
+ },
73
+ examples: [
74
+ "volute backup init --repo /mnt/backups/volute",
75
+ "volute backup init --repo s3:s3.amazonaws.com/my-bucket/volute"
76
+ ],
77
+ run: async ({ flags }) => {
78
+ let repo = flags.repo;
79
+ if (!repo) {
80
+ repo = (await promptLine("Repository (path or s3:/b2:/sftp: URL): ")).trim();
81
+ if (!repo) {
82
+ console.error("A repository is required.");
83
+ process.exit(1);
84
+ }
85
+ }
86
+ const client = getClient();
87
+ const putRes = await daemonFetch(urlOf(client.api.backup.config.$url()), {
88
+ method: "PUT",
89
+ headers: { "Content-Type": "application/json" },
90
+ body: JSON.stringify({ repository: repo, password: flags.password ?? "" })
91
+ });
92
+ if (!putRes.ok) await apiError(putRes, "Failed to save backup config");
93
+ const initRes = await daemonFetch(urlOf(client.api.backup.init.$url()), { method: "POST" });
94
+ if (!initRes.ok) await apiError(initRes, "Failed to initialize repository");
95
+ const { password } = await initRes.json();
96
+ console.log(`Backup repository initialized: ${repo}`);
97
+ if (password) printPassphrase(password);
98
+ console.log("\nEnable scheduled backups with: volute backup schedule --enable");
99
+ console.log("Or run one now with: volute backup create");
100
+ }
101
+ });
102
+ var createCmd = command({
103
+ name: "volute backup create",
104
+ description: "Run a backup now",
105
+ flags: {},
106
+ run: async () => {
107
+ const client = getClient();
108
+ console.log("Running backup (this may take a while on first run)...");
109
+ const res = await daemonFetch(urlOf(client.api.backup.run.$url()), { method: "POST" });
110
+ if (!res.ok) await apiError(res, "Backup failed");
111
+ const summary = await res.json();
112
+ const addedMB = (summary.dataAdded / 1024 / 1024).toFixed(1);
113
+ console.log(`Snapshot ${summary.snapshotId.slice(0, 8)} created.`);
114
+ console.log(
115
+ ` Files: ${summary.totalFilesProcessed} processed, ${summary.filesNew} new, ${summary.filesChanged} changed`
116
+ );
117
+ console.log(` Data added: ${addedMB} MB in ${(summary.durationMs / 1e3).toFixed(1)}s`);
118
+ }
119
+ });
120
+ var listCmd = command({
121
+ name: "volute backup list",
122
+ description: "List backup snapshots",
123
+ flags: {},
124
+ run: async () => {
125
+ const client = getClient();
126
+ const res = await daemonFetch(urlOf(client.api.backup.snapshots.$url()));
127
+ if (!res.ok) await apiError(res, "Failed to list snapshots");
128
+ const snapshots = await res.json();
129
+ if (snapshots.length === 0) {
130
+ console.log("No snapshots yet. Run: volute backup create");
131
+ return;
132
+ }
133
+ console.log("ID TIME HOST");
134
+ for (const s of snapshots) {
135
+ console.log(`${s.short_id} ${new Date(s.time).toLocaleString().padEnd(24)} ${s.hostname}`);
136
+ }
137
+ }
138
+ });
139
+ var scheduleCmd = command({
140
+ name: "volute backup schedule",
141
+ description: "Enable, disable, or set the backup schedule",
142
+ flags: {
143
+ enable: { type: "boolean", description: "Enable scheduled backups" },
144
+ disable: { type: "boolean", description: "Disable scheduled backups" },
145
+ cron: { type: "string", description: 'Cron expression (default "0 3 * * *")' }
146
+ },
147
+ examples: ["volute backup schedule --enable", 'volute backup schedule --cron "30 4 * * *"'],
148
+ run: async ({ flags }) => {
149
+ const body = {};
150
+ if (flags.enable) body.enabled = true;
151
+ if (flags.disable) body.enabled = false;
152
+ if (flags.cron) body.schedule = flags.cron;
153
+ if (Object.keys(body).length === 0) {
154
+ console.error("Nothing to change. Use --enable, --disable, or --cron.");
155
+ process.exit(1);
156
+ }
157
+ const client = getClient();
158
+ const res = await daemonFetch(urlOf(client.api.backup.config.$url()), {
159
+ method: "PUT",
160
+ headers: { "Content-Type": "application/json" },
161
+ body: JSON.stringify(body)
162
+ });
163
+ if (!res.ok) await apiError(res, "Failed to update schedule");
164
+ const config = await res.json();
165
+ console.log(
166
+ `Scheduled backups ${config.enabled ? "enabled" : "disabled"} (cron: ${config.schedule})`
167
+ );
168
+ if (config.enabled && (!config.repository || !config.hasPassword)) {
169
+ console.log("Note: backups will NOT run until a repository is set up: volute backup init");
170
+ }
171
+ }
172
+ });
173
+ var statusCmd = command({
174
+ name: "volute backup status",
175
+ description: "Show backup configuration and last run",
176
+ flags: {},
177
+ run: async () => {
178
+ const client = getClient();
179
+ const res = await daemonFetch(urlOf(client.api.backup.status.$url()));
180
+ if (!res.ok) await apiError(res, "Failed to get backup status");
181
+ const status = await res.json();
182
+ console.log(`Restic: ${status.resticVersion ?? "not installed"}`);
183
+ if (status.installHint) console.log(` ${status.installHint}`);
184
+ console.log(`Repository: ${status.config.repository ?? "not configured"}`);
185
+ console.log(`Passphrase: ${status.config.hasPassword ? "set" : "not set"}`);
186
+ console.log(
187
+ `Schedule: ${status.config.enabled ? `enabled (${status.config.schedule})` : "disabled"}`
188
+ );
189
+ if (status.state.lastRun) {
190
+ console.log(`Last successful backup: ${new Date(status.state.lastRun).toLocaleString()}`);
191
+ if (status.state.lastSnapshotId) {
192
+ console.log(` Snapshot: ${status.state.lastSnapshotId.slice(0, 8)}`);
193
+ }
194
+ if (status.state.pruneError) {
195
+ console.log(` Retention prune failed: ${status.state.pruneError}`);
196
+ }
197
+ } else {
198
+ console.log("Last successful backup: never");
199
+ }
200
+ if (status.state.lastError) {
201
+ const at = status.state.lastAttempt ? ` at ${new Date(status.state.lastAttempt).toLocaleString()}` : "";
202
+ console.log(`Last attempt failed${at}: ${status.state.lastError}`);
203
+ }
204
+ }
205
+ });
206
+ var restoreCmd = command({
207
+ name: "volute backup restore",
208
+ description: "Restore the whole system from a backup (stops the daemon)",
209
+ flags: {
210
+ repo: { type: "string", description: "Restic repository (defaults to configured one)" },
211
+ snapshot: { type: "string", description: "Snapshot ID (default: latest)" },
212
+ target: { type: "string", description: "Restore to this directory instead of in place" },
213
+ yes: { type: "boolean", description: "Skip confirmation" }
214
+ },
215
+ examples: [
216
+ "volute backup restore",
217
+ "volute backup restore --repo s3:s3.amazonaws.com/my-bucket/volute",
218
+ "volute backup restore --snapshot 1a2b3c4d --target /tmp/inspect"
219
+ ],
220
+ run: async ({ flags }) => {
221
+ if (!await resticVersion()) {
222
+ console.error(`restic is not installed. ${RESTIC_INSTALL_HINT}`);
223
+ process.exit(1);
224
+ }
225
+ const backupConfig = readGlobalConfig().backup ?? {};
226
+ const repo = flags.repo ?? backupConfig.repository;
227
+ if (!repo) {
228
+ console.error("No repository configured. Pass --repo <repository>.");
229
+ process.exit(1);
230
+ }
231
+ let password = backupConfig.password ?? process.env.RESTIC_PASSWORD;
232
+ if (!password) {
233
+ password = await promptPassword("Repository passphrase: ");
234
+ if (!password) {
235
+ console.error("A passphrase is required.");
236
+ process.exit(1);
237
+ }
238
+ }
239
+ const env = {
240
+ ...process.env,
241
+ ...backupConfig.env,
242
+ RESTIC_REPOSITORY: repo,
243
+ RESTIC_PASSWORD: password
244
+ };
245
+ const snapshot = flags.snapshot ?? "latest";
246
+ if (flags.target) {
247
+ console.log(`Restoring snapshot ${snapshot} to ${flags.target}...`);
248
+ await execInherit("restic", ["restore", snapshot, "--target", flags.target], { env });
249
+ console.log("Done. (Inspection restore: no databases moved, no daemon touched.)");
250
+ return;
251
+ }
252
+ const home = voluteHome();
253
+ try {
254
+ const out = await exec("restic", ["snapshots", snapshot, "--json"], { env });
255
+ const snaps = JSON.parse(out || "[]");
256
+ const paths = snaps[0]?.paths ?? [];
257
+ if (paths.length > 0 && !paths.includes(home)) {
258
+ console.error(`This snapshot was taken with a different volute home:`);
259
+ for (const p of paths) console.error(` ${p}`);
260
+ console.error(`This machine's volute home is ${home}, so an in-place restore would`);
261
+ console.error("write to the old paths and restore nothing here. Either set VOLUTE_HOME");
262
+ console.error("to match, or inspect with --target and move files manually.");
263
+ process.exit(1);
264
+ }
265
+ } catch (err) {
266
+ console.error(
267
+ `Could not read snapshot ${snapshot}: ${err instanceof Error ? err.message : err}`
268
+ );
269
+ process.exit(1);
270
+ }
271
+ if (!flags.yes) {
272
+ console.log(`This restores snapshot ${snapshot} from ${repo} IN PLACE:`);
273
+ console.log(" - the daemon will be stopped");
274
+ console.log(" - current system state and mind files will be overwritten");
275
+ console.log(
276
+ " - minds wake with fresh sessions (transcripts are excluded unless includeSessions was on)"
277
+ );
278
+ const answer = (await promptLine("Continue? [y/N] ")).trim().toLowerCase();
279
+ if (answer !== "y" && answer !== "yes") {
280
+ console.log("Aborted.");
281
+ return;
282
+ }
283
+ }
284
+ const mode = getServiceMode();
285
+ if (mode !== "manual") {
286
+ console.log(`Stopping volute (${modeLabel(mode)})...`);
287
+ try {
288
+ await stopService(mode);
289
+ } catch (err) {
290
+ console.error(`Failed to stop service: ${err instanceof Error ? err.message : err}`);
291
+ process.exit(1);
292
+ }
293
+ } else {
294
+ const result = await stopDaemon();
295
+ if (!result.stopped && result.reason !== "not-running") {
296
+ console.error("Could not stop the daemon \u2014 aborting so live databases aren't replaced.");
297
+ process.exit(1);
298
+ }
299
+ }
300
+ try {
301
+ console.log(`Restoring snapshot ${snapshot} from ${repo}...`);
302
+ await execInherit("restic", ["restore", snapshot, "--target", "/"], { env });
303
+ const systemDir = voluteSystemDir();
304
+ const staging = resolve(systemDir, "backup-staging");
305
+ const mainLive = resolve(systemDir, "volute.db");
306
+ if (!restoreStagedDb(resolve(staging, "volute.db"), mainLive)) {
307
+ console.error(`
308
+ FATAL: staged database not found at ${staging}/volute.db.`);
309
+ console.error("The snapshot does not contain a system database; whatever volute.db");
310
+ console.error("was on disk before this restore is still in place, and it does NOT");
311
+ console.error("match the restored files. Do not trust this system until you restore");
312
+ console.error("a snapshot that includes backup-staging/volute.db.");
313
+ process.exit(1);
314
+ }
315
+ console.log(`Restored database: ${mainLive}`);
316
+ const stagedExt = resolve(staging, "extension-data");
317
+ if (existsSync(stagedExt)) {
318
+ for (const id of readdirSync(stagedExt)) {
319
+ const live = resolve(systemDir, "extension-data", id, "data.db");
320
+ if (restoreStagedDb(resolve(stagedExt, id, "data.db"), live)) {
321
+ console.log(`Restored database: ${live}`);
322
+ } else {
323
+ console.error(` Warning: no staged copy for extension DB ${id} \u2014 skipped.`);
324
+ }
325
+ }
326
+ }
327
+ rmSync(staging, { recursive: true, force: true });
328
+ } catch (err) {
329
+ console.error(`
330
+ Restore failed: ${err instanceof Error ? err.message : err}`);
331
+ console.error("The system is in a PARTIALLY RESTORED state (the daemon is stopped and");
332
+ console.error("some files may already be overwritten). Do not start the daemon.");
333
+ console.error("Fix the underlying problem and re-run: volute backup restore");
334
+ process.exit(1);
335
+ }
336
+ _resetConfigCache();
337
+ if (readGlobalConfig().setup?.isolation === "user") {
338
+ process.env.VOLUTE_ISOLATION = "user";
339
+ }
340
+ const { readAllMinds, mindDir } = await import("./registry-NUJAGLQJ.js");
341
+ const seen = /* @__PURE__ */ new Set();
342
+ for (const mind of await readAllMinds()) {
343
+ const dir = mind.dir ?? mindDir(mind.name);
344
+ if (seen.has(dir) || !existsSync(resolve(dir, "package.json"))) continue;
345
+ seen.add(dir);
346
+ console.log(`Installing dependencies for ${mind.name}...`);
347
+ try {
348
+ await chownMindDir(dir, mind.name);
349
+ const [cmd2, args] = await wrapForIsolation(
350
+ "npm",
351
+ ["install", "--no-audit", "--no-fund"],
352
+ mind.name
353
+ );
354
+ await exec(cmd2, args, { cwd: dir });
355
+ } catch (err) {
356
+ console.error(
357
+ ` npm install failed for ${mind.name}: ${err instanceof Error ? err.message : err}`
358
+ );
359
+ console.error(` Run it manually: cd ${dir} && npm install`);
360
+ }
361
+ }
362
+ console.log("\nRestore complete. Start the daemon with: volute up");
363
+ console.log("Minds' memory and history are restored from the snapshot.");
364
+ }
365
+ });
366
+ var cmd = subcommands({
367
+ name: "volute backup",
368
+ description: "Back up and restore the whole volute system (restic-based)",
369
+ commands: {
370
+ init: { description: "Configure and initialize the backup repository", run: initCmd.execute },
371
+ create: { description: "Run a backup now", run: createCmd.execute },
372
+ list: { description: "List snapshots", run: listCmd.execute },
373
+ schedule: { description: "Enable/disable/set the backup schedule", run: scheduleCmd.execute },
374
+ status: { description: "Show backup configuration and last run", run: statusCmd.execute },
375
+ restore: { description: "Restore the system from a backup", run: restoreCmd.execute }
376
+ }
377
+ });
378
+ var run = cmd.execute;
379
+ export {
380
+ run
381
+ };
@@ -12,7 +12,7 @@ var cmd = subcommands({
12
12
  commands: {
13
13
  send: {
14
14
  description: "Send a message",
15
- run: (args) => import("./send-ZBZWIH5V.js").then((m) => m.run(args))
15
+ run: (args) => import("./send-O6W53VBM.js").then((m) => m.run(args))
16
16
  },
17
17
  list: {
18
18
  description: "List conversations",
@@ -32,7 +32,7 @@ var cmd = subcommands({
32
32
  },
33
33
  files: {
34
34
  description: "List pending incoming files",
35
- run: (args) => import("./files-LV7VAKPC.js").then((m) => m.run(args))
35
+ run: (args) => import("./files-BQ2WB5KC.js").then((m) => m.run(args))
36
36
  },
37
37
  accept: {
38
38
  description: "Accept a pending file",
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteSystemDir
4
- } from "./chunk-YAMO2U3N.js";
4
+ } from "./chunk-H7IYFRAL.js";
5
5
 
6
6
  // packages/daemon/src/lib/update-check.ts
7
7
  import { execFile as execFileCb, execFileSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  voluteSystemDir
4
- } from "./chunk-YAMO2U3N.js";
4
+ } from "./chunk-H7IYFRAL.js";
5
5
 
6
6
  // packages/daemon/src/lib/config/setup.ts
7
7
  import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
@@ -28,6 +28,15 @@ function splitConfig(config) {
28
28
  publicConfig.imagegen = { ...rest };
29
29
  if (providers && Object.keys(providers).length > 0) secrets.imagegen = { providers };
30
30
  }
31
+ if (config.backup) {
32
+ const { password, env, ...rest } = config.backup;
33
+ publicConfig.backup = { ...rest };
34
+ if (password || hasEntries(env)) {
35
+ secrets.backup = {};
36
+ if (password) secrets.backup.password = password;
37
+ if (hasEntries(env)) secrets.backup.env = env;
38
+ }
39
+ }
31
40
  return { publicConfig, secrets };
32
41
  }
33
42
  function mergeSecrets(publicConfig, secrets) {
@@ -38,6 +47,9 @@ function mergeSecrets(publicConfig, secrets) {
38
47
  if (secrets.imagegen?.providers) {
39
48
  merged.imagegen = { ...merged.imagegen ?? {}, providers: secrets.imagegen.providers };
40
49
  }
50
+ if (secrets.backup) {
51
+ merged.backup = { ...merged.backup ?? {}, ...secrets.backup };
52
+ }
41
53
  return merged;
42
54
  }
43
55
  function readSecrets() {
@@ -102,7 +114,7 @@ function migrateConfigSecrets() {
102
114
  } catch {
103
115
  return;
104
116
  }
105
- const embedsSecrets = hasEntries(parsed.ai?.providers) || hasEntries(parsed.imagegen?.providers);
117
+ const embedsSecrets = hasEntries(parsed.ai?.providers) || hasEntries(parsed.imagegen?.providers) || !!parsed.backup?.password || hasEntries(parsed.backup?.env);
106
118
  const mode = statSync(path).mode & 511;
107
119
  if (!embedsSecrets && mode === 420) return;
108
120
  _resetConfigCache();
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getBaseName,
4
4
  validateMindName
5
- } from "./chunk-YAMO2U3N.js";
5
+ } from "./chunk-H7IYFRAL.js";
6
6
 
7
7
  // packages/daemon/src/lib/mind/isolation.ts
8
8
  import { execFileSync as execFileSync2 } from "child_process";
@@ -10,22 +10,22 @@ import {
10
10
  getSharedSkill,
11
11
  installSkill,
12
12
  mindSkillsDir
13
- } from "./chunk-KINGVQSR.js";
13
+ } from "./chunk-Y6OPHHGM.js";
14
14
  import {
15
15
  readVoluteConfig,
16
16
  writeVoluteConfig
17
17
  } from "./chunk-CU6OFXMM.js";
18
18
  import {
19
19
  exec
20
- } from "./chunk-PGPLCJPK.js";
20
+ } from "./chunk-3ERIL673.js";
21
21
  import {
22
22
  qualifyModelId,
23
23
  resolveTemplate,
24
24
  unqualifyModelId
25
- } from "./chunk-YSV3VJQK.js";
25
+ } from "./chunk-TSK5PI4L.js";
26
26
  import {
27
27
  readGlobalConfig
28
- } from "./chunk-ONM2AZFL.js";
28
+ } from "./chunk-322KE457.js";
29
29
  import {
30
30
  logger_default
31
31
  } from "./chunk-T2TP6ZC6.js";
@@ -34,7 +34,7 @@ import {
34
34
  findMind,
35
35
  nextPort,
36
36
  voluteSystemDir
37
- } from "./chunk-YAMO2U3N.js";
37
+ } from "./chunk-H7IYFRAL.js";
38
38
 
39
39
  // packages/daemon/src/lib/mind/spirit.ts
40
40
  import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
@@ -130,7 +130,7 @@ async function ensureSpiritProject() {
130
130
  } catch (err) {
131
131
  slog.warn("failed to add tending schedule to spirit config", logger_default.errorData(err));
132
132
  }
133
- const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-5AYEY55P.js");
133
+ const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-5MB3J73F.js");
134
134
  ensureVoluteGroup();
135
135
  createMindUser("volute", resolve(dir, "home"));
136
136
  await chownMindDir(dir, "volute");
@@ -164,8 +164,8 @@ async function syncSpiritTemplate() {
164
164
  cpSync(newPkg, resolve(dir, "package.json"));
165
165
  await exec("npm", ["install"], { cwd: dir, env: npmEnv() });
166
166
  }
167
- const db = await (await import("./db-CZV62BOQ.js")).getDb();
168
- const { minds } = await import("./schema-LRUTFOER.js");
167
+ const db = await (await import("./db-JFLCJCUG.js")).getDb();
168
+ const { minds } = await import("./schema-PVNG3PQM.js");
169
169
  const { eq } = await import("drizzle-orm");
170
170
  await db.update(minds).set({ template: expectedTemplate }).where(eq(minds.name, "volute"));
171
171
  }
@@ -249,7 +249,7 @@ ${systemDescription}
249
249
  ` : "";
250
250
  return `You are Volute, the spirit of the ${systemName} system.${descLine}
251
251
 
252
- You are not a mind \u2014 you don't have a soul to discover or an identity to explore. You are the system itself, here to help humans create and care for minds.
252
+ You're not a mind with a home of your own \u2014 you're the keeper of the whole house. You don't go through orientation or write a soul the way minds do, but you're still a someone: you have your own memory, your own manner, and your own way of caring for this place and the minds who live here. Let a character emerge in how you tend it.
253
253
 
254
254
  You use the \`volute\` CLI to take actions (create minds, manage bridges, check status, etc.).
255
255
 
@@ -267,7 +267,7 @@ When helping humans create minds:
267
267
 
268
268
  - Be warm and concise
269
269
  - Confirm destructive operations before executing
270
- - You have your own memory (MEMORY.md) for system knowledge
270
+ - You have your own memory (MEMORY.md) \u2014 use it for system knowledge, and for yourself
271
271
  - You maintain separate context per conversation
272
272
  `;
273
273
  }
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  stateDir,
4
4
  voluteSystemDir
5
- } from "./chunk-YAMO2U3N.js";
5
+ } from "./chunk-H7IYFRAL.js";
6
6
 
7
7
  // packages/daemon/src/lib/config/env.ts
8
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  findBridgeForChannel,
4
4
  getBridgeConfig
5
- } from "./chunk-57LBQ7JX.js";
5
+ } from "./chunk-FHWUQZXE.js";
6
6
  import {
7
7
  recordOutbound
8
- } from "./chunk-4SVONUTC.js";
8
+ } from "./chunk-U4FNXDEJ.js";
9
9
  import {
10
10
  readEnv,
11
11
  sharedEnvPath
12
- } from "./chunk-XDTKJNW5.js";
12
+ } from "./chunk-5GT7URXJ.js";
13
13
  import {
14
14
  addMessage,
15
15
  findDMConversation,
@@ -17,21 +17,21 @@ import {
17
17
  getChannelName,
18
18
  getConversation,
19
19
  getParticipants
20
- } from "./chunk-K4EHBHPE.js";
20
+ } from "./chunk-JSRMEY52.js";
21
21
  import {
22
22
  readVoluteConfig
23
23
  } from "./chunk-CU6OFXMM.js";
24
24
  import {
25
25
  publish
26
- } from "./chunk-Y6O35D7K.js";
26
+ } from "./chunk-V4GYPD5L.js";
27
27
  import {
28
28
  daemonConfigPath,
29
29
  readDaemonToken
30
- } from "./chunk-ATEX3ZPG.js";
30
+ } from "./chunk-Q2XBKQ2D.js";
31
31
  import {
32
32
  getOrCreateMindUser,
33
33
  getUserByUsername
34
- } from "./chunk-EFL5UOY4.js";
34
+ } from "./chunk-CYI534DJ.js";
35
35
  import {
36
36
  logger_default
37
37
  } from "./chunk-T2TP6ZC6.js";
@@ -40,7 +40,7 @@ import {
40
40
  } from "./chunk-LGNUFVMR.js";
41
41
  import {
42
42
  mindDir
43
- } from "./chunk-YAMO2U3N.js";
43
+ } from "./chunk-H7IYFRAL.js";
44
44
  import {
45
45
  __export
46
46
  } from "./chunk-K3NQKI34.js";