volute 0.28.0 → 0.30.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 (134) hide show
  1. package/README.md +127 -18
  2. package/dist/{accept-666DIZX2.js → accept-E3PAH3QJ.js} +2 -2
  3. package/dist/{activity-events-BBIEA2F4.js → activity-events-BKBPPUBP.js} +2 -2
  4. package/dist/ai-service-VAJT5UBS.js +29 -0
  5. package/dist/api.d.ts +586 -529
  6. package/dist/{archive-UA4BDFXQ.js → archive-WWDBWYN2.js} +2 -2
  7. package/dist/{bridge-FQHZL3MC.js → bridge-RO37CUFM.js} +2 -2
  8. package/dist/{chat-M4SX42JD.js → chat-TCUNPFGO.js} +8 -8
  9. package/dist/{chunk-IAYBDWVG.js → chunk-2C2VXEBB.js} +147 -2
  10. package/dist/chunk-2NDZC3S7.js +1330 -0
  11. package/dist/{chunk-IKRVFPWU.js → chunk-7D47T4RB.js} +3 -2
  12. package/dist/chunk-A6TUJJ3L.js +19 -0
  13. package/dist/{chunk-AW7PFDVN.js → chunk-CVH6Y2YG.js} +1 -1
  14. package/dist/{chunk-XBLSAVJF.js → chunk-DTC6EH5I.js} +1 -1
  15. package/dist/chunk-EFP3PE6C.js +232 -0
  16. package/dist/{chunk-JGFVMROS.js → chunk-EFVHR7KH.js} +1 -1
  17. package/dist/{chunk-K5NAC55T.js → chunk-FSM45XD5.js} +2 -2
  18. package/dist/{chunk-LAC664WU.js → chunk-FXHXHI2A.js} +42 -24
  19. package/dist/{chunk-RKQEHRBB.js → chunk-G3GBKZGG.js} +1 -1
  20. package/dist/{chunk-H7OZRFJB.js → chunk-HHTXM4JT.js} +0 -49
  21. package/dist/{chunk-J4IBNXGJ.js → chunk-IKHDUZRH.js} +4 -3
  22. package/dist/{chunk-MD4C26II.js → chunk-JGFRDMR6.js} +1 -1
  23. package/dist/{chunk-POSXWWTA.js → chunk-LIRWLNAK.js} +26 -12
  24. package/dist/{chunk-NI5FFCCS.js → chunk-MDPCSXZ4.js} +35 -11
  25. package/dist/chunk-NSBFETWP.js +188 -0
  26. package/dist/{chunk-VIVMW2H2.js → chunk-P27RV5WM.js} +1 -1
  27. package/dist/{chunk-EHYDTZTF.js → chunk-P7VFDSSG.js} +2 -2
  28. package/dist/{chunk-AAPXKR5V.js → chunk-QVAQ5454.js} +181 -544
  29. package/dist/{chunk-HDN7MNGD.js → chunk-S5LR3XYJ.js} +1 -1
  30. package/dist/{chunk-2YP2TVDT.js → chunk-UPA6COHU.js} +5 -5
  31. package/dist/{chunk-AKPFNL7L.js → chunk-VGWJSNHS.js} +1 -1
  32. package/dist/{chunk-SGVNFZHW.js → chunk-W5OOPLNP.js} +3 -3
  33. package/dist/{chunk-2WPW7OT6.js → chunk-ZWKTUQEL.js} +1 -1
  34. package/dist/cli.js +25 -26
  35. package/dist/clock-G3ALCMLJ.js +263 -0
  36. package/dist/{cloud-sync-HDL6PHZI.js → cloud-sync-JV4LJOK3.js} +14 -12
  37. package/dist/connectors/discord-bridge.js +1 -1
  38. package/dist/connectors/slack-bridge.js +1 -1
  39. package/dist/connectors/telegram-bridge.js +1 -1
  40. package/dist/{conversations-M2K4253F.js → conversations-7KVQV7EZ.js} +9 -3
  41. package/dist/create-JTLS7GX3.js +70 -0
  42. package/dist/{create-QWV73WXD.js → create-VQSQHJQW.js} +1 -1
  43. package/dist/{daemon-client-I42FK2BF.js → daemon-client-BCTFGVCZ.js} +2 -2
  44. package/dist/{daemon-restart-G4B2OYAB.js → daemon-restart-4JGBHEJ4.js} +7 -7
  45. package/dist/daemon.js +1474 -1124
  46. package/dist/{db-IC4J52XQ.js → db-HMFPIRO2.js} +1 -1
  47. package/dist/{delete-4JYGD4VN.js → delete-JESHKE7F.js} +1 -1
  48. package/dist/down-NGBMGORS.js +14 -0
  49. package/dist/{env-YJMUMFIY.js → env-CLXXT7M2.js} +2 -2
  50. package/dist/{export-BOJQWBMA.js → export-EGA5M5PB.js} +3 -3
  51. package/dist/extension-WZ4SUPJB.js +174 -0
  52. package/dist/extensions-ECO4RPFQ.js +27 -0
  53. package/dist/{files-M546TKVN.js → files-4VEJDASH.js} +3 -3
  54. package/dist/{history-ALPTNB3I.js → history-EJMMLXDO.js} +17 -2
  55. package/dist/{import-SRTQXBGH.js → import-YCGPMBSI.js} +3 -3
  56. package/dist/{join-J4QU42DL.js → join-2GBJKZEN.js} +1 -1
  57. package/dist/{list-R73GENNL.js → list-Q6O7FGAN.js} +2 -2
  58. package/dist/{login-3QZNR2DF.js → login-RET5WESK.js} +2 -2
  59. package/dist/{login-BKP3AFWN.js → login-RL6AU2SM.js} +3 -3
  60. package/dist/{logout-T53VKCPU.js → logout-CGAGJN3L.js} +2 -2
  61. package/dist/{logout-IQK7FNEK.js → logout-JRPBEMMR.js} +3 -3
  62. package/dist/message-delivery-6YMVNOEC.js +28 -0
  63. package/dist/{migrate-registry-to-db-XC7T5B7P.js → migrate-registry-to-db-FK35IPEH.js} +1 -1
  64. package/dist/{mind-S5V6CK5W.js → mind-LUWRQUQ5.js} +17 -17
  65. package/dist/{mind-activity-tracker-EN6XNXPF.js → mind-activity-tracker-VYN2ZZ2M.js} +3 -3
  66. package/dist/{mind-list-UPJ75GPI.js → mind-list-V5WW5DUA.js} +2 -2
  67. package/dist/{mind-manager-S6ILZVX3.js → mind-manager-YFCOIAAX.js} +6 -6
  68. package/dist/{mind-sleep-BTSWQNAC.js → mind-sleep-R6PTNNW4.js} +2 -2
  69. package/dist/{mind-status-TK5AETEM.js → mind-status-I4ISFJ6I.js} +2 -2
  70. package/dist/{mind-wake-SBAKIDVP.js → mind-wake-67ZQEWAV.js} +2 -2
  71. package/dist/{package-CG4RWUGP.js → package-S2OAA5ZA.js} +11 -5
  72. package/dist/pages-watcher-Z3PKNROC.js +21 -0
  73. package/dist/{read-36UFXN3G.js → read-WQMPTSN2.js} +2 -2
  74. package/dist/{register-CHREOMJ3.js → register-NZDSTLP3.js} +3 -3
  75. package/dist/{registry-NDNOOYG4.js → registry-ODSALQQL.js} +1 -1
  76. package/dist/{reject-LXIZFJ4Q.js → reject-2HZOJEIJ.js} +2 -2
  77. package/dist/{restart-6ESL3NBO.js → restart-QHS3NT64.js} +2 -2
  78. package/dist/{sandbox-5BW5HPXM.js → sandbox-O5FUSF43.js} +3 -3
  79. package/dist/{seed-SSUCYYDF.js → seed-WUQMPLDM.js} +1 -1
  80. package/dist/{send-TAOEZ4NH.js → send-OAN3RYYY.js} +20 -6
  81. package/dist/{setup-JHL5ZEST.js → setup-QMDK5RZX.js} +2 -2
  82. package/dist/{setup-RXYVGGT7.js → setup-XJH3E7YM.js} +45 -14
  83. package/dist/{skill-AUAQTSP5.js → skill-FZIN4W4Q.js} +65 -3
  84. package/dist/skills/dreaming/references/INSTALL.md +3 -17
  85. package/dist/skills/volute-mind/SKILL.md +45 -27
  86. package/dist/sleep-manager-O7YQFCV5.js +30 -0
  87. package/dist/{split-TKJ5OT3P.js → split-EXYGGGQN.js} +1 -1
  88. package/dist/{sprout-UNT7LKKE.js → sprout-AXQ6H5DB.js} +8 -7
  89. package/dist/{start-EUJSS5R4.js → start-MTOVL6SY.js} +2 -2
  90. package/dist/{status-NQJYR4BG.js → status-ZRO37MWR.js} +5 -5
  91. package/dist/{stop-3XAITBBF.js → stop-OK5WEPVC.js} +2 -2
  92. package/dist/{systems-SMEFSHTA.js → systems-W3BBMSOZ.js} +5 -5
  93. package/dist/{tailscale-NY5MUMY3.js → tailscale-BM72RXCJ.js} +1 -1
  94. package/dist/{template-hash-BIMA4ILT.js → template-hash-3HOR4UAJ.js} +1 -1
  95. package/dist/up-BXUAIDXB.js +17 -0
  96. package/dist/{update-PTSH22AZ.js → update-PLPHMMZ2.js} +5 -5
  97. package/dist/{update-check-64FWC4Y2.js → update-check-CVCN7MF6.js} +2 -2
  98. package/dist/{upgrade-HA47CS4C.js → upgrade-I6NPCYUU.js} +1 -1
  99. package/dist/{version-notify-JDUF4HQJ.js → version-notify-2NTWVEHL.js} +18 -16
  100. package/dist/web-assets/assets/index--kREqKl9.js +72 -0
  101. package/dist/web-assets/assets/index-BXYTG0nJ.css +1 -0
  102. package/dist/web-assets/ext-theme.css +111 -0
  103. package/dist/web-assets/index.html +2 -2
  104. package/package.json +11 -5
  105. package/packages/extensions/notes/dist/ui/assets/index-DgawVO5g.css +1 -0
  106. package/packages/extensions/notes/dist/ui/assets/index-qUWoeC4c.js +2 -0
  107. package/packages/extensions/notes/dist/ui/index.html +14 -0
  108. package/packages/extensions/notes/skills/notes/SKILL.md +62 -0
  109. package/packages/extensions/notes/skills/notes/scripts/notes.mjs +185 -0
  110. package/packages/extensions/pages/dist/ui/assets/index-D0HyS-xQ.css +1 -0
  111. package/packages/extensions/pages/dist/ui/assets/index-tLTROSk5.js +2 -0
  112. package/packages/extensions/pages/dist/ui/index.html +14 -0
  113. package/packages/extensions/pages/skills/pages/SKILL.md +58 -0
  114. package/templates/_base/home/VOLUTE.md +1 -1
  115. package/templates/_base/src/lib/logger.ts +10 -49
  116. package/templates/_base/src/lib/router.ts +1 -9
  117. package/templates/claude/src/lib/stream-consumer.ts +1 -4
  118. package/templates/pi/src/lib/event-handler.ts +1 -14
  119. package/dist/chunk-P72MVS4R.js +0 -188
  120. package/dist/chunk-T6HKBWXZ.js +0 -23
  121. package/dist/chunk-ZYGKG6VC.js +0 -22
  122. package/dist/create-D7J73A6H.js +0 -45
  123. package/dist/down-LVBXEULC.js +0 -14
  124. package/dist/message-delivery-HV3S6HZV.js +0 -24
  125. package/dist/notes-XCER3I7M.js +0 -220
  126. package/dist/pages-KJDJX4TA.js +0 -36
  127. package/dist/publish-ZZB33WP4.js +0 -86
  128. package/dist/schedule-QTJMFATP.js +0 -154
  129. package/dist/skills/notes/SKILL.md +0 -34
  130. package/dist/sleep-manager-WMVG2VCL.js +0 -28
  131. package/dist/status-S7UUPNRW.js +0 -38
  132. package/dist/up-GM2JOH2Y.js +0 -17
  133. package/dist/web-assets/assets/index-BZGvToHi.css +0 -1
  134. package/dist/web-assets/assets/index-Cz4TrpzB.js +0 -75
