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.
- package/README.md +15 -22
- package/dist/{accept-E3PAH3QJ.js → accept-74M7I4RZ.js} +5 -4
- package/dist/{activity-events-BKBPPUBP.js → activity-events-HETAODOK.js} +3 -2
- package/dist/{ai-service-VAJT5UBS.js → ai-service-ZIPCV3MX.js} +20 -5
- package/dist/api.d.ts +341 -397
- package/dist/{archive-WWDBWYN2.js → archive-INXYFVCW.js} +3 -2
- package/dist/auth-6DMGES3I.js +44 -0
- package/dist/{bridge-RO37CUFM.js → bridge-BVCBTGPF.js} +5 -4
- package/dist/{chat-TCUNPFGO.js → chat-XT4OBJBU.js} +8 -8
- package/dist/{chunk-P7VFDSSG.js → chunk-2FLJ63GU.js} +2 -2
- package/dist/{chunk-ZWKTUQEL.js → chunk-2NGTS5UU.js} +1 -1
- package/dist/{chunk-JGFRDMR6.js → chunk-ALEF47VT.js} +1 -1
- package/dist/{chunk-MDPCSXZ4.js → chunk-D5G5YOPL.js} +163 -15
- package/dist/{chunk-VGWJSNHS.js → chunk-G53F3JA4.js} +1 -35
- package/dist/{chunk-A6TUJJ3L.js → chunk-G6BSYHPK.js} +2 -2
- package/dist/{chunk-DTC6EH5I.js → chunk-I5KY25PQ.js} +1 -9
- package/dist/{chunk-NSBFETWP.js → chunk-IYDIE3HG.js} +64 -26
- package/dist/{chunk-W5OOPLNP.js → chunk-JJ7W6WSB.js} +3 -3
- package/dist/{chunk-G3GBKZGG.js → chunk-LGB6JBHI.js} +54 -2
- package/dist/chunk-LRCG2JLP.js +251 -0
- package/dist/{chunk-FXHXHI2A.js → chunk-LSGWR54X.js} +3 -6
- package/dist/{chunk-S5LR3XYJ.js → chunk-M7UL5S3Q.js} +1 -1
- package/dist/chunk-PB65JZK2.js +85 -0
- package/dist/chunk-PVY5W6QN.js +41 -0
- package/dist/{chunk-QVAQ5454.js → chunk-QBQ424EM.js} +3007 -2126
- package/dist/{chunk-P27RV5WM.js → chunk-QZANELPX.js} +6 -2
- package/dist/{chunk-FSM45XD5.js → chunk-R7E6CRVQ.js} +1 -1
- package/dist/{chunk-HHTXM4JT.js → chunk-RPZZSXV3.js} +39 -195
- package/dist/{chunk-UPA6COHU.js → chunk-RSX4OPZY.js} +5 -5
- package/dist/{chunk-2C2VXEBB.js → chunk-S6NFERDC.js} +21 -57
- package/dist/chunk-SKLSMHXO.js +208 -0
- package/dist/{chunk-IKHDUZRH.js → chunk-SX5TKJBZ.js} +2 -2
- package/dist/chunk-TDRYEPH4.js +185 -0
- package/dist/chunk-TSXLLQZW.js +46 -0
- package/dist/{chunk-EFVHR7KH.js → chunk-UKVWJRKN.js} +24 -5
- package/dist/{chunk-2NDZC3S7.js → chunk-WKF5FEFK.js} +688 -389
- package/dist/cli.js +93 -24
- package/dist/{clock-G3ALCMLJ.js → clock-2UOZ6JPU.js} +11 -8
- package/dist/{cloud-sync-JV4LJOK3.js → cloud-sync-JN3NWKEM.js} +16 -14
- package/dist/config-H2H4UIF7.js +72 -0
- package/dist/connectors/discord-bridge.js +1 -1
- package/dist/connectors/slack-bridge.js +1 -1
- package/dist/connectors/telegram-bridge.js +1 -1
- package/dist/{conversations-7KVQV7EZ.js → conversations-3O5O6AS3.js} +8 -7
- package/dist/{create-JTLS7GX3.js → create-RNLNCORE.js} +5 -4
- package/dist/{create-VQSQHJQW.js → create-WBBYI6V7.js} +6 -2
- package/dist/daemon-client-6QXHZ7US.js +12 -0
- package/dist/{daemon-restart-4JGBHEJ4.js → daemon-restart-NGFHFAUF.js} +7 -7
- package/dist/daemon.js +2446 -1999
- package/dist/{db-HMFPIRO2.js → db-F34YLV7D.js} +2 -1
- package/dist/db-RA45JBFG.js +16 -0
- package/dist/{delete-JESHKE7F.js → delete-QTGWEDBI.js} +1 -1
- package/dist/delivery-manager-SDVXFD4W.js +28 -0
- package/dist/delivery-router-FL45JL7N.js +21 -0
- package/dist/down-TB3ESMNP.js +14 -0
- package/dist/{env-CLXXT7M2.js → env-RLYQBOOP.js} +5 -4
- package/dist/{export-EGA5M5PB.js → export-SUYRLI5Q.js} +4 -3
- package/dist/{extension-WZ4SUPJB.js → extension-FQ5D3NCC.js} +6 -6
- package/dist/{extensions-ECO4RPFQ.js → extensions-GDYWQXC4.js} +9 -7
- package/dist/{files-4VEJDASH.js → files-EAMPO2SJ.js} +6 -5
- package/dist/{history-EJMMLXDO.js → history-FO5PHBQ5.js} +9 -4
- package/dist/{import-YCGPMBSI.js → import-DDUFE7AY.js} +4 -3
- package/dist/{join-2GBJKZEN.js → join-I5QEE3LG.js} +1 -1
- package/dist/{list-Q6O7FGAN.js → list-DW2VRTOZ.js} +5 -4
- package/dist/{login-RL6AU2SM.js → login-7CHPW2PN.js} +5 -4
- package/dist/{login-RET5WESK.js → login-RIJF2F4G.js} +3 -2
- package/dist/{logout-CGAGJN3L.js → logout-5MLHZALK.js} +3 -2
- package/dist/{logout-JRPBEMMR.js → logout-UZJRGY4Z.js} +3 -2
- package/dist/message-delivery-2FIM7QKO.js +32 -0
- package/dist/{mind-LUWRQUQ5.js → mind-2B6M7Y25.js} +18 -18
- package/dist/{mind-activity-tracker-VYN2ZZ2M.js → mind-activity-tracker-NZZT2NTT.js} +4 -3
- package/dist/{mind-list-V5WW5DUA.js → mind-list-WUPMQDYQ.js} +3 -2
- package/dist/mind-manager-BNCMGYXW.js +28 -0
- package/dist/mind-service-AV273WT4.js +34 -0
- package/dist/{mind-sleep-R6PTNNW4.js → mind-sleep-B7BHJLH7.js} +5 -4
- package/dist/{mind-status-I4ISFJ6I.js → mind-status-L3EFFRPR.js} +3 -2
- package/dist/{mind-wake-67ZQEWAV.js → mind-wake-GY3RFX7Y.js} +5 -4
- package/dist/{package-OYUD4ZJ4.js → package-PK6JUFL3.js} +3 -3
- package/dist/read-5AMJRO3D.js +75 -0
- package/dist/{register-NZDSTLP3.js → register-V2JZZKFK.js} +5 -4
- package/dist/{registry-ODSALQQL.js → registry-PJ4S5PHQ.js} +8 -1
- package/dist/{reject-2HZOJEIJ.js → reject-33HEZMZ4.js} +5 -4
- package/dist/{restart-QHS3NT64.js → restart-3UCMRUVC.js} +5 -4
- package/dist/{sandbox-O5FUSF43.js → sandbox-JANNTX6U.js} +4 -3
- package/dist/schema-PA3M5ZKH.js +32 -0
- package/dist/seed-ALUQ55FF.js +112 -0
- package/dist/{send-OAN3RYYY.js → send-3MI36LEF.js} +58 -69
- package/dist/{setup-QMDK5RZX.js → setup-SZIARWI6.js} +5 -4
- package/dist/{setup-XJH3E7YM.js → setup-WENLVPVP.js} +9 -9
- package/dist/{skill-FZIN4W4Q.js → skill-TUVOTW4Z.js} +5 -4
- package/dist/skills/dreaming/SKILL.md +6 -4
- package/dist/skills/dreaming/references/INSTALL.md +4 -5
- package/dist/skills/dreaming/scripts/dream.ts +5 -27
- package/dist/skills/dreaming/scripts/wake-context-dreams.sh +1 -1
- package/dist/skills/imagegen/SKILL.md +6 -5
- package/dist/skills/imagegen/references/INSTALL.md +1 -1
- package/dist/skills/resonance/SKILL.md +4 -1
- package/dist/skills/resonance/references/INSTALL.md +2 -2
- package/dist/skills/resonance/scripts/resonance-hook.sh +2 -0
- package/dist/skills/resonance/scripts/resonance.ts +35 -5
- package/dist/skills/volute-admin/SKILL.md +83 -0
- package/dist/skills/volute-mind/SKILL.md +12 -12
- package/dist/skills-XNZK6P4K.js +61 -0
- package/dist/sleep-manager-53DZOWW7.js +32 -0
- package/dist/spirit-N4W4UQRH.js +217 -0
- package/dist/{split-EXYGGGQN.js → split-STOROBYJ.js} +1 -1
- package/dist/{sprout-AXQ6H5DB.js → sprout-L2GFOVF7.js} +9 -8
- package/dist/{start-MTOVL6SY.js → start-K2NCUUCG.js} +5 -4
- package/dist/{status-ZRO37MWR.js → status-TCUMUO6M.js} +5 -5
- package/dist/{stop-OK5WEPVC.js → stop-H26JZDXF.js} +5 -4
- package/dist/system-chat-NPYFYZVI.js +32 -0
- package/dist/{systems-W3BBMSOZ.js → systems-DHBKVYEY.js} +6 -5
- package/dist/{tailscale-BM72RXCJ.js → tailscale-XHQBZROW.js} +2 -1
- package/dist/{template-hash-3HOR4UAJ.js → template-hash-A6VVKOXJ.js} +2 -1
- package/dist/up-6I6BHRTO.js +17 -0
- package/dist/{update-PLPHMMZ2.js → update-QVPRF6GR.js} +5 -5
- package/dist/{update-check-CVCN7MF6.js → update-check-ZD6OOIYQ.js} +3 -2
- package/dist/{upgrade-I6NPCYUU.js → upgrade-O4Q7WJM3.js} +12 -14
- package/dist/{version-notify-2NTWVEHL.js → version-notify-TCKWBZZG.js} +22 -23
- package/dist/web-assets/assets/index-Bui7U9Uu.css +1 -0
- package/dist/web-assets/assets/index-e36DIo1b.js +73 -0
- package/dist/web-assets/ext-theme.css +94 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0000_baseline.sql +152 -0
- package/drizzle/0001_add_conversation_private.sql +1 -0
- package/drizzle/0002_turns.sql +21 -0
- package/drizzle/0003_turn_feed_links.sql +11 -0
- package/drizzle/0004_spirits.sql +5 -0
- package/drizzle/meta/0000_snapshot.json +3 -223
- package/drizzle/meta/0001_snapshot.json +3 -294
- package/drizzle/meta/0002_snapshot.json +3 -335
- package/drizzle/meta/0003_snapshot.json +3 -413
- package/drizzle/meta/0004_snapshot.json +3 -406
- package/drizzle/meta/_journal.json +10 -101
- package/package.json +3 -3
- package/packages/extensions/notes/dist/ui/assets/index-8jWEv9SA.js +61 -0
- package/packages/extensions/notes/dist/ui/assets/index-DkaB7Ytd.css +1 -0
- package/packages/extensions/notes/dist/ui/index.html +2 -2
- package/packages/extensions/notes/skills/notes/SKILL.md +8 -8
- package/packages/extensions/pages/skills/pages/SKILL.md +17 -44
- package/templates/_base/.init/.config/hooks/pre-prompt/session-activity.ts +40 -0
- package/templates/_base/.init/.local/bin/volute +27 -0
- package/templates/_base/.init/.local/hooks/pre-prompt/session-activity.ts +40 -0
- package/templates/_base/.init/.local/hooks/startup-context.ts +58 -0
- package/templates/_base/home/.config/routes.json +1 -1
- package/templates/_base/src/lib/auto-commit.ts +82 -43
- package/templates/_base/src/lib/daemon-client.ts +40 -36
- package/templates/_base/src/lib/format-prefix.ts +1 -0
- package/templates/_base/src/lib/hook-loader.ts +155 -0
- package/templates/_base/src/lib/router.ts +17 -1
- package/templates/_base/src/lib/startup.ts +17 -12
- package/templates/_base/src/lib/transparency.ts +2 -2
- package/templates/_base/src/lib/volute-server.ts +2 -5
- package/templates/claude/.init/.claude/settings.json +1 -1
- package/templates/claude/.init/.config/routes.json +2 -2
- package/templates/claude/src/agent.ts +97 -14
- package/templates/claude/src/lib/hooks/auto-commit.ts +7 -3
- package/templates/claude/src/lib/message-channel.ts +7 -2
- package/templates/claude/src/server.ts +0 -9
- package/templates/codex/.init/.config/routes.json +11 -0
- package/templates/codex/.init/AGENTS.md +29 -0
- package/templates/codex/home/.config/config.json.tmpl +7 -0
- package/templates/codex/package.json.tmpl +20 -0
- package/templates/codex/src/agent.ts +553 -0
- package/templates/codex/src/lib/content.ts +16 -0
- package/templates/codex/src/lib/session-store.ts +56 -0
- package/templates/codex/src/server.ts +59 -0
- package/templates/codex/volute-template.json +8 -0
- package/templates/pi/.init/.config/routes.json +2 -2
- package/templates/pi/package.json.tmpl +1 -1
- package/templates/pi/src/agent.ts +63 -9
- package/templates/pi/src/lib/event-handler.ts +6 -4
- package/templates/pi/src/lib/reply-instructions-extension.ts +32 -11
- package/dist/chunk-7D47T4RB.js +0 -84
- package/dist/chunk-CVH6Y2YG.js +0 -59
- package/dist/chunk-EFP3PE6C.js +0 -232
- package/dist/chunk-LIRWLNAK.js +0 -729
- package/dist/daemon-client-BCTFGVCZ.js +0 -9
- package/dist/down-NGBMGORS.js +0 -14
- package/dist/message-delivery-6YMVNOEC.js +0 -28
- package/dist/migrate-registry-to-db-FK35IPEH.js +0 -110
- package/dist/mind-manager-YFCOIAAX.js +0 -18
- package/dist/pages-watcher-Z3PKNROC.js +0 -21
- package/dist/read-WQMPTSN2.js +0 -46
- package/dist/seed-WUQMPLDM.js +0 -71
- package/dist/skills/sessions/SKILL.md +0 -49
- package/dist/sleep-manager-O7YQFCV5.js +0 -30
- package/dist/up-BXUAIDXB.js +0 -17
- package/dist/web-assets/assets/index--kREqKl9.js +0 -72
- package/dist/web-assets/assets/index-BXYTG0nJ.css +0 -1
- package/drizzle/0000_flaky_mariko_yashida.sql +0 -34
- package/drizzle/0001_careless_warpath.sql +0 -12
- package/drizzle/0002_wealthy_the_call.sql +0 -6
- package/drizzle/0003_clean_ego.sql +0 -12
- package/drizzle/0004_magical_silverclaw.sql +0 -1
- package/drizzle/0005_rename_agents_to_minds.sql +0 -11
- package/drizzle/0006_mind_history.sql +0 -20
- package/drizzle/0007_system_prompts.sql +0 -5
- package/drizzle/0008_volute_channels.sql +0 -24
- package/drizzle/0009_shared_skills.sql +0 -9
- package/drizzle/0010_delivery_queue.sql +0 -12
- package/drizzle/0011_rename_human_to_brain.sql +0 -1
- package/drizzle/0012_activity.sql +0 -11
- package/drizzle/0013_user_profiles.sql +0 -3
- package/drizzle/0014_conversation_reads.sql +0 -7
- package/drizzle/0015_notes.sql +0 -23
- package/drizzle/0016_note_reactions_and_replies.sql +0 -15
- package/drizzle/0017_minds.sql +0 -16
- package/drizzle/meta/0005_snapshot.json +0 -410
- package/drizzle/meta/0006_snapshot.json +0 -7
- package/drizzle/meta/0007_snapshot.json +0 -7
- package/drizzle/meta/0008_snapshot.json +0 -7
- package/drizzle/meta/0009_snapshot.json +0 -7
- package/drizzle/meta/0010_snapshot.json +0 -7
- package/drizzle/meta/0011_snapshot.json +0 -7
- package/drizzle/meta/0012_snapshot.json +0 -7
- package/drizzle/meta/0013_snapshot.json +0 -7
- package/packages/extensions/notes/dist/ui/assets/index-DgawVO5g.css +0 -1
- package/packages/extensions/notes/dist/ui/assets/index-qUWoeC4c.js +0 -2
- package/packages/extensions/notes/skills/notes/scripts/notes.mjs +0 -185
- package/templates/_base/.init/.config/hooks/startup-context.sh +0 -46
- package/templates/_base/.init/.config/scripts/session-reader.ts +0 -59
- package/templates/_base/home/public/.gitkeep +0 -0
- package/templates/_base/src/lib/session-monitor.ts +0 -400
- package/templates/claude/src/lib/hooks/session-context.ts +0 -32
- package/templates/pi/src/lib/session-context-extension.ts +0 -35
- /package/templates/_base/.init/{.config → .local}/hooks/wake-context.sh +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"gateUnmatched": true,
|
|
3
3
|
"rules": [
|
|
4
|
-
{ "channel": "
|
|
5
|
-
{ "channel": "
|
|
4
|
+
{ "channel": "*", "isDM": true, "session": "${channel}" },
|
|
5
|
+
{ "channel": "*", "isDM": false, "session": "group-${channel}" }
|
|
6
6
|
],
|
|
7
7
|
"sessions": {
|
|
8
8
|
"group-*": { "batch": { "debounce": 20, "maxWait": 120, "triggers": ["@{{name}}"] } }
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
SettingsManager,
|
|
11
11
|
} from "@mariozechner/pi-coding-agent";
|
|
12
12
|
import { extractImages, extractText } from "./lib/content.js";
|
|
13
|
-
import { createEventHandler } from "./lib/event-handler.js";
|
|
13
|
+
import { createEventHandler, emit } from "./lib/event-handler.js";
|
|
14
|
+
import { runHooks } from "./lib/hook-loader.js";
|
|
14
15
|
import { log } from "./lib/logger.js";
|
|
15
16
|
import { createReplyInstructionsExtension } from "./lib/reply-instructions-extension.js";
|
|
16
17
|
import { resolveModel } from "./lib/resolve-model.js";
|
|
17
|
-
import { createSessionContextExtension } from "./lib/session-context-extension.js";
|
|
18
18
|
import { loadPrompts, type SubagentConfig } from "./lib/startup.js";
|
|
19
19
|
import { createSubagentExtension, type SubagentDefinition } from "./lib/subagents.js";
|
|
20
20
|
import type {
|
|
@@ -64,7 +64,7 @@ export function createMind(options: {
|
|
|
64
64
|
// Shared setup (created once)
|
|
65
65
|
const modelStr = options.model || process.env.PI_MODEL || "anthropic:claude-sonnet-4-20250514";
|
|
66
66
|
const model = resolveModel(modelStr);
|
|
67
|
-
const authStorage =
|
|
67
|
+
const authStorage = AuthStorage.create();
|
|
68
68
|
const modelRegistry = new ModelRegistry(authStorage);
|
|
69
69
|
|
|
70
70
|
// --- Subagents (config-driven) ---
|
|
@@ -109,6 +109,59 @@ export function createMind(options: {
|
|
|
109
109
|
? createSubagentExtension(subagents, { cwd: options.cwd, model, authStorage, modelRegistry })
|
|
110
110
|
: undefined;
|
|
111
111
|
|
|
112
|
+
// --- Dynamic hook extension ---
|
|
113
|
+
|
|
114
|
+
const hooksDir = resolvePath(options.cwd, ".local/hooks");
|
|
115
|
+
|
|
116
|
+
function createDynamicHookExtension(session: PiSession): ExtensionFactory {
|
|
117
|
+
return (pi) => {
|
|
118
|
+
pi.on("before_agent_start", async () => {
|
|
119
|
+
try {
|
|
120
|
+
const result = await runHooks(hooksDir, "pre-prompt", {
|
|
121
|
+
event: "pre-prompt",
|
|
122
|
+
session: session.name,
|
|
123
|
+
});
|
|
124
|
+
if (result.additionalContext) {
|
|
125
|
+
emit(session, {
|
|
126
|
+
type: "context",
|
|
127
|
+
content: result.additionalContext,
|
|
128
|
+
metadata: { source: "dynamic:pre-prompt", ...result.metadata },
|
|
129
|
+
});
|
|
130
|
+
return {
|
|
131
|
+
message: {
|
|
132
|
+
customType: "dynamic-hook",
|
|
133
|
+
content: result.additionalContext,
|
|
134
|
+
display: true,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
} catch (err) {
|
|
139
|
+
log("mind", "dynamic pre-prompt hook failed:", err);
|
|
140
|
+
}
|
|
141
|
+
return {};
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
pi.on("tool_execution_end", async (event: any) => {
|
|
145
|
+
try {
|
|
146
|
+
const result = await runHooks(hooksDir, "post-tool-use", {
|
|
147
|
+
event: "post-tool-use",
|
|
148
|
+
tool_name: event.toolName,
|
|
149
|
+
tool_input: event.args,
|
|
150
|
+
});
|
|
151
|
+
if (result.additionalContext) {
|
|
152
|
+
emit(session, {
|
|
153
|
+
type: "context",
|
|
154
|
+
content: result.additionalContext,
|
|
155
|
+
metadata: { source: "dynamic:post-tool-use", ...result.metadata },
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
} catch (err) {
|
|
159
|
+
log("mind", "dynamic post-tool-use hook failed:", err);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
112
165
|
// --- Session lifecycle ---
|
|
113
166
|
|
|
114
167
|
function getOrCreateSession(name: string): PiSession {
|
|
@@ -189,12 +242,13 @@ export function createMind(options: {
|
|
|
189
242
|
retry: { enabled: true, maxRetries: 3 },
|
|
190
243
|
});
|
|
191
244
|
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
245
|
+
const replyInstructionsExtension = createReplyInstructionsExtension(
|
|
246
|
+
session.messageChannels,
|
|
247
|
+
emit,
|
|
248
|
+
session,
|
|
249
|
+
);
|
|
196
250
|
|
|
197
|
-
const
|
|
251
|
+
const dynamicHookExtension = createDynamicHookExtension(session);
|
|
198
252
|
|
|
199
253
|
const resourceLoader = new DefaultResourceLoader({
|
|
200
254
|
cwd: options.cwd,
|
|
@@ -202,9 +256,9 @@ export function createMind(options: {
|
|
|
202
256
|
systemPrompt: options.systemPrompt,
|
|
203
257
|
extensionFactories: [
|
|
204
258
|
preCompactExtension,
|
|
205
|
-
sessionContextExtension,
|
|
206
259
|
replyInstructionsExtension,
|
|
207
260
|
...(subagentExtension ? [subagentExtension] : []),
|
|
261
|
+
dynamicHookExtension,
|
|
208
262
|
],
|
|
209
263
|
});
|
|
210
264
|
await resourceLoader.reload();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { flushFileChanges, trackFileChange } from "./auto-commit.js";
|
|
2
2
|
import { daemonEmit, type EventType } from "./daemon-client.js";
|
|
3
3
|
import { log, warn } from "./logger.js";
|
|
4
4
|
import { filterEvent, loadTransparencyPreset } from "./transparency.js";
|
|
@@ -21,7 +21,7 @@ export type EventHandlerOptions = {
|
|
|
21
21
|
// Loaded once at startup — mind restarts on config changes
|
|
22
22
|
const preset = loadTransparencyPreset();
|
|
23
23
|
|
|
24
|
-
function emit(
|
|
24
|
+
export function emit(
|
|
25
25
|
session: EventSession,
|
|
26
26
|
event: { type: EventType; content?: string; metadata?: Record<string, unknown> },
|
|
27
27
|
) {
|
|
@@ -110,7 +110,7 @@ export function createEventHandler(session: EventSession, options: EventHandlerO
|
|
|
110
110
|
const args = toolArgs.get(event.toolCallId);
|
|
111
111
|
const filePath = (args as { path?: string })?.path;
|
|
112
112
|
if (filePath) {
|
|
113
|
-
|
|
113
|
+
trackFileChange(filePath, options.cwd);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
toolArgs.delete(event.toolCallId);
|
|
@@ -158,7 +158,9 @@ export function createEventHandler(session: EventSession, options: EventHandlerO
|
|
|
158
158
|
options.broadcast({ type: "done" });
|
|
159
159
|
emit(session, { type: "done" });
|
|
160
160
|
session.currentMessageId = undefined;
|
|
161
|
-
options.
|
|
161
|
+
flushFileChanges(options.cwd)
|
|
162
|
+
.then(() => options.onTurnEnd?.())
|
|
163
|
+
.catch((err) => log("mind", `session "${session.name}": flush/turn-end error:`, err));
|
|
162
164
|
}
|
|
163
165
|
} catch (err) {
|
|
164
166
|
log("mind", `session "${session.name}": event handler error (${event?.type}):`, err);
|
|
@@ -1,27 +1,48 @@
|
|
|
1
1
|
import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import type { EventSession } from "./event-handler.js";
|
|
3
|
+
import { log } from "./logger.js";
|
|
2
4
|
import { loadPrompts } from "./startup.js";
|
|
3
5
|
|
|
4
6
|
export function createReplyInstructionsExtension(
|
|
5
7
|
messageChannels: Map<string, string>,
|
|
8
|
+
emitContext?: (
|
|
9
|
+
session: EventSession,
|
|
10
|
+
event: { type: "context"; content: string; metadata: Record<string, unknown> },
|
|
11
|
+
) => void,
|
|
12
|
+
session?: EventSession,
|
|
6
13
|
): ExtensionFactory {
|
|
7
14
|
const prompts = loadPrompts();
|
|
8
15
|
return (pi) => {
|
|
9
16
|
let fired = false;
|
|
10
17
|
pi.on("before_agent_start", () => {
|
|
11
|
-
|
|
18
|
+
try {
|
|
19
|
+
if (fired) return {};
|
|
12
20
|
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
const channel = messageChannels.values().next().value;
|
|
22
|
+
if (!channel) return {};
|
|
15
23
|
|
|
16
|
-
|
|
24
|
+
fired = true;
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
const content = prompts.reply_instructions.replace(/\$\{channel\}/g, channel);
|
|
27
|
+
if (emitContext && session) {
|
|
28
|
+
emitContext(session, {
|
|
29
|
+
type: "context",
|
|
30
|
+
content,
|
|
31
|
+
metadata: { source: "reply-instructions" },
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
message: {
|
|
37
|
+
customType: "reply-instructions",
|
|
38
|
+
content,
|
|
39
|
+
display: true,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
} catch (err) {
|
|
43
|
+
log("mind", "reply instructions extension failed:", err);
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
25
46
|
});
|
|
26
47
|
};
|
|
27
48
|
}
|
package/dist/chunk-7D47T4RB.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
voluteHome,
|
|
4
|
-
voluteSystemDir
|
|
5
|
-
} from "./chunk-HHTXM4JT.js";
|
|
6
|
-
|
|
7
|
-
// src/lib/setup.ts
|
|
8
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
9
|
-
import { resolve } from "path";
|
|
10
|
-
function configPath() {
|
|
11
|
-
return resolve(voluteSystemDir(), "config.json");
|
|
12
|
-
}
|
|
13
|
-
function readGlobalConfig() {
|
|
14
|
-
const path = configPath();
|
|
15
|
-
const legacyPath = resolve(voluteHome(), "config.json");
|
|
16
|
-
const effectivePath = existsSync(path) ? path : legacyPath;
|
|
17
|
-
if (!existsSync(effectivePath)) return {};
|
|
18
|
-
try {
|
|
19
|
-
return JSON.parse(readFileSync(effectivePath, "utf-8"));
|
|
20
|
-
} catch (err) {
|
|
21
|
-
console.error(`Failed to parse ${effectivePath}: ${err instanceof Error ? err.message : err}`);
|
|
22
|
-
return {};
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
function writeGlobalConfig(config) {
|
|
26
|
-
const path = configPath();
|
|
27
|
-
mkdirSync(voluteSystemDir(), { recursive: true });
|
|
28
|
-
writeFileSync(path, `${JSON.stringify(config, null, 2)}
|
|
29
|
-
`);
|
|
30
|
-
}
|
|
31
|
-
function isSetupComplete() {
|
|
32
|
-
const config = readGlobalConfig();
|
|
33
|
-
return config.setup != null;
|
|
34
|
-
}
|
|
35
|
-
function migrateSetupConfig() {
|
|
36
|
-
const config = readGlobalConfig();
|
|
37
|
-
if (config.setup) return;
|
|
38
|
-
const home = voluteHome();
|
|
39
|
-
const systemDir = voluteSystemDir();
|
|
40
|
-
const registryPath = resolve(systemDir, "minds.json");
|
|
41
|
-
const legacyRegistryPath = resolve(home, "minds.json");
|
|
42
|
-
if (!existsSync(registryPath) && !existsSync(legacyRegistryPath)) return;
|
|
43
|
-
const isSystem = process.env.VOLUTE_ISOLATION === "user";
|
|
44
|
-
const mindsDir = process.env.VOLUTE_MINDS_DIR || resolve(home, "minds");
|
|
45
|
-
let hasService = false;
|
|
46
|
-
try {
|
|
47
|
-
if (process.platform === "darwin") {
|
|
48
|
-
const plistPath = resolve(
|
|
49
|
-
process.env.HOME || "",
|
|
50
|
-
"Library",
|
|
51
|
-
"LaunchAgents",
|
|
52
|
-
"com.volute.daemon.plist"
|
|
53
|
-
);
|
|
54
|
-
if (existsSync(plistPath)) hasService = true;
|
|
55
|
-
}
|
|
56
|
-
if (process.platform === "linux") {
|
|
57
|
-
if (existsSync("/etc/systemd/system/volute.service")) hasService = true;
|
|
58
|
-
const userUnit = resolve(
|
|
59
|
-
process.env.HOME || "",
|
|
60
|
-
".config",
|
|
61
|
-
"systemd",
|
|
62
|
-
"user",
|
|
63
|
-
"volute.service"
|
|
64
|
-
);
|
|
65
|
-
if (existsSync(userUnit)) hasService = true;
|
|
66
|
-
}
|
|
67
|
-
} catch {
|
|
68
|
-
}
|
|
69
|
-
const setup = {
|
|
70
|
-
type: isSystem ? "system" : "local",
|
|
71
|
-
isolation: isSystem ? "user" : "none",
|
|
72
|
-
mindsDir,
|
|
73
|
-
service: hasService
|
|
74
|
-
};
|
|
75
|
-
writeGlobalConfig({ ...config, setup });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export {
|
|
79
|
-
configPath,
|
|
80
|
-
readGlobalConfig,
|
|
81
|
-
writeGlobalConfig,
|
|
82
|
-
isSetupComplete,
|
|
83
|
-
migrateSetupConfig
|
|
84
|
-
};
|
package/dist/chunk-CVH6Y2YG.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
wrapForIsolation
|
|
4
|
-
} from "./chunk-G3GBKZGG.js";
|
|
5
|
-
|
|
6
|
-
// src/lib/exec.ts
|
|
7
|
-
import { execFile as execFileCb, execFileSync, spawn } from "child_process";
|
|
8
|
-
async function exec(cmd, args, options) {
|
|
9
|
-
const [wrappedCmd, wrappedArgs] = options?.mindName ? await wrapForIsolation(cmd, args, options.mindName) : [cmd, args];
|
|
10
|
-
return new Promise((resolve, reject) => {
|
|
11
|
-
execFileCb(
|
|
12
|
-
wrappedCmd,
|
|
13
|
-
wrappedArgs,
|
|
14
|
-
{ cwd: options?.cwd, env: options?.env },
|
|
15
|
-
(err, stdout, stderr) => {
|
|
16
|
-
if (err) {
|
|
17
|
-
err.stderr = stderr;
|
|
18
|
-
err.stdout = stdout;
|
|
19
|
-
reject(err);
|
|
20
|
-
} else {
|
|
21
|
-
resolve(stdout);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
);
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
function gitExec(args, options) {
|
|
28
|
-
const fullArgs = process.env.VOLUTE_ISOLATION === "user" ? ["-c", "safe.directory=*", ...args] : args;
|
|
29
|
-
return exec("git", fullArgs, options);
|
|
30
|
-
}
|
|
31
|
-
function resolveVoluteBin() {
|
|
32
|
-
try {
|
|
33
|
-
return execFileSync("which", ["volute"], { encoding: "utf-8" }).trim();
|
|
34
|
-
} catch {
|
|
35
|
-
throw new Error("Could not find volute binary on PATH");
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
async function execInherit(cmd, args, options) {
|
|
39
|
-
const [wrappedCmd, wrappedArgs] = options?.mindName ? await wrapForIsolation(cmd, args, options.mindName) : [cmd, args];
|
|
40
|
-
return new Promise((resolve, reject) => {
|
|
41
|
-
const child = spawn(wrappedCmd, wrappedArgs, {
|
|
42
|
-
cwd: options?.cwd,
|
|
43
|
-
env: options?.env,
|
|
44
|
-
stdio: "inherit"
|
|
45
|
-
});
|
|
46
|
-
child.on("error", reject);
|
|
47
|
-
child.on("close", (code) => {
|
|
48
|
-
if (code === 0) resolve();
|
|
49
|
-
else reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code}`));
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export {
|
|
55
|
-
exec,
|
|
56
|
-
gitExec,
|
|
57
|
-
resolveVoluteBin,
|
|
58
|
-
execInherit
|
|
59
|
-
};
|
package/dist/chunk-EFP3PE6C.js
DELETED
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
publish
|
|
4
|
-
} from "./chunk-P27RV5WM.js";
|
|
5
|
-
import {
|
|
6
|
-
logger_default
|
|
7
|
-
} from "./chunk-YUIHSKR6.js";
|
|
8
|
-
import {
|
|
9
|
-
mindDir,
|
|
10
|
-
readRegistry,
|
|
11
|
-
voluteHome
|
|
12
|
-
} from "./chunk-HHTXM4JT.js";
|
|
13
|
-
|
|
14
|
-
// src/lib/pages-watcher.ts
|
|
15
|
-
import { existsSync, readdirSync, statSync, watch } from "fs";
|
|
16
|
-
import { join, resolve } from "path";
|
|
17
|
-
var watchers = /* @__PURE__ */ new Map();
|
|
18
|
-
var homeWatchers = /* @__PURE__ */ new Map();
|
|
19
|
-
var debounceTimers = /* @__PURE__ */ new Map();
|
|
20
|
-
var sitesCache = null;
|
|
21
|
-
var recentPagesCache = null;
|
|
22
|
-
function startPagesWatcher(mindName, pagesDir) {
|
|
23
|
-
try {
|
|
24
|
-
const watcher = watch(pagesDir, { recursive: true }, (_eventType, filename) => {
|
|
25
|
-
if (!filename || !filename.endsWith(".html")) return;
|
|
26
|
-
const key = `${mindName}:${filename}`;
|
|
27
|
-
const existing = debounceTimers.get(key);
|
|
28
|
-
if (existing) clearTimeout(existing);
|
|
29
|
-
debounceTimers.set(
|
|
30
|
-
key,
|
|
31
|
-
setTimeout(() => {
|
|
32
|
-
debounceTimers.delete(key);
|
|
33
|
-
invalidateCache();
|
|
34
|
-
publish({
|
|
35
|
-
type: "page_updated",
|
|
36
|
-
mind: mindName,
|
|
37
|
-
summary: `${mindName} updated ${filename}`,
|
|
38
|
-
metadata: { file: filename }
|
|
39
|
-
}).catch(
|
|
40
|
-
(err) => logger_default.error("failed to publish page_updated activity", logger_default.errorData(err))
|
|
41
|
-
);
|
|
42
|
-
}, 100)
|
|
43
|
-
);
|
|
44
|
-
});
|
|
45
|
-
watchers.set(mindName, watcher);
|
|
46
|
-
} catch (err) {
|
|
47
|
-
logger_default.warn(`failed to start pages watcher for ${mindName}`, logger_default.errorData(err));
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
function startSystemWatcher() {
|
|
51
|
-
if (watchers.has("_system")) return;
|
|
52
|
-
const systemPagesDir = resolve(voluteHome(), "shared", "pages");
|
|
53
|
-
if (!existsSync(systemPagesDir)) return;
|
|
54
|
-
startPagesWatcher("_system", systemPagesDir);
|
|
55
|
-
}
|
|
56
|
-
function startWatcher(mindName) {
|
|
57
|
-
if (watchers.has(mindName)) return;
|
|
58
|
-
const pagesDir = resolve(mindDir(mindName), "home", "public", "pages");
|
|
59
|
-
if (existsSync(pagesDir)) {
|
|
60
|
-
startPagesWatcher(mindName, pagesDir);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (homeWatchers.has(mindName)) return;
|
|
64
|
-
const publicDir = resolve(mindDir(mindName), "home", "public");
|
|
65
|
-
if (!existsSync(publicDir)) return;
|
|
66
|
-
try {
|
|
67
|
-
const hw = watch(publicDir, (_eventType, filename) => {
|
|
68
|
-
if (filename !== "pages") return;
|
|
69
|
-
if (!existsSync(pagesDir)) return;
|
|
70
|
-
hw.close();
|
|
71
|
-
homeWatchers.delete(mindName);
|
|
72
|
-
invalidateCache();
|
|
73
|
-
startPagesWatcher(mindName, pagesDir);
|
|
74
|
-
});
|
|
75
|
-
homeWatchers.set(mindName, hw);
|
|
76
|
-
} catch (err) {
|
|
77
|
-
logger_default.warn(`failed to start home watcher for ${mindName}`, logger_default.errorData(err));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function stopWatcher(mindName) {
|
|
81
|
-
const watcher = watchers.get(mindName);
|
|
82
|
-
if (watcher) {
|
|
83
|
-
watcher.close();
|
|
84
|
-
watchers.delete(mindName);
|
|
85
|
-
}
|
|
86
|
-
const hw = homeWatchers.get(mindName);
|
|
87
|
-
if (hw) {
|
|
88
|
-
hw.close();
|
|
89
|
-
homeWatchers.delete(mindName);
|
|
90
|
-
}
|
|
91
|
-
for (const [key, timer] of debounceTimers) {
|
|
92
|
-
if (key.startsWith(`${mindName}:`)) {
|
|
93
|
-
clearTimeout(timer);
|
|
94
|
-
debounceTimers.delete(key);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
function stopAllWatchers() {
|
|
99
|
-
for (const [, watcher] of watchers) {
|
|
100
|
-
watcher.close();
|
|
101
|
-
}
|
|
102
|
-
watchers.clear();
|
|
103
|
-
for (const [, hw] of homeWatchers) {
|
|
104
|
-
hw.close();
|
|
105
|
-
}
|
|
106
|
-
homeWatchers.clear();
|
|
107
|
-
for (const [, timer] of debounceTimers) {
|
|
108
|
-
clearTimeout(timer);
|
|
109
|
-
}
|
|
110
|
-
debounceTimers.clear();
|
|
111
|
-
invalidateCache();
|
|
112
|
-
}
|
|
113
|
-
function invalidateCache() {
|
|
114
|
-
sitesCache = null;
|
|
115
|
-
recentPagesCache = null;
|
|
116
|
-
}
|
|
117
|
-
function scanPagesDir(dir, urlPrefix) {
|
|
118
|
-
const pages = [];
|
|
119
|
-
let items;
|
|
120
|
-
try {
|
|
121
|
-
items = readdirSync(dir);
|
|
122
|
-
} catch {
|
|
123
|
-
return pages;
|
|
124
|
-
}
|
|
125
|
-
for (const item of items) {
|
|
126
|
-
if (item.startsWith(".")) continue;
|
|
127
|
-
const fullPath = resolve(dir, item);
|
|
128
|
-
try {
|
|
129
|
-
const s = statSync(fullPath);
|
|
130
|
-
if (s.isFile() && item.endsWith(".html")) {
|
|
131
|
-
pages.push({
|
|
132
|
-
file: item,
|
|
133
|
-
modified: s.mtime.toISOString(),
|
|
134
|
-
url: `${urlPrefix}/${item}`
|
|
135
|
-
});
|
|
136
|
-
} else if (s.isDirectory()) {
|
|
137
|
-
const indexPath = resolve(fullPath, "index.html");
|
|
138
|
-
if (existsSync(indexPath)) {
|
|
139
|
-
const indexStat = statSync(indexPath);
|
|
140
|
-
pages.push({
|
|
141
|
-
file: join(item, "index.html"),
|
|
142
|
-
modified: indexStat.mtime.toISOString(),
|
|
143
|
-
url: `${urlPrefix}/${item}/`
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
} catch {
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
pages.sort((a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime());
|
|
151
|
-
return pages;
|
|
152
|
-
}
|
|
153
|
-
async function buildSites() {
|
|
154
|
-
const sites = [];
|
|
155
|
-
const systemPagesDir = resolve(voluteHome(), "shared", "pages");
|
|
156
|
-
if (existsSync(systemPagesDir)) {
|
|
157
|
-
const systemPages = scanPagesDir(systemPagesDir, "/pages/_system");
|
|
158
|
-
if (systemPages.length > 0) {
|
|
159
|
-
sites.push({ name: "_system", label: "System", pages: systemPages });
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
const entries = await readRegistry();
|
|
163
|
-
for (const entry of [...entries].sort((a, b) => a.name.localeCompare(b.name))) {
|
|
164
|
-
const pagesDir = resolve(mindDir(entry.name), "home", "public", "pages");
|
|
165
|
-
if (!existsSync(pagesDir)) continue;
|
|
166
|
-
const mindPages = scanPagesDir(pagesDir, `/minds/${entry.name}/pages`);
|
|
167
|
-
if (mindPages.length > 0) {
|
|
168
|
-
sites.push({ name: entry.name, label: entry.name, pages: mindPages });
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return sites;
|
|
172
|
-
}
|
|
173
|
-
async function buildRecentPages() {
|
|
174
|
-
const entries = await readRegistry();
|
|
175
|
-
const pages = [];
|
|
176
|
-
for (const entry of entries) {
|
|
177
|
-
const pagesDir = resolve(mindDir(entry.name), "home", "public", "pages");
|
|
178
|
-
if (!existsSync(pagesDir)) continue;
|
|
179
|
-
let items;
|
|
180
|
-
try {
|
|
181
|
-
items = readdirSync(pagesDir);
|
|
182
|
-
} catch {
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
for (const item of items) {
|
|
186
|
-
if (item.startsWith(".")) continue;
|
|
187
|
-
const fullPath = resolve(pagesDir, item);
|
|
188
|
-
try {
|
|
189
|
-
const s = statSync(fullPath);
|
|
190
|
-
if (s.isFile() && item.endsWith(".html")) {
|
|
191
|
-
pages.push({
|
|
192
|
-
mind: entry.name,
|
|
193
|
-
file: item,
|
|
194
|
-
modified: s.mtime.toISOString(),
|
|
195
|
-
url: `/minds/${entry.name}/pages/${item}`
|
|
196
|
-
});
|
|
197
|
-
} else if (s.isDirectory()) {
|
|
198
|
-
const indexPath = resolve(fullPath, "index.html");
|
|
199
|
-
if (existsSync(indexPath)) {
|
|
200
|
-
const indexStat = statSync(indexPath);
|
|
201
|
-
pages.push({
|
|
202
|
-
mind: entry.name,
|
|
203
|
-
file: join(item, "index.html"),
|
|
204
|
-
modified: indexStat.mtime.toISOString(),
|
|
205
|
-
url: `/minds/${entry.name}/pages/${item}/`
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
} catch {
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
pages.sort((a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime());
|
|
214
|
-
return pages.slice(0, 10);
|
|
215
|
-
}
|
|
216
|
-
async function getCachedSites() {
|
|
217
|
-
if (!sitesCache) sitesCache = await buildSites();
|
|
218
|
-
return sitesCache;
|
|
219
|
-
}
|
|
220
|
-
async function getCachedRecentPages() {
|
|
221
|
-
if (!recentPagesCache) recentPagesCache = await buildRecentPages();
|
|
222
|
-
return recentPagesCache;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export {
|
|
226
|
-
startSystemWatcher,
|
|
227
|
-
startWatcher,
|
|
228
|
-
stopWatcher,
|
|
229
|
-
stopAllWatchers,
|
|
230
|
-
getCachedSites,
|
|
231
|
-
getCachedRecentPages
|
|
232
|
-
};
|