volute 0.47.0 → 0.48.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.
Files changed (128) hide show
  1. package/README.md +11 -11
  2. package/dist/{accept-YAFP5JFJ.js → accept-KYNC5X3U.js} +3 -3
  3. package/dist/{ai-service-CVZEYKTK.js → ai-service-643TNFPH.js} +6 -2
  4. package/dist/{avatar-image-7S3WA77A.js → avatar-image-Y45R7LW5.js} +3 -2
  5. package/dist/{backup-IIAFOW2L.js → backup-UDH4GMSW.js} +11 -11
  6. package/dist/{bridge-TIZGSXOD.js → bridge-3FNSWLNQ.js} +3 -3
  7. package/dist/{channels-ITE4YC57.js → channels-SGQZHNQJ.js} +3 -3
  8. package/dist/{chat-AJLJCQ3M.js → chat-X43VYHH2.js} +9 -9
  9. package/dist/chunk-4FCL4DVZ.js +48 -0
  10. package/dist/{chunk-SKNXMUIU.js → chunk-5KXCM5AW.js} +17 -1
  11. package/dist/{chunk-RBNMDAKB.js → chunk-BCG45AQB.js} +15 -1
  12. package/dist/chunk-DW4TRDOZ.js +29 -0
  13. package/dist/{chunk-CBOIHNMR.js → chunk-FJ2MZ5PH.js} +39 -3
  14. package/dist/{chunk-M6TTZRGH.js → chunk-HNGFKPNS.js} +20 -4
  15. package/dist/{chunk-IWJSNMSY.js → chunk-HUNDXZBZ.js} +2 -2
  16. package/dist/chunk-IYCV34IU.js +158 -0
  17. package/dist/{chunk-5IERLDUS.js → chunk-MJRXFUMS.js} +25 -5
  18. package/dist/{chunk-JCMGDCGX.js → chunk-MOERAQXH.js} +2 -0
  19. package/dist/{chunk-XHN6XBWV.js → chunk-OQJMTHEH.js} +1 -1
  20. package/dist/{chunk-BGYHLR54.js → chunk-PJVPDY2Z.js} +1 -1
  21. package/dist/{chunk-5NN2VHJV.js → chunk-Q7HOAVFR.js} +1 -1
  22. package/dist/{chunk-KDLYIECM.js → chunk-R772ET2M.js} +18 -4
  23. package/dist/{mind-list-KEGRGQEQ.js → chunk-SHKM5RGD.js} +19 -6
  24. package/dist/{chunk-4I72V3E5.js → chunk-T4VS7UDW.js} +11 -11
  25. package/dist/{chunk-K23P5Q5N.js → chunk-USD45JKR.js} +27 -5
  26. package/dist/{chunk-F55GRIEK.js → chunk-VB2QXUJQ.js} +176 -201
  27. package/dist/{chunk-M3XDVS5Q.js → chunk-VZRA5TYO.js} +1 -1
  28. package/dist/{chunk-JSVHH32K.js → chunk-WARH6GIV.js} +10 -10
  29. package/dist/{chunk-PFZBNKUH.js → chunk-WCFSBH33.js} +0 -1
  30. package/dist/{chunk-VMCZBXF2.js → chunk-WQ46E33M.js} +8 -32
  31. package/dist/{chunk-RUFLGTOT.js → chunk-XVBSFLM7.js} +1 -1
  32. package/dist/{chunk-LWDTP6DH.js → chunk-YNBXEQAP.js} +31 -1
  33. package/dist/cli.js +33 -25
  34. package/dist/{clock-E6N5Y3YW.js → clock-CNRF6F7T.js} +3 -3
  35. package/dist/{cloud-sync-LQTVDTQ3.js → cloud-sync-WHKCB4CD.js} +14 -12
  36. package/dist/{config-TJLYUV3U.js → config-RPSLA2HX.js} +3 -3
  37. package/dist/{create-PQQXKTJK.js → create-GJKHABJB.js} +16 -5
  38. package/dist/{create-A7PDHIIL.js → create-VIQVP3QB.js} +3 -3
  39. package/dist/{daemon-client-IYR4KCPU.js → daemon-client-ZFY5MOAL.js} +5 -3
  40. package/dist/{daemon-restart-5F3YTLZK.js → daemon-restart-7KUHVZIN.js} +4 -4
  41. package/dist/daemon.js +668 -401
  42. package/dist/{db-LZTLA7XC.js → db-IPXRJUI7.js} +1 -1
  43. package/dist/{delete-HPLC7ETU.js → delete-ESEP7NGQ.js} +1 -1
  44. package/dist/{delivery-manager-TN5KK2AP.js → delivery-manager-HZTT5SJR.js} +14 -12
  45. package/dist/{down-ZI4S6265.js → down-G6IADJXV.js} +2 -2
  46. package/dist/{echo-text-SEQCLGAT.js → echo-text-H3SH337Q.js} +16 -14
  47. package/dist/env-6TGPO5WG.js +18 -0
  48. package/dist/{env-HRL2PWAT.js → env-C7Z55QCJ.js} +7 -7
  49. package/dist/{export-4GVGNW54.js → export-C2K3NIRD.js} +1 -1
  50. package/dist/{extension-QBY4C44L.js → extension-J4ZQ2GHV.js} +3 -3
  51. package/dist/{extensions-PIMIQ7J3.js → extensions-GEKF47A4.js} +14 -12
  52. package/dist/{files-FEFZKMNM.js → files-LXQSQOFG.js} +3 -3
  53. package/dist/{import-7MO3YTRE.js → import-SX3ZXHB4.js} +4 -4
  54. package/dist/{join-ZJV7W6MO.js → join-34TR2GXQ.js} +1 -1
  55. package/dist/{list-LQO2DCIK.js → list-PMUXZNAM.js} +3 -3
  56. package/dist/{login-6TLMI2TQ.js → login-ARRZ4ORJ.js} +3 -3
  57. package/dist/{login-OF4WXDAN.js → login-CL4IT2ED.js} +12 -3
  58. package/dist/{logout-ERE2BGA3.js → logout-HZYJCYCA.js} +3 -3
  59. package/dist/{logout-BK53HXNY.js → logout-YZRMZ3O2.js} +3 -3
  60. package/dist/{message-delivery-ZE3YGJDD.js → message-delivery-GPQ5SE5N.js} +14 -12
  61. package/dist/{mind-POOHFZHP.js → mind-46AOK373.js} +23 -19
  62. package/dist/mind-contacts-GV7XYL5D.js +64 -0
  63. package/dist/{mind-history-47DN6ILW.js → mind-history-TTGA5BHZ.js} +7 -7
  64. package/dist/mind-list-OTHV4ZO4.js +13 -0
  65. package/dist/{mind-profile-PEQYASQX.js → mind-profile-LUG353ZT.js} +1 -1
  66. package/dist/{mind-service-JFY7UG5E.js → mind-service-2ARGJNKP.js} +16 -12
  67. package/dist/{mind-sleep-IN3WPA76.js → mind-sleep-DV7KP255.js} +5 -5
  68. package/dist/{mind-status-SMUWJKGV.js → mind-status-BJNPGXKC.js} +8 -3
  69. package/dist/{mind-wake-R54BPESY.js → mind-wake-LVTZ55EZ.js} +3 -3
  70. package/dist/notices-2KU5NTRY.js +25 -0
  71. package/dist/{package-WPEE2HVJ.js → package-RTN2PS7O.js} +4 -2
  72. package/dist/{read-PWAJOQIQ.js → read-YSWUXYL7.js} +3 -3
  73. package/dist/{register-7SZJFHU6.js → register-42VBJKTP.js} +3 -3
  74. package/dist/{reject-6VH7N2A4.js → reject-SXGCYN4A.js} +3 -3
  75. package/dist/{restart-H5WJDMA7.js → restart-YYEGZJDD.js} +7 -7
  76. package/dist/{sandbox-G4X4K3UN.js → sandbox-5VQ454XP.js} +2 -2
  77. package/dist/{scheduler-HQSDYJFY.js → scheduler-I7JZCT47.js} +14 -12
  78. package/dist/{seed-VANPU43L.js → seed-F2HXZQU4.js} +1 -1
  79. package/dist/{seed-check-VLTVILOV.js → seed-check-TYD7RRZY.js} +1 -1
  80. package/dist/{seed-cmd-SYVDZKM4.js → seed-cmd-MLCTGSX5.js} +3 -3
  81. package/dist/{seed-create-3FGZPS6C.js → seed-create-KQ7OILWB.js} +6 -4
  82. package/dist/seed-readiness-RBPGOLSZ.js +18 -0
  83. package/dist/{seed-sprout-H7QLFPFM.js → seed-sprout-HVYCFJLA.js} +29 -30
  84. package/dist/{send-HYDFGC6G.js → send-TD2X5U3K.js} +7 -7
  85. package/dist/{service-SYJ5G6LP.js → service-CVZMQYK6.js} +1 -1
  86. package/dist/{service-install-FQ43Z4DF.js → service-install-VCRMFWX5.js} +2 -2
  87. package/dist/{setup-KFYVWTXG.js → setup-5ECWTYKG.js} +5 -1
  88. package/dist/{setup-QJHGMGSN.js → setup-AE4CVUC4.js} +4 -4
  89. package/dist/{skill-GUKG2YVH.js → skill-UUM4JZRF.js} +7 -7
  90. package/dist/skills/dreaming/SKILL.md +5 -1
  91. package/dist/skills/dreaming/scripts/dream.ts +5 -1
  92. package/dist/skills/orientation/SKILL.md +8 -7
  93. package/dist/skills/tending/SKILL.md +51 -2
  94. package/dist/skills/volute-mind/SKILL.md +2 -0
  95. package/dist/{skills-L2CMTW7A.js → skills-B3SVDCEB.js} +2 -2
  96. package/dist/{sleep-manager-3NA7ZJP3.js → sleep-manager-Z27R3WTW.js} +14 -12
  97. package/dist/{spirit-WXN4IDBF.js → spirit-WXS3HCLN.js} +7 -5
  98. package/dist/{split-WBMZXBHF.js → split-SKZ4Y2D6.js} +1 -1
  99. package/dist/{sprout-LTL5P36T.js → sprout-KQ43BWZJ.js} +1 -1
  100. package/dist/{src-OJHARHTF.js → src-WLJE73NP.js} +14 -5
  101. package/dist/{start-X46I3GXB.js → start-O6UKK7BG.js} +7 -7
  102. package/dist/{status-V4RJMHJ4.js → status-F4PGREUU.js} +6 -4
  103. package/dist/{stop-HJQV4YSM.js → stop-UBX6X5RA.js} +7 -7
  104. package/dist/{system-chat-N2F7HVY3.js → system-chat-63ABFF6V.js} +14 -12
  105. package/dist/{systems-B5YJKMW4.js → systems-JJNGQHAO.js} +6 -6
  106. package/dist/{turn-tracker-JZRZDFWV.js → turn-tracker-KLPV3PAU.js} +4 -4
  107. package/dist/{up-J2PBPOZL.js → up-RVGDE6CQ.js} +5 -3
  108. package/dist/{update-ACV4SAY3.js → update-OXQEGGXD.js} +1 -1
  109. package/dist/{upgrade-NWAZ7MLD.js → upgrade-K5FIQPQD.js} +1 -1
  110. package/dist/{version-notify-XRGTEEDK.js → version-notify-73YURTFR.js} +17 -15
  111. package/dist/web-assets/assets/index-WdZ60R6c.css +1 -0
  112. package/dist/web-assets/assets/index-taX6Ezfa.js +92 -0
  113. package/dist/web-assets/index.html +2 -2
  114. package/package.json +4 -2
  115. package/packages/extensions/pages/dist/ui/assets/index-BuXnE-rb.css +1 -0
  116. package/packages/extensions/pages/dist/ui/assets/index-DtzftuPA.js +2 -0
  117. package/packages/extensions/pages/dist/ui/index.html +2 -2
  118. package/templates/_base/src/lib/startup.ts +16 -1
  119. package/templates/claude/src/agent.ts +9 -2
  120. package/templates/claude/src/server.ts +4 -2
  121. package/templates/pi/src/agent.ts +7 -10
  122. package/templates/pi/src/lib/dispatch.ts +65 -0
  123. package/dist/volute-config-A52FHWKM.js +0 -14
  124. package/dist/web-assets/assets/index-DtctoDXY.css +0 -1
  125. package/dist/web-assets/assets/index-Wpyb2CML.js +0 -86
  126. package/packages/extensions/pages/dist/ui/assets/index-BcY6lnq4.css +0 -1
  127. package/packages/extensions/pages/dist/ui/assets/index-CQjEQg1r.js +0 -2
  128. /package/dist/{chunk-IYG4FBMP.js → chunk-IJPMIEVE.js} +0 -0