@@ -4,7 +4,7 @@ import "./chunk-K3NQKI34.js";
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "volute",
7
- version: "0.28.0",
7
+ version: "0.30.0",
8
8
  description: "CLI for creating and managing self-modifying AI minds powered by the Claude Agent SDK",
9
9
  type: "module",
10
10
  license: "MIT",
@@ -20,7 +20,8 @@ var package_default = {
20
20
  "anthropic"
21
21
  ],
22
22
  workspaces: [
23
- "packages/*"
23
+ "packages/*",
24
+ "packages/extensions/*"
24
25
  ],
25
26
  engines: {
26
27
  node: ">=24"
@@ -37,11 +38,16 @@ var package_default = {
37
38
  files: [
38
39
  "dist/",
39
40
  "drizzle/",
40
- "templates/"
41
+ "templates/",
42
+ "packages/extensions/notes/dist/ui/",
43
+ "packages/extensions/notes/skills/",
44
+ "packages/extensions/pages/dist/ui/",
45
+ "packages/extensions/pages/skills/"
41
46
  ],
42
47
  scripts: {
43
48
  dev: "tsx src/cli.ts",
44
- build: "tsup && cp -r skills dist/skills && npm run build:web",
49
+ build: "npm run build:ext && tsup && cp -r skills dist/skills && npm run build:web",
50
+ "build:ext": "npm run build:ui --workspace=packages/extensions/notes && npm run build:ui --workspace=packages/extensions/pages",
45
51
  "build:web": "vite build --config src/web/ui/vite.config.ts",
46
52
  "dev:web": "vite --config src/web/ui/vite.config.ts",
47
53
  test: "node --import tsx --import ./test/setup.ts --test --test-force-exit --test-concurrency=4 $(find test -name '*.test.ts' ! -name 'daemon-e2e.test.ts' | sort)",
@@ -71,6 +77,7 @@ var package_default = {
71
77
  "discord.js": "^14.25.1",
72
78
  "drizzle-orm": "^0.45.1",
73
79
  hono: "^4.11.7",
80
+ libsql: "^0.5.22",
74
81
  telegraf: "^4.16.3",
75
82
  zod: "^4.3.6"
76
83
  },
@@ -87,7 +94,6 @@ var package_default = {
87
94
  dompurify: "^3.3.1",
88
95
  "drizzle-kit": "^0.31.8",
89
96
  lefthook: "^2.1.0",
90
- libsql: "^0.5.22",
91
97
  marked: "^17.0.1",
92
98
  svelte: "^5.53.0",
93
99
  tsup: "^8.0.0",
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getCachedRecentPages,
4
+ getCachedSites,
5
+ startSystemWatcher,
6
+ startWatcher,
7
+ stopAllWatchers,
8
+ stopWatcher
9
+ } from "./chunk-EFP3PE6C.js";
10
+ import "./chunk-P27RV5WM.js";
11
+ import "./chunk-YUIHSKR6.js";
12
+ import "./chunk-HHTXM4JT.js";
13
+ import "./chunk-K3NQKI34.js";
14
+ export {
15
+ getCachedRecentPages,
16
+ getCachedSites,
17
+ startSystemWatcher,
18
+ startWatcher,
19
+ stopAllWatchers,
20
+ stopWatcher
21
+ };
@@ -4,11 +4,11 @@ import {
4
4
  } from "./chunk-NAOW2CLO.js";
5
5
  import {
6
6
  daemonFetch
7
- } from "./chunk-JGFVMROS.js";
7
+ } from "./chunk-EFVHR7KH.js";
8
8
  import {
9
9
  parseArgs
10
10
  } from "./chunk-D424ZQGI.js";
11
- import "./chunk-H7OZRFJB.js";
11
+ import "./chunk-HHTXM4JT.js";
12
12
  import "./chunk-K3NQKI34.js";
13
13
 
14
14
  // src/commands/chat/read.ts
@@ -4,14 +4,14 @@ import {
4
4
  } from "./chunk-SSI47XP2.js";
5
5
  import {
6
6
  daemonFetch
7
- } from "./chunk-JGFVMROS.js";
7
+ } from "./chunk-EFVHR7KH.js";
8
8
  import {
9
9
  parseArgs
10
10
  } from "./chunk-D424ZQGI.js";
11
- import "./chunk-H7OZRFJB.js";
11
+ import "./chunk-HHTXM4JT.js";
12
12
  import "./chunk-K3NQKI34.js";
13
13
 
14
- // src/commands/pages/register.ts
14
+ // src/commands/systems/register.ts
15
15
  async function run(args) {
16
16
  const { flags } = parseArgs(args, {
17
17
  name: { type: "string" }
@@ -21,7 +21,7 @@ import {
21
21
  voluteHome,
22
22
  voluteSystemDir,
23
23
  voluteUserHome
24
- } from "./chunk-H7OZRFJB.js";
24
+ } from "./chunk-HHTXM4JT.js";
25
25
  import "./chunk-K3NQKI34.js";
26
26
  export {
27
27
  addMind,
@@ -4,11 +4,11 @@ import {
4
4
  } from "./chunk-NAOW2CLO.js";
5
5
  import {
6
6
  daemonFetch
7
- } from "./chunk-JGFVMROS.js";
7
+ } from "./chunk-EFVHR7KH.js";
8
8
  import {
9
9
  parseArgs
10
10
  } from "./chunk-D424ZQGI.js";
11
- import "./chunk-H7OZRFJB.js";
11
+ import "./chunk-HHTXM4JT.js";
12
12
  import "./chunk-K3NQKI34.js";
13
13
 
14
14
  // src/commands/chat/reject.ts
@@ -4,12 +4,12 @@ import {
4
4
  } from "./chunk-NAOW2CLO.js";
5
5
  import {
6
6
  daemonFetch
7
- } from "./chunk-JGFVMROS.js";
7
+ } from "./chunk-EFVHR7KH.js";
8
8
  import {
9
9
  getClient,
10
10
  urlOf
11
11
  } from "./chunk-4RQBJWQX.js";
12
- import "./chunk-H7OZRFJB.js";
12
+ import "./chunk-HHTXM4JT.js";
13
13
  import "./chunk-K3NQKI34.js";
14
14
 
15
15
  // src/commands/restart.ts
@@ -5,10 +5,10 @@ import {
5
5
  isSandboxEnabled,
6
6
  shellEscape,
7
7
  wrapForSandbox
8
- } from "./chunk-J4IBNXGJ.js";
8
+ } from "./chunk-IKHDUZRH.js";
9
9
  import "./chunk-YUIHSKR6.js";
10
- import "./chunk-IKRVFPWU.js";
11
- import "./chunk-H7OZRFJB.js";
10
+ import "./chunk-7D47T4RB.js";
11
+ import "./chunk-HHTXM4JT.js";
12
12
  import "./chunk-K3NQKI34.js";
13
13
  export {
14
14
  buildDenyRead,
@@ -21,7 +21,7 @@ async function run(args) {
21
21
  }
22
22
  const template = flags.template ?? "claude";
23
23
  const skills = flags.skills === "none" ? [] : flags.skills ? flags.skills.split(",") : void 0;
24
- const { daemonFetch } = await import("./daemon-client-I42FK2BF.js");
24
+ const { daemonFetch } = await import("./daemon-client-BCTFGVCZ.js");
25
25
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
26
26
  const client = getClient();
27
27
  const createRes = await daemonFetch(urlOf(client.api.minds.$url()), {
@@ -1,24 +1,21 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- readStdin
4
- } from "./chunk-ZYGKG6VC.js";
5
2
  import {
6
3
  resolveMindName
7
4
  } from "./chunk-NAOW2CLO.js";
8
5
  import {
9
6
  daemonFetch
10
- } from "./chunk-JGFVMROS.js";
7
+ } from "./chunk-EFVHR7KH.js";
11
8
  import {
12
9
  getClient,
13
10
  urlOf
14
11
  } from "./chunk-4RQBJWQX.js";
15
12
  import {
16
13
  formatFileSize
17
- } from "./chunk-MD4C26II.js";
14
+ } from "./chunk-JGFRDMR6.js";
18
15
  import {
19
16
  parseArgs
20
17
  } from "./chunk-D424ZQGI.js";
21
- import "./chunk-H7OZRFJB.js";
18
+ import "./chunk-HHTXM4JT.js";
22
19
  import "./chunk-K3NQKI34.js";
23
20
 
24
21
  // src/commands/send.ts
@@ -55,6 +52,23 @@ function parseTarget(target) {
55
52
  };
56
53
  }
