mono-pilot 0.2.9 → 0.2.12
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 +270 -7
- package/dist/src/agents-paths.js +36 -0
- package/dist/src/brief/blocks.js +83 -0
- package/dist/src/brief/defaults.js +60 -0
- package/dist/src/brief/frontmatter.js +53 -0
- package/dist/src/brief/paths.js +10 -0
- package/dist/src/brief/reflection.js +27 -0
- package/dist/src/cli.js +62 -5
- package/dist/src/cluster/bus.js +102 -0
- package/dist/src/cluster/follower.js +137 -0
- package/dist/src/cluster/init.js +182 -0
- package/dist/src/cluster/leader.js +97 -0
- package/dist/src/cluster/log.js +49 -0
- package/dist/src/cluster/protocol.js +34 -0
- package/dist/src/cluster/services/bus.js +243 -0
- package/dist/src/cluster/services/embedding.js +12 -0
- package/dist/src/cluster/socket.js +86 -0
- package/dist/src/cluster/test-bus.js +175 -0
- package/dist/src/cluster_v2/connection-lifecycle.js +31 -0
- package/dist/src/cluster_v2/connection-lifecycle.test.js +24 -0
- package/dist/src/cluster_v2/connection.js +159 -0
- package/dist/src/cluster_v2/connection.test.js +55 -0
- package/dist/src/cluster_v2/events.js +102 -0
- package/dist/src/cluster_v2/index.js +2 -0
- package/dist/src/cluster_v2/observability.js +99 -0
- package/dist/src/cluster_v2/observability.test.js +46 -0
- package/dist/src/cluster_v2/rpc.js +389 -0
- package/dist/src/cluster_v2/rpc.test.js +110 -0
- package/dist/src/cluster_v2/runtime.failover.integration.test.js +156 -0
- package/dist/src/cluster_v2/runtime.js +531 -0
- package/dist/src/cluster_v2/runtime.lease-compromise.integration.test.js +91 -0
- package/dist/src/cluster_v2/runtime.lifecycle.integration.test.js +225 -0
- package/dist/src/cluster_v2/services/bus.integration.test.js +140 -0
- package/dist/src/cluster_v2/services/bus.js +450 -0
- package/dist/src/cluster_v2/services/discord/auth-store.js +82 -0
- package/dist/src/cluster_v2/services/discord/collector.js +569 -0
- package/dist/src/cluster_v2/services/discord/index.js +1 -0
- package/dist/src/cluster_v2/services/discord/oauth.js +87 -0
- package/dist/src/cluster_v2/services/discord/rpc-client.js +325 -0
- package/dist/src/cluster_v2/services/embedding.js +66 -0
- package/dist/src/cluster_v2/services/registry-cache.js +107 -0
- package/dist/src/cluster_v2/services/registry-cache.test.js +66 -0
- package/dist/src/cluster_v2/services/registry.js +36 -0
- package/dist/src/cluster_v2/services/twitter/collector.js +1055 -0
- package/dist/src/cluster_v2/services/twitter/index.js +1 -0
- package/dist/src/config/digest.js +78 -0
- package/dist/src/config/discord.js +143 -0
- package/dist/src/config/image-gen.js +48 -0
- package/dist/src/config/mono-pilot.js +31 -0
- package/dist/src/config/twitter.js +100 -0
- package/dist/src/extensions/cluster.js +311 -0
- package/dist/src/extensions/commands/build-memory.js +76 -0
- package/dist/src/extensions/commands/digest/backfill.js +779 -0
- package/dist/src/extensions/commands/digest/index.js +1133 -0
- package/dist/src/extensions/commands/image-model.js +214 -0
- package/dist/src/extensions/game/bus-injection.js +47 -0
- package/dist/src/extensions/game/identity.js +83 -0
- package/dist/src/extensions/game/mailbox.js +61 -0
- package/dist/src/extensions/game/system-prompt.js +134 -0
- package/dist/src/extensions/game/tools.js +28 -0
- package/dist/src/extensions/lifecycle.js +337 -0
- package/dist/src/extensions/mode-runtime.js +26 -2
- package/dist/src/extensions/mono-game.js +66 -0
- package/dist/src/extensions/mono-pilot.js +100 -18
- package/dist/src/extensions/nvim.js +47 -0
- package/dist/src/extensions/session-hints.js +60 -35
- package/dist/src/extensions/sftp.js +897 -0
- package/dist/src/extensions/status.js +676 -0
- package/dist/src/extensions/system-events.js +478 -0
- package/dist/src/extensions/system-prompt.js +24 -14
- package/dist/src/extensions/user-message.js +94 -50
- package/dist/src/lsp/client.js +235 -0
- package/dist/src/lsp/index.js +165 -0
- package/dist/src/lsp/runtime.js +67 -0
- package/dist/src/lsp/server.js +242 -0
- package/dist/src/mcp/config.js +112 -0
- package/dist/src/{utils/mcp-client.js → mcp/protocol.js} +1 -100
- package/dist/src/mcp/servers.js +90 -0
- package/dist/src/memory/build-memory.js +103 -0
- package/dist/src/memory/config/defaults.js +55 -0
- package/dist/src/memory/config/loader.js +29 -0
- package/dist/src/memory/config/paths.js +9 -0
- package/dist/src/memory/config/resolve.js +90 -0
- package/dist/src/memory/config/types.js +1 -0
- package/dist/src/memory/embeddings/batch-runner.js +39 -0
- package/dist/src/memory/embeddings/cache.js +47 -0
- package/dist/src/memory/embeddings/chunk-limits.js +26 -0
- package/dist/src/memory/embeddings/input-limits.js +48 -0
- package/dist/src/memory/embeddings/local.js +108 -0
- package/dist/src/memory/embeddings/types.js +1 -0
- package/dist/src/memory/index-manager.js +552 -0
- package/dist/src/memory/indexing/embeddings.js +67 -0
- package/dist/src/memory/indexing/files.js +180 -0
- package/dist/src/memory/indexing/index-file.js +105 -0
- package/dist/src/memory/log.js +38 -0
- package/dist/src/memory/paths.js +15 -0
- package/dist/src/memory/runtime/index.js +299 -0
- package/dist/src/memory/runtime/thread.js +116 -0
- package/dist/src/memory/search/fts.js +57 -0
- package/dist/src/memory/search/hybrid.js +50 -0
- package/dist/src/memory/search/text.js +30 -0
- package/dist/src/memory/search/vector.js +43 -0
- package/dist/src/memory/session/content-hash.js +7 -0
- package/dist/src/memory/session/entry.js +33 -0
- package/dist/src/memory/session/flush-policy.js +34 -0
- package/dist/src/memory/session/hook.js +191 -0
- package/dist/src/memory/session/paths.js +15 -0
- package/dist/src/memory/session/session-reader.js +88 -0
- package/dist/src/memory/session/transcript/content-hash.js +7 -0
- package/dist/src/memory/session/transcript/entry.js +28 -0
- package/dist/src/memory/session/transcript/flush.js +56 -0
- package/dist/src/memory/session/transcript/paths.js +28 -0
- package/dist/src/memory/session/transcript/reader.js +112 -0
- package/dist/src/memory/session/transcript/state.js +31 -0
- package/dist/src/memory/store/schema.js +89 -0
- package/dist/src/memory/store/sqlite.js +89 -0
- package/dist/src/memory/types.js +1 -0
- package/dist/src/memory/warm.js +25 -0
- package/dist/src/rules/discovery.js +41 -0
- package/dist/{tools → src/tools}/README.md +29 -3
- package/dist/{tools → src/tools}/apply-patch-description.md +8 -2
- package/dist/{tools → src/tools}/apply-patch.js +174 -104
- package/dist/{tools → src/tools}/apply-patch.test.js +52 -1
- package/dist/{tools/ask-question.js → src/tools/ask-user-question.js} +3 -3
- package/dist/src/tools/ast-grep.js +357 -0
- package/dist/src/tools/brief-write.js +122 -0
- package/dist/src/tools/bus-send.js +100 -0
- package/dist/{tools → src/tools}/call-mcp-tool.js +40 -124
- package/dist/src/tools/codex-apply-patch-description.md +52 -0
- package/dist/src/tools/codex-apply-patch.js +540 -0
- package/dist/{tools → src/tools}/delete.js +24 -0
- package/dist/src/tools/exit-plan-mode.js +83 -0
- package/dist/{tools → src/tools}/fetch-mcp-resource.js +56 -100
- package/dist/src/tools/generate-image.js +567 -0
- package/dist/{tools → src/tools}/glob.js +55 -1
- package/dist/{tools → src/tools}/list-mcp-resources.js +46 -57
- package/dist/{tools → src/tools}/list-mcp-tools.js +52 -63
- package/dist/src/tools/ls.js +48 -0
- package/dist/src/tools/lsp-diagnostics.js +67 -0
- package/dist/src/tools/lsp-symbols.js +54 -0
- package/dist/src/tools/mailbox.js +85 -0
- package/dist/src/tools/memory-get.js +90 -0
- package/dist/src/tools/memory-search.js +180 -0
- package/dist/{tools → src/tools}/plan-mode-reminder.md +3 -4
- package/dist/{tools → src/tools}/read-file.js +8 -19
- package/dist/{tools → src/tools}/rg.js +10 -20
- package/dist/{tools → src/tools}/shell.js +19 -42
- package/dist/{tools → src/tools}/subagent.js +255 -6
- package/dist/{tools → src/tools}/switch-mode.js +37 -6
- package/dist/{tools → src/tools}/web-fetch.js +105 -7
- package/dist/{tools → src/tools}/web-search.js +29 -1
- package/package.json +21 -9
- /package/dist/{tools → src/tools}/ask-mode-reminder.md +0 -0
- /package/dist/{tools → src/tools}/rg.test.js +0 -0
- /package/dist/{tools → src/tools}/semantic-search-description.md +0 -0
- /package/dist/{tools → src/tools}/semantic-search.js +0 -0
- /package/dist/{tools → src/tools}/shell-description.md +0 -0
- /package/dist/{tools → src/tools}/subagent-description.md +0 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { closeCluster, getActiveClusterService } from "../cluster/init.js";
|
|
2
|
+
import { publishSystemEvent } from "./system-events.js";
|
|
3
|
+
import { closeClusterV2, getActiveClusterV2Service, reelectClusterV2, stepdownClusterV2Leader, } from "../cluster_v2/index.js";
|
|
4
|
+
const USAGE = [
|
|
5
|
+
"Usage:",
|
|
6
|
+
" /cluster send <agentId> <message> — send a direct message",
|
|
7
|
+
" /cluster broadcast <message> — broadcast to public channel",
|
|
8
|
+
" /cluster broadcast:<channel> <msg> — broadcast to specific channel",
|
|
9
|
+
" /cluster who — list connected agents",
|
|
10
|
+
" /cluster inbox — show received messages",
|
|
11
|
+
" /cluster status — show runtime cluster status",
|
|
12
|
+
" /cluster services — show cluster_v2 service registry",
|
|
13
|
+
" /cluster reelect — force this node to re-elect/rejoin",
|
|
14
|
+
" /cluster stepdown — leader steps down and rejoins",
|
|
15
|
+
" /cluster close — close local cluster subsystem",
|
|
16
|
+
].join("\n");
|
|
17
|
+
/** Mutable slot — set once the bus is connected in session_start. */
|
|
18
|
+
const inbox = [];
|
|
19
|
+
let defaultBroadcastChannel;
|
|
20
|
+
function resolveClusterBusHandle() {
|
|
21
|
+
const activeV2 = getActiveClusterV2Service();
|
|
22
|
+
if (activeV2?.bus) {
|
|
23
|
+
return activeV2.bus;
|
|
24
|
+
}
|
|
25
|
+
const activeV1 = getActiveClusterService();
|
|
26
|
+
if (activeV1?.bus) {
|
|
27
|
+
return activeV1.bus;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
export function setClusterHandle(bus) {
|
|
32
|
+
if (!bus) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
bus.onMessage((msg) => {
|
|
36
|
+
inbox.push(msg);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export function setClusterCommandDefaultChannel(channel) {
|
|
40
|
+
defaultBroadcastChannel = channel;
|
|
41
|
+
}
|
|
42
|
+
export function registerClusterCommands(pi) {
|
|
43
|
+
pi.registerCommand("cluster", {
|
|
44
|
+
description: "Cluster commands: send, broadcast, who, status, services, reelect, stepdown, close",
|
|
45
|
+
handler: async (args, ctx) => {
|
|
46
|
+
const sub = parseSubcommand(args);
|
|
47
|
+
switch (sub.cmd) {
|
|
48
|
+
case "send": {
|
|
49
|
+
const bus = resolveClusterBusHandle();
|
|
50
|
+
if (!bus) {
|
|
51
|
+
notify(ctx, "Bus not connected. Is the cluster running?", "warning");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (!sub.target || !sub.body) {
|
|
55
|
+
notify(ctx, "Usage: /cluster send <agentId> <message>", "warning");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const { agentId, displayName } = await bus.resolveTarget(sub.target);
|
|
60
|
+
const privateChannel = `private:${agentId}`;
|
|
61
|
+
const { seq } = await bus.broadcast({ text: sub.body }, privateChannel);
|
|
62
|
+
const label = displayName?.trim() ? `${displayName} (${agentId})` : agentId;
|
|
63
|
+
notify(ctx, `→ [seq=${seq}] sent to ${label} via ${privateChannel}`, "info");
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
notify(ctx, `send failed: ${err.message}`, "error");
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case "broadcast": {
|
|
71
|
+
const bus = resolveClusterBusHandle();
|
|
72
|
+
if (!bus) {
|
|
73
|
+
notify(ctx, "Bus not connected. Is the cluster running?", "warning");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (!sub.body) {
|
|
77
|
+
notify(ctx, "Usage: /cluster broadcast <message>", "warning");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const { seq, delivered } = await bus.broadcast({ text: sub.body }, sub.channel ?? defaultBroadcastChannel);
|
|
82
|
+
const ch = sub.channel ?? defaultBroadcastChannel ?? "public";
|
|
83
|
+
notify(ctx, `→ [seq=${seq}] broadcast to ${ch} (${delivered} recipients)`, "info");
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
notify(ctx, `broadcast failed: ${err.message}`, "error");
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case "who": {
|
|
91
|
+
const bus = resolveClusterBusHandle();
|
|
92
|
+
if (!bus) {
|
|
93
|
+
notify(ctx, "Bus not connected. Is the cluster running?", "warning");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const { agents } = await bus.roster();
|
|
98
|
+
if (agents.length === 0) {
|
|
99
|
+
notify(ctx, "No agents connected", "info");
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const lines = agents.map((a) => {
|
|
103
|
+
const name = a.displayName?.trim();
|
|
104
|
+
const label = name ? `${name} (${a.agentId})` : a.agentId;
|
|
105
|
+
const roleTag = a.role === "leader" ? "[leader]" : "[follower]";
|
|
106
|
+
return ` ${roleTag} ${label} [${a.channels.join(", ")}]`;
|
|
107
|
+
});
|
|
108
|
+
notify(ctx, `Connected agents:\n${lines.join("\n")}`, "info");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
notify(ctx, `roster failed: ${err.message}`, "error");
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case "inbox": {
|
|
117
|
+
if (inbox.length === 0) {
|
|
118
|
+
notify(ctx, "No messages", "info");
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const lines = inbox.map((m) => {
|
|
122
|
+
const text = typeof m.payload === "object" && m.payload !== null && "text" in m.payload
|
|
123
|
+
? m.payload.text
|
|
124
|
+
: JSON.stringify(m.payload);
|
|
125
|
+
const ch = m.channel ? ` [${m.channel}]` : "";
|
|
126
|
+
return ` [seq=${m.seq}] ${m.from}${ch}: ${text}`;
|
|
127
|
+
});
|
|
128
|
+
notify(ctx, `Messages (${inbox.length}):\n${lines.join("\n")}`, "info");
|
|
129
|
+
inbox.length = 0;
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case "status": {
|
|
134
|
+
const activeV2 = getActiveClusterV2Service();
|
|
135
|
+
if (activeV2) {
|
|
136
|
+
const lines = [
|
|
137
|
+
"cluster: v2",
|
|
138
|
+
`role: ${activeV2.role}`,
|
|
139
|
+
`bus: ${activeV2.bus ? "connected" : "disconnected"}`,
|
|
140
|
+
`embedding: ${activeV2.embedding.id} (${activeV2.embedding.model})`,
|
|
141
|
+
];
|
|
142
|
+
notify(ctx, lines.join("\n"), "info");
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
const activeV1 = getActiveClusterService();
|
|
146
|
+
if (activeV1) {
|
|
147
|
+
const lines = [
|
|
148
|
+
"cluster: v1",
|
|
149
|
+
`role: ${activeV1.role}`,
|
|
150
|
+
`bus: ${activeV1.bus ? "connected" : "disconnected"}`,
|
|
151
|
+
`embedding: ${activeV1.embedding.id} (${activeV1.embedding.model})`,
|
|
152
|
+
];
|
|
153
|
+
notify(ctx, lines.join("\n"), "info");
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
notify(ctx, "Cluster not initialized", "warning");
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
case "services": {
|
|
160
|
+
const activeV2 = getActiveClusterV2Service();
|
|
161
|
+
if (!activeV2) {
|
|
162
|
+
if (getActiveClusterService()) {
|
|
163
|
+
notify(ctx, "services is currently available only for cluster_v2", "warning");
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
notify(ctx, "Cluster not initialized", "warning");
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const snapshot = await activeV2.getServiceRegistrySnapshot();
|
|
171
|
+
if (snapshot.services.length === 0) {
|
|
172
|
+
notify(ctx, `cluster_v2 services: revision=${snapshot.revision}, no services`, "info");
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
const lines = snapshot.services.map((service) => {
|
|
176
|
+
const capabilities = service.capabilities;
|
|
177
|
+
const methodsValue = typeof capabilities === "object" && capabilities !== null
|
|
178
|
+
? capabilities.methods
|
|
179
|
+
: undefined;
|
|
180
|
+
const methods = Array.isArray(methodsValue)
|
|
181
|
+
? methodsValue.filter((method) => typeof method === "string")
|
|
182
|
+
: [];
|
|
183
|
+
const methodsText = methods.length > 0 ? methods.join(", ") : "none";
|
|
184
|
+
return ` ${service.name}@${service.version} methods=[${methodsText}]`;
|
|
185
|
+
});
|
|
186
|
+
notify(ctx, `cluster_v2 services (revision=${snapshot.revision}):\n${lines.join("\n")}`, "info");
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
notify(ctx, `services failed: ${err.message}`, "error");
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case "reelect": {
|
|
194
|
+
const activeV2 = getActiveClusterV2Service();
|
|
195
|
+
if (!activeV2) {
|
|
196
|
+
if (getActiveClusterService()) {
|
|
197
|
+
notify(ctx, "reelect is currently available only for cluster_v2", "warning");
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
notify(ctx, "Cluster not initialized", "warning");
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
const previousRole = activeV2.role;
|
|
204
|
+
try {
|
|
205
|
+
const next = await reelectClusterV2();
|
|
206
|
+
notify(ctx, `cluster_v2 reelect complete: ${previousRole} -> ${next.role}`, "info");
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
notify(ctx, `reelect failed: ${err.message}`, "error");
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
case "stepdown": {
|
|
214
|
+
const activeV2 = getActiveClusterV2Service();
|
|
215
|
+
if (!activeV2) {
|
|
216
|
+
if (getActiveClusterService()) {
|
|
217
|
+
notify(ctx, "stepdown is currently available only for cluster_v2", "warning");
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
notify(ctx, "Cluster not initialized", "warning");
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
if (activeV2.role !== "leader") {
|
|
224
|
+
notify(ctx, `stepdown requires leader role, current role: ${activeV2.role}`, "warning");
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
const next = await stepdownClusterV2Leader();
|
|
229
|
+
notify(ctx, `cluster_v2 stepdown complete: leader -> ${next.role}`, "info");
|
|
230
|
+
}
|
|
231
|
+
catch (err) {
|
|
232
|
+
notify(ctx, `stepdown failed: ${err.message}`, "error");
|
|
233
|
+
}
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
case "close": {
|
|
237
|
+
const activeV2 = getActiveClusterV2Service();
|
|
238
|
+
if (activeV2) {
|
|
239
|
+
try {
|
|
240
|
+
const role = activeV2.role;
|
|
241
|
+
await closeClusterV2();
|
|
242
|
+
notify(ctx, `cluster_v2 closed (previous role: ${role})`, "info");
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
notify(ctx, `close failed: ${err.message}`, "error");
|
|
246
|
+
}
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
const activeV1 = getActiveClusterService();
|
|
250
|
+
if (activeV1) {
|
|
251
|
+
try {
|
|
252
|
+
const role = activeV1.role;
|
|
253
|
+
await closeCluster();
|
|
254
|
+
notify(ctx, `cluster_v1 closed (previous role: ${role})`, "info");
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
notify(ctx, `close failed: ${err.message}`, "error");
|
|
258
|
+
}
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
notify(ctx, "Cluster not initialized", "warning");
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
default:
|
|
265
|
+
notify(ctx, `Unknown subcommand: ${sub.cmd ?? "(empty)"}\n${USAGE}`, "warning");
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function parseSubcommand(raw) {
|
|
271
|
+
const trimmed = raw.trim();
|
|
272
|
+
if (!trimmed)
|
|
273
|
+
return {};
|
|
274
|
+
const spaceIdx = trimmed.indexOf(" ");
|
|
275
|
+
const cmd = spaceIdx === -1 ? trimmed : trimmed.slice(0, spaceIdx);
|
|
276
|
+
const rest = spaceIdx === -1 ? "" : trimmed.slice(spaceIdx + 1).trim();
|
|
277
|
+
if (cmd === "send") {
|
|
278
|
+
const targetEnd = rest.indexOf(" ");
|
|
279
|
+
if (targetEnd === -1)
|
|
280
|
+
return { cmd, target: rest };
|
|
281
|
+
return {
|
|
282
|
+
cmd,
|
|
283
|
+
target: rest.slice(0, targetEnd),
|
|
284
|
+
body: rest.slice(targetEnd + 1).trim(),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
// broadcast or broadcast:<channel>
|
|
288
|
+
if (cmd === "broadcast" || cmd.startsWith("broadcast:")) {
|
|
289
|
+
const channel = cmd.includes(":") ? cmd.slice("broadcast:".length) : undefined;
|
|
290
|
+
return { cmd: "broadcast", channel, body: rest };
|
|
291
|
+
}
|
|
292
|
+
return { cmd, body: rest };
|
|
293
|
+
}
|
|
294
|
+
function notify(ctx, message, level) {
|
|
295
|
+
if (level !== "info") {
|
|
296
|
+
publishSystemEvent({
|
|
297
|
+
source: "cluster",
|
|
298
|
+
level,
|
|
299
|
+
message,
|
|
300
|
+
toast: false,
|
|
301
|
+
ctx,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
if (ctx.hasUI && ctx.ui?.notify) {
|
|
305
|
+
ctx.ui.notify(message, level);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
const prefix = level === "error" ? "[error]" : level === "warning" ? "[warn]" : "[info]";
|
|
309
|
+
console.log(`${prefix} ${message}`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { buildMemoryIndex } from "../../memory/build-memory.js";
|
|
2
|
+
import { publishSystemEvent } from "../system-events.js";
|
|
3
|
+
const USAGE = "Usage: /build-memory --mode full|dirty";
|
|
4
|
+
function parseArgs(raw) {
|
|
5
|
+
const tokens = raw.trim().split(/\s+/);
|
|
6
|
+
let mode;
|
|
7
|
+
for (let i = 0; i < tokens.length; i += 1) {
|
|
8
|
+
const token = tokens[i];
|
|
9
|
+
if (!token)
|
|
10
|
+
continue;
|
|
11
|
+
if (token === "--mode") {
|
|
12
|
+
mode = tokens[i + 1];
|
|
13
|
+
i += 1;
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (token.startsWith("--mode=")) {
|
|
17
|
+
mode = token.slice("--mode=".length);
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
return { error: `Unknown argument: ${token}. ${USAGE}` };
|
|
21
|
+
}
|
|
22
|
+
return { mode };
|
|
23
|
+
}
|
|
24
|
+
function isValidMode(value) {
|
|
25
|
+
return value === "full" || value === "dirty";
|
|
26
|
+
}
|
|
27
|
+
export function registerBuildMemoryCommand(pi) {
|
|
28
|
+
pi.registerCommand("build-memory", {
|
|
29
|
+
description: "Rebuild memory index. --mode full|dirty",
|
|
30
|
+
handler: async (args, ctx) => {
|
|
31
|
+
const parsed = parseArgs(args);
|
|
32
|
+
if (parsed.error) {
|
|
33
|
+
notify(ctx, parsed.error, "warning");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (!isValidMode(parsed.mode)) {
|
|
37
|
+
notify(ctx, `--mode is required (full or dirty). ${USAGE}`, "warning");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const mode = parsed.mode;
|
|
41
|
+
notify(ctx, `Building memory index (mode=${mode})...`, "info");
|
|
42
|
+
try {
|
|
43
|
+
const result = await buildMemoryIndex({
|
|
44
|
+
workspaceDir: ctx.cwd,
|
|
45
|
+
mode,
|
|
46
|
+
});
|
|
47
|
+
if (result.ok) {
|
|
48
|
+
notify(ctx, result.message, "info");
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
notify(ctx, result.message, "warning");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
56
|
+
notify(ctx, `build-memory failed: ${message}`, "error");
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function notify(ctx, message, level) {
|
|
62
|
+
publishSystemEvent({
|
|
63
|
+
source: "memory",
|
|
64
|
+
level,
|
|
65
|
+
message,
|
|
66
|
+
toast: false,
|
|
67
|
+
ctx,
|
|
68
|
+
});
|
|
69
|
+
if (ctx.hasUI && ctx.ui?.notify) {
|
|
70
|
+
ctx.ui.notify(message, level);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const prefix = level === "error" ? "[error]" : level === "warning" ? "[warn]" : "[info]";
|
|
74
|
+
console.log(`${prefix} ${message}`);
|
|
75
|
+
}
|
|
76
|
+
}
|