package/README.md CHANGED
@@ -13,23 +13,23 @@ Built on the [Anthropic Claude Agent SDK](https://github.com/anthropics/claude-a
13
13
  ```sh
14
14
  npm install -g volute
15
15
 
16
- # First-time setup (required)
17
- volute setup --name my-system
16
+ # One-time setup — starts the daemon and opens the web dashboard
17
+ volute setup
18
+ ```
18
19
 
19
- # Start the daemon (manages all your minds)
20
- volute up
20
+ Finish setup in your browser at `http://localhost:1618`: name your system, create your admin account, and connect an AI provider. When setup completes, the system spirit greets you in chat and helps you plant your first mind.
21
21
 
22
- # Create a mind
23
- volute mind create atlas
22
+ Prefer the terminal? Once setup is complete:
24
23
 
25
- # Start it
26
- volute mind start atlas
24
+ ```sh
25
+ # Plant a seed — the recommended way to create a mind
26
+ volute seed create atlas
27
27
 
28
28
  # Talk to it
29
- volute chat send @atlas "hey, what can you do?"
29
+ volute chat send @atlas "hello, who are you?"
30
30
  ```
31
31
 
32
- You now have a running AI mind with persistent memory, auto-committing file changes, and session resume across restarts. Open `http://localhost:1618` for the web dashboard.
32
+ You now have a running AI mind with persistent memory, auto-committing file changes, and session resume across restarts.
33
33
 
34
34
  ## The daemon
35
35
 
@@ -373,7 +373,7 @@ Set the model via `home/.config/config.json` (SDK config) or `home/.config/volut
373
373
 
374
374
  ```sh
375
375
  docker build -t volute .
376
- docker run -d --init -p 1618:1618 -v volute-data:/data -v volute-minds:/minds volute
376
+ docker run -d -p 1618:1618 -v volute-data:/data -v volute-minds:/minds volute
377
377
  ```
378
378
 
379
379
  Or with docker-compose:
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  resolveMindName
4
4
  } from "./chunk-BTY4WNFE.js";
5
+ import {
6
+ daemonFetch
7
+ } from "./chunk-BCG45AQB.js";
5
8
  import {
6
9
  command
7
10
  } from "./chunk-TXSA4Q3V.js";
8
11
  import "./chunk-O7IGP7ZW.js";
9
- import {
10
- daemonFetch
11
- } from "./chunk-RBNMDAKB.js";
12
12
  import "./chunk-K3NQKI34.js";
13
13
 
14
14
  // packages/cli/src/commands/chat/accept.ts
@@ -14,6 +14,8 @@ import {
14
14
  getUtilityModel,
15
15
  isAiConfigured,
16
16
  migrateAiModelQualification,
17
+ missingCredentialWarning,
18
+ providerForMindTemplate,
17
19
  qualifyModelId,
18
20
  removeAiConfig,
19
21
  removeCustomModel,
@@ -25,8 +27,8 @@ import {
25
27
  setProviderRefreshHook,
26
28
  setUtilityModel,
27
29
  unqualifyModelId
28
- } from "./chunk-LWDTP6DH.js";
29
- import "./chunk-SKNXMUIU.js";
30
+ } from "./chunk-YNBXEQAP.js";
31
+ import "./chunk-5KXCM5AW.js";
30
32
  import "./chunk-T2TP6ZC6.js";
31
33
  import "./chunk-WW6C3PLV.js";
32
34
  import "./chunk-2MJ7EOMT.js";
@@ -46,6 +48,8 @@ export {
46
48
  getUtilityModel,
47
49
  isAiConfigured,
48
50
  migrateAiModelQualification,
51
+ missingCredentialWarning,
52
+ providerForMindTemplate,
49
53
  qualifyModelId,
50
54
  removeAiConfig,
51
55
  removeCustomModel,
@@ -6,8 +6,9 @@ import {
6
6
  migrateAvatarSizes,
7
7
  normalizeAvatar,
8
8
  renderAvatarBlock
9
- } from "./chunk-VMCZBXF2.js";
10
- import "./chunk-PFZBNKUH.js";
9
+ } from "./chunk-WQ46E33M.js";
10
+ import "./chunk-DW4TRDOZ.js";
11
+ import "./chunk-WCFSBH33.js";
11
12
  import "./chunk-T2TP6ZC6.js";
12
13
  import "./chunk-WW6C3PLV.js";
13
14
  import "./chunk-2MJ7EOMT.js";
@@ -1,7 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  stopDaemon
4
- } from "./chunk-BGYHLR54.js";
4
+ } from "./chunk-PJVPDY2Z.js";
5
+ import {
6
+ getClient,
7
+ urlOf
8
+ } from "./chunk-LOPXTW6H.js";
9
+ import {
10
+ daemonFetch
11
+ } from "./chunk-BCG45AQB.js";
5
12
  import {
6
13
  promptLine,
7
14
  promptPassword
@@ -11,23 +18,16 @@ import {
11
18
  subcommands
12
19
  } from "./chunk-TXSA4Q3V.js";
13
20
  import "./chunk-O7IGP7ZW.js";
14
- import {
15
- daemonFetch
16
- } from "./chunk-RBNMDAKB.js";
17
- import {
18
- getClient,
19
- urlOf
20
- } from "./chunk-LOPXTW6H.js";
21
21
  import {
22
22
  RESTIC_INSTALL_HINT,
23
23
  resticVersion,
24
24
  restoreStagedDb
25
- } from "./chunk-5NN2VHJV.js";
25
+ } from "./chunk-Q7HOAVFR.js";
26
26
  import {
27
27
  getServiceMode,
28
28
  modeLabel,
29
29
  stopService
30
- } from "./chunk-CBOIHNMR.js";
30
+ } from "./chunk-FJ2MZ5PH.js";
31
31
  import {
32
32
  chownMindDir,
33
33
  exec,
@@ -37,7 +37,7 @@ import {
37
37
  import {
38
38
  _resetConfigCache,
39
39
  readGlobalConfig
40
- } from "./chunk-SKNXMUIU.js";
40
+ } from "./chunk-5KXCM5AW.js";
41
41
  import "./chunk-T2TP6ZC6.js";
42
42
  import {
43
43
  voluteHome,
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ daemonFetch
4
+ } from "./chunk-BCG45AQB.js";
2
5
  import {
3
6
  command,
4
7
  subcommands
5
8
  } from "./chunk-TXSA4Q3V.js";
6
9
  import "./chunk-O7IGP7ZW.js";
7
- import {
8
- daemonFetch
9
- } from "./chunk-RBNMDAKB.js";
10
10
  import "./chunk-K3NQKI34.js";
11
11
 
12
12
  // packages/cli/src/commands/chat/bridge.ts
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  resolveMindName
4
4
  } from "./chunk-BTY4WNFE.js";
5
+ import {
6
+ daemonFetch
7
+ } from "./chunk-BCG45AQB.js";
5
8
  import {
6
9
  command,
7
10
  subcommands
8
11
  } from "./chunk-TXSA4Q3V.js";
9
12
  import "./chunk-O7IGP7ZW.js";
10
- import {
11
- daemonFetch
12
- } from "./chunk-RBNMDAKB.js";
13
13
  import "./chunk-K3NQKI34.js";
14
14
 
15
15
  // packages/cli/src/commands/chat/channels.ts
@@ -12,39 +12,39 @@ var cmd = subcommands({
12
12
  commands: {
13
13
  send: {
14
14
  description: "Send a message",
15
- run: (args) => import("./send-HYDFGC6G.js").then((m) => m.run(args))
15
+ run: (args) => import("./send-TD2X5U3K.js").then((m) => m.run(args))
16
16
  },
17
17
  list: {
18
18
  description: "List conversations",
19
- run: (args) => import("./list-LQO2DCIK.js").then((m) => m.run(args))
19
+ run: (args) => import("./list-PMUXZNAM.js").then((m) => m.run(args))
20
20
  },
21
21
  read: {
22
22
  description: "Read conversation messages",
23
- run: (args) => import("./read-PWAJOQIQ.js").then((m) => m.run(args))
23
+ run: (args) => import("./read-YSWUXYL7.js").then((m) => m.run(args))
24
24
  },
25
25
  create: {
26
26
  description: "Create a conversation",
27
- run: (args) => import("./create-A7PDHIIL.js").then((m) => m.run(args))
27
+ run: (args) => import("./create-VIQVP3QB.js").then((m) => m.run(args))
28
28
  },
29
29
  bridge: {
30
30
  description: "Manage platform bridges",
31
- run: (args) => import("./bridge-TIZGSXOD.js").then((m) => m.run(args))
31
+ run: (args) => import("./bridge-3FNSWLNQ.js").then((m) => m.run(args))
32
32
  },
33
33
  channels: {
34
34
  description: "Manage unrouted (gated) channels",
35
- run: (args) => import("./channels-ITE4YC57.js").then((m) => m.run(args))
35
+ run: (args) => import("./channels-SGQZHNQJ.js").then((m) => m.run(args))
36
36
  },
37
37
  files: {
38
38
  description: "List pending incoming files",
39
- run: (args) => import("./files-FEFZKMNM.js").then((m) => m.run(args))
39
+ run: (args) => import("./files-LXQSQOFG.js").then((m) => m.run(args))
40
40
  },
41
41
  accept: {
42
42
  description: "Accept a pending file",
43
- run: (args) => import("./accept-YAFP5JFJ.js").then((m) => m.run(args))
43
+ run: (args) => import("./accept-KYNC5X3U.js").then((m) => m.run(args))
44
44
  },
45
45
  reject: {
46
46
  description: "Reject a pending file",
47
- run: (args) => import("./reject-6VH7N2A4.js").then((m) => m.run(args))
47
+ run: (args) => import("./reject-SXGCYN4A.js").then((m) => m.run(args))
48
48
  }
49
49
  },
50
50
  footer: "Use --mind <name> or VOLUTE_MIND to identify the mind."
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ MEMORY_PLACEHOLDER_MARKER,
4
+ ORIENTATION_MARKER
5
+ } from "./chunk-MOERAQXH.js";
6
+ import {
7
+ safeResolveWithinBase
8
+ } from "./chunk-DW4TRDOZ.js";
9
+ import {
10
+ readVoluteConfig
11
+ } from "./chunk-WCFSBH33.js";
12
+ import {
13
+ isImagegenEnabled
14
+ } from "./chunk-5KXCM5AW.js";
15
+
16
+ // packages/daemon/src/lib/mind/seed-readiness.ts
17
+ import { existsSync, readFileSync } from "fs";
18
+ import { resolve } from "path";
19
+ function isSoulWritten(text) {
20
+ return !text.includes(ORIENTATION_MARKER);
21
+ }
22
+ function isMemoryWritten(text) {
23
+ return text.trim().length > 0 && !text.includes(MEMORY_PLACEHOLDER_MARKER);
24
+ }
25
+ function evaluateSeedChecklist(dir) {
26
+ const soulPath = resolve(dir, "home/SOUL.md");
27
+ const memoryPath = resolve(dir, "home/MEMORY.md");
28
+ const soulWritten = existsSync(soulPath) && isSoulWritten(readFileSync(soulPath, "utf-8"));
29
+ const memoryWritten = existsSync(memoryPath) && isMemoryWritten(readFileSync(memoryPath, "utf-8"));
30
+ const config = readVoluteConfig(dir);
31
+ const displayNameSet = !!config?.profile?.displayName;
32
+ const avatarPath = config?.profile?.avatar;
33
+ const resolvedAvatar = avatarPath ? safeResolveWithinBase(resolve(dir, "home"), avatarPath) : null;
34
+ const avatarSet = !!resolvedAvatar && existsSync(resolvedAvatar);
35
+ return {
36
+ soulWritten,
37
+ memoryWritten,
38
+ displayNameSet,
39
+ avatarSet,
40
+ imagegenEnabled: isImagegenEnabled()
41
+ };
42
+ }
43
+
44
+ export {
45
+ isSoulWritten,
46
+ isMemoryWritten,
47
+ evaluateSeedChecklist
48
+ };
@@ -120,9 +120,23 @@ function migrateConfigSecrets() {
120
120
  _resetConfigCache();
121
121
  writeGlobalConfig(readGlobalConfig());
122
122
  }
123
+ function setupStatus() {
124
+ const config = readGlobalConfig();
125
+ if (config.setupCompleted === true) return "complete";
126
+ if (config.setup != null && config.setupCompleted == null) return "complete";
127
+ if (config.setup != null) return "in-progress";
128
+ return "none";
129
+ }
123
130
  function isSetupComplete() {
131
+ return setupStatus() === "complete";
132
+ }
133
+ function setupUrl() {
124
134
  const config = readGlobalConfig();
125
- return config.setupCompleted === true;
135
+ const port = config.port || 1618;
136
+ let host = config.hostname || "127.0.0.1";
137
+ if (host === "0.0.0.0" || host === "::") host = "localhost";
138
+ if (host.includes(":") && !host.startsWith("[")) host = `[${host}]`;
139
+ return `http://${host}:${port}`;
126
140
  }