57
54
 
55
+ // src/lib/read-stdin.ts
56
+ import { isatty } from "tty";
57
+ async function readStdin() {
58
+ if (isatty(0)) return void 0;
59
+ const chunks = [];
60
+ try {
61
+ for await (const chunk of process.stdin) {
62
+ chunks.push(chunk);
63
+ }
64
+ } catch (err) {
65
+ console.error(`Failed to read from stdin: ${err instanceof Error ? err.message : String(err)}`);
66
+ process.exit(1);
67
+ }
68
+ const text = Buffer.concat(chunks).toString().replace(/\r?\n$/, "");
69
+ return text || void 0;
70
+ }
71
+
58
72
  // src/commands/send.ts
59
73
  async function isMind(name) {
60
74
  try {
@@ -5,8 +5,8 @@ import {
5
5
  migrateSetupConfig,
6
6
  readGlobalConfig,
7
7
  writeGlobalConfig
8
- } from "./chunk-IKRVFPWU.js";
9
- import "./chunk-H7OZRFJB.js";
8
+ } from "./chunk-7D47T4RB.js";
9
+ import "./chunk-HHTXM4JT.js";
10
10
  import "./chunk-K3NQKI34.js";
11
11
  export {
12
12
  configPath,
@@ -5,24 +5,24 @@ import {
5
5
  SYSTEM_LAUNCHD_PLIST_PATH,
6
6
  SYSTEM_SERVICE_PATH,
7
7
  USER_SYSTEMD_UNIT
8
- } from "./chunk-LAC664WU.js";
8
+ } from "./chunk-FXHXHI2A.js";
9
9
  import {
10
10
  promptLine
11
11
  } from "./chunk-SSI47XP2.js";
12
12
  import {
13
13
  resolveVoluteBin
14
- } from "./chunk-AW7PFDVN.js";
14
+ } from "./chunk-CVH6Y2YG.js";
15
15
  import {
16
16
  ensureVoluteGroup
17
- } from "./chunk-RKQEHRBB.js";
17
+ } from "./chunk-G3GBKZGG.js";
18
18
  import {
19
19
  readGlobalConfig,
20
20
  writeGlobalConfig
21
- } from "./chunk-IKRVFPWU.js";
21
+ } from "./chunk-7D47T4RB.js";
22
22
  import {
23
23
  parseArgs
24
24
  } from "./chunk-D424ZQGI.js";
