volute 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +7 -7
  2. package/dist/{activity-events-OMXKXD5N.js → activity-events-3WHHCOBB.js} +3 -4
  3. package/dist/api.d.ts +4294 -0
  4. package/dist/{archive-ZCFOSTKB.js → archive-4ZQYK5MN.js} +4 -2
  5. package/dist/auth-HM2RSPY7.js +37 -0
  6. package/dist/{channel-PUQKGSQM.js → channel-BOOMFULW.js} +2 -2
  7. package/dist/{chunk-UU7A7KLB.js → chunk-A4S7H6G6.js} +5 -7
  8. package/dist/chunk-AKPFNL7L.js +148 -0
  9. package/dist/{chunk-EBGCNDMM.js → chunk-B2CPS4QU.js} +128 -114
  10. package/dist/chunk-G5KRTU2F.js +76 -0
  11. package/dist/{chunk-FCDU5BFX.js → chunk-HFCBO2GL.js} +2 -2
  12. package/dist/{chunk-GZ7DW4YL.js → chunk-HGCDWKSP.js} +2 -2
  13. package/dist/{chunk-7UFKREVW.js → chunk-JNFRY2WU.js} +2 -2
  14. package/dist/{chunk-DYZGP3EW.js → chunk-JTDFJWI2.js} +2 -1
  15. package/dist/{chunk-WC6ZHVRL.js → chunk-KFI7TQJ6.js} +2 -2
  16. package/dist/{chunk-AW7P4EVV.js → chunk-KTJGZ7M7.js} +55 -7
  17. package/dist/{chunk-OGXOMR65.js → chunk-NWPT4ASZ.js} +1 -1
  18. package/dist/{chunk-SCUDS4US.js → chunk-ON3FF5JA.js} +1 -1
  19. package/dist/chunk-OSFGKF2T.js +2651 -0
  20. package/dist/{chunk-TIWH32HP.js → chunk-PHHKNGA3.js} +3 -3
  21. package/dist/{chunk-VDWCHYTS.js → chunk-PHU4DEAJ.js} +1 -1
  22. package/dist/{chunk-7NO7EV5Z.js → chunk-QIXPN3OO.js} +2 -2
  23. package/dist/{chunk-O6ASDHFO.js → chunk-RK627D57.js} +40 -63
  24. package/dist/{chunk-NSE7VJQA.js → chunk-SGPEZ32F.js} +29 -1
  25. package/dist/{chunk-IKMY5X76.js → chunk-TFS25FIM.js} +12 -9
  26. package/dist/{chunk-PUVXOZ6T.js → chunk-VNVCRVYI.js} +118 -69
  27. package/dist/{chunk-32VR2EOH.js → chunk-VT5QODNE.js} +2 -2
  28. package/dist/{chunk-RHEGSQFJ.js → chunk-WSLPZF72.js} +1 -1
  29. package/dist/chunk-XLC342FO.js +29 -0
  30. package/dist/cli.js +57 -119
  31. package/dist/cloud-sync-C6WRYRVR.js +96 -0
  32. package/dist/{connector-JBVNZ7VK.js → connector-PYT5UOTZ.js} +6 -6
  33. package/dist/connectors/discord.js +2 -2
  34. package/dist/connectors/slack.js +2 -2
  35. package/dist/connectors/telegram.js +2 -2
  36. package/dist/{create-HP4OVVHF.js → create-WIDA3M4C.js} +1 -1
  37. package/dist/{daemon-client-ITWUCNFO.js → daemon-client-ZHCDL4RS.js} +2 -2
  38. package/dist/{daemon-restart-KPSWNYTH.js → daemon-restart-TPQ2XBRZ.js} +6 -6
  39. package/dist/daemon.js +2250 -1985
  40. package/dist/{delete-BSU7K3RY.js → delete-LOIANQGD.js} +1 -1
  41. package/dist/down-WSUASL5E.js +14 -0
  42. package/dist/{env-A3LMO777.js → env-4PHIHTF4.js} +2 -2
  43. package/dist/{export-6QBUOQGC.js → export-XD6PJBQP.js} +19 -8
  44. package/dist/{file-C57SK5DK.js → file-X4L5TTOL.js} +2 -2
  45. package/dist/{history-WNK3DFUM.js → history-HTEKRNID.js} +2 -2
  46. package/dist/{import-XEC34Y4Z.js → import-EAXTHHXL.js} +4 -3
  47. package/dist/{log-PPPZDVEF.js → log-SRO5Q6AD.js} +2 -2
  48. package/dist/{login-HNH3EUQV.js → login-UO6AOVEA.js} +4 -4
  49. package/dist/{logout-I5CB5UZS.js → logout-UKD5LA37.js} +2 -2
  50. package/dist/{logs-SF2IMJN4.js → logs-HNTNNBDW.js} +2 -2
  51. package/dist/{merge-33C237A4.js → merge-B6SYTGI7.js} +2 -2
  52. package/dist/message-delivery-WUS4K4ZC.js +21 -0
  53. package/dist/{mind-Z7CKD6DG.js → mind-BTXR5B3C.js} +35 -11
  54. package/dist/{mind-activity-tracker-624QLQLC.js → mind-activity-tracker-PGC3DBJ7.js} +4 -5
  55. package/dist/{mind-manager-3DMYKZPB.js → mind-manager-P5OBDUKI.js} +5 -6
  56. package/dist/mind-sleep-FWRBIFBS.js +41 -0
  57. package/dist/mind-wake-LJK2YU5X.js +36 -0
  58. package/dist/{package-4NHAVUUI.js → package-A7PEYJI2.js} +10 -1
  59. package/dist/{pages-4DGQT7ZA.js → pages-YSTRWJR4.js} +6 -6
  60. package/dist/{publish-TAJUET4I.js → publish-BZNHKUUK.js} +6 -6
  61. package/dist/{pull-XAEWQJ47.js → pull-GRQAXM2E.js} +2 -2
  62. package/dist/{register-VSPCMHKX.js → register-U2UO6TC4.js} +5 -5
  63. package/dist/registry-D2BSQ2X5.js +42 -0
  64. package/dist/{restart-IQKMCK5M.js → restart-CIDAKGG2.js} +3 -6
  65. package/dist/{schedule-FFZG23IW.js → schedule-NLR3LZLY.js} +2 -2
  66. package/dist/{seed-J43YDKXG.js → seed-3H2MRREW.js} +2 -2
  67. package/dist/{send-KVIZIGCE.js → send-RP2TA7SG.js} +132 -36
  68. package/dist/{service-LUR7WDO7.js → service-7BFXDI6J.js} +31 -13
  69. package/dist/{setup-52YRV7VP.js → setup-SSIIXQMI.js} +9 -34
  70. package/dist/{shared-KO35ZM44.js → shared-2OGT3NSL.js} +4 -4
  71. package/dist/{skill-BCVNI6TV.js → skill-Q2Y6PQ3L.js} +2 -2
  72. package/dist/skills/orientation/SKILL.md +2 -2
  73. package/dist/skills/volute-mind/SKILL.md +5 -5
  74. package/dist/sleep-manager-3RWUX2ZR.js +27 -0
  75. package/dist/{sprout-QN7Y4VVO.js → sprout-UKCYBGHK.js} +34 -30
  76. package/dist/{start-I5JYB65M.js → start-JR6CUUWF.js} +3 -6
  77. package/dist/{status-D7E5HHBV.js → status-5XDGYHKP.js} +2 -2
  78. package/dist/{status-4ESFLGH4.js → status-H2MKDN6L.js} +5 -5
  79. package/dist/{status-FU2PFVVF.js → status-LV34BG6G.js} +3 -3
  80. package/dist/{stop-NBVKEFQQ.js → stop-VKPGK25U.js} +2 -5
  81. package/dist/template-hash-BIMA4ILT.js +8 -0
  82. package/dist/{up-FS7CKM6V.js → up-JKGC7PPF.js} +5 -5
  83. package/dist/{update-FJIHDJKM.js → update-ELC6MEUT.js} +5 -5
  84. package/dist/{update-check-MWE5AH4U.js → update-check-F5Z3ALXX.js} +2 -2
  85. package/dist/{upgrade-AIT24B5I.js → upgrade-GXW2EQY3.js} +12 -3
  86. package/dist/{variant-63ZWO2W7.js → variant-A4I7PHXS.js} +16 -24
  87. package/dist/version-notify-5FGUAVSF.js +181 -0
  88. package/dist/web-assets/assets/index-DWBxl4LO.js +69 -0
  89. package/dist/web-assets/assets/index-ZqMd1mx1.css +1 -0
  90. package/dist/web-assets/index.html +2 -2
  91. package/package.json +10 -1
  92. package/templates/_base/.init/.config/prompts.json +1 -0
  93. package/templates/_base/home/.config/config.json.tmpl +4 -1
  94. package/templates/_base/src/lib/logger.ts +68 -23
  95. package/templates/_base/src/lib/startup.ts +12 -3
  96. package/templates/claude/src/agent.ts +150 -29
  97. package/templates/claude/src/lib/hooks/pre-compact.ts +18 -4
  98. package/templates/claude/src/lib/message-channel.ts +6 -0
  99. package/templates/claude/src/lib/stream-consumer.ts +7 -0
  100. package/templates/claude/src/server.ts +3 -1
  101. package/templates/pi/home/.config/config.json.tmpl +4 -1
  102. package/templates/pi/src/agent.ts +87 -0
  103. package/templates/pi/src/lib/event-handler.ts +13 -1
  104. package/templates/pi/src/server.ts +3 -1
  105. package/dist/chunk-5XNT2472.js +0 -36
  106. package/dist/chunk-FGSYHIS3.js +0 -891
  107. package/dist/chunk-UJ6GHNR7.js +0 -675
  108. package/dist/db-C2CJ46ZU.js +0 -10
  109. package/dist/delivery-manager-CSG7LXA4.js +0 -16
  110. package/dist/down-ZY35KMHR.js +0 -14
  111. package/dist/schema-GFH6RV3W.js +0 -26
  112. package/dist/variants-JAGWGBXG.js +0 -26
  113. package/dist/web-assets/assets/index-CUZTZzaW.js +0 -64
  114. package/dist/web-assets/assets/index-adVuCkqy.css +0 -1
