mono-pilot 0.2.10 → 0.2.13
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 +260 -2
- 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 +1 -2
- 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 +70 -1
- 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/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/{tools → src/tools}/README.md +28 -2
- 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 +20 -24
- 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 +31 -3
- 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 +32 -3
- package/dist/{tools → src/tools}/list-mcp-tools.js +38 -3
- 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/src/utils/mcp-client.js +0 -282
- /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,337 @@
|
|
|
1
|
+
import { LSP } from "../lsp/index.js";
|
|
2
|
+
import { deriveAgentId } from "../agents-paths.js";
|
|
3
|
+
import { loadResolvedMemorySearchConfig } from "../memory/config/loader.js";
|
|
4
|
+
import { initCluster, closeCluster } from "../cluster/init.js";
|
|
5
|
+
import { getActiveClusterV2Service, initClusterV2, closeClusterV2, onClusterV2DiscordChannelBatch, onClusterV2LeaderOffline, onClusterV2LeaderRecovered, onClusterV2TwitterCollectorStartupFailed, onClusterV2TwitterPullBatch, onClusterV2TwitterPullFailed, } from "../cluster_v2/index.js";
|
|
6
|
+
import { setMemoryWorkersEmbeddingProvider, closeMemorySearchManagers } from "../memory/runtime/index.js";
|
|
7
|
+
import { warmMemorySearch } from "../memory/warm.js";
|
|
8
|
+
import { setMailBoxHandle } from "./game/mailbox.js";
|
|
9
|
+
import { publishSystemEvent } from "./system-events.js";
|
|
10
|
+
let activeClusterVersion = null;
|
|
11
|
+
/**
|
|
12
|
+
* Initialize all subsystems. Fire-and-forget from session_start.
|
|
13
|
+
*/
|
|
14
|
+
export async function initSubsystems(pi, ctx, options) {
|
|
15
|
+
const agentId = deriveAgentId(ctx.cwd);
|
|
16
|
+
const sessionManager = ctx.sessionManager;
|
|
17
|
+
const getSessionId = () => sessionManager?.getSessionId?.() ?? "unknown";
|
|
18
|
+
const disposers = [];
|
|
19
|
+
// 1. LSP
|
|
20
|
+
LSP.init(ctx.cwd);
|
|
21
|
+
// 2. Cluster + 3. Memory (cluster provides embedding for memory)
|
|
22
|
+
const settings = await loadResolvedMemorySearchConfig();
|
|
23
|
+
let cluster = null;
|
|
24
|
+
const useClusterV2 = process.env.MONO_PILOT_CLUSTER_VERSION === "2" || process.env.MONO_PILOT_CLUSTER_V2 === "1";
|
|
25
|
+
if (useClusterV2) {
|
|
26
|
+
disposers.push(onClusterV2DiscordChannelBatch((event) => {
|
|
27
|
+
publishDiscordChannelBatchSystemEvent(ctx, event);
|
|
28
|
+
}));
|
|
29
|
+
disposers.push(onClusterV2TwitterPullBatch((event) => {
|
|
30
|
+
publishTwitterPullBatchSystemEvent(ctx, event);
|
|
31
|
+
}));
|
|
32
|
+
disposers.push(onClusterV2TwitterPullFailed((event) => {
|
|
33
|
+
publishTwitterPullFailedSystemEvent(ctx, event);
|
|
34
|
+
}));
|
|
35
|
+
disposers.push(onClusterV2TwitterCollectorStartupFailed((event) => {
|
|
36
|
+
publishTwitterCollectorStartupFailedSystemEvent(ctx, event);
|
|
37
|
+
}));
|
|
38
|
+
disposers.push(onClusterV2LeaderOffline(() => {
|
|
39
|
+
publishSystemEvent({
|
|
40
|
+
source: "cluster",
|
|
41
|
+
level: "warning",
|
|
42
|
+
message: "Leader offline. Re-election in progress.",
|
|
43
|
+
dedupeKey: "cluster|leader_offline",
|
|
44
|
+
toast: false,
|
|
45
|
+
ctx,
|
|
46
|
+
});
|
|
47
|
+
}));
|
|
48
|
+
disposers.push(onClusterV2LeaderRecovered(() => {
|
|
49
|
+
refreshMemoryEmbeddingProviderFromActiveClusterV2();
|
|
50
|
+
void publishClusterV2LeaderRecoveredEvent(ctx);
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
if (settings.enabled && settings.provider === "local") {
|
|
55
|
+
if (useClusterV2) {
|
|
56
|
+
cluster = await initClusterV2({
|
|
57
|
+
...settings.local,
|
|
58
|
+
agentId,
|
|
59
|
+
displayName: options?.displayName,
|
|
60
|
+
getSessionId,
|
|
61
|
+
});
|
|
62
|
+
activeClusterVersion = "v2";
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
cluster = await initCluster({
|
|
66
|
+
...settings.local,
|
|
67
|
+
agentId,
|
|
68
|
+
displayName: options?.displayName,
|
|
69
|
+
getSessionId,
|
|
70
|
+
});
|
|
71
|
+
activeClusterVersion = "v1";
|
|
72
|
+
}
|
|
73
|
+
setMemoryWorkersEmbeddingProvider(cluster.embedding);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
for (const dispose of [...disposers].reverse()) {
|
|
78
|
+
dispose();
|
|
79
|
+
}
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
if (settings.enabled && settings.sync.onSessionStart) {
|
|
83
|
+
startMemoryWarmupInBackground(ctx, { workspaceDir: ctx.cwd, agentId });
|
|
84
|
+
}
|
|
85
|
+
// 4. Bus (message injection into agent conversation)
|
|
86
|
+
const bus = cluster?.bus ?? null;
|
|
87
|
+
if (bus) {
|
|
88
|
+
if (options?.busChannels && options.busChannels.length > 0) {
|
|
89
|
+
await bus.subscribe(options.busChannels);
|
|
90
|
+
}
|
|
91
|
+
const filter = options?.busMessageFilter;
|
|
92
|
+
const injector = options?.busMessageInjector ?? createDefaultBusMessageInjector(pi);
|
|
93
|
+
bus.onMessage((msg) => {
|
|
94
|
+
if (filter && !filter(msg))
|
|
95
|
+
return;
|
|
96
|
+
injector(msg);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
setMailBoxHandle(bus ?? null);
|
|
100
|
+
const dispose = disposers.length > 0
|
|
101
|
+
? () => {
|
|
102
|
+
for (const fn of [...disposers].reverse()) {
|
|
103
|
+
fn();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
: undefined;
|
|
107
|
+
return { bus, dispose };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Shutdown all subsystems in reverse dependency order.
|
|
111
|
+
*/
|
|
112
|
+
export async function shutdownSubsystems(handles) {
|
|
113
|
+
try {
|
|
114
|
+
handles?.dispose?.();
|
|
115
|
+
// Bus
|
|
116
|
+
if (handles?.bus)
|
|
117
|
+
handles.bus.close();
|
|
118
|
+
setMailBoxHandle(null);
|
|
119
|
+
// Memory
|
|
120
|
+
await closeMemorySearchManagers();
|
|
121
|
+
// Cluster
|
|
122
|
+
if (activeClusterVersion === "v2") {
|
|
123
|
+
await closeClusterV2();
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
await closeCluster();
|
|
127
|
+
}
|
|
128
|
+
activeClusterVersion = null;
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
console.warn(`[subsystems] shutdown failed: ${String(err)}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function formatLeaderLabel(leader) {
|
|
135
|
+
const name = leader.displayName?.trim();
|
|
136
|
+
return name ? `${name} (${leader.agentId})` : leader.agentId;
|
|
137
|
+
}
|
|
138
|
+
function buildLeaderKey(leaders) {
|
|
139
|
+
return leaders
|
|
140
|
+
.map((leader) => leader.agentId)
|
|
141
|
+
.sort()
|
|
142
|
+
.join(",");
|
|
143
|
+
}
|
|
144
|
+
function buildLeaderLabel(leaders) {
|
|
145
|
+
return leaders.map((leader) => formatLeaderLabel(leader)).join(", ");
|
|
146
|
+
}
|
|
147
|
+
async function publishClusterV2LeaderRecoveredEvent(ctx) {
|
|
148
|
+
const active = getActiveClusterV2Service();
|
|
149
|
+
const bus = active?.bus ?? null;
|
|
150
|
+
if (!bus) {
|
|
151
|
+
publishSystemEvent({
|
|
152
|
+
source: "cluster",
|
|
153
|
+
level: "info",
|
|
154
|
+
message: "Re-election complete.",
|
|
155
|
+
dedupeKey: "cluster|leader_elected",
|
|
156
|
+
toast: true,
|
|
157
|
+
ctx,
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const roster = await bus.roster();
|
|
163
|
+
const leaders = roster.agents.filter((agent) => agent.role === "leader");
|
|
164
|
+
if (leaders.length === 0) {
|
|
165
|
+
publishSystemEvent({
|
|
166
|
+
source: "cluster",
|
|
167
|
+
level: "info",
|
|
168
|
+
message: "Re-election complete.",
|
|
169
|
+
dedupeKey: "cluster|leader_elected",
|
|
170
|
+
toast: true,
|
|
171
|
+
ctx,
|
|
172
|
+
});
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const leaderKey = buildLeaderKey(leaders);
|
|
176
|
+
const leaderLabel = buildLeaderLabel(leaders);
|
|
177
|
+
publishSystemEvent({
|
|
178
|
+
source: "cluster",
|
|
179
|
+
level: "info",
|
|
180
|
+
message: `Re-election complete. Leader: ${leaderLabel}.`,
|
|
181
|
+
dedupeKey: `cluster|leader_elected|${leaderKey}`,
|
|
182
|
+
toast: true,
|
|
183
|
+
ctx,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
publishSystemEvent({
|
|
188
|
+
source: "cluster",
|
|
189
|
+
level: "info",
|
|
190
|
+
message: "Re-election complete.",
|
|
191
|
+
dedupeKey: "cluster|leader_elected",
|
|
192
|
+
toast: true,
|
|
193
|
+
ctx,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function refreshMemoryEmbeddingProviderFromActiveClusterV2() {
|
|
198
|
+
const active = getActiveClusterV2Service();
|
|
199
|
+
if (!active) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
setMemoryWorkersEmbeddingProvider(active.embedding);
|
|
203
|
+
}
|
|
204
|
+
function publishDiscordChannelBatchSystemEvent(ctx, event) {
|
|
205
|
+
const channelLabel = event.channelAlias?.trim() ||
|
|
206
|
+
(event.guildName?.trim() && event.channelName?.trim()
|
|
207
|
+
? `${event.guildName.trim()} / ${event.channelName.trim()}`
|
|
208
|
+
: event.channelName?.trim()) ||
|
|
209
|
+
event.channelId;
|
|
210
|
+
publishSystemEvent({
|
|
211
|
+
source: "discord",
|
|
212
|
+
level: "info",
|
|
213
|
+
message: `Channel ${channelLabel} collected ${event.count} messages.`,
|
|
214
|
+
dedupeKey: `discord|channel_batch|${event.scope}|${event.channelId}|${event.sequence}`,
|
|
215
|
+
toast: false,
|
|
216
|
+
ctx,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function publishTwitterPullBatchSystemEvent(ctx, event) {
|
|
220
|
+
publishSystemEvent({
|
|
221
|
+
source: "twitter",
|
|
222
|
+
level: "info",
|
|
223
|
+
message: `For You pull complete: ${event.count}/${event.requestedCount} tweets.`,
|
|
224
|
+
dedupeKey: `twitter|pull_batch|${event.scope}|${event.sequence}`,
|
|
225
|
+
toast: false,
|
|
226
|
+
ctx,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function publishTwitterPullFailedSystemEvent(ctx, event) {
|
|
230
|
+
const triggerLabel = event.trigger === "startup" ? "startup" : "interval";
|
|
231
|
+
publishSystemEvent({
|
|
232
|
+
source: "twitter",
|
|
233
|
+
level: "warning",
|
|
234
|
+
message: `For You pull failed (${triggerLabel}): ${event.error}`,
|
|
235
|
+
dedupeKey: `twitter|pull_failed|${event.scope}|${event.trigger}`,
|
|
236
|
+
toast: false,
|
|
237
|
+
ctx,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
function publishTwitterCollectorStartupFailedSystemEvent(ctx, event) {
|
|
241
|
+
publishSystemEvent({
|
|
242
|
+
source: "twitter",
|
|
243
|
+
level: "warning",
|
|
244
|
+
message: `Collector startup failed: ${event.error}`,
|
|
245
|
+
dedupeKey: `twitter|collector_start_failed|${event.scope}`,
|
|
246
|
+
toast: false,
|
|
247
|
+
ctx,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
function startMemoryWarmupInBackground(ctx, params) {
|
|
251
|
+
let startNotified = false;
|
|
252
|
+
const notifyWarmupStartIfNeeded = () => {
|
|
253
|
+
if (startNotified) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
startNotified = true;
|
|
257
|
+
publishSystemEvent({
|
|
258
|
+
source: "memory",
|
|
259
|
+
level: "info",
|
|
260
|
+
message: "Memory warmup in progress.",
|
|
261
|
+
dedupeKey: `memory|warmup|start|${params.agentId}`,
|
|
262
|
+
toast: false,
|
|
263
|
+
ctx,
|
|
264
|
+
});
|
|
265
|
+
};
|
|
266
|
+
void warmMemorySearch({
|
|
267
|
+
...params,
|
|
268
|
+
onWorkDetected: notifyWarmupStartIfNeeded,
|
|
269
|
+
})
|
|
270
|
+
.then((result) => {
|
|
271
|
+
if (!result.attempted || !startNotified) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (result.succeeded) {
|
|
275
|
+
publishSystemEvent({
|
|
276
|
+
source: "memory",
|
|
277
|
+
level: "info",
|
|
278
|
+
message: "Memory warmup complete.",
|
|
279
|
+
dedupeKey: `memory|warmup|done|${params.agentId}`,
|
|
280
|
+
toast: false,
|
|
281
|
+
ctx,
|
|
282
|
+
});
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
publishSystemEvent({
|
|
286
|
+
source: "memory",
|
|
287
|
+
level: "warning",
|
|
288
|
+
message: `Memory warmup failed: ${result.error ?? "unknown error"}`,
|
|
289
|
+
dedupeKey: `memory|warmup|failed|${params.agentId}`,
|
|
290
|
+
toast: false,
|
|
291
|
+
ctx,
|
|
292
|
+
});
|
|
293
|
+
})
|
|
294
|
+
.catch((error) => {
|
|
295
|
+
if (!startNotified) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
299
|
+
publishSystemEvent({
|
|
300
|
+
source: "memory",
|
|
301
|
+
level: "warning",
|
|
302
|
+
message: `Memory warmup failed: ${message}`,
|
|
303
|
+
dedupeKey: `memory|warmup|failed|${params.agentId}`,
|
|
304
|
+
toast: false,
|
|
305
|
+
ctx,
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
// --- Bus message injection (debounced) ---
|
|
310
|
+
function createDefaultBusMessageInjector(pi) {
|
|
311
|
+
let pending = [];
|
|
312
|
+
let timer = null;
|
|
313
|
+
function flush() {
|
|
314
|
+
if (pending.length === 0)
|
|
315
|
+
return;
|
|
316
|
+
const msgs = pending;
|
|
317
|
+
pending = [];
|
|
318
|
+
timer = null;
|
|
319
|
+
const lines = msgs.map((m) => {
|
|
320
|
+
const text = typeof m.payload === "object" && m.payload !== null && "text" in m.payload
|
|
321
|
+
? m.payload.text
|
|
322
|
+
: JSON.stringify(m.payload);
|
|
323
|
+
const ch = m.channel && m.channel !== "public" ? ` [${m.channel}]` : "";
|
|
324
|
+
return `[from ${m.from}${ch}] ${text}`;
|
|
325
|
+
});
|
|
326
|
+
const envelope = "<bus_messages>\n" + lines.join("\n") + "\n</bus_messages>\n\n" +
|
|
327
|
+
"You received the above messages from other agents via the message bus. " +
|
|
328
|
+
"Respond in character. Use the bus_send tool to reply.";
|
|
329
|
+
pi.sendUserMessage(envelope, { deliverAs: "followUp" });
|
|
330
|
+
}
|
|
331
|
+
return (msg) => {
|
|
332
|
+
pending.push(msg);
|
|
333
|
+
if (timer)
|
|
334
|
+
clearTimeout(timer);
|
|
335
|
+
timer = setTimeout(flush, 300);
|
|
336
|
+
};
|
|
337
|
+
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export const MODE_STATE_ENTRY_TYPE = "switch-mode-state";
|
|
2
|
+
function normalizeOptionalString(value) {
|
|
3
|
+
if (typeof value !== "string") {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
const trimmed = value.trim();
|
|
7
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
8
|
+
}
|
|
2
9
|
export const PLAN_MODE_STILL_ACTIVE_REMINDER = `<system_reminder>
|
|
3
10
|
Plan mode is still active. Continue with the task in the current mode.
|
|
4
11
|
</system_reminder>`;
|
|
@@ -24,6 +31,7 @@ export function parseModeStateEntry(entry) {
|
|
|
24
31
|
return undefined;
|
|
25
32
|
const state = data;
|
|
26
33
|
if (state.activeMode === "plan" || state.activeMode === "agent" || state.activeMode === "ask") {
|
|
34
|
+
const planFilePath = normalizeOptionalString(state.planFilePath);
|
|
27
35
|
return {
|
|
28
36
|
activeMode: state.activeMode,
|
|
29
37
|
pendingReminder: state.pendingReminder === "plan-entry" ||
|
|
@@ -31,12 +39,15 @@ export function parseModeStateEntry(entry) {
|
|
|
31
39
|
state.pendingReminder === "ask-entry"
|
|
32
40
|
? state.pendingReminder
|
|
33
41
|
: undefined,
|
|
42
|
+
planFilePath,
|
|
34
43
|
};
|
|
35
44
|
}
|
|
36
45
|
if (typeof state.planModeActive === "boolean") {
|
|
46
|
+
const planFilePath = normalizeOptionalString(state.planFilePath);
|
|
37
47
|
return {
|
|
38
48
|
activeMode: state.planModeActive ? "plan" : "agent",
|
|
39
49
|
pendingReminder: undefined,
|
|
50
|
+
planFilePath,
|
|
40
51
|
};
|
|
41
52
|
}
|
|
42
53
|
return undefined;
|
|
@@ -51,6 +62,7 @@ export function createModeStateData(snapshot) {
|
|
|
51
62
|
return {
|
|
52
63
|
activeMode: snapshot.activeMode,
|
|
53
64
|
pendingReminder: snapshot.pendingReminder,
|
|
65
|
+
planFilePath: snapshot.planFilePath,
|
|
54
66
|
planModeActive: snapshot.activeMode === "plan",
|
|
55
67
|
};
|
|
56
68
|
}
|
|
@@ -64,7 +76,7 @@ export function hasMessageEntries(entries) {
|
|
|
64
76
|
}
|
|
65
77
|
return false;
|
|
66
78
|
}
|
|
67
|
-
export function buildRuntimeEnvelope(userQuery, reminder, mcpInstructions, rulesEnvelope) {
|
|
79
|
+
export function buildRuntimeEnvelope(userQuery, reminder, mcpInstructions, rulesEnvelope, briefReminder) {
|
|
68
80
|
const sections = [];
|
|
69
81
|
if (rulesEnvelope) {
|
|
70
82
|
sections.push(rulesEnvelope.trim());
|
|
@@ -75,6 +87,9 @@ export function buildRuntimeEnvelope(userQuery, reminder, mcpInstructions, rules
|
|
|
75
87
|
if (reminder) {
|
|
76
88
|
sections.push(reminder.trim());
|
|
77
89
|
}
|
|
90
|
+
if (briefReminder) {
|
|
91
|
+
sections.push(briefReminder.trim());
|
|
92
|
+
}
|
|
78
93
|
sections.push(`<user_query>\n${userQuery}\n</user_query>`);
|
|
79
94
|
return sections.join("\n\n");
|
|
80
95
|
}
|
|
@@ -86,13 +101,22 @@ class ModeRuntimeStore {
|
|
|
86
101
|
getSnapshot() {
|
|
87
102
|
return { ...this.state };
|
|
88
103
|
}
|
|
89
|
-
setMode(nextMode) {
|
|
104
|
+
setMode(nextMode, options) {
|
|
105
|
+
const nextPlanFilePath = normalizeOptionalString(options?.planFilePath);
|
|
90
106
|
if (this.state.activeMode === nextMode) {
|
|
107
|
+
if (nextMode === "plan" && nextPlanFilePath !== undefined && nextPlanFilePath !== this.state.planFilePath) {
|
|
108
|
+
this.state.planFilePath = nextPlanFilePath;
|
|
109
|
+
this.state.pendingReminder = "plan-entry";
|
|
110
|
+
return { changed: true, snapshot: this.getSnapshot() };
|
|
111
|
+
}
|
|
91
112
|
return { changed: false, snapshot: this.getSnapshot() };
|
|
92
113
|
}
|
|
93
114
|
this.state.activeMode = nextMode;
|
|
94
115
|
switch (nextMode) {
|
|
95
116
|
case "plan":
|
|
117
|
+
if (nextPlanFilePath !== undefined) {
|
|
118
|
+
this.state.planFilePath = nextPlanFilePath;
|
|
119
|
+
}
|
|
96
120
|
this.state.pendingReminder = "plan-entry";
|
|
97
121
|
break;
|
|
98
122
|
case "ask":
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { setBusSendDefaultChannel, setBusSendHandle } from "../tools/bus-send.js";
|
|
2
|
+
import registerGameSystemPromptExtension from "./game/system-prompt.js";
|
|
3
|
+
import { initSubsystems, shutdownSubsystems } from "./lifecycle.js";
|
|
4
|
+
import { getGameChannel, getGameGmChannel, loadGameIdentity } from "./game/identity.js";
|
|
5
|
+
import { createGameBusMessageInjector } from "./game/bus-injection.js";
|
|
6
|
+
import { setMailBoxHandle } from "./game/mailbox.js";
|
|
7
|
+
import { resolveGameToolExtensions } from "./game/tools.js";
|
|
8
|
+
import { registerClusterCommands, setClusterCommandDefaultChannel, setClusterHandle, } from "./cluster.js";
|
|
9
|
+
export default function monoGameExtension(pi) {
|
|
10
|
+
pi.registerFlag("game-channel", {
|
|
11
|
+
description: "Override the game channel name",
|
|
12
|
+
type: "string",
|
|
13
|
+
});
|
|
14
|
+
registerGameSystemPromptExtension(pi);
|
|
15
|
+
registerClusterCommands(pi);
|
|
16
|
+
let handles = null;
|
|
17
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
18
|
+
if (handles) {
|
|
19
|
+
setClusterHandle(null);
|
|
20
|
+
setClusterCommandDefaultChannel(undefined);
|
|
21
|
+
setBusSendHandle(null);
|
|
22
|
+
setBusSendDefaultChannel(undefined);
|
|
23
|
+
setMailBoxHandle(null);
|
|
24
|
+
await shutdownSubsystems(handles);
|
|
25
|
+
handles = null;
|
|
26
|
+
}
|
|
27
|
+
const identity = loadGameIdentity(ctx.cwd);
|
|
28
|
+
const channelOverride = pi.getFlag("game-channel");
|
|
29
|
+
const gameChannel = getGameChannel(ctx.cwd, typeof channelOverride === "string" ? channelOverride : undefined);
|
|
30
|
+
const gmChannel = getGameGmChannel(gameChannel);
|
|
31
|
+
const roleTools = resolveGameToolExtensions(identity.tools);
|
|
32
|
+
for (const register of roleTools) {
|
|
33
|
+
register(pi);
|
|
34
|
+
}
|
|
35
|
+
setBusSendDefaultChannel(gameChannel);
|
|
36
|
+
try {
|
|
37
|
+
const h = await initSubsystems(pi, ctx, {
|
|
38
|
+
displayName: identity.displayName,
|
|
39
|
+
busChannels: [gameChannel, gmChannel],
|
|
40
|
+
busMessageFilter: (msg) => {
|
|
41
|
+
if (!msg.channel)
|
|
42
|
+
return false;
|
|
43
|
+
return msg.channel === gmChannel;
|
|
44
|
+
},
|
|
45
|
+
busMessageInjector: createGameBusMessageInjector(pi, { gmChannel }),
|
|
46
|
+
});
|
|
47
|
+
handles = h;
|
|
48
|
+
setClusterHandle(h.bus);
|
|
49
|
+
setClusterCommandDefaultChannel(gameChannel);
|
|
50
|
+
setBusSendHandle(h.bus);
|
|
51
|
+
setMailBoxHandle(h.bus, { gmChannel });
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
console.warn(`[subsystems] init failed: ${String(err)}`);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
pi.on("session_shutdown", async () => {
|
|
58
|
+
setClusterHandle(null);
|
|
59
|
+
setClusterCommandDefaultChannel(undefined);
|
|
60
|
+
setBusSendHandle(null);
|
|
61
|
+
setBusSendDefaultChannel(undefined);
|
|
62
|
+
setMailBoxHandle(null);
|
|
63
|
+
await shutdownSubsystems(handles);
|
|
64
|
+
handles = null;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
@@ -1,45 +1,127 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
1
|
+
import { onCompaction } from "../brief/reflection.js";
|
|
2
|
+
import lsExtension from "../tools/ls.js";
|
|
3
|
+
import shellExtension from "../tools/shell.js";
|
|
4
|
+
import globExtension from "../tools/glob.js";
|
|
5
|
+
import rgExtension from "../tools/rg.js";
|
|
6
|
+
import astGrepExtension from "../tools/ast-grep.js";
|
|
7
|
+
import readFileExtension from "../tools/read-file.js";
|
|
8
|
+
import deleteExtension from "../tools/delete.js";
|
|
9
|
+
import semanticSearchExtension from "../tools/semantic-search.js";
|
|
10
|
+
import webSearchExtension from "../tools/web-search.js";
|
|
11
|
+
import webFetchExtension from "../tools/web-fetch.js";
|
|
12
|
+
import generateImageExtension from "../tools/generate-image.js";
|
|
13
|
+
import askUserQuestionExtension from "../tools/ask-user-question.js";
|
|
14
|
+
import subagentExtension from "../tools/subagent.js";
|
|
15
|
+
import listMcpResourcesExtension from "../tools/list-mcp-resources.js";
|
|
16
|
+
import fetchMcpResourceExtension from "../tools/fetch-mcp-resource.js";
|
|
17
|
+
import listMcpToolsExtension from "../tools/list-mcp-tools.js";
|
|
18
|
+
import callMcpToolExtension from "../tools/call-mcp-tool.js";
|
|
19
|
+
import switchModeExtension from "../tools/switch-mode.js";
|
|
20
|
+
import exitPlanModeExtension from "../tools/exit-plan-mode.js";
|
|
21
|
+
// import applyPatchExtension from "../tools/apply-patch.js";
|
|
22
|
+
import codexApplyPatchExtension from "../tools/codex-apply-patch.js";
|
|
17
23
|
import userMessageExtension from "./user-message.js";
|
|
18
24
|
import systemPromptExtension from "./system-prompt.js";
|
|
19
25
|
import sessionHintsExtension from "./session-hints.js";
|
|
26
|
+
import nvimExtension from "./nvim.js";
|
|
27
|
+
import lspDiagnosticsExtension from "../tools/lsp-diagnostics.js";
|
|
28
|
+
import lspSymbolsExtension from "../tools/lsp-symbols.js";
|
|
29
|
+
import briefWriteExtension from "../tools/brief-write.js";
|
|
30
|
+
import memorySearchExtension from "../tools/memory-search.js";
|
|
31
|
+
import memoryGetExtension from "../tools/memory-get.js";
|
|
32
|
+
import busSendExtension, { setBusSendHandle } from "../tools/bus-send.js";
|
|
33
|
+
import mailboxExtension from "../tools/mailbox.js";
|
|
34
|
+
import { registerSessionMemoryHook } from "../memory/session/hook.js";
|
|
35
|
+
import { registerBuildMemoryCommand } from "./commands/build-memory.js";
|
|
36
|
+
import { registerDigestCommand } from "./commands/digest/index.js";
|
|
37
|
+
import { registerClusterCommands, setClusterHandle } from "./cluster.js";
|
|
38
|
+
import { registerStatusCommand } from "./status.js";
|
|
39
|
+
import { registerImageModelCommands } from "./commands/image-model.js";
|
|
40
|
+
import { registerSftpCommands } from "./sftp.js";
|
|
41
|
+
import { registerSystemEvents } from "./system-events.js";
|
|
42
|
+
import { initSubsystems, shutdownSubsystems } from "./lifecycle.js";
|
|
20
43
|
const toolExtensions = [
|
|
21
44
|
shellExtension,
|
|
22
45
|
globExtension,
|
|
23
46
|
rgExtension,
|
|
47
|
+
astGrepExtension,
|
|
24
48
|
readFileExtension,
|
|
25
49
|
deleteExtension,
|
|
50
|
+
lsExtension,
|
|
26
51
|
semanticSearchExtension,
|
|
27
52
|
webSearchExtension,
|
|
28
53
|
webFetchExtension,
|
|
29
|
-
|
|
54
|
+
generateImageExtension,
|
|
55
|
+
askUserQuestionExtension,
|
|
30
56
|
subagentExtension,
|
|
31
57
|
listMcpResourcesExtension,
|
|
32
58
|
fetchMcpResourceExtension,
|
|
33
59
|
listMcpToolsExtension,
|
|
34
60
|
callMcpToolExtension,
|
|
35
61
|
switchModeExtension,
|
|
36
|
-
|
|
62
|
+
exitPlanModeExtension,
|
|
63
|
+
// applyPatchExtension,
|
|
64
|
+
codexApplyPatchExtension,
|
|
37
65
|
userMessageExtension,
|
|
38
66
|
systemPromptExtension,
|
|
39
67
|
sessionHintsExtension,
|
|
68
|
+
nvimExtension,
|
|
69
|
+
lspDiagnosticsExtension,
|
|
70
|
+
lspSymbolsExtension,
|
|
71
|
+
briefWriteExtension,
|
|
72
|
+
memorySearchExtension,
|
|
73
|
+
memoryGetExtension,
|
|
74
|
+
busSendExtension,
|
|
75
|
+
mailboxExtension,
|
|
40
76
|
];
|
|
41
77
|
export default function monoPilotExtension(pi) {
|
|
42
78
|
for (const register of toolExtensions) {
|
|
43
79
|
register(pi);
|
|
44
80
|
}
|
|
81
|
+
registerSessionMemoryHook(pi);
|
|
82
|
+
registerSystemEvents(pi);
|
|
83
|
+
registerBuildMemoryCommand(pi);
|
|
84
|
+
registerDigestCommand(pi);
|
|
85
|
+
registerClusterCommands(pi);
|
|
86
|
+
registerStatusCommand(pi);
|
|
87
|
+
registerImageModelCommands(pi);
|
|
88
|
+
registerSftpCommands(pi);
|
|
89
|
+
let handles = null;
|
|
90
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
91
|
+
if (handles) {
|
|
92
|
+
setClusterHandle(null);
|
|
93
|
+
setBusSendHandle(null);
|
|
94
|
+
await shutdownSubsystems(handles);
|
|
95
|
+
handles = null;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const h = await initSubsystems(pi, ctx, {
|
|
99
|
+
busMessageInjector: (msg) => {
|
|
100
|
+
const text = typeof msg.payload === "object" && msg.payload !== null && "text" in msg.payload
|
|
101
|
+
? msg.payload.text
|
|
102
|
+
: JSON.stringify(msg.payload);
|
|
103
|
+
const sender = msg.fromName ? `${msg.fromName} (${msg.from})` : msg.from;
|
|
104
|
+
const ch = msg.channel && msg.channel !== "public" ? ` [${msg.channel}]` : "";
|
|
105
|
+
const envelope = `<bus_messages>\n[from ${sender}${ch}] ${text}\n</bus_messages>\n\n` +
|
|
106
|
+
"You received the above messages from other agents via the message bus.";
|
|
107
|
+
pi.sendUserMessage(envelope, { deliverAs: "followUp" });
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
handles = h;
|
|
111
|
+
setClusterHandle(h.bus);
|
|
112
|
+
setBusSendHandle(h.bus);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
console.warn(`[subsystems] init failed: ${String(err)}`);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
pi.on("session_compact", async () => {
|
|
119
|
+
onCompaction();
|
|
120
|
+
});
|
|
121
|
+
pi.on("session_shutdown", async () => {
|
|
122
|
+
setClusterHandle(null);
|
|
123
|
+
setBusSendHandle(null);
|
|
124
|
+
await shutdownSubsystems(handles);
|
|
125
|
+
handles = null;
|
|
126
|
+
});
|
|
45
127
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
const NVIM_SHORTCUT = "alt+o";
|
|
3
|
+
function commandExists(command) {
|
|
4
|
+
const probe = process.platform === "win32" ? "where" : "which";
|
|
5
|
+
const result = spawnSync(probe, [command], { stdio: "ignore", shell: process.platform === "win32" });
|
|
6
|
+
return result.status === 0;
|
|
7
|
+
}
|
|
8
|
+
function resolveEditor() {
|
|
9
|
+
if (commandExists("nvim"))
|
|
10
|
+
return "nvim";
|
|
11
|
+
if (commandExists("vim"))
|
|
12
|
+
return "vim";
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
function openWorkspaceInEditor(ctx, editor) {
|
|
16
|
+
const result = spawnSync(editor, [ctx.cwd], {
|
|
17
|
+
stdio: "inherit",
|
|
18
|
+
shell: process.platform === "win32",
|
|
19
|
+
cwd: ctx.cwd,
|
|
20
|
+
});
|
|
21
|
+
if (result.error) {
|
|
22
|
+
return { ok: false, reason: result.error.message };
|
|
23
|
+
}
|
|
24
|
+
if (result.status !== 0) {
|
|
25
|
+
return { ok: false, reason: `${editor} exited with code ${result.status ?? 1}` };
|
|
26
|
+
}
|
|
27
|
+
return { ok: true };
|
|
28
|
+
}
|
|
29
|
+
export default function nvimExtension(pi) {
|
|
30
|
+
pi.registerShortcut(NVIM_SHORTCUT, {
|
|
31
|
+
description: "Open workspace in nvim file explorer (fallback: vim)",
|
|
32
|
+
handler: async (ctx) => {
|
|
33
|
+
if (!ctx.hasUI) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const editor = resolveEditor();
|
|
37
|
+
if (!editor) {
|
|
38
|
+
ctx.ui.notify("nvim/vim not found in PATH.", "warning");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const result = openWorkspaceInEditor(ctx, editor);
|
|
42
|
+
if (!result.ok) {
|
|
43
|
+
ctx.ui.notify(`Failed to open ${editor}: ${result.reason}`, "warning");
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|