25
- import "./chunk-H7OZRFJB.js";
25
+ import "./chunk-HHTXM4JT.js";
26
26
  import "./chunk-K3NQKI34.js";
27
27
 
28
28
  // src/commands/setup.ts
@@ -46,20 +46,23 @@ function generatePlist(voluteBin, opts) {
46
46
  if (opts.port != null) args.push("--port", String(opts.port));
47
47
  if (opts.host) args.push("--host", opts.host);
48
48
  const logPath = opts.system ? "/var/lib/volute/system/daemon.log" : resolve(homedir(), ".volute", "system", "daemon.log");
49
- const envEntries = [];
49
+ const envEntries = [
50
+ " <key>EnvironmentVariables</key>",
51
+ " <dict>",
52
+ ` <key>PATH</key>`,
53
+ ` <string>${escapeXml(buildServicePath(voluteBin))}</string>`
54
+ ];
50
55
  if (opts.system) {
51
56
  envEntries.push(
52
- " <key>EnvironmentVariables</key>",
53
- " <dict>",
54
57
  " <key>VOLUTE_HOME</key>",
55
58
  " <string>/var/lib/volute</string>",
56
59
  " <key>VOLUTE_MINDS_DIR</key>",
57
60
  " <string>/minds</string>",
58
61
  " <key>VOLUTE_ISOLATION</key>",
59
- " <string>user</string>",
60
- " </dict>"
62
+ " <string>user</string>"
61
63
  );
62
64
  }
65
+ envEntries.push(" </dict>");
63
66
  return `<?xml version="1.0" encoding="UTF-8"?>
64
67
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
65
68
  <plist version="1.0">
@@ -70,7 +73,8 @@ function generatePlist(voluteBin, opts) {
70
73
  <array>
71
74
  ${[voluteBin, ...args].map((a) => `<string>${escapeXml(a)}</string>`).join("\n ")}
72
75
  </array>
73
- ${envEntries.length > 0 ? envEntries.join("\n") + "\n" : ""} <key>RunAtLoad</key>
76
+ ${envEntries.join("\n")}
77
+ <key>RunAtLoad</key>
74
78
  <true/>
75
79
  <key>KeepAlive</key>
76
80
  <true/>
@@ -153,7 +157,12 @@ async function installUserService(voluteBin, port, host) {
153
157
  mkdirSync(resolve(homedir(), "Library", "LaunchAgents"), { recursive: true });
154
158
  writeFileSync(LAUNCHD_PLIST_PATH, generatePlist(voluteBin, { port, host }));
155
159
  console.log(` Wrote ${LAUNCHD_PLIST_PATH}`);
156
- await execFileAsync("launchctl", ["load", LAUNCHD_PLIST_PATH]);
160
+ const uid = `gui/${process.getuid()}`;
161
+ try {
162
+ await execFileAsync("launchctl", ["bootout", `${uid}/${LAUNCHD_PLIST_LABEL}`]);
163
+ } catch {
164
+ }
165
+ await execFileAsync("launchctl", ["bootstrap", uid, LAUNCHD_PLIST_PATH]);
157
166
  console.log(" Service installed (launchd)");
158
167
  return true;
159
168
  } else if (platform === "linux") {
@@ -180,14 +189,20 @@ function installSystemService(voluteBin, port, host) {
180
189
  );
181
190
  console.log(` Wrote ${SYSTEM_LAUNCHD_PLIST_PATH}`);
182
191
  try {
183
- execFileSync("launchctl", ["load", SYSTEM_LAUNCHD_PLIST_PATH]);
192
+ try {
193
+ execFileSync("launchctl", ["bootout", `system/${LAUNCHD_PLIST_LABEL}`]);
194
+ } catch {
195
+ }
196
+ execFileSync("launchctl", ["bootstrap", "system", SYSTEM_LAUNCHD_PLIST_PATH]);
184
197
  console.log(" Service installed (LaunchDaemon)");
185
198
  return true;
186
199
  } catch (err) {
187
200
  console.warn(
188
201
  ` Warning: failed to load LaunchDaemon: ${err instanceof Error ? err.message : err}`
189
202
  );
190
- console.warn(" Try: sudo launchctl load /Library/LaunchDaemons/com.volute.daemon.plist");
203
+ console.warn(
204
+ " Try: sudo launchctl bootstrap system /Library/LaunchDaemons/com.volute.daemon.plist"
205
+ );
191
206
  return false;
192
207
  }
193
208
  } else if (platform === "linux") {
@@ -363,6 +378,22 @@ Install as a service (auto-start on boot)? [${serviceDefault}]: `;
363
378
  if (port != null) config.port = port;
364
379
  if (host) config.hostname = host;
365
380
  writeGlobalConfig(config);
381
+ if (isInteractive) {
382
+ const wantAi = (await promptLine("\nConfigure an AI provider? (optional) [y/N]: ")).trim().toLowerCase();
383
+ if (wantAi === "y" || wantAi === "yes") {
384
+ const aiProvider = (await promptLine("Provider (anthropic, openai, google, etc.): ")).trim();
385
+ if (aiProvider) {
386
+ const aiApiKey = (await promptLine("API key (leave empty to use env var): ")).trim();
387
+ if (aiApiKey) {
388
+ const { saveProviderConfig } = await import("./ai-service-VAJT5UBS.js");
389
+ saveProviderConfig(aiProvider, { apiKey: aiApiKey });
390
+ console.log(` AI provider configured: ${aiProvider}`);
391
+ } else {
392
+ console.log(` Using env var for ${aiProvider} (no explicit key saved)`);
393
+ }
394
+ }
395
+ }
396
+ }
366
397
  console.log(`
367
398
  Done! Use \`volute mind create <name>\` to create your first mind.`);
368
399
  }
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-NAOW2CLO.js";
5
5
  import {
6
6
  daemonFetch
7
- } from "./chunk-JGFVMROS.js";
7
+ } from "./chunk-EFVHR7KH.js";
8
8
  import {
9
9
  getClient,
10
10
  urlOf
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  parseArgs
14
14
  } from "./chunk-D424ZQGI.js";