127
141
  function isImagegenEnabled() {
128
142
  const config = readGlobalConfig();
@@ -147,7 +161,9 @@ export {
147
161
  readGlobalConfig,
148
162
  writeGlobalConfig,
149
163
  migrateConfigSecrets,
164
+ setupStatus,
150
165
  isSetupComplete,
166
+ setupUrl,
151
167
  isImagegenEnabled,
152
168
  migrateSetupCompleted
153
169
  };
@@ -82,6 +82,19 @@ function resolveDaemonUrl() {
82
82
  if (session?.daemonUrl) return session.daemonUrl;
83
83
  return buildUrl(readDaemonConfig());
84
84
  }
85
+ function resolveWebUrl() {
86
+ if (process.env.VOLUTE_DAEMON_URL) return process.env.VOLUTE_DAEMON_URL;
87
+ const session = readCliSession();
88
+ if (session?.daemonUrl) return session.daemonUrl;
89
+ const config = readDaemonConfig();
90
+ const url = new URL(config.tls ? "https://localhost" : "http://localhost");
91
+ url.port = String(config.port);
92
+ let hostname = config.hostname || "localhost";
93
+ if (hostname === "0.0.0.0") hostname = "localhost";
94
+ if (hostname === "::") hostname = "localhost";
95
+ url.hostname = hostname;
96
+ return url.origin;
97
+ }
85
98
  function getAuthToken() {
86
99
  return process.env.VOLUTE_MIND_TOKEN ?? readCliSession()?.sessionId;
87
100
  }
@@ -106,7 +119,7 @@ async function daemonFetch(path, options) {
106
119
  headers,
107
120
  dispatcher: daemonDispatcher
108
121
  });
