volute 0.30.1 → 0.32.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 (227) hide show
  1. package/README.md +15 -22
  2. package/dist/{accept-E3PAH3QJ.js → accept-74M7I4RZ.js} +5 -4
  3. package/dist/{activity-events-BKBPPUBP.js → activity-events-HETAODOK.js} +3 -2
  4. package/dist/{ai-service-VAJT5UBS.js → ai-service-ZIPCV3MX.js} +20 -5
  5. package/dist/api.d.ts +341 -397
  6. package/dist/{archive-WWDBWYN2.js → archive-INXYFVCW.js} +3 -2
  7. package/dist/auth-6DMGES3I.js +44 -0
  8. package/dist/{bridge-RO37CUFM.js → bridge-BVCBTGPF.js} +5 -4
  9. package/dist/{chat-TCUNPFGO.js → chat-XT4OBJBU.js} +8 -8
  10. package/dist/{chunk-P7VFDSSG.js → chunk-2FLJ63GU.js} +2 -2
  11. package/dist/{chunk-ZWKTUQEL.js → chunk-2NGTS5UU.js} +1 -1
  12. package/dist/{chunk-JGFRDMR6.js → chunk-ALEF47VT.js} +1 -1
  13. package/dist/{chunk-MDPCSXZ4.js → chunk-D5G5YOPL.js} +163 -15
  14. package/dist/{chunk-VGWJSNHS.js → chunk-G53F3JA4.js} +1 -35
  15. package/dist/{chunk-A6TUJJ3L.js → chunk-G6BSYHPK.js} +2 -2
  16. package/dist/{chunk-DTC6EH5I.js → chunk-I5KY25PQ.js} +1 -9
  17. package/dist/{chunk-NSBFETWP.js → chunk-IYDIE3HG.js} +64 -26
  18. package/dist/{chunk-W5OOPLNP.js → chunk-JJ7W6WSB.js} +3 -3
  19. package/dist/{chunk-G3GBKZGG.js → chunk-LGB6JBHI.js} +54 -2
  20. package/dist/chunk-LRCG2JLP.js +251 -0
  21. package/dist/{chunk-FXHXHI2A.js → chunk-LSGWR54X.js} +3 -6
  22. package/dist/{chunk-S5LR3XYJ.js → chunk-M7UL5S3Q.js} +1 -1
  23. package/dist/chunk-PB65JZK2.js +85 -0
  24. package/dist/chunk-PVY5W6QN.js +41 -0
  25. package/dist/{chunk-QVAQ5454.js → chunk-QBQ424EM.js} +3007 -2126
  26. package/dist/{chunk-P27RV5WM.js → chunk-QZANELPX.js} +6 -2
  27. package/dist/{chunk-FSM45XD5.js → chunk-R7E6CRVQ.js} +1 -1
  28. package/dist/{chunk-HHTXM4JT.js → chunk-RPZZSXV3.js} +39 -195
  29. package/dist/{chunk-UPA6COHU.js → chunk-RSX4OPZY.js} +5 -5
  30. package/dist/{chunk-2C2VXEBB.js → chunk-S6NFERDC.js} +21 -57
  31. package/dist/chunk-SKLSMHXO.js +208 -0
  32. package/dist/{chunk-IKHDUZRH.js → chunk-SX5TKJBZ.js} +2 -2
  33. package/dist/chunk-TDRYEPH4.js +185 -0
  34. package/dist/chunk-TSXLLQZW.js +46 -0
  35. package/dist/{chunk-EFVHR7KH.js → chunk-UKVWJRKN.js} +24 -5
  36. package/dist/{chunk-2NDZC3S7.js → chunk-WKF5FEFK.js} +688 -389
  37. package/dist/cli.js +93 -24
  38. package/dist/{clock-G3ALCMLJ.js → clock-2UOZ6JPU.js} +11 -8
  39. package/dist/{cloud-sync-JV4LJOK3.js → cloud-sync-JN3NWKEM.js} +16 -14
  40. package/dist/config-H2H4UIF7.js +72 -0
  41. package/dist/connectors/discord-bridge.js +1 -1
  42. package/dist/connectors/slack-bridge.js +1 -1
  43. package/dist/connectors/telegram-bridge.js +1 -1
  44. package/dist/{conversations-7KVQV7EZ.js → conversations-3O5O6AS3.js} +8 -7
  45. package/dist/{create-JTLS7GX3.js → create-RNLNCORE.js} +5 -4
  46. package/dist/{create-VQSQHJQW.js → create-WBBYI6V7.js} +6 -2
  47. package/dist/daemon-client-6QXHZ7US.js +12 -0
  48. package/dist/{daemon-restart-4JGBHEJ4.js → daemon-restart-NGFHFAUF.js} +7 -7
  49. package/dist/daemon.js +2446 -1999
  50. package/dist/{db-HMFPIRO2.js → db-F34YLV7D.js} +2 -1
  51. package/dist/db-RA45JBFG.js +16 -0
  52. package/dist/{delete-JESHKE7F.js → delete-QTGWEDBI.js} +1 -1
  53. package/dist/delivery-manager-SDVXFD4W.js +28 -0
  54. package/dist/delivery-router-FL45JL7N.js +21 -0
  55. package/dist/down-TB3ESMNP.js +14 -0
  56. package/dist/{env-CLXXT7M2.js → env-RLYQBOOP.js} +5 -4
  57. package/dist/{export-EGA5M5PB.js → export-SUYRLI5Q.js} +4 -3
  58. package/dist/{extension-WZ4SUPJB.js → extension-FQ5D3NCC.js} +6 -6
  59. package/dist/{extensions-ECO4RPFQ.js → extensions-GDYWQXC4.js} +9 -7
  60. package/dist/{files-4VEJDASH.js → files-EAMPO2SJ.js} +6 -5
  61. package/dist/{history-EJMMLXDO.js → history-FO5PHBQ5.js} +9 -4
  62. package/dist/{import-YCGPMBSI.js → import-DDUFE7AY.js} +4 -3
  63. package/dist/{join-2GBJKZEN.js → join-I5QEE3LG.js} +1 -1
  64. package/dist/{list-Q6O7FGAN.js → list-DW2VRTOZ.js} +5 -4
  65. package/dist/{login-RL6AU2SM.js → login-7CHPW2PN.js} +5 -4
  66. package/dist/{login-RET5WESK.js → login-RIJF2F4G.js} +3 -2
  67. package/dist/{logout-CGAGJN3L.js → logout-5MLHZALK.js} +3 -2
  68. package/dist/{logout-JRPBEMMR.js → logout-UZJRGY4Z.js} +3 -2
  69. package/dist/message-delivery-2FIM7QKO.js +32 -0
  70. package/dist/{mind-LUWRQUQ5.js → mind-2B6M7Y25.js} +18 -18
  71. package/dist/{mind-activity-tracker-VYN2ZZ2M.js → mind-activity-tracker-NZZT2NTT.js} +4 -3
  72. package/dist/{mind-list-V5WW5DUA.js → mind-list-WUPMQDYQ.js} +3 -2
  73. package/dist/mind-manager-BNCMGYXW.js +28 -0
  74. package/dist/mind-service-AV273WT4.js +34 -0
  75. package/dist/{mind-sleep-R6PTNNW4.js → mind-sleep-B7BHJLH7.js} +5 -4
  76. package/dist/{mind-status-I4ISFJ6I.js → mind-status-L3EFFRPR.js} +3 -2
  77. package/dist/{mind-wake-67ZQEWAV.js → mind-wake-GY3RFX7Y.js} +5 -4
  78. package/dist/{package-OYUD4ZJ4.js → package-PK6JUFL3.js} +3 -3
  79. package/dist/read-5AMJRO3D.js +75 -0
  80. package/dist/{register-NZDSTLP3.js → register-V2JZZKFK.js} +5 -4
  81. package/dist/{registry-ODSALQQL.js → registry-PJ4S5PHQ.js} +8 -1
  82. package/dist/{reject-2HZOJEIJ.js → reject-33HEZMZ4.js} +5 -4
  83. package/dist/{restart-QHS3NT64.js → restart-3UCMRUVC.js} +5 -4
  84. package/dist/{sandbox-O5FUSF43.js → sandbox-JANNTX6U.js} +4 -3
  85. package/dist/schema-PA3M5ZKH.js +32 -0
  86. package/dist/seed-ALUQ55FF.js +112 -0
  87. package/dist/{send-OAN3RYYY.js → send-3MI36LEF.js} +58 -69
  88. package/dist/{setup-QMDK5RZX.js → setup-SZIARWI6.js} +5 -4
  89. package/dist/{setup-XJH3E7YM.js → setup-WENLVPVP.js} +9 -9
  90. package/dist/{skill-FZIN4W4Q.js → skill-TUVOTW4Z.js} +5 -4
  91. package/dist/skills/dreaming/SKILL.md +6 -4
  92. package/dist/skills/dreaming/references/INSTALL.md +4 -5
  93. package/dist/skills/dreaming/scripts/dream.ts +5 -27
  94. package/dist/skills/dreaming/scripts/wake-context-dreams.sh +1 -1
  95. package/dist/skills/imagegen/SKILL.md +6 -5
  96. package/dist/skills/imagegen/references/INSTALL.md +1 -1
  97. package/dist/skills/resonance/SKILL.md +4 -1
  98. package/dist/skills/resonance/references/INSTALL.md +2 -2
  99. package/dist/skills/resonance/scripts/resonance-hook.sh +2 -0
  100. package/dist/skills/resonance/scripts/resonance.ts +35 -5
  101. package/dist/skills/volute-admin/SKILL.md +83 -0
  102. package/dist/skills/volute-mind/SKILL.md +12 -12
  103. package/dist/skills-XNZK6P4K.js +61 -0
  104. package/dist/sleep-manager-53DZOWW7.js +32 -0
  105. package/dist/spirit-N4W4UQRH.js +217 -0
  106. package/dist/{split-EXYGGGQN.js → split-STOROBYJ.js} +1 -1
  107. package/dist/{sprout-AXQ6H5DB.js → sprout-L2GFOVF7.js} +9 -8
  108. package/dist/{start-MTOVL6SY.js → start-K2NCUUCG.js} +5 -4
  109. package/dist/{status-ZRO37MWR.js → status-TCUMUO6M.js} +5 -5
  110. package/dist/{stop-OK5WEPVC.js → stop-H26JZDXF.js} +5 -4
  111. package/dist/system-chat-NPYFYZVI.js +32 -0
  112. package/dist/{systems-W3BBMSOZ.js → systems-DHBKVYEY.js} +6 -5
  113. package/dist/{tailscale-BM72RXCJ.js → tailscale-XHQBZROW.js} +2 -1
  114. package/dist/{template-hash-3HOR4UAJ.js → template-hash-A6VVKOXJ.js} +2 -1
  115. package/dist/up-6I6BHRTO.js +17 -0
  116. package/dist/{update-PLPHMMZ2.js → update-QVPRF6GR.js} +5 -5
  117. package/dist/{update-check-CVCN7MF6.js → update-check-ZD6OOIYQ.js} +3 -2
  118. package/dist/{upgrade-I6NPCYUU.js → upgrade-O4Q7WJM3.js} +12 -14
  119. package/dist/{version-notify-2NTWVEHL.js → version-notify-TCKWBZZG.js} +22 -23
  120. package/dist/web-assets/assets/index-Bui7U9Uu.css +1 -0
  121. package/dist/web-assets/assets/index-e36DIo1b.js +73 -0
  122. package/dist/web-assets/ext-theme.css +94 -0
  123. package/dist/web-assets/index.html +2 -2
  124. package/drizzle/0000_baseline.sql +152 -0
  125. package/drizzle/0001_add_conversation_private.sql +1 -0
  126. package/drizzle/0002_turns.sql +21 -0
  127. package/drizzle/0003_turn_feed_links.sql +11 -0
  128. package/drizzle/0004_spirits.sql +5 -0
  129. package/drizzle/meta/0000_snapshot.json +3 -223
  130. package/drizzle/meta/0001_snapshot.json +3 -294
  131. package/drizzle/meta/0002_snapshot.json +3 -335
  132. package/drizzle/meta/0003_snapshot.json +3 -413
  133. package/drizzle/meta/0004_snapshot.json +3 -406
  134. package/drizzle/meta/_journal.json +10 -101
  135. package/package.json +3 -3
  136. package/packages/extensions/notes/dist/ui/assets/index-8jWEv9SA.js +61 -0
  137. package/packages/extensions/notes/dist/ui/assets/index-DkaB7Ytd.css +1 -0
  138. package/packages/extensions/notes/dist/ui/index.html +2 -2
  139. package/packages/extensions/notes/skills/notes/SKILL.md +8 -8
  140. package/packages/extensions/pages/skills/pages/SKILL.md +17 -44
  141. package/templates/_base/.init/.config/hooks/pre-prompt/session-activity.ts +40 -0
  142. package/templates/_base/.init/.local/bin/volute +27 -0
  143. package/templates/_base/.init/.local/hooks/pre-prompt/session-activity.ts +40 -0
  144. package/templates/_base/.init/.local/hooks/startup-context.ts +58 -0
  145. package/templates/_base/home/.config/routes.json +1 -1
  146. package/templates/_base/src/lib/auto-commit.ts +82 -43
  147. package/templates/_base/src/lib/daemon-client.ts +40 -36
  148. package/templates/_base/src/lib/format-prefix.ts +1 -0
  149. package/templates/_base/src/lib/hook-loader.ts +155 -0
  150. package/templates/_base/src/lib/router.ts +17 -1
  151. package/templates/_base/src/lib/startup.ts +17 -12
  152. package/templates/_base/src/lib/transparency.ts +2 -2
  153. package/templates/_base/src/lib/volute-server.ts +2 -5
  154. package/templates/claude/.init/.claude/settings.json +1 -1
  155. package/templates/claude/.init/.config/routes.json +2 -2
  156. package/templates/claude/src/agent.ts +97 -14
  157. package/templates/claude/src/lib/hooks/auto-commit.ts +7 -3
  158. package/templates/claude/src/lib/message-channel.ts +7 -2
  159. package/templates/claude/src/server.ts +0 -9
  160. package/templates/codex/.init/.config/routes.json +11 -0
  161. package/templates/codex/.init/AGENTS.md +29 -0
  162. package/templates/codex/home/.config/config.json.tmpl +7 -0
  163. package/templates/codex/package.json.tmpl +20 -0
  164. package/templates/codex/src/agent.ts +553 -0
  165. package/templates/codex/src/lib/content.ts +16 -0
  166. package/templates/codex/src/lib/session-store.ts +56 -0
  167. package/templates/codex/src/server.ts +59 -0
  168. package/templates/codex/volute-template.json +8 -0
  169. package/templates/pi/.init/.config/routes.json +2 -2
  170. package/templates/pi/package.json.tmpl +1 -1
  171. package/templates/pi/src/agent.ts +63 -9
  172. package/templates/pi/src/lib/event-handler.ts +6 -4
  173. package/templates/pi/src/lib/reply-instructions-extension.ts +32 -11
  174. package/dist/chunk-7D47T4RB.js +0 -84
  175. package/dist/chunk-CVH6Y2YG.js +0 -59
  176. package/dist/chunk-EFP3PE6C.js +0 -232
  177. package/dist/chunk-LIRWLNAK.js +0 -729
  178. package/dist/daemon-client-BCTFGVCZ.js +0 -9
  179. package/dist/down-NGBMGORS.js +0 -14
  180. package/dist/message-delivery-6YMVNOEC.js +0 -28
  181. package/dist/migrate-registry-to-db-FK35IPEH.js +0 -110
  182. package/dist/mind-manager-YFCOIAAX.js +0 -18
  183. package/dist/pages-watcher-Z3PKNROC.js +0 -21
  184. package/dist/read-WQMPTSN2.js +0 -46
  185. package/dist/seed-WUQMPLDM.js +0 -71
  186. package/dist/skills/sessions/SKILL.md +0 -49
  187. package/dist/sleep-manager-O7YQFCV5.js +0 -30
  188. package/dist/up-BXUAIDXB.js +0 -17
  189. package/dist/web-assets/assets/index--kREqKl9.js +0 -72
  190. package/dist/web-assets/assets/index-BXYTG0nJ.css +0 -1
  191. package/drizzle/0000_flaky_mariko_yashida.sql +0 -34
  192. package/drizzle/0001_careless_warpath.sql +0 -12
  193. package/drizzle/0002_wealthy_the_call.sql +0 -6
  194. package/drizzle/0003_clean_ego.sql +0 -12
  195. package/drizzle/0004_magical_silverclaw.sql +0 -1
  196. package/drizzle/0005_rename_agents_to_minds.sql +0 -11
  197. package/drizzle/0006_mind_history.sql +0 -20
  198. package/drizzle/0007_system_prompts.sql +0 -5
  199. package/drizzle/0008_volute_channels.sql +0 -24
  200. package/drizzle/0009_shared_skills.sql +0 -9
  201. package/drizzle/0010_delivery_queue.sql +0 -12
  202. package/drizzle/0011_rename_human_to_brain.sql +0 -1
  203. package/drizzle/0012_activity.sql +0 -11
  204. package/drizzle/0013_user_profiles.sql +0 -3
  205. package/drizzle/0014_conversation_reads.sql +0 -7
  206. package/drizzle/0015_notes.sql +0 -23
  207. package/drizzle/0016_note_reactions_and_replies.sql +0 -15
  208. package/drizzle/0017_minds.sql +0 -16
  209. package/drizzle/meta/0005_snapshot.json +0 -410
  210. package/drizzle/meta/0006_snapshot.json +0 -7
  211. package/drizzle/meta/0007_snapshot.json +0 -7
  212. package/drizzle/meta/0008_snapshot.json +0 -7
  213. package/drizzle/meta/0009_snapshot.json +0 -7
  214. package/drizzle/meta/0010_snapshot.json +0 -7
  215. package/drizzle/meta/0011_snapshot.json +0 -7
  216. package/drizzle/meta/0012_snapshot.json +0 -7
  217. package/drizzle/meta/0013_snapshot.json +0 -7
  218. package/packages/extensions/notes/dist/ui/assets/index-DgawVO5g.css +0 -1
  219. package/packages/extensions/notes/dist/ui/assets/index-qUWoeC4c.js +0 -2
  220. package/packages/extensions/notes/skills/notes/scripts/notes.mjs +0 -185
  221. package/templates/_base/.init/.config/hooks/startup-context.sh +0 -46
  222. package/templates/_base/.init/.config/scripts/session-reader.ts +0 -59
  223. package/templates/_base/home/public/.gitkeep +0 -0
  224. package/templates/_base/src/lib/session-monitor.ts +0 -400
  225. package/templates/claude/src/lib/hooks/session-context.ts +0 -32
  226. package/templates/pi/src/lib/session-context-extension.ts +0 -35
  227. /package/templates/_base/.init/{.config → .local}/hooks/wake-context.sh +0 -0