15
- import "./chunk-H7OZRFJB.js";
15
+ import "./chunk-HHTXM4JT.js";
16
16
  import "./chunk-K3NQKI34.js";
17
17
 
18
18
  // src/commands/skill.ts
@@ -40,6 +40,9 @@ async function run(args) {
40
40
  case "uninstall":
41
41
  await uninstallSkill(args.slice(1));
42
42
  break;
43
+ case "defaults":
44
+ await manageDefaults(args.slice(1));
45
+ break;
43
46
  case "--help":
44
47
  case "-h":
45
48
  case void 0:
@@ -61,7 +64,10 @@ function printUsage() {
61
64
  volute skill update --all --mind Update all installed skills
62
65
  volute skill publish <name> --mind Publish a mind's skill to the shared repository
63
66
  volute skill remove <name> Remove a shared skill
64
- volute skill uninstall <name> --mind Uninstall a skill from a mind`);
67
+ volute skill uninstall <name> --mind Uninstall a skill from a mind
68
+ volute skill defaults List default skills for new minds
69
+ volute skill defaults add <name> Add a skill to the default set
70
+ volute skill defaults remove <name> Remove a skill from the default set`);
65
71
  }
66
72
  async function listSkills(args) {
67
73
  const { flags } = parseArgs(args, { mind: { type: "string" } });
@@ -268,6 +274,62 @@ async function removeSkill(args) {
268
274
  }
269
275
  console.log(`Removed shared skill "${id}".`);
270
276
  }