@@ -1,19 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- STANDARD_SKILLS,
4
- getSharedSkill,
5
- installSkill,
6
- uninstallSkill
7
- } from "./chunk-IKMY5X76.js";
3
+ STANDARD_SKILLS
4
+ } from "./chunk-TFS25FIM.js";
5
+ import "./chunk-SGPEZ32F.js";
8
6
  import "./chunk-YUIHSKR6.js";
9
- import "./chunk-5XNT2472.js";
10
- import "./chunk-NSE7VJQA.js";
11
- import "./chunk-DYZGP3EW.js";
12
- import "./chunk-OGXOMR65.js";
7
+ import "./chunk-JTDFJWI2.js";
8
+ import "./chunk-NWPT4ASZ.js";
13
9
  import {
14
10
  findMind,
15
11
  mindDir
16
- } from "./chunk-EBGCNDMM.js";
12
+ } from "./chunk-B2CPS4QU.js";
17
13
  import "./chunk-K3NQKI34.js";
18
14
 
19
15
  // src/commands/sprout.ts
@@ -23,7 +19,7 @@ var ORIENTATION_MARKER = "You don't have a soul yet";
23
19
  async function run(_args) {
24
20
  const mindName = process.env.VOLUTE_MIND;
25
21
  if (!mindName) {
26
- console.error("volute sprout must be run by a mind (VOLUTE_MIND not set)");
22
+ console.error("volute mind sprout must be run by a mind (VOLUTE_MIND not set)");
27
23
  process.exit(1);
28
24
  }
29
25
  const entry = findMind(mindName);
@@ -53,44 +49,52 @@ async function run(_args) {
53
49
  console.error("Write your MEMORY.md before sprouting.");
54
50
  process.exit(1);
55
51
  }
52
+ const { daemonFetch } = await import("./daemon-client-ZHCDL4RS.js");
53
+ const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
54
+ const client = getClient();
56
55
  const failedSkills = [];
57
56
  for (const skillId of STANDARD_SKILLS) {
58
- const shared = await getSharedSkill(skillId);
59
- if (!shared) {
60
- console.error(`Shared skill not found: ${skillId} \u2014 run 'volute up' to sync built-in skills`);
61
- failedSkills.push(skillId);
62
- continue;
63
- }
64
57
  const skillDir = resolve(dir, "home", ".claude", "skills", skillId);
65
58
  if (!existsSync(skillDir)) {
66
- try {
67
- await installSkill(mindName, dir, skillId);
68
- } catch (err) {
69
- console.error(`Failed to install skill ${skillId}: ${err.message}`);
59
+ const installRes = await daemonFetch(
60
+ urlOf(client.api.minds[":name"].skills.install.$url({ param: { name: mindName } })),
61
+ {
62
+ method: "POST",
63
+ headers: { "Content-Type": "application/json" },
64
+ body: JSON.stringify({ skillId })
65
+ }
66
+ );
67
+ if (!installRes.ok) {
68
+ const data = await installRes.json().catch(() => ({ error: `HTTP ${installRes.status}` }));
69
+ console.error(`Failed to install skill ${skillId}: ${data.error}`);
70
70
  failedSkills.push(skillId);
71
71
  }
72
72
  }
73
73
  }
74
74
  const orientationDir = resolve(dir, "home", ".claude", "skills", "orientation");
75
75
  if (existsSync(orientationDir)) {
76
- try {
77
- await uninstallSkill(mindName, dir, "orientation");
78
- } catch (err) {
79
- console.error(`Failed to uninstall orientation skill: ${err.message}`);
76
+ const delRes = await daemonFetch(
77
+ urlOf(
78
+ client.api.minds[":name"].skills[":skill"].$url({
79
+ param: { name: mindName, skill: "orientation" }
80
+ })
81
+ ),
82
+ { method: "DELETE" }
83
+ );
84
+ if (!delRes.ok) {
85
+ const data = await delRes.json().catch(() => ({ error: `HTTP ${delRes.status}` }));
86
+ console.error(`Failed to uninstall orientation skill: ${data.error}`);
80
87
  }
81
88
  }
82
89
  if (failedSkills.length > 0) {
83
90
  console.error(`Warning: failed to install skills: ${failedSkills.join(", ")}`);
84
91
  }
85
- const { daemonFetch } = await import("./daemon-client-ITWUCNFO.js");
86
- const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
87
- const client = getClient();
88
92
  const sproutRes = await daemonFetch(
89
93
  urlOf(client.api.minds[":name"].sprout.$url({ param: { name: mindName } })),
90
94
  { method: "POST" }
91
95
  );
92
96
  if (!sproutRes.ok) {
93
- const data = await sproutRes.json();
97
+ const data = await sproutRes.json().catch(() => ({ error: `HTTP ${sproutRes.status}` }));
94
98
  console.error(data.error ?? "Failed to update stage");
95
99
  process.exit(1);
96
100
  }
@@ -103,7 +107,7 @@ async function run(_args) {
103
107
  }
104
108
  );
105
109
  if (!res.ok) {
106
- const data = await res.json();
110
+ const data = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
107
111
  console.error(data.error ?? "Failed to restart after sprouting");
108
112
  process.exit(1);
109
113
  }
@@ -5,10 +5,8 @@ import {
5
5
  } from "./chunk-4RQBJWQX.js";
6
6
  import {
7
7
  daemonFetch
8
- } from "./chunk-WC6ZHVRL.js";
9
- import {
10
- resolveMind
11
- } from "./chunk-EBGCNDMM.js";
8
+ } from "./chunk-KFI7TQJ6.js";
9
+ import "./chunk-B2CPS4QU.js";
12
10
  import "./chunk-K3NQKI34.js";
13
11
 
14
12
  // src/commands/start.ts
@@ -18,7 +16,6 @@ async function run(args) {
18
16
  console.error("Usage: volute mind start <name>");
19
17
  process.exit(1);
20
18
  }
21
- const { entry } = resolveMind(name);
22
19
  const client = getClient();
23
20
  const res = await daemonFetch(urlOf(client.api.minds[":name"].start.$url({ param: { name } })), {
24
21
  method: "POST"
@@ -28,7 +25,7 @@ async function run(args) {
28
25
  console.error(data.error || "Failed to start mind");
29
26
  process.exit(1);
30
27
  }
31
- console.log(`${name} started on port ${entry.port}`);
28
+ console.log(`${name} started on port ${data.port}`);
32
29
  }
33
30
  export {
34
31
  run
@@ -7,8 +7,8 @@ import {
7
7
  } from "./chunk-D424ZQGI.js";
8
8
  import {
9
9
  daemonFetch
10
- } from "./chunk-WC6ZHVRL.js";
11
- import "./chunk-EBGCNDMM.js";
10
+ } from "./chunk-KFI7TQJ6.js";
11
+ import "./chunk-B2CPS4QU.js";
12
12
  import "./chunk-K3NQKI34.js";
13
13
 
14
14
  // src/commands/shared/status.ts
@@ -4,13 +4,13 @@ import {
4
4
  getServiceMode,
5
5
  modeLabel,
6
6
  readDaemonConfig
7
- } from "./chunk-32VR2EOH.js";
8
- import "./chunk-DYZGP3EW.js";
9
- import "./chunk-OGXOMR65.js";
7
+ } from "./chunk-VT5QODNE.js";
8
+ import "./chunk-JTDFJWI2.js";
9
+ import "./chunk-NWPT4ASZ.js";
10
10
  import {
11
11
  checkForUpdate
12
- } from "./chunk-SCUDS4US.js";
13
- import "./chunk-EBGCNDMM.js";
12
+ } from "./chunk-ON3FF5JA.js";
13
+ import "./chunk-B2CPS4QU.js";
14
14
  import "./chunk-K3NQKI34.js";
