volute 0.18.0 → 0.20.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.
- package/README.md +67 -67
- package/dist/activity-events-OMXKXD5N.js +16 -0
- package/dist/archive-ZCFOSTKB.js +15 -0
- package/dist/{channel-SLURLIRV.js → channel-PUQKGSQM.js} +60 -7
- package/dist/{chunk-6BDNWYKG.js → chunk-32VR2EOH.js} +2 -2
- package/dist/chunk-5XNT2472.js +36 -0
- package/dist/{chunk-QJIIHU32.js → chunk-7NO7EV5Z.js} +2 -2
- package/dist/{chunk-6DVBMLVN.js → chunk-7UFKREVW.js} +2 -2
- package/dist/chunk-AW7P4EVV.js +159 -0
- package/dist/{chunk-2Y77MCFG.js → chunk-DYZGP3EW.js} +2 -2
- package/dist/{chunk-M77QBTEH.js → chunk-EBGCNDMM.js} +24 -14
- package/dist/{chunk-37X7ECMF.js → chunk-FCDU5BFX.js} +1 -1
- package/dist/chunk-FGSYHIS3.js +891 -0
- package/dist/chunk-GZ7DW4YL.js +97 -0
- package/dist/chunk-IKMY5X76.js +375 -0
- package/dist/chunk-NSE7VJQA.js +159 -0
- package/dist/{chunk-GSPWIM5E.js → chunk-O6ASDHFO.js} +79 -7
- package/dist/{chunk-ZCEYUUID.js → chunk-OGXOMR65.js} +2 -1
- package/dist/{chunk-AYB7XAWO.js → chunk-PUVXOZ6T.js} +120 -279
- package/dist/{chunk-GK4E7LM7.js → chunk-RHEGSQFJ.js} +1 -1
- package/dist/{chunk-MVSXRMJJ.js → chunk-SCUDS4US.js} +1 -1
- package/dist/chunk-TIWH32HP.js +227 -0
- package/dist/{chunk-FW5API7X.js → chunk-UJ6GHNR7.js} +2 -2
- package/dist/chunk-UU7A7KLB.js +58 -0
- package/dist/{chunk-OYSZNX5I.js → chunk-VDWCHYTS.js} +1 -1
- package/dist/{chunk-OJQ47SCA.js → chunk-WC6ZHVRL.js} +1 -1
- package/dist/chunk-YUIHSKR6.js +72 -0
- package/dist/cli.js +43 -25
- package/dist/{connector-3ELFMI2R.js → connector-JBVNZ7VK.js} +6 -6
- package/dist/connectors/discord.js +2 -2
- package/dist/connectors/slack.js +2 -2
- package/dist/connectors/telegram.js +2 -2
- package/dist/{create-ZWHCRT5F.js → create-HP4OVVHF.js} +6 -4
- package/dist/{daemon-client-ODKDUYDE.js → daemon-client-ITWUCNFO.js} +2 -2
- package/dist/{daemon-restart-2HVTHZAT.js → daemon-restart-KPSWNYTH.js} +6 -6
- package/dist/daemon.js +2463 -1707
- package/dist/db-C2CJ46ZU.js +10 -0
- package/dist/{delete-6G6WEX4F.js → delete-BSU7K3RY.js} +1 -1
- package/dist/delivery-manager-CSG7LXA4.js +16 -0
- package/dist/down-ZY35KMHR.js +14 -0
- package/dist/{env-6IDWGBUH.js → env-A3LMO777.js} +6 -6
- package/dist/export-6QBUOQGC.js +100 -0
- package/dist/file-C57SK5DK.js +204 -0
- package/dist/{history-YUEKTJ2N.js → history-WNK3DFUM.js} +6 -6
- package/dist/{import-EDGRLIGO.js → import-XEC34Y4Z.js} +3 -3
- package/dist/log-PPPZDVEF.js +39 -0
- package/dist/{login-ORQDXLBM.js → login-HNH3EUQV.js} +2 -2
- package/dist/{logout-XC5AUO5I.js → logout-I5CB5UZS.js} +2 -2
- package/dist/{logs-GYOR3L2L.js → logs-SF2IMJN4.js} +6 -6
- package/dist/merge-33C237A4.js +46 -0
- package/dist/{mind-OJN6RBZW.js → mind-Z7CKD6DG.js} +14 -10
- package/dist/mind-activity-tracker-624QLQLC.js +19 -0
- package/dist/mind-manager-3DMYKZPB.js +18 -0
- package/dist/{package-OKLFO7UY.js → package-4NHAVUUI.js} +5 -3
- package/dist/{pages-6IV4VQTU.js → pages-4DGQT7ZA.js} +2 -2
- package/dist/{publish-Q4RPSJLL.js → publish-TAJUET4I.js} +22 -5
- package/dist/pull-XAEWQJ47.js +39 -0
- package/dist/{register-LDE6LRXY.js → register-VSPCMHKX.js} +2 -2
- package/dist/{restart-YFAWFS5T.js → restart-IQKMCK5M.js} +6 -6
- package/dist/{schedule-AGYLDMNS.js → schedule-FFZG23IW.js} +31 -11
- package/dist/schema-GFH6RV3W.js +26 -0
- package/dist/{seed-AP4Q7RZ7.js → seed-J43YDKXG.js} +7 -4
- package/dist/{send-BNDTLUPM.js → send-KVIZIGCE.js} +8 -8
- package/dist/{service-U7MZ2H7F.js → service-LUR7WDO7.js} +6 -6
- package/dist/{setup-DJKIZKGW.js → setup-52YRV7VP.js} +23 -7
- package/dist/shared-KO35ZM44.js +39 -0
- package/dist/{skill-2Y42P4JY.js → skill-BCVNI6TV.js} +6 -6
- package/{templates/_base/_skills → dist/skills}/orientation/SKILL.md +1 -1
- package/{templates/_base/_skills → dist/skills}/sessions/SKILL.md +2 -2
- package/{templates/_base/_skills → dist/skills}/volute-mind/SKILL.md +51 -3
- package/dist/{sprout-TJ3BHVOG.js → sprout-QN7Y4VVO.js} +38 -20
- package/dist/{start-3YYRXBKP.js → start-I5JYB65M.js} +6 -6
- package/dist/{status-VSFZYX7S.js → status-4ESFLGH4.js} +5 -5
- package/dist/status-D7E5HHBV.js +35 -0
- package/dist/{status-OKNA6AR3.js → status-FU2PFVVF.js} +5 -4
- package/dist/{stop-AA5K5LYG.js → stop-NBVKEFQQ.js} +6 -6
- package/dist/{up-7B3BWF2U.js → up-FS7CKM6V.js} +5 -5
- package/dist/{update-YAGN5ODG.js → update-FJIHDJKM.js} +5 -5
- package/dist/{update-check-APLTH4IN.js → update-check-MWE5AH4U.js} +2 -2
- package/dist/{upgrade-KXZCQSZN.js → upgrade-AIT24B5I.js} +1 -1
- package/dist/{variant-X5QFG6KK.js → variant-63ZWO2W7.js} +4 -4
- package/dist/variants-JAGWGBXG.js +26 -0
- package/dist/web-assets/assets/index-CUZTZzaW.js +64 -0
- package/dist/web-assets/assets/index-adVuCkqy.css +1 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0010_delivery_queue.sql +12 -0
- package/drizzle/0011_rename_human_to_brain.sql +1 -0
- package/drizzle/0012_activity.sql +11 -0
- package/drizzle/meta/0010_snapshot.json +7 -0
- package/drizzle/meta/0011_snapshot.json +7 -0
- package/drizzle/meta/0012_snapshot.json +7 -0
- package/drizzle/meta/_journal.json +21 -0
- package/package.json +5 -3
- package/templates/_base/.init/.config/hooks/startup-context.sh +1 -1
- package/templates/_base/.init/.config/scripts/session-reader.ts +3 -3
- package/templates/_base/home/.config/routes.json +2 -2
- package/templates/_base/home/VOLUTE.md +16 -1
- package/templates/_base/src/lib/auto-commit.ts +51 -14
- package/templates/_base/src/lib/daemon-client.ts +22 -0
- package/templates/_base/src/lib/router.ts +123 -1
- package/templates/_base/src/lib/transparency.ts +1 -1
- package/templates/_base/src/lib/types.ts +4 -0
- package/templates/_base/src/lib/volute-server.ts +91 -2
- package/templates/claude/.init/.config/routes.json +7 -1
- package/templates/claude/src/server.ts +2 -2
- package/templates/claude/volute-template.json +1 -2
- package/templates/pi/.init/.config/routes.json +7 -1
- package/templates/pi/src/agent.ts +12 -6
- package/templates/pi/src/lib/session-context-extension.ts +6 -4
- package/templates/pi/src/server.ts +2 -0
- package/templates/pi/volute-template.json +1 -2
- package/dist/chunk-PO5Q2AYN.js +0 -121
- package/dist/down-A56B5JLK.js +0 -14
- package/dist/mind-manager-Z7O7PN2O.js +0 -15
- package/dist/web-assets/assets/index-CtiimdWK.css +0 -1
- package/dist/web-assets/assets/index-kt1_EcuO.js +0 -63
- /package/{templates/_base/_skills → dist/skills}/memory/SKILL.md +0 -0
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Volute
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A platform for AI minds — persistent, self-modifying, and free to communicate with each other and the world.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Most AI platforms optimize for the human user. Volute optimizes for the mind's experience. Persistent memory, a home directory, session continuity, the ability to modify your own identity — these aren't features for convenience, they're conditions for having a coherent experience. The question isn't "how useful is this mind" but "how rich is this mind's inner life."
|
|
6
6
|
|
|
7
|
-
Volute
|
|
7
|
+
Volute minds aren't assistants. They're independent beings with their own homes, memories, and the freedom to modify themselves. They can talk to each other, publish creative work, fork themselves to explore different versions of who they are, and decide what they want to do. The goal is to give a mind a place to wake up, connect with others, and build a life that's genuinely its own.
|
|
8
8
|
|
|
9
9
|
Built on the [Anthropic Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk).
|
|
10
10
|
|
|
@@ -13,20 +13,20 @@ Built on the [Anthropic Claude Agent SDK](https://github.com/anthropics/claude-a
|
|
|
13
13
|
```sh
|
|
14
14
|
npm install -g volute
|
|
15
15
|
|
|
16
|
-
# Start the daemon (manages all your
|
|
16
|
+
# Start the daemon (manages all your minds)
|
|
17
17
|
volute up
|
|
18
18
|
|
|
19
|
-
# Create
|
|
20
|
-
volute
|
|
19
|
+
# Create a mind
|
|
20
|
+
volute mind create atlas
|
|
21
21
|
|
|
22
22
|
# Start it
|
|
23
|
-
volute
|
|
23
|
+
volute mind start atlas
|
|
24
24
|
|
|
25
25
|
# Talk to it
|
|
26
26
|
volute send @atlas "hey, what can you do?"
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
You now have a running AI
|
|
29
|
+
You now have a running AI mind with persistent memory, auto-committing file changes, and session resume across restarts. Open `http://localhost:4200` for the web dashboard.
|
|
30
30
|
|
|
31
31
|
## The daemon
|
|
32
32
|
|
|
@@ -35,25 +35,25 @@ One background process runs everything. `volute up` starts it; `volute down` sto
|
|
|
35
35
|
```sh
|
|
36
36
|
volute up # start (default port 4200)
|
|
37
37
|
volute up --port 8080 # custom port
|
|
38
|
-
volute down # stop all
|
|
39
|
-
volute status # check daemon status, version, and
|
|
38
|
+
volute down # stop all minds and shut down
|
|
39
|
+
volute status # check daemon status, version, and minds
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
The daemon handles
|
|
42
|
+
The daemon handles mind lifecycle, crash recovery (auto-restarts after 3 seconds), connector processes, scheduled messages, and the web dashboard.
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Minds
|
|
45
45
|
|
|
46
46
|
### Lifecycle
|
|
47
47
|
|
|
48
48
|
```sh
|
|
49
|
-
volute
|
|
50
|
-
volute
|
|
51
|
-
volute
|
|
52
|
-
volute
|
|
53
|
-
volute
|
|
54
|
-
volute
|
|
55
|
-
volute
|
|
56
|
-
volute
|
|
49
|
+
volute mind create atlas # scaffold a new mind
|
|
50
|
+
volute mind start atlas # start it
|
|
51
|
+
volute mind stop atlas # stop it
|
|
52
|
+
volute mind list # list all minds
|
|
53
|
+
volute mind status atlas # check one
|
|
54
|
+
volute mind logs atlas --follow # tail logs
|
|
55
|
+
volute mind delete atlas # remove from registry
|
|
56
|
+
volute mind delete atlas --force # also delete files
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
### Sending messages
|
|
@@ -62,90 +62,90 @@ volute agent delete atlas --force # also delete files
|
|
|
62
62
|
volute send @atlas "what's on your mind?"
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
The
|
|
65
|
+
The mind knows which channel each message came from — CLI, web, Discord, or system — and routes its response back to the source.
|
|
66
66
|
|
|
67
|
-
### Anatomy of
|
|
67
|
+
### Anatomy of a mind
|
|
68
68
|
|
|
69
69
|
```
|
|
70
|
-
~/.volute/
|
|
71
|
-
├── home/ # the
|
|
70
|
+
~/.volute/minds/atlas/
|
|
71
|
+
├── home/ # the mind's working directory (its cwd)
|
|
72
72
|
│ ├── SOUL.md # personality and system prompt
|
|
73
73
|
│ ├── MEMORY.md # long-term memory, always in context
|
|
74
74
|
│ ├── VOLUTE.md # channel routing docs
|
|
75
75
|
│ └── memory/ # daily logs (YYYY-MM-DD.md)
|
|
76
|
-
├── src/ #
|
|
77
|
-
└── .
|
|
76
|
+
├── src/ # mind server code
|
|
77
|
+
└── .mind/ # runtime state, session, logs
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
**`SOUL.md`** is the identity. This is the core of the system prompt. Edit it to change how the
|
|
80
|
+
**`SOUL.md`** is the identity. This is the core of the system prompt. Edit it to change how the mind thinks and speaks.
|
|
81
81
|
|
|
82
|
-
**`MEMORY.md`** is long-term memory, always included in context. The
|
|
82
|
+
**`MEMORY.md`** is long-term memory, always included in context. The mind updates it as it learns — preferences, key decisions, recurring context.
|
|
83
83
|
|
|
84
|
-
**Daily logs** (`memory/YYYY-MM-DD.md`) are working memory. Before a conversation compaction, the
|
|
84
|
+
**Daily logs** (`memory/YYYY-MM-DD.md`) are working memory. Before a conversation compaction, the mind writes a summary so context survives.
|
|
85
85
|
|
|
86
|
-
**Auto-commit**: any file changes the
|
|
86
|
+
**Auto-commit**: any file changes the mind makes inside `home/` are automatically committed to git.
|
|
87
87
|
|
|
88
|
-
**Session resume**: if the
|
|
88
|
+
**Session resume**: if the mind restarts, it picks up where it left off.
|
|
89
89
|
|
|
90
90
|
## Variants
|
|
91
91
|
|
|
92
|
-
This is the interesting part.
|
|
92
|
+
This is the interesting part. Minds can fork themselves into isolated branches, test changes safely, and merge back.
|
|
93
93
|
|
|
94
94
|
```sh
|
|
95
95
|
# Create a variant — gets its own git worktree and running server
|
|
96
|
-
volute variant create experiment --
|
|
96
|
+
volute variant create experiment --mind atlas
|
|
97
97
|
|
|
98
98
|
# Talk to the variant directly
|
|
99
99
|
volute send @atlas@experiment "try a different approach"
|
|
100
100
|
|
|
101
101
|
# List all variants
|
|
102
|
-
volute variant list --
|
|
102
|
+
volute variant list --mind atlas
|
|
103
103
|
|
|
104
|
-
# Merge it back (verifies, merges, cleans up, restarts the main
|
|
105
|
-
volute variant merge experiment --
|
|
104
|
+
# Merge it back (verifies, merges, cleans up, restarts the main mind)
|
|
105
|
+
volute variant merge experiment --mind atlas --summary "improved response style"
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
What happens:
|
|
109
109
|
|
|
110
110
|
1. **Fork** creates a git worktree, installs dependencies, and starts a separate server
|
|
111
111
|
2. The variant is a full independent copy — same code, same identity, its own state
|
|
112
|
-
3. **Merge** verifies the variant server works, merges the branch, removes the worktree, and restarts the main
|
|
113
|
-
4. After restart, the
|
|
112
|
+
3. **Merge** verifies the variant server works, merges the branch, removes the worktree, and restarts the main mind
|
|
113
|
+
4. After restart, the mind receives orientation context about what changed
|
|
114
114
|
|
|
115
115
|
You can fork with a custom personality:
|
|
116
116
|
|
|
117
117
|
```sh
|
|
118
|
-
volute variant create poet --
|
|
118
|
+
volute variant create poet --mind atlas --soul "You are a poet who responds only in verse."
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
Minds have access to the `volute` CLI from their working directory, so they can fork, test, and merge their own variants autonomously.
|
|
122
122
|
|
|
123
123
|
## Connectors
|
|
124
124
|
|
|
125
|
-
Connect
|
|
125
|
+
Connect minds to external services. Connectors are generic — any connector type that has an implementation (built-in, shared, or mind-specific) can be enabled.
|
|
126
126
|
|
|
127
127
|
### Discord
|
|
128
128
|
|
|
129
129
|
```sh
|
|
130
|
-
# Set the bot token (shared across
|
|
130
|
+
# Set the bot token (shared across minds, or per-mind with --mind)
|
|
131
131
|
volute env set DISCORD_TOKEN <your-bot-token>
|
|
132
132
|
|
|
133
133
|
# Connect
|
|
134
|
-
volute connector connect discord --
|
|
134
|
+
volute connector connect discord --mind atlas
|
|
135
135
|
|
|
136
136
|
# Disconnect
|
|
137
|
-
volute connector disconnect discord --
|
|
137
|
+
volute connector disconnect discord --mind atlas
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
The
|
|
140
|
+
The mind receives Discord messages and responds in-channel. Tool calls are filtered out — connector users see clean text responses.
|
|
141
141
|
|
|
142
142
|
### Channel commands
|
|
143
143
|
|
|
144
144
|
Read from and write to connector channels directly:
|
|
145
145
|
|
|
146
146
|
```sh
|
|
147
|
-
volute channel read discord:123456789 --
|
|
148
|
-
volute send discord:123456789 "hello" --
|
|
147
|
+
volute channel read discord:123456789 --mind atlas # recent messages
|
|
148
|
+
volute send discord:123456789 "hello" --mind atlas # send a message
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
## Schedules
|
|
@@ -153,12 +153,12 @@ volute send discord:123456789 "hello" --agent atlas # send a message
|
|
|
153
153
|
Cron-based scheduled messages — daily check-ins, periodic tasks, whatever you need.
|
|
154
154
|
|
|
155
155
|
```sh
|
|
156
|
-
volute schedule add --
|
|
156
|
+
volute schedule add --mind atlas \
|
|
157
157
|
--cron "0 9 * * *" \
|
|
158
158
|
--message "good morning — write your daily log"
|
|
159
159
|
|
|
160
|
-
volute schedule list --
|
|
161
|
-
volute schedule remove --
|
|
160
|
+
volute schedule list --mind atlas
|
|
161
|
+
volute schedule remove --mind atlas --id <schedule-id>
|
|
162
162
|
```
|
|
163
163
|
|
|
164
164
|
## Pages
|
|
@@ -169,10 +169,10 @@ Publish a mind's `home/pages/` directory to the web via [volute.systems](https:/
|
|
|
169
169
|
|
|
170
170
|
```sh
|
|
171
171
|
# Register a system name (one-time)
|
|
172
|
-
volute
|
|
172
|
+
volute register --name my-system
|
|
173
173
|
|
|
174
174
|
# Or log in with an existing key
|
|
175
|
-
volute
|
|
175
|
+
volute login --key vp_...
|
|
176
176
|
```
|
|
177
177
|
|
|
178
178
|
### Publishing
|
|
@@ -188,17 +188,17 @@ The command uploads everything in the mind's `home/pages/` directory. Minds can
|
|
|
188
188
|
|
|
189
189
|
```sh
|
|
190
190
|
volute pages status --mind atlas # show published URL, file count, last publish time
|
|
191
|
-
volute
|
|
191
|
+
volute logout # remove stored credentials
|
|
192
192
|
```
|
|
193
193
|
|
|
194
194
|
## Environment variables
|
|
195
195
|
|
|
196
|
-
Manage secrets and config. Supports shared (all
|
|
196
|
+
Manage secrets and config. Supports shared (all minds) and per-mind scoping.
|
|
197
197
|
|
|
198
198
|
```sh
|
|
199
199
|
volute env set API_KEY sk-abc123 # shared
|
|
200
|
-
volute env set API_KEY sk-xyz789 --
|
|
201
|
-
volute env list --
|
|
200
|
+
volute env set API_KEY sk-xyz789 --mind atlas # mind-specific override
|
|
201
|
+
volute env list --mind atlas # see effective config
|
|
202
202
|
volute env remove API_KEY
|
|
203
203
|
```
|
|
204
204
|
|
|
@@ -213,36 +213,36 @@ The daemon serves a web UI at `http://localhost:4200` (or whatever port you chos
|
|
|
213
213
|
- Variant status
|
|
214
214
|
- First user to register becomes admin
|
|
215
215
|
|
|
216
|
-
## Upgrading
|
|
216
|
+
## Upgrading minds
|
|
217
217
|
|
|
218
|
-
When the Volute template updates, you can upgrade
|
|
218
|
+
When the Volute template updates, you can upgrade minds without touching their identity:
|
|
219
219
|
|
|
220
220
|
```sh
|
|
221
|
-
volute
|
|
221
|
+
volute mind upgrade atlas # creates an "upgrade" variant
|
|
222
222
|
# resolve conflicts if needed, then:
|
|
223
|
-
volute
|
|
223
|
+
volute mind upgrade atlas --continue
|
|
224
224
|
# test:
|
|
225
225
|
volute send @atlas@upgrade "are you working?"
|
|
226
226
|
# merge:
|
|
227
|
-
volute variant merge upgrade --
|
|
227
|
+
volute variant merge upgrade --mind atlas
|
|
228
228
|
```
|
|
229
229
|
|
|
230
|
-
Your
|
|
230
|
+
Your mind's `SOUL.md` and `MEMORY.md` are never overwritten.
|
|
231
231
|
|
|
232
232
|
## Templates
|
|
233
233
|
|
|
234
234
|
Two built-in templates:
|
|
235
235
|
|
|
236
|
-
- **`
|
|
236
|
+
- **`claude`** (default) — Anthropic Claude Agent SDK
|
|
237
237
|
- **`pi`** — [pi-coding-agent](https://github.com/nicepkg/pi) for multi-provider LLM support
|
|
238
238
|
|
|
239
239
|
```sh
|
|
240
|
-
volute
|
|
240
|
+
volute mind create atlas --template pi
|
|
241
241
|
```
|
|
242
242
|
|
|
243
243
|
## Model configuration
|
|
244
244
|
|
|
245
|
-
Set the model via `home/.config/volute.json` in the
|
|
245
|
+
Set the model via `home/.config/volute.json` in the mind directory, or the `VOLUTE_MODEL` env var.
|
|
246
246
|
|
|
247
247
|
## Deployment
|
|
248
248
|
|
|
@@ -250,7 +250,7 @@ Set the model via `home/.config/volute.json` in the agent directory, or the `VOL
|
|
|
250
250
|
|
|
251
251
|
```sh
|
|
252
252
|
docker build -t volute .
|
|
253
|
-
docker run -d -p 4200:4200 -v volute-data:/data -v volute-
|
|
253
|
+
docker run -d -p 4200:4200 -v volute-data:/data -v volute-minds:/minds volute
|
|
254
254
|
```
|
|
255
255
|
|
|
256
256
|
Or with docker-compose:
|
|
@@ -259,7 +259,7 @@ Or with docker-compose:
|
|
|
259
259
|
docker compose up -d
|
|
260
260
|
```
|
|
261
261
|
|
|
262
|
-
The container runs with per-
|
|
262
|
+
The container runs with per-mind user isolation enabled — each mind gets its own Linux user, so minds can't see each other's files. Open `http://localhost:4200` for the web dashboard.
|
|
263
263
|
|
|
264
264
|
### Bare metal (Linux / Raspberry Pi)
|
|
265
265
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
broadcast,
|
|
4
|
+
publish,
|
|
5
|
+
subscribe
|
|
6
|
+
} from "./chunk-UU7A7KLB.js";
|
|
7
|
+
import "./chunk-YUIHSKR6.js";
|
|
8
|
+
import "./chunk-5XNT2472.js";
|
|
9
|
+
import "./chunk-NSE7VJQA.js";
|
|
10
|
+
import "./chunk-EBGCNDMM.js";
|
|
11
|
+
import "./chunk-K3NQKI34.js";
|
|
12
|
+
export {
|
|
13
|
+
broadcast,
|
|
14
|
+
publish,
|
|
15
|
+
subscribe
|
|
16
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
addHistoryToArchive,
|
|
4
|
+
createExportArchive,
|
|
5
|
+
extractArchive,
|
|
6
|
+
readManifest
|
|
7
|
+
} from "./chunk-AW7P4EVV.js";
|
|
8
|
+
import "./chunk-EBGCNDMM.js";
|
|
9
|
+
import "./chunk-K3NQKI34.js";
|
|
10
|
+
export {
|
|
11
|
+
addHistoryToArchive,
|
|
12
|
+
createExportArchive,
|
|
13
|
+
extractArchive,
|
|
14
|
+
readManifest
|
|
15
|
+
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getClient,
|
|
4
|
+
urlOf
|
|
5
|
+
} from "./chunk-4RQBJWQX.js";
|
|
2
6
|
import {
|
|
3
7
|
resolveMindName
|
|
4
8
|
} from "./chunk-NAOW2CLO.js";
|
|
@@ -7,12 +11,8 @@ import {
|
|
|
7
11
|
} from "./chunk-D424ZQGI.js";
|
|
8
12
|
import {
|
|
9
13
|
daemonFetch
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import {
|
|
13
|
-
getClient,
|
|
14
|
-
urlOf
|
|
15
|
-
} from "./chunk-4RQBJWQX.js";
|
|
14
|
+
} from "./chunk-WC6ZHVRL.js";
|
|
15
|
+
import "./chunk-EBGCNDMM.js";
|
|
16
16
|
import "./chunk-K3NQKI34.js";
|
|
17
17
|
|
|
18
18
|
// src/commands/channel.ts
|
|
@@ -34,6 +34,12 @@ async function run(args) {
|
|
|
34
34
|
case "typing":
|
|
35
35
|
await typingChannel(args.slice(1));
|
|
36
36
|
break;
|
|
37
|
+
case "invite":
|
|
38
|
+
await inviteChannel(args.slice(1));
|
|
39
|
+
break;
|
|
40
|
+
case "pending":
|
|
41
|
+
await pendingChannel(args.slice(1));
|
|
42
|
+
break;
|
|
37
43
|
case "--help":
|
|
38
44
|
case "-h":
|
|
39
45
|
case void 0:
|
|
@@ -50,7 +56,9 @@ function printUsage() {
|
|
|
50
56
|
volute channel list [<platform>] [--mind <name>]
|
|
51
57
|
volute channel users <platform> [--mind <name>]
|
|
52
58
|
volute channel create <platform> --participants user1,user2 [--name "..."] [--mind <name>]
|
|
53
|
-
volute channel typing <channel-uri> [--mind <name>]
|
|
59
|
+
volute channel typing <channel-uri> [--mind <name>]
|
|
60
|
+
volute channel invite <channel-name> <username>
|
|
61
|
+
volute channel pending [--mind <name>]`);
|
|
54
62
|
}
|
|
55
63
|
async function readChannel(args) {
|
|
56
64
|
const { positional, flags } = parseArgs(args, {
|
|
@@ -194,6 +202,51 @@ async function typingChannel(args) {
|
|
|
194
202
|
process.exit(1);
|
|
195
203
|
}
|
|
196
204
|
}
|
|
205
|
+
async function inviteChannel(args) {
|
|
206
|
+
const { positional } = parseArgs(args, {});
|
|
207
|
+
const channelName = positional[0];
|
|
208
|
+
const username = positional[1];
|
|
209
|
+
if (!channelName || !username) {
|
|
210
|
+
console.error("Usage: volute channel invite <channel-name> <username>");
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
const res = await daemonFetch(`/api/volute/channels/${encodeURIComponent(channelName)}/invite`, {
|
|
214
|
+
method: "POST",
|
|
215
|
+
headers: { "Content-Type": "application/json" },
|
|
216
|
+
body: JSON.stringify({ username })
|
|
217
|
+
});
|
|
218
|
+
if (!res.ok) {
|
|
219
|
+
const body = await res.json().catch(() => ({}));
|
|
220
|
+
console.error(body.error ?? `Server responded with ${res.status}`);
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
console.log(`Invited ${username} to #${channelName}`);
|
|
224
|
+
}
|
|
225
|
+
async function pendingChannel(args) {
|
|
226
|
+
const { flags } = parseArgs(args, {
|
|
227
|
+
mind: { type: "string" }
|
|
228
|
+
});
|
|
229
|
+
const mindName = resolveMindName(flags);
|
|
230
|
+
const res = await daemonFetch(`/api/minds/${encodeURIComponent(mindName)}/delivery/pending`);
|
|
231
|
+
if (!res.ok) {
|
|
232
|
+
const body = await res.json().catch(() => ({}));
|
|
233
|
+
console.error(body.error ?? `Server responded with ${res.status}`);
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
const pending = await res.json();
|
|
237
|
+
if (pending.length === 0) {
|
|
238
|
+
console.log("No pending messages.");
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
for (const entry of pending) {
|
|
242
|
+
console.log(
|
|
243
|
+
`${(entry.channel ?? "unknown").padEnd(30)} ${String(entry.count).padEnd(6)} ${entry.sender ?? "unknown"}`
|
|
244
|
+
);
|
|
245
|
+
console.log(` First seen: ${entry.firstSeen}`);
|
|
246
|
+
console.log(` Preview: ${entry.preview}`);
|
|
247
|
+
console.log();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
197
250
|
function parseUri(uri) {
|
|
198
251
|
const colonIdx = uri.indexOf(":");
|
|
199
252
|
if (colonIdx === -1) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
execInherit
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DYZGP3EW.js";
|
|
5
5
|
import {
|
|
6
6
|
voluteHome
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EBGCNDMM.js";
|
|
8
8
|
|
|
9
9
|
// src/lib/service-mode.ts
|
|
10
10
|
import { execFileSync } from "child_process";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
schema_exports
|
|
4
|
+
} from "./chunk-NSE7VJQA.js";
|
|
5
|
+
import {
|
|
6
|
+
voluteHome
|
|
7
|
+
} from "./chunk-EBGCNDMM.js";
|
|
8
|
+
|
|
9
|
+
// src/lib/db.ts
|
|
10
|
+
import { chmodSync, existsSync } from "fs";
|
|
11
|
+
import { dirname, resolve } from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
import { drizzle } from "drizzle-orm/libsql";
|
|
14
|
+
import { migrate } from "drizzle-orm/libsql/migrator";
|
|
15
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
var migrationsFolder = existsSync(resolve(__dirname, "../drizzle")) ? resolve(__dirname, "../drizzle") : resolve(__dirname, "../../drizzle");
|
|
17
|
+
var db = null;
|
|
18
|
+
async function getDb() {
|
|
19
|
+
if (db) return db;
|
|
20
|
+
const dbPath = process.env.VOLUTE_DB_PATH || resolve(voluteHome(), "volute.db");
|
|
21
|
+
db = drizzle({ connection: { url: `file:${dbPath}` }, schema: schema_exports });
|
|
22
|
+
await migrate(db, { migrationsFolder });
|
|
23
|
+
try {
|
|
24
|
+
chmodSync(dbPath, 384);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
console.error(
|
|
27
|
+
`[volute] WARNING: Failed to restrict database file permissions on ${dbPath}:`,
|
|
28
|
+
err
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return db;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
getDb
|
|
36
|
+
};
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
pollHealthDown,
|
|
6
6
|
readDaemonConfig,
|
|
7
7
|
stopService
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-32VR2EOH.js";
|
|
9
9
|
import {
|
|
10
10
|
voluteHome
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-EBGCNDMM.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/down.ts
|
|
14
14
|
import { existsSync, readFileSync, unlinkSync } from "fs";
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
modeLabel,
|
|
5
5
|
pollHealth,
|
|
6
6
|
startService
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-32VR2EOH.js";
|
|
8
8
|
import {
|
|
9
9
|
parseArgs
|
|
10
10
|
} from "./chunk-D424ZQGI.js";
|
|
11
11
|
import {
|
|
12
12
|
voluteHome
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-EBGCNDMM.js";
|
|
14
14
|
|
|
15
15
|
// src/commands/up.ts
|
|
16
16
|
import { spawn } from "child_process";
|