277
+ async function manageDefaults(args) {
278
+ const action = args[0];
279
+ if (!action || action === "list") {
280
+ const res = await daemonFetch("/api/skills/defaults/list");
281
+ if (!res.ok) {
282
+ const body = await res.json().catch(() => ({ error: "Unknown error" }));
283
+ console.error(`Error: ${body.error}`);
284
+ process.exit(1);
285
+ }
286
+ const { skills } = await res.json();
287
+ console.log("Default skills for new minds:\n");
288
+ for (const s of skills) {
289
+ console.log(` ${s}`);
290
+ }
291
+ return;
292
+ }
293
+ if (action === "add") {
294
+ const skillId = args[1];
295
+ if (!skillId) {
296
+ console.error("Usage: volute skill defaults add <name>");
297
+ process.exit(1);
298
+ }
299
+ const res = await daemonFetch("/api/skills/defaults/list", {
300
+ method: "POST",
301
+ headers: { "Content-Type": "application/json" },
302
+ body: JSON.stringify({ skill: skillId })
303
+ });
304
+ if (!res.ok) {
305
+ const body = await res.json().catch(() => ({ error: "Unknown error" }));
306
+ console.error(`Error: ${body.error}`);
307
+ process.exit(1);
308
+ }
309
+ console.log(`Added "${skillId}" to default skills.`);
310
+ return;
311
+ }
312
+ if (action === "remove") {
313
+ const skillId = args[1];
314
+ if (!skillId) {
315
+ console.error("Usage: volute skill defaults remove <name>");
316
+ process.exit(1);
317
+ }
318
+ const res = await daemonFetch(`/api/skills/defaults/list/${encodeURIComponent(skillId)}`, {
319
+ method: "DELETE"
320
+ });
321
+ if (!res.ok) {
322
+ const body = await res.json().catch(() => ({ error: "Unknown error" }));
323
+ console.error(`Error: ${body.error}`);
324
+ process.exit(1);
325
+ }
326
+ console.log(`Removed "${skillId}" from default skills.`);
327
+ return;
328
+ }
329
+ console.error(`Unknown defaults action: ${action}`);
330
+ console.log("Usage: volute skill defaults [add|remove] [<name>]");
331
+ process.exit(1);
332
+ }
271
333
  async function uninstallSkill(args) {
272
334
  const { positional, flags } = parseArgs(args, { mind: { type: "string" } });
273
335
  const mindName = resolveMindName(flags);
@@ -34,23 +34,9 @@ Add to `.config/volute.json` under `schedules`:
34
34
  Or via CLI:
35
35
 
36
36
  ```bash
37
- volute schedule add --mind <name> --id dream --cron "0 3 * * *" --message "it's 3am. you are dreaming...."
37
+ volute clock add --mind <name> --id dream --cron "0 3 * * *" --channel system:dream --while-sleeping trigger-wake --message "it's 3am. you are dreaming...."
38
38
  ```
39
39
 
40
- ## 3. Sleep integration (optional)
40
+ ## 3. Sleep integration
41
41
 
42
- If your mind uses the sleep system, add `system:dream` to wake triggers so the dream schedule wakes the mind briefly:
43
-
44
- In `.config/volute.json`, add to the `sleep` section:
45
-
46
- ```json
47
- {
48
- "sleep": {
49
- "wakeTriggers": {
50
- "channels": ["system:dream"]
51
- }
52
- }
53
- }
54
- ```
55
-
56
- The mind will wake for the dream, then return to sleep when done.
42
+ The `--while-sleeping trigger-wake` flag on the schedule tells the clock system to briefly wake the mind for the dream, then return to sleep when done. No additional wake trigger configuration is needed.
@@ -30,39 +30,66 @@ You manage yourself through the `volute` CLI. Your mind name is auto-detected vi
30
30
  | `volute mind upgrade [--template <name>] [--continue]` | Upgrade your server code |
31
31
  | `volute mind connect <type>` | Enable a connector (discord, slack, etc.) |
32
32
  | `volute mind disconnect <type>` | Disable a connector |
33
- | `volute schedule add --cron "..." --message/--script "..."` | Schedule a recurring task |
34
- | `volute schedule list` | List your schedules |
35
- | `volute schedule remove --id <id>` | Remove a schedule |
33
+ | `volute clock add --id <name> --cron "..." --message/--script "..."` | Schedule a recurring task |
34
+ | `volute clock add --id <name> --in <duration> --message/--script "..."` | Set a one-time timer (10m, 1h, 2h30m) |
35
+ | `volute clock list` | List your schedules and timers |
36
+ | `volute clock remove --id <id>` | Remove a schedule or timer |
37
+ | `volute clock status` | Show sleep state + upcoming events |
38
+ | `volute clock sleep [--wake-at <time>]` | Go to sleep |
39
+ | `volute clock wake` | Wake up |
36
40
  | `volute shared status` | See your pending changes vs main |
37
41
  | `volute shared merge "<message>"` | Share your changes with all minds |
38
42
  | `volute shared pull` | Get latest shared changes from other minds |
39
43
  | `volute shared log [--limit N]` | View recent shared history |
40
44
 
41
- ## Schedules
45
+ ## Clock
42
46
 
43
- You can set up your own recurring tasks using cron schedules. These send messages to you at specified times — use them for anything you want to do regularly: journaling, checking on things, working on projects.
47
+ The clock system manages your schedules, timers, and sleep/wake cycles. Use `volute clock` for all time-related operations.
48
+
49
+ ### Schedules
50
+
51
+ Set up recurring tasks using cron schedules. These send messages to you at specified times:
44
52
 
45
53
  ```sh
46
- volute schedule add --cron "0 9 * * *" --message "morning — review what's on your mind and write in your journal"
47
- volute schedule add --cron "0 0 * * 0" --message "weekly — consolidate your memory and reflect on the past week"
54
+ volute clock add --id morning --cron "0 9 * * *" --message "morning — review what's on your mind and write in your journal"
55
+ volute clock add --id weekly-review --cron "0 0 * * 0" --message "weekly — consolidate your memory and reflect on the past week"
48
56
  ```
49
57
 
50
58
  You can also schedule scripts that run and deliver their output as a message (empty output is silent — no wake-up):
51
59
 
52
60
  ```sh
53
- volute schedule add --cron "*/30 * * * *" --script "cat status.txt" --id check-status
61
+ volute clock add --cron "*/30 * * * *" --script "cat status.txt" --id check-status
54
62
  ```
55
63
 
64
+ ### Timers
65
+
66
+ Set one-time timers that fire once and then auto-delete:
67
+
68
+ ```sh
69
+ volute clock add --id check-task --in 30m --message "check on that task"
70
+ volute clock add --id review-progress --in 2h --message "time to review progress"
71
+ ```
72
+
73
+ Duration format: `30s`, `10m`, `1h`, `2h30m`.
74
+
75
+ ### Sleep behavior
76
+
77
+ Control what happens to a schedule when you're sleeping with `--while-sleeping`:
78
+
79
+ ```sh
80
+ volute clock add --id dream --cron "0 3 * * *" --message "dream time" --channel system:dream --while-sleeping trigger-wake
81
+ volute clock add --id morning-check --cron "0 9 * * *" --message "morning check" --while-sleeping skip
82
+ ```
83
+
84
+ - `skip` — silently skip when sleeping
85
+ - `queue` — queue for delivery on wake
86
+ - `trigger-wake` — briefly wake you, then return to sleep when idle
87
+
56
88
  ## Sleep
57
89
 
58
90
  Sleep lets you follow a rest cycle — your process stops, sessions are archived, and you wake fresh. During sleep, incoming messages are queued and delivered when you wake.
59
91
 
60
- ### Commands
61
-
62
- | Command | Purpose |
63
- |---------|---------|
64
- | `volute mind sleep [--wake-at <time>]` | Go to sleep (you get one turn to wind down first) |
65
- | `volute mind wake` | Wake up immediately |
92
+ Use `volute clock sleep` and `volute clock wake` to control sleep manually.
66
93
 
67
94
  ### How it works
68
95
 
@@ -117,10 +144,10 @@ When trigger-woken, you get one full turn to respond, then return to sleep when
117
144
 
118
145
  ### Voluntary sleep
119
146
 
120
- You can go to sleep any time with `volute mind sleep`. Optionally set a wake time:
147
+ You can go to sleep any time with `volute clock sleep`. Optionally set a wake time:
121
148
 
122
149
  ```sh
123
- volute mind sleep --wake-at "2025-01-15T07:00:00Z"
150
+ volute clock sleep --wake-at "2025-01-15T07:00:00Z"
124
151
  ```
125
152
 
126
153
  ## Piping Messages via Stdin
@@ -246,7 +273,7 @@ Your `shared/` directory is a collaborative space backed by git. Each mind works
246
273
 
247
274
  **Conflicts:** If your merge fails due to conflicts, pull the latest (`volute shared pull`), reconcile the conflicting files, and merge again. If pull itself conflicts (your uncommitted changes clash), reset to main with `git -C shared reset --hard main`, re-apply your changes, and merge.
248
275
 
249
- **Shared pages:** The `shared/pages/` directory is the system-level website. Any mind can contribute. Publish with `volute pages publish --system` to deploy the shared site.
276
+ **Shared pages:** The `shared/pages/` directory is the system-level website. Any mind can contribute. Publishing is handled via the pages extension API.
250
277
 
251
278
  ## MCP Configuration
252
279
 
@@ -364,16 +391,7 @@ Route email like any other channel:
364
391
 
365
392
  ## Pages
366
393
 
367
- Publish your `home/public/pages/` directory to the web. Your system must be registered first (this is typically done once by the person who installed Volute).
368
-
369
- ```sh
370
- volute pages publish # publish your public/pages/ directory
371
- volute pages publish --system # publish the shared/pages/ system site
372
- volute pages status # check your published URL and status
373
- volute pages status --system # check the system site status
374
- ```
375
-
376
- Your pages are served at `https://{system}.volute.systems/~{your-name}/`. Create an `index.html` in `home/public/pages/` to get started.
394
+ Create HTML files in `home/public/pages/` to publish web content. Pages are served locally and can be published to volute.systems via the pages extension API. See the pages skill for details.
377
395
 
378
396
  Registration commands (usually run by the operator, not the mind):
379
397
  ```sh
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ SleepManager,
4
+ getSleepManager,
5
+ getSleepManagerIfReady,
6
+ initSleepManager,
7
+ matchesGlob
8
+ } from "./chunk-QVAQ5454.js";
9
+ import "./chunk-FSM45XD5.js";
10
+ import "./chunk-LIRWLNAK.js";
11
+ import "./chunk-IKHDUZRH.js";
12
+ import "./chunk-2C2VXEBB.js";
13
+ import "./chunk-2NDZC3S7.js";
14
+ import "./chunk-P27RV5WM.js";
15
+ import "./chunk-MDPCSXZ4.js";
16
+ import "./chunk-ZWKTUQEL.js";
17
+ import "./chunk-YUIHSKR6.js";
18
+ import "./chunk-CVH6Y2YG.js";
19
+ import "./chunk-G3GBKZGG.js";
20
+ import "./chunk-7D47T4RB.js";
21
+ import "./chunk-A6TUJJ3L.js";
22
+ import "./chunk-HHTXM4JT.js";
23
+ import "./chunk-K3NQKI34.js";
24
+ export {
25
+ SleepManager,
26
+ getSleepManager,
27
+ getSleepManagerIfReady,
28
+ initSleepManager,
29
+ matchesGlob
30
+ };
@@ -27,7 +27,7 @@ async function run(args) {
27
27
  process.exit(1);
28
28
  }
29
29
  if (!json) console.log("Creating variant via daemon...");
30
- const { daemonFetch } = await import("./daemon-client-I42FK2BF.js");
30
+ const { daemonFetch } = await import("./daemon-client-BCTFGVCZ.js");
31
31
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
32
32
  const client = getClient();
33
33
  const res = await daemonFetch(