15
15
 
16
16
  // src/commands/status.ts
@@ -7,11 +7,11 @@ import {
7
7
  } from "./chunk-NAOW2CLO.js";
8
8
  import {
9
9
  readSystemsConfig
10
- } from "./chunk-FCDU5BFX.js";
10
+ } from "./chunk-HFCBO2GL.js";
11
11
  import {
12
12
  parseArgs
13
13
  } from "./chunk-D424ZQGI.js";
14
- import "./chunk-EBGCNDMM.js";
14
+ import "./chunk-B2CPS4QU.js";
15
15
  import "./chunk-K3NQKI34.js";
16
16
 
17
17
  // src/commands/pages/status.ts
@@ -22,7 +22,7 @@ async function run(args) {
22
22
  });
23
23
  const config = readSystemsConfig();
24
24
  if (!config) {
25
- console.error('Not logged in. Run "volute pages register" or "volute pages login" first.');
25
+ console.error('Not logged in. Run "volute auth register" or "volute auth login" first.');
26
26
  process.exit(1);
27
27
  }
28
28
  const mindName = flags.mind || process.env.VOLUTE_MIND ? resolveMindName(flags) : "system";
@@ -8,16 +8,13 @@ import {
8
8
  } from "./chunk-NAOW2CLO.js";