@@ -3,9 +3,11 @@ import {
3
3
  logger_default
4
4
  } from "./chunk-YUIHSKR6.js";
5
5
  import {
6
- activity,
7
6
  getDb
8
- } from "./chunk-HHTXM4JT.js";
7
+ } from "./chunk-LRCG2JLP.js";
8
+ import {
9
+ activity
10
+ } from "./chunk-RPZZSXV3.js";
9
11
 
10
12
  // src/lib/events/activity-events.ts
11
13
  var subscribers = /* @__PURE__ */ new Set();
@@ -25,6 +27,8 @@ async function publish(event) {
25
27
  mind: event.mind,
26
28
  summary: event.summary,
27
29
  metadata: event.metadata ? JSON.stringify(event.metadata) : null,
30
+ turn_id: event.turn_id ?? null,
31
+ source_event_id: event.source_event_id ?? null,
28
32
  created_at
29
33
  });
30
34
  id = Number(result.lastInsertRowid);
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  publish
4
- } from "./chunk-P27RV5WM.js";
4
+ } from "./chunk-QZANELPX.js";
5
5
  import {
6
6
  logger_default
7
7
  } from "./chunk-YUIHSKR6.js";
@@ -3,20 +3,6 @@ import {
3
3
  __export
4
4
  } from "./chunk-K3NQKI34.js";
