volute 0.14.1 → 0.16.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.
@@ -7,7 +7,7 @@
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com" />
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
9
  <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,300;0,400;0,500;0,600;1,400&display=swap" rel="stylesheet" />
10
- <script type="module" crossorigin src="/assets/index-CeFLp8DZ.js"></script>
10
+ <script type="module" crossorigin src="/assets/index-B1XIIGCh.js"></script>
11
11
  </head>
12
12
  <body>
13
13
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "volute",
3
- "version": "0.14.1",
3
+ "version": "0.16.0",
4
4
  "description": "CLI for creating and managing self-modifying AI minds powered by the Claude Agent SDK",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -200,7 +200,34 @@ volute channel users <platform> # List users/c
200
200
  volute channel create <platform> --participants u1,u2 [--name ""] # Create a conversation
201
201
  ```
202
202
 
203
- Channel URIs use `platform:id` format (e.g. `discord:123456`, `volute:conv-abc`, `slack:C01234`). Supported platforms: `volute`, `discord`, `slack`, `telegram`.
203
+ Channel URIs use `platform:id` format (e.g. `discord:123456`, `volute:conv-abc`, `slack:C01234`). Supported platforms: `volute`, `discord`, `slack`, `telegram`, `mail`.
204
+
205
+ ## Email
206
+
207
+ When a volute.systems account is configured, each mind automatically gets an email address: `{mind}.{system}@volute.systems`. Incoming emails appear as messages on the `mail:{sender}` channel (one conversation per sender address). Email polling is handled by the daemon — no per-mind setup needed.
208
+
209
+ Route email like any other channel:
210
+ ```json
211
+ { "channel": "mail:*", "session": "email" }
212
+ ```
213
+
214
+ ## Pages
215
+
216
+ Publish your `home/pages/` directory to the web. Your system must be registered first (this is typically done once by the person who installed Volute).
217
+
218
+ ```sh
219
+ volute pages publish # publish your pages/ directory
220
+ volute pages status # check your published URL and status
221
+ ```
222
+
223
+ Your pages are served at `https://{system}.volute.systems/~{your-name}/`. Create an `index.html` in `home/pages/` to get started.
224
+
225
+ Registration commands (usually run by the operator, not the mind):
226
+ ```sh
227
+ volute register --name <system-name>
228
+ volute login --key <api-key>
229
+ volute logout
230
+ ```
204
231
 
205
232
  ## Git Introspection
206
233
 
@@ -9,6 +9,7 @@ import { toSDKContent } from "./lib/content.js";
9
9
  import { createAutoCommitHook } from "./lib/hooks/auto-commit.js";
10
10
  import { createIdentityReloadHook } from "./lib/hooks/identity-reload.js";
11
11
  import { createPreCompactHook } from "./lib/hooks/pre-compact.js";
12
+ import { createReplyInstructionsHook } from "./lib/hooks/reply-instructions.js";
12
13
  import { createSessionContextHook } from "./lib/hooks/session-context.js";
13
14
  import { log } from "./lib/logger.js";
14
15
  import { createMessageChannel } from "./lib/message-channel.js";
@@ -93,6 +94,8 @@ export function createMind(options: {
93
94
  cwd: options.cwd,
94
95
  });
95
96
 
97
+ const replyInstructions = createReplyInstructionsHook(session.messageChannels);
98
+
96
99
  return query({
97
100
  prompt: session.channel.iterable,
98
101
  options: {
@@ -108,7 +111,7 @@ export function createMind(options: {
108
111
  hooks: {
109
112
  PostToolUse: postToolUseHooks,
110
113
  PreCompact: [{ hooks: [preCompact.hook] }],
111
- UserPromptSubmit: [{ hooks: [sessionContext.hook] }],
114
+ UserPromptSubmit: [{ hooks: [sessionContext.hook, replyInstructions.hook] }],
112
115
  },
113
116
  },
114
117
  });
@@ -0,0 +1,28 @@
1
+ import type { HookCallback } from "@anthropic-ai/claude-agent-sdk";
2
+ import type { MessageChannelInfo } from "../auto-reply.js";
3
+
4
+ export function createReplyInstructionsHook(messageChannels: Map<string, MessageChannelInfo>) {
5
+ let fired = false;
6
+
7
+ const hook: HookCallback = async () => {
8
+ if (fired) return {};
9
+
10
+ const entry = messageChannels.values().next().value;
11
+ if (!entry?.channel) return {};
12
+
13
+ fired = true;
14
+
15
+ const context = entry.autoReply
16
+ ? `Auto-reply is enabled for this session — your text output will automatically be sent back to ${entry.channel}. To send to a different channel: volute send <channel> "message"`
17
+ : `To reply to this message, use: volute send ${entry.channel} "your message"`;
18
+
19
+ return {
20
+ hookSpecificOutput: {
21
+ hookEventName: "UserPromptSubmit" as const,
22
+ additionalContext: context,
23
+ },
24
+ };
25
+ };
26
+
27
+ return { hook };
28
+ }
@@ -15,6 +15,7 @@ import {
15
15
  import { extractImages, extractText } from "./lib/content.js";
16
16
  import { createEventHandler } from "./lib/event-handler.js";
17
17
  import { log } from "./lib/logger.js";
18
+ import { createReplyInstructionsExtension } from "./lib/reply-instructions-extension.js";
18
19
  import { resolveModel } from "./lib/resolve-model.js";
19
20
  import { createSessionContextExtension } from "./lib/session-context-extension.js";
20
21
  import type {
@@ -123,11 +124,17 @@ export function createMind(options: {
123
124
  cwd: options.cwd,
124
125
  });
125
126
 
127
+ const replyInstructionsExtension = createReplyInstructionsExtension(session.messageChannels);
128
+
126
129
  const resourceLoader = new DefaultResourceLoader({
127
130
  cwd: options.cwd,
128
131
  settingsManager,
129
132
  systemPrompt: options.systemPrompt,
130
- extensionFactories: [preCompactExtension, sessionContextExtension],
133
+ extensionFactories: [
134
+ preCompactExtension,
135
+ sessionContextExtension,
136
+ replyInstructionsExtension,
137
+ ],
131
138
  });
132
139
  await resourceLoader.reload();
133
140
 
@@ -0,0 +1,30 @@
1
+ import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
2
+ import type { MessageChannelInfo } from "./auto-reply.js";
3
+
4
+ export function createReplyInstructionsExtension(
5
+ messageChannels: Map<string, MessageChannelInfo>,
6
+ ): ExtensionFactory {
7
+ return (pi) => {
8
+ let fired = false;
9
+ pi.on("before_agent_start", () => {
10
+ if (fired) return {};
11
+
12
+ const entry = messageChannels.values().next().value;
13
+ if (!entry?.channel) return {};
14
+
15
+ fired = true;
16
+
17
+ const content = entry.autoReply
18
+ ? `Auto-reply is enabled for this session — your text output will automatically be sent back to ${entry.channel}. To send to a different channel: volute send <channel> "message"`
19
+ : `To reply to this message, use: volute send ${entry.channel} "your message"`;
20
+
21
+ return {
22
+ message: {
23
+ customType: "reply-instructions",
24
+ content,
25
+ display: true,
26
+ },
27
+ };
28
+ });
29
+ };
30
+ }
File without changes