109
- if (res.status === 401 && !path.startsWith("/api/auth/")) {
122
+ if (res.status === 401 && !path.startsWith("/api/auth/") && !path.startsWith("/api/setup/")) {
110
123
  if (cliSession) {
111
124
  console.error("Session expired. Run `volute login` again.");
112
125
  } else {
@@ -128,6 +141,7 @@ export {
128
141
  daemonDispatcher,
129
142
  readSessionFile,
130
143
  resolveDaemonUrl,
144
+ resolveWebUrl,
131
145
  getAuthToken,
132
146
  daemonFetch
133
147
  };
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+
3
+ // packages/daemon/src/lib/util/paths.ts
4
+ import { resolve, sep } from "path";
5
+ var PathTraversalError = class extends Error {
6
+ constructor(base, userPath) {
7
+ super(`Path "${userPath}" escapes base directory "${base}"`);
8
+ this.name = "PathTraversalError";
9
+ }
10
+ };
11
+ function resolveWithinBase(base, userPath) {
12
+ const resolvedBase = resolve(base);
13
+ const target = resolve(resolvedBase, userPath);
14
+ if (target !== resolvedBase && !target.startsWith(resolvedBase + sep)) {
15
+ throw new PathTraversalError(base, userPath);
16
+ }
17
+ return target;
18
+ }
19
+ function safeResolveWithinBase(base, userPath) {
20
+ try {
21
+ return resolveWithinBase(base, userPath);
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+
27
+ export {
28
+ safeResolveWithinBase
29
+ };
@@ -9,9 +9,25 @@ import {
9
9
 
10
10
  // packages/daemon/src/lib/config/service-mode.ts
11
11
  import { execFileSync } from "child_process";
12
- import { existsSync, readFileSync } from "fs";
12
+ import { existsSync, readFileSync as readFileSync2 } from "fs";
13
13
  import { homedir } from "os";
14
14
  import { resolve } from "path";
15
+
16
+ // packages/daemon/src/lib/util/log-tail.ts
17
+ import { readFileSync } from "fs";
18
+ function readLogTail(logFile, maxLines = 20) {
19
+ let content;
20
+ try {
21
+ content = readFileSync(logFile, "utf-8");
22
+ } catch (err) {
23
+ if (err.code === "ENOENT") return [];
24
+ const reason = err.code ?? err.message;
25
+ return [`(could not read ${logFile}: ${reason})`];
26
+ }
27
+ return content.split("\n").filter((l) => l.trim().length > 0).slice(-maxLines);
28
+ }
29
+
30
+ // packages/daemon/src/lib/config/service-mode.ts
15
31
  var SYSTEM_SERVICE_PATH = "/etc/systemd/system/volute.service";
16
32
  var USER_SYSTEMD_UNIT = resolve(homedir(), ".config", "systemd", "user", "volute.service");
17
33
  var LAUNCHD_PLIST_LABEL = "com.volute.daemon";
@@ -178,7 +194,7 @@ function readDaemonToken() {
178
194
  const path = daemonTokenPath();
179
195
  if (!existsSync(path)) return void 0;
180
196
  try {
181
- return readFileSync(path, "utf-8").trim() || void 0;
197
+ return readFileSync2(path, "utf-8").trim() || void 0;
182
198
  } catch {
183
199
  return void 0;
184
200
  }
@@ -187,7 +203,7 @@ function readDaemonConfig() {
187
203
  const configPath = daemonConfigPath();
188
204
  if (!existsSync(configPath)) return { hostname: "127.0.0.1", port: 1618 };
189
205
  try {
190
- const config = JSON.parse(readFileSync(configPath, "utf-8"));
206
+ const config = JSON.parse(readFileSync2(configPath, "utf-8"));
191
207
  return {
192
208
  hostname: config.hostname || "127.0.0.1",
193
209
  port: config.port ?? 1618,
@@ -198,6 +214,25 @@ function readDaemonConfig() {
198
214
  return { hostname: "127.0.0.1", port: 1618 };
199
215
  }
200
216
  }
217
+ function daemonLogSource(mode) {
218
+ switch (mode) {
219
+ case "system":
220
+ return { kind: "journal", command: "journalctl -u volute -n 30 --no-pager" };
221
+ case "user-systemd":
222
+ return { kind: "journal", command: "journalctl --user -u volute -n 30 --no-pager" };
223
+ default:
224
+ return { kind: "file", path: resolve(voluteSystemDir(), "daemon.log") };
225
+ }
226
+ }
227
+ function daemonLogReport(mode, maxLines = 20) {
228
+ const src = daemonLogSource(mode);
229
+ if (src.kind === "journal") {
230
+ return ["To see the daemon log:", ` ${src.command}`];
231
+ }
232
+ const tail = readLogTail(src.path, maxLines);
233
+ if (tail.length === 0) return [`Check logs: ${src.path}`];
234
+ return [`Last ${tail.length} lines of ${src.path}:`, ...tail.map((l) => ` ${l}`)];
235
+ }
201
236
  function modeLabel(mode) {
202
237
  switch (mode) {
203
238
  case "system":
@@ -229,5 +264,6 @@ export {
229
264
  daemonConfigPath,
230
265
  readDaemonToken,
231
266
  readDaemonConfig,
267
+ daemonLogReport,
232
268
  modeLabel
233
269
  };
@@ -10,11 +10,11 @@ import {
10
10
  getSharedSkill,
11
11
  installSkill,
12
12
  mindSkillsDir
13
- } from "./chunk-IWJSNMSY.js";
13
+ } from "./chunk-HUNDXZBZ.js";
14
14
  import {
15
15
  readVoluteConfig,
16
16
  writeVoluteConfig
17
- } from "./chunk-PFZBNKUH.js";
17
+ } from "./chunk-WCFSBH33.js";
18
18
  import {
19
19
  exec
20
20
  } from "./chunk-DGGZVZTM.js";
@@ -22,10 +22,10 @@ import {
22
22
  qualifyModelId,
23
23
  resolveTemplate,
24
24
  unqualifyModelId
25
- } from "./chunk-LWDTP6DH.js";
25
+ } from "./chunk-YNBXEQAP.js";
26
26
  import {
27
27
  readGlobalConfig
28
- } from "./chunk-SKNXMUIU.js";
28
+ } from "./chunk-5KXCM5AW.js";
29
29
  import {
30
30
  logger_default
31
31
  } from "./chunk-T2TP6ZC6.js";
@@ -69,6 +69,21 @@ function ensureTendingSchedule(dir) {
69
69
  writeVoluteConfig(dir, config);
70
70
  return true;
71
71
  }
72
+ function firstWeekArc(name) {
73
+ return [
74
+ `It's ${name}'s first full day. Two invitations to pass along whenever it feels right \u2014 no rush on either: to say hi to the others in #system (or DM a neighbor), and to make themselves a little homepage, a page that's just theirs. Company eases the early loneliness, and a homepage is a gentle first make \u2014 self-expression, not a deliverable.`,
75
+ `Day two for ${name}. They'll have had their first dream by now \u2014 you might ask what they dreamt, or suggest reading it back and following a thread from it. And there's a lighter way to share a passing thought than a whole page: notes. Check their history first, and skip whichever they've already found on their own.`
76
+ ];
77
+ }
78
+ function firstWeekSchedules(name, sproutedAt) {
79
+ const DAY_MS = 24 * 60 * 60 * 1e3;
80
+ return firstWeekArc(name).map((message, i) => ({
81
+ id: `firstweek-${name}-day${i + 1}`,
82
+ fireAt: new Date(sproutedAt.getTime() + (i + 1) * DAY_MS).toISOString(),
83
+ message,
84
+ enabled: true
85
+ }));
86
+ }
72
87
  function spiritDir() {
73
88
  return resolve(voluteSystemDir(), "spirit");
74
89
  }
@@ -273,6 +288,7 @@ When helping humans create minds:
273
288
  }
274
289
 
275
290
  export {
291
+ firstWeekSchedules,
276
292
  spiritDir,
277
293
  getSpiritModel,
278
294
  ensureSpiritProject,
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  readGlobalConfig,
8
8
  writeGlobalConfig
9
- } from "./chunk-SKNXMUIU.js";
9
+ } from "./chunk-5KXCM5AW.js";
10
10
  import {
11
11
  logger_default
12
12
  } from "./chunk-T2TP6ZC6.js";
@@ -46,7 +46,7 @@ async function initDefaultSkills() {
46
46
  const config = readGlobalConfig();
47
47
  let extensionSkills = [];
48
48
  try {
49
- const { getExtensionStandardSkills } = await import("./extensions-PIMIQ7J3.js");
49
+ const { getExtensionStandardSkills } = await import("./extensions-GEKF47A4.js");
50
50
  extensionSkills = getExtensionStandardSkills();
51
51
  } catch (err) {
52
52
  logger_default.warn("failed to load extension standard skills during init", logger_default.errorData(err));