9
9
  import {
10
10
  daemonFetch
11
- } from "./chunk-WC6ZHVRL.js";
12
- import {
13
- resolveMind
14
- } from "./chunk-EBGCNDMM.js";
11
+ } from "./chunk-KFI7TQJ6.js";
12
+ import "./chunk-B2CPS4QU.js";
15
13
  import "./chunk-K3NQKI34.js";
16
14
 
17
15
  // src/commands/stop.ts
18
16
  async function run(args) {
19
17
  const name = resolveMindName({ mind: args[0] });
20
- resolveMind(name);
21
18
  const client = getClient();
22
19
  const res = await daemonFetch(urlOf(client.api.minds[":name"].stop.$url({ param: { name } })), {
23
20
  method: "POST"
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ computeTemplateHash
4
+ } from "./chunk-AKPFNL7L.js";
5
+ import "./chunk-K3NQKI34.js";
6
+ export {
7
+ computeTemplateHash
8
+ };
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  readGlobalConfig,
4
4
  run
5
- } from "./chunk-7UFKREVW.js";
6
- import "./chunk-32VR2EOH.js";
5
+ } from "./chunk-JNFRY2WU.js";
6
+ import "./chunk-VT5QODNE.js";
7
7
  import "./chunk-D424ZQGI.js";