5
5
 
6
- // src/lib/db.ts
7
- import { chmodSync, existsSync } from "fs";
8
- import { dirname as dirname2, resolve as resolve2 } from "path";
9
- import { fileURLToPath as fileURLToPath2 } from "url";
10
- import { drizzle } from "drizzle-orm/libsql";
11
- import { migrate } from "drizzle-orm/libsql/migrator";
12
-
13
- // src/lib/registry.ts
14
- import { mkdirSync } from "fs";
15
- import { homedir } from "os";
16
- import { dirname, resolve } from "path";
17
- import { fileURLToPath } from "url";
18
- import { eq, isNull } from "drizzle-orm";
19
-
20
6
  // src/lib/schema.ts
21
7
  var schema_exports = {};
22
8
  __export(schema_exports, {
@@ -31,6 +17,7 @@ __export(schema_exports, {
31
17
  sessions: () => sessions,
32
18
  sharedSkills: () => sharedSkills,
33
19
  systemPrompts: () => systemPrompts,
20
+ turns: () => turns,
34
21
  users: () => users
35
22
  });
36
23
  import { sql } from "drizzle-orm";
@@ -47,9 +34,14 @@ var minds = sqliteTable(
47
34
  template: text("template"),
48
35
  template_hash: text("template_hash"),
49
36
  running: integer("running").notNull().default(0),
37
+ mind_type: text("mind_type").notNull().default("mind"),
38
+ created_by: text("created_by"),
50
39
  created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
51
40
  },
52
- (table) => [index("idx_minds_parent").on(table.parent)]
41
+ (table) => [
42
+ index("idx_minds_parent").on(table.parent),
43
+ index("idx_minds_mind_type").on(table.mind_type)
44
+ ]
53
45
  );
54
46
  var users = sqliteTable("users", {
55
47
  id: integer("id").primaryKey({ autoIncrement: true }),
@@ -72,6 +64,7 @@ var conversations = sqliteTable(
72
64
  name: text("name"),
73
65
  user_id: integer("user_id").references(() => users.id),
74
66
  title: text("title"),
67
+ private: integer("private").notNull().default(0),
75
68
  created_at: text("created_at").notNull().default(sql`(datetime('now'))`),
76
69
  updated_at: text("updated_at").notNull().default(sql`(datetime('now'))`)
77
70
  },
@@ -82,6 +75,22 @@ var conversations = sqliteTable(
82
75
  uniqueIndex("idx_conversations_name").on(table.name)
83
76
  ]
84
77
  );
78
+ var turns = sqliteTable(
79
+ "turns",
80
+ {
81
+ id: text("id").primaryKey(),
82
+ mind: text("mind").notNull(),
83
+ session: text("session"),
84
+ trigger_event_id: integer("trigger_event_id"),
85
+ summary_event_id: integer("summary_event_id"),
86
+ status: text("status").notNull().default("active"),
87
+ created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
88
+ },
89
+ (table) => [
90
+ index("idx_turns_mind").on(table.mind),
91
+ index("idx_turns_mind_status").on(table.mind, table.status)
92
+ ]
93
+ );
85
94
  var mindHistory = sqliteTable(
86
95
  "mind_history",
87
96
  {
@@ -94,12 +103,14 @@ var mindHistory = sqliteTable(
94
103
  type: text("type").notNull(),
95
104
  content: text("content"),
96
105
  metadata: text("metadata"),
106
+ turn_id: text("turn_id"),
97
107
  created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
98
108
  },
99
109
  (table) => [
100
110
  index("idx_mind_history_mind").on(table.mind),
101
111
  index("idx_mind_history_mind_channel").on(table.mind, table.channel),
102
- index("idx_mind_history_mind_type").on(table.mind, table.type)
112
+ index("idx_mind_history_mind_type").on(table.mind, table.type),
113
+ index("idx_mind_history_turn_id").on(table.turn_id)
103
114
  ]
104
115
  );
105
116
  var conversationParticipants = sqliteTable(
@@ -159,11 +170,14 @@ var activity = sqliteTable(
159
170
  mind: text("mind").notNull(),
160
171
  summary: text("summary").notNull(),
161
172
  metadata: text("metadata"),
173
+ turn_id: text("turn_id"),
174
+ source_event_id: integer("source_event_id"),
162
175
  created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
163
176
  },
164
177
  (table) => [
165
178
  index("idx_activity_created_at").on(table.created_at),
166
- index("idx_activity_mind").on(table.mind)
179
+ index("idx_activity_mind").on(table.mind),
180
+ index("idx_activity_turn_id").on(table.turn_id)
167
181
  ]
168
182
  );
169
183
  var conversationReads = sqliteTable(
@@ -185,170 +199,21 @@ var messages = sqliteTable(
185
199
  role: text("role").notNull(),
186
200
  sender_name: text("sender_name"),
187
201
  content: text("content").notNull(),
202
+ source_event_id: integer("source_event_id"),
203
+ turn_id: text("turn_id"),
188
204
  created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
189
205
  },
190
- (table) => [index("idx_messages_conversation_id").on(table.conversation_id)]
206
+ (table) => [
207
+ index("idx_messages_conversation_id").on(table.conversation_id),
208
+ index("idx_messages_turn_id").on(table.turn_id)
209
+ ]
191
210
  );
192
211
 
193
- // src/lib/registry.ts
194
- function voluteHome() {
195
- if (process.env.VOLUTE_HOME) return process.env.VOLUTE_HOME;
196
- const dir = dirname(fileURLToPath(import.meta.url));
197
- if (dir.endsWith("/src/lib")) {
198
- throw new Error(
199
- 'VOLUTE_HOME must be set when running from source. For tests, run via "npm test" or add "--import ./test/setup.ts".'
200
- );
201
- }
202
- return resolve(homedir(), ".volute");
203
- }
204
- function voluteUserHome() {
205
- if (process.env.VOLUTE_USER_HOME) return process.env.VOLUTE_USER_HOME;
206
- return resolve(homedir(), ".volute");
207
- }
208
- function voluteSystemDir() {
209
- return resolve(voluteHome(), "system");
210
- }
211
- function ensureSystemDir() {
212
- mkdirSync(voluteSystemDir(), { recursive: true });
213
- }
214
- function ensureVoluteHome() {
215
- const mindsBase = process.env.VOLUTE_MINDS_DIR ?? resolve(voluteHome(), "minds");
216
- mkdirSync(mindsBase, { recursive: true });
217
- ensureSystemDir();
218
- }
219
- function rowToEntry(row) {
220
- return {
221
- name: row.name,
222
- port: row.port,
223
- created: row.created_at,
224
- running: row.running === 1,
225
- stage: row.stage ?? (row.parent ? void 0 : "sprouted"),
226
- template: row.template ?? void 0,
227
- templateHash: row.template_hash ?? void 0,
228
- parent: row.parent ?? void 0,
229
- dir: row.dir ?? void 0,
230
- branch: row.branch ?? void 0
231
- };
232
- }
233
- async function readRegistry() {
234
- const db2 = await getDb();
235
- const rows = await db2.select().from(minds).where(isNull(minds.parent));
236
- return rows.map(rowToEntry);
237
- }
238
- async function readAllMinds() {
239
- const db2 = await getDb();
240
- const rows = await db2.select().from(minds);
241
- return rows.map(rowToEntry);
242
- }
243
- var MIND_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
244
- var MIND_NAME_MAX = 64;
245
- function validateMindName(name) {
246
- if (!name) return "Mind name is required";
247
- if (name.length > MIND_NAME_MAX) return `Mind name must be at most ${MIND_NAME_MAX} characters`;
248
- if (!MIND_NAME_RE.test(name)) {
249
- return "Mind name must start with alphanumeric and contain only alphanumeric, dots, dashes, or underscores";
250
- }
251
- return null;
252
- }
253
- async function addMind(name, port, stage, template) {
254
- const err = validateMindName(name);
255
- if (err) throw new Error(err);
256
- const db2 = await getDb();
257
- await db2.insert(minds).values({ name, port, stage: stage ?? null, template: template ?? null }).onConflictDoUpdate({
258
- target: minds.name,
259
- set: { port, stage: stage ?? null, template: template ?? null }
260
- });
261
- }
262
- async function addVariant(name, parent, port, dir, branch) {
263
- const err = validateMindName(name);
264
- if (err) throw new Error(err);
265
- const db2 = await getDb();
266
- await db2.insert(minds).values({ name, port, parent, dir, branch }).onConflictDoUpdate({
267
- target: minds.name,
268
- set: { port, parent, dir, branch }
269
- });
270
- }
271
- async function removeMind(name) {
272
- const db2 = await getDb();
273
- await db2.delete(minds).where(eq(minds.name, name));
274
- }
275
- async function setMindRunning(name, running) {
276
- const db2 = await getDb();
277
- await db2.update(minds).set({ running: running ? 1 : 0 }).where(eq(minds.name, name));
278
- }
279
- async function setMindStage(name, stage) {
280
- const db2 = await getDb();
281
- await db2.update(minds).set({ stage }).where(eq(minds.name, name));
282
- }
283
- async function setMindTemplateHash(name, hash) {
284
- const db2 = await getDb();
285
- await db2.update(minds).set({ template_hash: hash }).where(eq(minds.name, name));
286
- }
287
- async function findMind(name) {
288
- const db2 = await getDb();
289
- const rows = await db2.select().from(minds).where(eq(minds.name, name));
290
- if (rows.length === 0) return void 0;
291
- return rowToEntry(rows[0]);
292
- }
293
- async function findVariants(parent) {
294
- const db2 = await getDb();
295
- const rows = await db2.select().from(minds).where(eq(minds.parent, parent));
296
- return rows.map(rowToEntry);
297
- }
298
- async function getBaseName(name) {
299
- const entry = await findMind(name);
300
- return entry?.parent ?? name;
301
- }
302
- function mindDir(name) {
303
- if (process.env.VOLUTE_MINDS_DIR) {
304
- return resolve(process.env.VOLUTE_MINDS_DIR, name);
305
- }
306
- return resolve(voluteHome(), "minds", name);
307
- }
308
- function stateDir(name) {
309
- return resolve(voluteSystemDir(), "state", name);
310
- }
311
- async function nextPort() {
312
- const db2 = await getDb();
313
- const rows = await db2.select({ port: minds.port }).from(minds);
314
- const usedPorts = new Set(rows.map((r) => r.port));
315
- const basePort = parseInt(process.env.VOLUTE_BASE_PORT || "4100", 10);
316
- let port = basePort;
317
- while (usedPorts.has(port)) port++;
318
- if (port > 65535) throw new Error("No available ports \u2014 all ports 4100-65535 are allocated");
319
- return port;
320
- }
321
- function daemonLoopback() {
322
- const host = process.env.VOLUTE_DAEMON_HOSTNAME || "127.0.0.1";
323
- if (host === "0.0.0.0") return "127.0.0.1";
324
- if (host === "::") return "[::1]";
325
- return host;
326
- }
327
-
328
- // src/lib/db.ts
329
- var __dirname = dirname2(fileURLToPath2(import.meta.url));
330
- var migrationsFolder = existsSync(resolve2(__dirname, "../drizzle")) ? resolve2(__dirname, "../drizzle") : resolve2(__dirname, "../../drizzle");
331
- var db = null;
332
- async function getDb() {
333
- if (db) return db;
334
- const dbPath = process.env.VOLUTE_DB_PATH || resolve2(voluteSystemDir(), "volute.db");
335
- db = drizzle({ connection: { url: `file:${dbPath}` }, schema: schema_exports });
336
- await migrate(db, { migrationsFolder });
337
- try {
338
- chmodSync(dbPath, 384);
339
- } catch (err) {
340
- console.error(
341
- `[volute] WARNING: Failed to restrict database file permissions on ${dbPath}:`,
342
- err
343
- );
344
- }
345
- return db;
346
- }
347
-
348
212
  export {
349
213
  minds,
350
214
  users,
351
215
  conversations,
216
+ turns,
352
217
  mindHistory,
353
218
  conversationParticipants,
354
219
  sessions,
@@ -358,26 +223,5 @@ export {
358
223
  activity,
359
224
  conversationReads,
360
225
  messages,
361
- getDb,
362
- voluteHome,
363
- voluteUserHome,
364
- voluteSystemDir,
365
- ensureSystemDir,
366
- ensureVoluteHome,
367
- readRegistry,
368
- readAllMinds,
369
- validateMindName,
370
- addMind,
371
- addVariant,
372
- removeMind,
373
- setMindRunning,
374
- setMindStage,
375
- setMindTemplateHash,
376
- findMind,
377
- findVariants,
378
- getBaseName,
379
- mindDir,
380
- stateDir,
381
- nextPort,
382
- daemonLoopback
226
+ schema_exports
383
227
  };
@@ -3,7 +3,7 @@ import {
3
3
  readEnv,
4
4
  sharedEnvPath,
5
5
  writeEnv
6
- } from "./chunk-ZWKTUQEL.js";
6
+ } from "./chunk-2NGTS5UU.js";
7
7
  import {
8
8
  logger_default
9
9
  } from "./chunk-YUIHSKR6.js";
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-D424ZQGI.js";
13
13
  import {
14
14
  voluteSystemDir
15
- } from "./chunk-HHTXM4JT.js";
15
+ } from "./chunk-LRCG2JLP.js";
16
16
 
17
17
  // src/commands/import.ts
18
18
  import {
@@ -112,7 +112,7 @@ async function run(args) {
112
112
  return;
113
113
  }
114
114
  const wsDir = resolveWorkspace(inputPath);
115
- const { daemonFetch } = await import("./daemon-client-BCTFGVCZ.js");
115
+ const { daemonFetch } = await import("./daemon-client-6QXHZ7US.js");
116
116
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
117
117
  const client = getClient();
118
118
  const res = await daemonFetch(urlOf(client.api.minds.import.$url()), {
@@ -152,7 +152,7 @@ async function importArchive(archivePath, nameOverride) {
152
152
  console.error(`File not found: ${archivePath}`);
153
153
  process.exit(1);
154
154
  }
155
- const { extractArchive } = await import("./archive-WWDBWYN2.js");
155
+ const { extractArchive } = await import("./archive-INXYFVCW.js");
156
156
  const tempDir = resolve2(tmpdir(), `volute-import-${Date.now()}`);
157
157
  mkdirSync(tempDir, { recursive: true });
158
158
  let extracted;
@@ -164,7 +164,7 @@ async function importArchive(archivePath, nameOverride) {
164
164
  process.exit(1);
165
165
  }
166
166
  try {
167
- const { daemonFetch } = await import("./daemon-client-BCTFGVCZ.js");
167
+ const { daemonFetch } = await import("./daemon-client-6QXHZ7US.js");
168
168
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
169
169
  const client = getClient();
170
170
  const res = await daemonFetch(urlOf(client.api.minds.import.$url()), {
@@ -1,18 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  subscribe
4
- } from "./chunk-P27RV5WM.js";
4
+ } from "./chunk-QZANELPX.js";
5
5
  import {
6
6
  logger_default
7
7
  } from "./chunk-YUIHSKR6.js";
8
+ import {
9
+ getDb
10
+ } from "./chunk-LRCG2JLP.js";
8
11
  import {
9
12
  conversationParticipants,
10
13
  conversationReads,
11
14
  conversations,
12
- getDb,
13
15
  messages,
14
16
  users
15
- } from "./chunk-HHTXM4JT.js";
17
+ } from "./chunk-RPZZSXV3.js";
16
18
 
17
19
  // src/lib/events/conversations.ts
18
20
  import { randomUUID } from "crypto";
@@ -109,53 +111,6 @@ function publish(conversationId, event) {
109
111
  }
110
112
 
111
113
  // src/lib/events/conversations.ts
112
- async function migrateGroupDMsToChannels() {
113
- const db = await getDb();
114
- await db.transaction(async (tx) => {
115
- const overloadedDMs = await tx.select({
116
- conversationId: conversationParticipants.conversation_id,
117
- count: sql`COUNT(*)`
118
- }).from(conversationParticipants).innerJoin(conversations, eq(conversationParticipants.conversation_id, conversations.id)).where(eq(conversations.type, "dm")).groupBy(conversationParticipants.conversation_id).having(sql`COUNT(*) > 2`);
119
- const dmIds = overloadedDMs.map((r) => r.conversationId);
120
- await tx.update(conversations).set({
121
- type: "channel",
122
- name: sql`COALESCE(${conversations.name}, ${conversations.title})`
123
- }).where(eq(conversations.type, "group"));
124
- if (dmIds.length > 0) {
125
- await tx.update(conversations).set({
126
- type: "channel",
127
- name: sql`COALESCE(${conversations.name}, ${conversations.title})`
128
- }).where(inArray(conversations.id, dmIds));
129
- }
130
- });
131
- await migrateChannelEntryTypes();
132
- }
133
- async function migrateChannelEntryTypes() {
134
- const { existsSync, readdirSync, readFileSync, writeFileSync } = await import("fs");
135
- const { join } = await import("path");
136
- const home = join((await import("os")).homedir(), ".volute", "state");
137
- if (!existsSync(home)) return;
138
- for (const name of readdirSync(home)) {
139
- const filePath = join(home, name, "channels.json");
140
- if (!existsSync(filePath)) continue;
141
- try {
142
- const raw = readFileSync(filePath, "utf-8");
143
- const map = JSON.parse(raw);
144
- let changed = false;
145
- for (const entry of Object.values(map)) {
146
- if (entry.type === "group") {
147
- entry.type = "channel";
148
- changed = true;
149
- }
150
- }
151
- if (changed) {
152
- writeFileSync(filePath, `${JSON.stringify(map, null, 2)}
153
- `);
154
- }
155
- } catch {
156
- }
157
- }
158
- }
159
114
  async function createConversation(mindName, channel, opts) {
160
115
  const db = await getDb();
161
116
  const id = randomUUID();
@@ -194,6 +149,7 @@ async function createConversation(mindName, channel, opts) {
194
149
  name,
195
150
  user_id: opts?.userId ?? null,
196
151
  title: opts?.title ?? null,
152
+ private: 0,
197
153
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
198
154
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
199
155
  };
@@ -263,20 +219,24 @@ async function listConversationsForUser(userId) {
263
219
  return await db.select().from(conversations).where(inArray(conversations.id, convIds)).orderBy(desc(conversations.updated_at)).all();
264
220
  }
265
221
  async function isParticipantOrOwner(conversationId, userId) {
266
- if (await isParticipant(conversationId, userId)) return true;
267
- const db = await getDb();
268
- const row = await db.select().from(conversations).where(and(eq(conversations.id, conversationId), eq(conversations.user_id, userId))).get();
269
- return row != null;
222
+ return isParticipant(conversationId, userId);
270
223
  }
271
224
  async function deleteConversationForUser(id, userId) {
272
225
  if (!await isParticipantOrOwner(id, userId)) return false;
273
226
  await deleteConversation(id);
274
227
  return true;
275
228
  }
276
- async function addMessage(conversationId, role, senderName, content) {
229
+ async function addMessage(conversationId, role, senderName, content, opts) {
277
230
  const db = await getDb();
278
231
  const serialized = JSON.stringify(content);
279
- const [result] = await db.insert(messages).values({ conversation_id: conversationId, role, sender_name: senderName, content: serialized }).returning({ id: messages.id, created_at: messages.created_at });
232
+ const [result] = await db.insert(messages).values({
233
+ conversation_id: conversationId,
234
+ role,
235
+ sender_name: senderName,
236
+ content: serialized,
237
+ source_event_id: opts?.sourceEventId ?? null,
238
+ turn_id: opts?.turnId ?? null
239
+ }).returning({ id: messages.id, created_at: messages.created_at });
280
240
  await db.update(conversations).set({ updated_at: sql`datetime('now')` }).where(eq(conversations.id, conversationId));
281
241
  if (role === "user") {
282
242
  const firstText = content.find((b) => b.type === "text");
@@ -522,6 +482,10 @@ async function isConversationForMind(mindName, conversationId) {
522
482
  ).get();
523
483
  return !!participant;
524
484
  }
485
+ async function setConversationPrivate(id, isPrivate) {
486
+ const db = await getDb();
487
+ await db.update(conversations).set({ private: isPrivate ? 1 : 0 }).where(eq(conversations.id, id));
488
+ }
525
489
  async function deleteConversation(id) {
526
490
  const db = await getDb();
527
491
  await db.delete(conversations).where(eq(conversations.id, id));
@@ -593,7 +557,6 @@ export {
593
557
  initWebhook,
594
558
  subscribe2 as subscribe,
595
559
  publish,
596
- migrateGroupDMsToChannels,
597
560
  createConversation,
598
561
  getOrCreateConversation,
599
562
  getConversation,
@@ -611,6 +574,7 @@ export {
611
574
  findDMConversation,
612
575
  listConversationsForMind,
613
576
  isConversationForMind,
577
+ setConversationPrivate,
614
578
  deleteConversation,
615
579
  createChannel,
616
580
  getChannelByName,