8
- import "./chunk-DYZGP3EW.js";
9
- import "./chunk-OGXOMR65.js";
10
- import "./chunk-EBGCNDMM.js";
8
+ import "./chunk-JTDFJWI2.js";
9
+ import "./chunk-NWPT4ASZ.js";
10
+ import "./chunk-B2CPS4QU.js";
11
11
  import "./chunk-K3NQKI34.js";
12
12
  export {
13
13
  readGlobalConfig,
@@ -5,19 +5,19 @@ import {
5
5
  pollHealth,
6
6
  readDaemonConfig,
7
7
  restartService
8
- } from "./chunk-32VR2EOH.js";
8
+ } from "./chunk-VT5QODNE.js";
9
9
  import {
10
10
  exec,
11
11
  execInherit,
12
12
  resolveVoluteBin
13
- } from "./chunk-DYZGP3EW.js";
14
- import "./chunk-OGXOMR65.js";
13
+ } from "./chunk-JTDFJWI2.js";
14
+ import "./chunk-NWPT4ASZ.js";
15
15
  import {
16
16
  checkForUpdate
17
- } from "./chunk-SCUDS4US.js";
17
+ } from "./chunk-ON3FF5JA.js";
18
18
  import {
19
19
  voluteHome
20
- } from "./chunk-EBGCNDMM.js";
20
+ } from "./chunk-B2CPS4QU.js";
21
21
  import "./chunk-K3NQKI34.js";
22
22
 
23
23
  // src/commands/update.ts
@@ -5,8 +5,8 @@ import {
5
5
  fetchLatestVersion,
6
6
  getCurrentVersion,
7
7
  isNewer
8
- } from "./chunk-SCUDS4US.js";
9
- import "./chunk-EBGCNDMM.js";
8
+ } from "./chunk-ON3FF5JA.js";
9
+ import "./chunk-B2CPS4QU.js";
10
10
  import "./chunk-K3NQKI34.js";
11
11
  export {
12
12
  checkForUpdate,
@@ -11,10 +11,11 @@ import "./chunk-K3NQKI34.js";
11
11
  async function run(args) {
12
12
  const { positional, flags } = parseArgs(args, {
13
13
  template: { type: "string" },
14
- continue: { type: "boolean" }
14
+ continue: { type: "boolean" },
15
+ abort: { type: "boolean" }
15
16
  });
16
17
  const mindName = resolveMindName({ mind: positional[0] });
17
- const { daemonFetch } = await import("./daemon-client-ITWUCNFO.js");
18
+ const { daemonFetch } = await import("./daemon-client-ZHCDL4RS.js");
18
19
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
19
20
  const client = getClient();
20
21
  const res = await daemonFetch(
@@ -24,7 +25,8 @@ async function run(args) {
24
25
  headers: { "Content-Type": "application/json" },
25
26
  body: JSON.stringify({
26
27
  template: flags.template,
27
- continue: flags.continue
28
+ continue: flags.continue,
29
+ abort: flags.abort
28
30
  })
29
31
  }
30
32
  );
@@ -33,12 +35,19 @@ async function run(args) {
33
35
  console.error(data.error ?? "Failed to upgrade mind");
34
36
  process.exit(1);
35
37
  }
38
+ if (flags.abort) {
39
+ console.log(`Upgrade aborted for ${mindName}.`);
40
+ return;
41
+ }
36
42
  if (data.conflicts) {
37
43
  console.log("\nMerge conflicts detected. Resolve them in:");
38
44
  console.log(` ${data.worktreeDir}`);
39
45
  console.log(`
40
46
  Then run:`);
41
47
  console.log(` volute mind upgrade ${mindName} --continue`);
48
+ console.log(`
49
+ Or abort:`);
50
+ console.log(` volute mind upgrade ${mindName} --abort`);
42
51
  return;
43
52
  }
44
53
  console.log(`
@@ -5,12 +5,6 @@ import {
5
5
  import {
6
6
  parseArgs
7
7
  } from "./chunk-D424ZQGI.js";
8
- import {
9
- checkHealth,
10
- readVariants,
11
- resolveMind,
12
- writeVariants
13
- } from "./chunk-EBGCNDMM.js";
14
8
  import "./chunk-K3NQKI34.js";
15
9
 
16
10
  // src/commands/variant.ts
@@ -65,7 +59,7 @@ async function createVariant(args) {
65
59
  process.exit(1);
66
60
  }
67
61
  if (!json) console.log("Creating variant via daemon...");
68
- const { daemonFetch } = await import("./daemon-client-ITWUCNFO.js");
62
+ const { daemonFetch } = await import("./daemon-client-ZHCDL4RS.js");
69
63
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
70
64
  const client = getClient();
71
65
  const res = await daemonFetch(
@@ -103,9 +97,19 @@ async function listVariants(args) {
103
97
  });
104
98
  const mindName = resolveMindName(flags);
105
99
  const { json } = flags;
106
- resolveMind(mindName);
107
- const variants = readVariants(mindName);
108
- if (variants.length === 0) {
100
+ const { daemonFetch } = await import("./daemon-client-ZHCDL4RS.js");
101
+ const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
102
+ const client = getClient();
103
+ const res = await daemonFetch(
104
+ urlOf(client.api.minds[":name"].variants.$url({ param: { name: mindName } }))
105
+ );
106
+ if (!res.ok) {
107
+ const data = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
108
+ console.error(data.error ?? "Failed to list variants");
109
+ process.exit(1);
110
+ }
111
+ const results = await res.json();
112
+ if (results.length === 0) {
109
113
  if (json) {
110
114
  console.log("[]");
111
115
  } else {
@@ -113,18 +117,6 @@ async function listVariants(args) {
113
117
  }
114
118
  return;
115
119
  }
116
- const results = await Promise.all(
117
- variants.map(async (v) => {
118
- if (!v.port) return { ...v, status: "no-server" };
119
- const health = await checkHealth(v.port);
120
- return { ...v, status: health.ok ? "running" : "dead" };
121
- })
122
- );
123
- const updated = results.map(({ status, ...v }) => ({
124
- ...v,
125
- running: status === "running"
126
- }));
127
- writeVariants(mindName, updated);
128
120
  if (json) {
129
121
  console.log(JSON.stringify(results, null, 2));
130
122
  return;
@@ -155,7 +147,7 @@ async function mergeVariant(args) {
155
147
  process.exit(1);
156
148
  }
157
149
  console.log(`Merging variant ${variantName}...`);
158
- const { daemonFetch } = await import("./daemon-client-ITWUCNFO.js");
150
+ const { daemonFetch } = await import("./daemon-client-ZHCDL4RS.js");
159
151
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
160
152
  const client = getClient();
161
153
  const res = await daemonFetch(
@@ -192,7 +184,7 @@ async function deleteVariant(args) {
192
184
  console.error("Usage: volute variant delete <variant> [--mind <name>]");
193
185
  process.exit(1);
194
186
  }
195
- const { daemonFetch } = await import("./daemon-client-ITWUCNFO.js");
187
+ const { daemonFetch } = await import("./daemon-client-ZHCDL4RS.js");
196
188
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
197
189
  const client = getClient();
198
190
  const res = await daemonFetch(
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ computeTemplateHash
4
+ } from "./chunk-AKPFNL7L.js";
5
+ import {
6
+ deliverMessage
7
+ } from "./chunk-OSFGKF2T.js";
8
+ import "./chunk-HFCBO2GL.js";
9
+ import "./chunk-HGCDWKSP.js";
10
+ import "./chunk-A4S7H6G6.js";
11
+ import "./chunk-VNVCRVYI.js";
12
+ import "./chunk-XLC342FO.js";
13
+ import "./chunk-PHU4DEAJ.js";
14
+ import "./chunk-SGPEZ32F.js";
15
+ import {
16
+ logger_default
17
+ } from "./chunk-YUIHSKR6.js";
18
+ import "./chunk-JTDFJWI2.js";
19
+ import "./chunk-NWPT4ASZ.js";
20
+ import {
21
+ getCurrentVersion
22
+ } from "./chunk-ON3FF5JA.js";
23
+ import {
24
+ readRegistry,
25
+ voluteHome,
26
+ writeRegistry
27
+ } from "./chunk-B2CPS4QU.js";
28
+ import "./chunk-K3NQKI34.js";
29
+
30
+ // src/lib/version-notify.ts
31
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
32
+ import { resolve as resolve2 } from "path";
33
+
34
+ // src/lib/release-notes.ts
35
+ import { existsSync, readFileSync } from "fs";
36
+ import { resolve } from "path";
37
+ function parseReleaseNotes(version) {
38
+ const changelog = findChangelog();
39
+ if (!changelog) return null;
40
+ const v = version.replace(/^v/, "");
41
+ const lines = changelog.split("\n");
42
+ let startIdx = -1;
43
+ let endIdx = lines.length;
44
+ for (let i = 0; i < lines.length; i++) {
45
+ const line = lines[i];
46
+ if (line.startsWith("## ")) {
47
+ if (startIdx === -1 && line.includes(`[${v}]`)) {
48
+ startIdx = i + 1;
49
+ } else if (startIdx !== -1) {
50
+ endIdx = i;
51
+ break;
52
+ }
53
+ }
54
+ }
55
+ if (startIdx === -1) return null;
56
+ const content = lines.slice(startIdx, endIdx).join("\n").trim();
57
+ if (!content) return null;
58
+ return stripGitHubLinks(content);
59
+ }
60
+ function stripGitHubLinks(text) {
61
+ return text.replace(/ \(\[#\d+\]\([^)]*\)\)/g, "").replace(/ \(\[[a-f0-9]+\]\([^)]*\)\)/g, "").replace(/\n{3,}/g, "\n\n").trim();
62
+ }
63
+ function findChangelog() {
64
+ const thisDir = new URL(".", import.meta.url).pathname;
65
+ const candidates = [
66
+ resolve(thisDir, "../CHANGELOG.md"),
67
+ resolve(thisDir, "../../CHANGELOG.md"),
68
+ resolve(thisDir, "../../../CHANGELOG.md")
69
+ ];
70
+ for (const p of candidates) {
71
+ if (existsSync(p)) {
72
+ try {
73
+ return readFileSync(p, "utf-8");
74
+ } catch {
75
+ return null;
76
+ }
77
+ }
78
+ }
79
+ return null;
80
+ }
81
+
82
+ // src/lib/version-notify.ts
83
+ function statePath() {
84
+ return resolve2(voluteHome(), "version-notify.json");
85
+ }
86
+ function readState() {
87
+ try {
88
+ if (!existsSync2(statePath())) return null;
89
+ return JSON.parse(readFileSync2(statePath(), "utf-8"));
90
+ } catch {
91
+ return null;
92
+ }
93
+ }
94
+ function writeState(state) {
95
+ writeFileSync(statePath(), `${JSON.stringify(state, null, 2)}
96
+ `);
97
+ }
98
+ function backfillTemplateHashes() {
99
+ const entries = readRegistry();
100
+ let changed = false;
101
+ for (const entry of entries) {
102
+ if (entry.templateHash != null) continue;
103
+ if (entry.stage === "seed") continue;
104
+ const tmpl = entry.template ?? "claude";
105
+ try {
106
+ entry.templateHash = computeTemplateHash(tmpl);
107
+ changed = true;
108
+ } catch (err) {
109
+ logger_default.warn(`failed to compute template hash for ${entry.name}`, logger_default.errorData(err));
110
+ }
111
+ }
112
+ if (changed) {
113
+ writeRegistry(entries);
114
+ }
115
+ }
116
+ async function notifyVersionUpdate() {
117
+ const currentVersion = getCurrentVersion();
118
+ const state = readState();
119
+ if (!state) {
120
+ writeState({ lastNotifiedVersion: currentVersion });
121
+ return;
122
+ }
123
+ if (state.lastNotifiedVersion === currentVersion) return;
124
+ const entries = readRegistry();
125
+ const runningMinds = entries.filter((e) => e.running && e.stage !== "seed");
126
+ if (runningMinds.length === 0) {
127
+ writeState({ lastNotifiedVersion: currentVersion });
128
+ return;
129
+ }
130
+ const releaseNotes = parseReleaseNotes(currentVersion);
131
+ const templateHashes = /* @__PURE__ */ new Map();
132
+ for (const entry of runningMinds) {
133
+ const tmpl = entry.template ?? "claude";
134
+ if (!templateHashes.has(tmpl)) {
135
+ try {
136
+ templateHashes.set(tmpl, computeTemplateHash(tmpl));
137
+ } catch (err) {
138
+ logger_default.warn(`failed to compute template hash for ${tmpl}`, logger_default.errorData(err));
139
+ }
140
+ }
141
+ }
142
+ const promises = runningMinds.map(async (entry) => {
143
+ const tmpl = entry.template ?? "claude";
144
+ const currentHash = templateHashes.get(tmpl);
145
+ const needsUpgrade = entry.templateHash != null && currentHash != null && entry.templateHash !== currentHash;
146
+ const message = formatNotification(currentVersion, releaseNotes, needsUpgrade, entry.name);
147
+ await deliverMessage(entry.name, {
148
+ channel: "system:version",
149
+ sender: "volute",
150
+ content: message
151
+ });
152
+ });
153
+ const results = await Promise.allSettled(promises);
154
+ for (const result of results) {
155
+ if (result.status === "rejected") {
156
+ logger_default.warn("failed to notify mind about version update", logger_default.errorData(result.reason));
157
+ }
158
+ }
159
+ writeState({ lastNotifiedVersion: currentVersion });
160
+ }
161
+ function formatNotification(version, releaseNotes, needsUpgrade, mindName) {
162
+ let message = `Volute has been updated to v${version}.`;
163
+ if (releaseNotes) {
164
+ message += `
165
+
166
+ ${releaseNotes}`;
167
+ }
168
+ if (needsUpgrade) {
169
+ message += `
170
+
171
+ ---
172
+
173
+ A template update is available for you. To upgrade, your operator can run:
174
+ volute mind upgrade ${mindName}`;
175
+ }
176
+ return message;
177
+ }
178
+ export {
179
+ backfillTemplateHashes,
180
+ notifyVersionUpdate
181
+ };