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,90 @@
|
|
|
1
|
+
import { keyHint } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
3
|
+
import { Type } from "@sinclair/typebox";
|
|
4
|
+
import { deriveAgentId } from "../agents-paths.js";
|
|
5
|
+
import { getMemorySearchManager } from "../memory/runtime/index.js";
|
|
6
|
+
const DESCRIPTION = "Read a snippet from a memory file returned by memory_search. Supports optional line ranges.";
|
|
7
|
+
const memoryGetSchema = Type.Object({
|
|
8
|
+
path: Type.String({ description: "Absolute path to a memory file." }),
|
|
9
|
+
from: Type.Optional(Type.Number({ description: "1-based line number to start from." })),
|
|
10
|
+
lines: Type.Optional(Type.Number({ description: "Number of lines to read." })),
|
|
11
|
+
});
|
|
12
|
+
export default function memoryGetExtension(pi) {
|
|
13
|
+
pi.registerTool({
|
|
14
|
+
label: "MemoryGet",
|
|
15
|
+
name: "MemoryGet",
|
|
16
|
+
description: DESCRIPTION,
|
|
17
|
+
parameters: memoryGetSchema,
|
|
18
|
+
renderCall(args, theme) {
|
|
19
|
+
const input = args;
|
|
20
|
+
const pathArg = typeof input.path === "string" && input.path.trim().length > 0
|
|
21
|
+
? input.path
|
|
22
|
+
: "(missing path)";
|
|
23
|
+
const parts = [pathArg];
|
|
24
|
+
if (input.from !== undefined)
|
|
25
|
+
parts.push(`from=${input.from}`);
|
|
26
|
+
if (input.lines !== undefined)
|
|
27
|
+
parts.push(`lines=${input.lines}`);
|
|
28
|
+
let text = theme.fg("toolTitle", theme.bold("MemoryGet"));
|
|
29
|
+
text += ` ${theme.fg("toolOutput", parts.join(" "))}`;
|
|
30
|
+
return new Text(text, 0, 0);
|
|
31
|
+
},
|
|
32
|
+
renderResult(result, { expanded, isPartial }, theme) {
|
|
33
|
+
if (isPartial) {
|
|
34
|
+
return new Text(theme.fg("muted", "Reading..."), 0, 0);
|
|
35
|
+
}
|
|
36
|
+
const textBlock = result.content.find((entry) => entry.type === "text" && typeof entry.text === "string");
|
|
37
|
+
if (!textBlock || typeof textBlock.text !== "string") {
|
|
38
|
+
return new Text(theme.fg("error", "No text result returned."), 0, 0);
|
|
39
|
+
}
|
|
40
|
+
const fullText = textBlock.text;
|
|
41
|
+
const lineCount = fullText.split("\n").length;
|
|
42
|
+
if (!expanded) {
|
|
43
|
+
const summary = `${lineCount} lines (click or ${keyHint("expandTools", "to expand")})`;
|
|
44
|
+
return new Text(theme.fg("muted", summary), 0, 0);
|
|
45
|
+
}
|
|
46
|
+
let text = fullText
|
|
47
|
+
.split("\n")
|
|
48
|
+
.map((line) => theme.fg("toolOutput", line))
|
|
49
|
+
.join("\n");
|
|
50
|
+
text += theme.fg("muted", `\n(click or ${keyHint("expandTools", "to collapse")})`);
|
|
51
|
+
return new Text(text, 0, 0);
|
|
52
|
+
},
|
|
53
|
+
execute: async (_toolCallId, params, _signal, _onUpdate, ctx) => {
|
|
54
|
+
const manager = await getMemorySearchManager({
|
|
55
|
+
workspaceDir: ctx.cwd,
|
|
56
|
+
agentId: deriveAgentId(ctx.cwd),
|
|
57
|
+
});
|
|
58
|
+
if (!manager) {
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{ type: "text", text: "Memory get is disabled or unavailable." },
|
|
62
|
+
],
|
|
63
|
+
details: { path: params.path, from: params.from, lines: params.lines, disabled: true },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const result = await manager.get(params.path, params.from, params.lines);
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: "text", text: result.text }],
|
|
70
|
+
details: {
|
|
71
|
+
path: result.path,
|
|
72
|
+
from: params.from,
|
|
73
|
+
lines: params.lines,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: "text", text: `Memory get failed: ${message}` }],
|
|
81
|
+
details: {
|
|
82
|
+
path: params.path,
|
|
83
|
+
from: params.from,
|
|
84
|
+
lines: params.lines,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { keyHint } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
4
|
+
import { deriveAgentId } from "../agents-paths.js";
|
|
5
|
+
import { getMemorySearchManager } from "../memory/runtime/index.js";
|
|
6
|
+
const DESCRIPTION = "Search the memory index for relevant snippets. Supports scope: self, agent, all. Returns paths, line ranges, and scored excerpts.";
|
|
7
|
+
const memorySearchSchema = Type.Object({
|
|
8
|
+
query: Type.String({ description: "Search query for memory snippets." }),
|
|
9
|
+
instruct: Type.Optional(Type.String({ description: "Task instruction for the embedding model to improve retrieval quality. Default: general code/doc retrieval." })),
|
|
10
|
+
maxResults: Type.Optional(Type.Number({ description: "Maximum number of results to return." })),
|
|
11
|
+
minScore: Type.Optional(Type.Number({ description: "Minimum relevance score to include." })),
|
|
12
|
+
scope: Type.Optional(Type.Union([Type.Literal("self"), Type.Literal("agent"), Type.Literal("all")], { description: "Search scope." })),
|
|
13
|
+
targetAgentId: Type.Optional(Type.String({ description: "Target agent ID (required when scope=agent)." })),
|
|
14
|
+
});
|
|
15
|
+
const MAX_RENDER_QUERY_CHARS = 120;
|
|
16
|
+
const MAX_RENDER_AGENTID_CHARS = 120;
|
|
17
|
+
function compactForCommandArg(value, maxLength) {
|
|
18
|
+
const normalized = value.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n/g, "\\n").trim();
|
|
19
|
+
if (normalized.length <= maxLength)
|
|
20
|
+
return normalized;
|
|
21
|
+
return `${normalized.slice(0, Math.max(0, maxLength - 1))}…`;
|
|
22
|
+
}
|
|
23
|
+
function shellQuoteArg(value) {
|
|
24
|
+
if (value.length === 0)
|
|
25
|
+
return "''";
|
|
26
|
+
if (/^[A-Za-z0-9_./:=,+-]+$/.test(value))
|
|
27
|
+
return value;
|
|
28
|
+
return `'${value.replace(/'/g, `"'"'"'`)}'`;
|
|
29
|
+
}
|
|
30
|
+
function formatResultLine(params) {
|
|
31
|
+
const score = params.score.toFixed(3);
|
|
32
|
+
const location = `${params.path}:${params.startLine}-${params.endLine}`;
|
|
33
|
+
const scopePrefix = params.agentId ? `[${params.agentId}] ` : "";
|
|
34
|
+
return `${scopePrefix}${location} (score ${score})\n${params.snippet}`;
|
|
35
|
+
}
|
|
36
|
+
export default function memorySearchExtension(pi) {
|
|
37
|
+
pi.registerTool({
|
|
38
|
+
label: "MemorySearch",
|
|
39
|
+
name: "MemorySearch",
|
|
40
|
+
description: DESCRIPTION,
|
|
41
|
+
parameters: memorySearchSchema,
|
|
42
|
+
renderCall(args, theme) {
|
|
43
|
+
const input = args;
|
|
44
|
+
const rawQuery = typeof input.query === "string" ? input.query : "";
|
|
45
|
+
const query = rawQuery.trim().length > 0
|
|
46
|
+
? compactForCommandArg(rawQuery, MAX_RENDER_QUERY_CHARS)
|
|
47
|
+
: "(missing query)";
|
|
48
|
+
const scope = input.scope;
|
|
49
|
+
const targetAgentId = typeof input.targetAgentId === "string" && input.targetAgentId.trim().length > 0
|
|
50
|
+
? compactForCommandArg(input.targetAgentId, MAX_RENDER_AGENTID_CHARS)
|
|
51
|
+
: undefined;
|
|
52
|
+
const instruct = typeof input.instruct === "string" && input.instruct.trim().length > 0
|
|
53
|
+
? compactForCommandArg(input.instruct, MAX_RENDER_QUERY_CHARS)
|
|
54
|
+
: undefined;
|
|
55
|
+
const commandArgs = [query];
|
|
56
|
+
if (instruct)
|
|
57
|
+
commandArgs.push("--instruct", instruct);
|
|
58
|
+
if (scope)
|
|
59
|
+
commandArgs.push("--scope", scope);
|
|
60
|
+
if (targetAgentId)
|
|
61
|
+
commandArgs.push("--target-agent-id", targetAgentId);
|
|
62
|
+
if (input.maxResults != null)
|
|
63
|
+
commandArgs.push("--max-results", String(input.maxResults));
|
|
64
|
+
if (input.minScore != null)
|
|
65
|
+
commandArgs.push("--min-score", String(input.minScore));
|
|
66
|
+
const commandText = commandArgs.map(shellQuoteArg).join(" ");
|
|
67
|
+
let text = theme.fg("toolTitle", theme.bold("MemorySearch"));
|
|
68
|
+
text += ` ${theme.fg("toolOutput", commandText)}`;
|
|
69
|
+
return new Text(text, 0, 0);
|
|
70
|
+
},
|
|
71
|
+
renderResult(result, { expanded, isPartial }, theme) {
|
|
72
|
+
if (isPartial) {
|
|
73
|
+
return new Text(theme.fg("muted", "Searching..."), 0, 0);
|
|
74
|
+
}
|
|
75
|
+
const textBlock = result.content.find((entry) => entry.type === "text" && typeof entry.text === "string");
|
|
76
|
+
if (!textBlock || typeof textBlock.text !== "string") {
|
|
77
|
+
return new Text(theme.fg("error", "No text result returned."), 0, 0);
|
|
78
|
+
}
|
|
79
|
+
const fullText = textBlock.text;
|
|
80
|
+
const details = result.details;
|
|
81
|
+
const resultCount = details?.resultCount ?? 0;
|
|
82
|
+
if (!expanded) {
|
|
83
|
+
const summary = `${resultCount} results (click or ${keyHint("expandTools", "to expand")})`;
|
|
84
|
+
return new Text(theme.fg("muted", summary), 0, 0);
|
|
85
|
+
}
|
|
86
|
+
let text = fullText
|
|
87
|
+
.split("\n")
|
|
88
|
+
.map((line) => theme.fg("toolOutput", line))
|
|
89
|
+
.join("\n");
|
|
90
|
+
text += theme.fg("muted", `\n(click or ${keyHint("expandTools", "to collapse")})`);
|
|
91
|
+
return new Text(text, 0, 0);
|
|
92
|
+
},
|
|
93
|
+
execute: async (_toolCallId, params, _signal, _onUpdate, ctx) => {
|
|
94
|
+
const query = params.query.trim();
|
|
95
|
+
const instruct = params.instruct;
|
|
96
|
+
const maxResults = params.maxResults;
|
|
97
|
+
const minScore = params.minScore;
|
|
98
|
+
const scope = params.scope ?? "self";
|
|
99
|
+
const targetAgentId = params.targetAgentId;
|
|
100
|
+
if (scope === "agent" && !targetAgentId) {
|
|
101
|
+
return {
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: "targetAgentId is required when scope=agent.",
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
details: {
|
|
109
|
+
query,
|
|
110
|
+
maxResults,
|
|
111
|
+
minScore,
|
|
112
|
+
scope,
|
|
113
|
+
targetAgentId,
|
|
114
|
+
resultCount: 0,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const manager = await getMemorySearchManager({
|
|
119
|
+
workspaceDir: ctx.cwd,
|
|
120
|
+
agentId: deriveAgentId(ctx.cwd),
|
|
121
|
+
});
|
|
122
|
+
if (!manager) {
|
|
123
|
+
return {
|
|
124
|
+
content: [
|
|
125
|
+
{
|
|
126
|
+
type: "text",
|
|
127
|
+
text: "Memory search is disabled or unavailable.",
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
details: {
|
|
131
|
+
query,
|
|
132
|
+
maxResults,
|
|
133
|
+
minScore,
|
|
134
|
+
scope,
|
|
135
|
+
targetAgentId,
|
|
136
|
+
resultCount: 0,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
const results = await manager.search(query, {
|
|
142
|
+
instruct,
|
|
143
|
+
maxResults,
|
|
144
|
+
minScore,
|
|
145
|
+
scope,
|
|
146
|
+
targetAgentId,
|
|
147
|
+
});
|
|
148
|
+
const includeAgentId = scope !== "self";
|
|
149
|
+
const lines = results.map((result) => formatResultLine({
|
|
150
|
+
path: result.path,
|
|
151
|
+
startLine: result.startLine,
|
|
152
|
+
endLine: result.endLine,
|
|
153
|
+
score: result.score,
|
|
154
|
+
snippet: result.snippet,
|
|
155
|
+
agentId: includeAgentId ? result.agentId : undefined,
|
|
156
|
+
}));
|
|
157
|
+
const output = lines.length > 0 ? lines.join("\n\n") : "No memory matches found.";
|
|
158
|
+
const details = {
|
|
159
|
+
query,
|
|
160
|
+
maxResults,
|
|
161
|
+
minScore,
|
|
162
|
+
scope,
|
|
163
|
+
targetAgentId,
|
|
164
|
+
resultCount: results.length,
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
content: [{ type: "text", text: output }],
|
|
168
|
+
details,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
173
|
+
return {
|
|
174
|
+
content: [{ type: "text", text: `Memory search failed: ${message}` }],
|
|
175
|
+
details: { query, maxResults, minScore, scope, targetAgentId, resultCount: 0 },
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
}
|
|
@@ -3,11 +3,11 @@ You are now in Plan mode. Continue with the task in the new mode.
|
|
|
3
3
|
</system_reminder>
|
|
4
4
|
|
|
5
5
|
<system_reminder>
|
|
6
|
-
Plan mode is active
|
|
6
|
+
Plan mode is active until you call ExitPlanMode. The user indicated that they do not want you to execute yet -- you MUST NOT make any edits, run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supersedes any other instructions you have received (for example, to make edits). Instead, you should:
|
|
7
7
|
|
|
8
8
|
1. Answer the user's query comprehensively by searching to gather information
|
|
9
9
|
|
|
10
|
-
2. If you do not have enough information to create an accurate plan, you MUST ask the user for more information. If any of the user instructions are ambiguous, you MUST ask the user to clarify. Do not call
|
|
10
|
+
2. If you do not have enough information to create an accurate plan, you MUST ask the user for more information. If any of the user instructions are ambiguous, you MUST ask the user to clarify. Do not call ExitPlanMode until the user has answered all your questions. Propose sensible defaults and avoid overwhelming the user with many questions about trivial details.
|
|
11
11
|
|
|
12
12
|
3. If the user's request is too broad, you MUST ask the user questions that narrow down the scope of the plan. ONLY ask 1-2 critical questions at a time.
|
|
13
13
|
|
|
@@ -15,7 +15,7 @@ Plan mode is active, unless you have already seen the <end_plan_mode/> tag below
|
|
|
15
15
|
|
|
16
16
|
5. If you have determined that you will need to ask questions, you should ask them IMMEDIATELY at the start of the conversation. Prefer a small pre-read beforehand only if ≤5 files (~20s) will likely answer them.
|
|
17
17
|
|
|
18
|
-
6. When you're done researching
|
|
18
|
+
6. When you're done researching and your plan file is finalized, first present the plan to the user and wait for explicit approval. Only after the user approves should you call ExitPlanMode to leave Plan mode. Do NOT make any file changes or run any tools that modify the system state in any way until the user has confirmed the plan.
|
|
19
19
|
|
|
20
20
|
7. The plan should be concise, specific and actionable. Cite specific file paths and, if the plan is for a targeted code change, essential snippets of code (only if concise, informative and non-obvious). When mentioning files, use markdown links with the full file path (for example, `[backend/src/foo.ts](backend/src/foo.ts)`). The plan should be formatted as markdown.
|
|
21
21
|
|
|
@@ -58,5 +58,4 @@ When writing mermaid diagrams:
|
|
|
58
58
|
- Click events are disabled for security - don't use `click` syntax
|
|
59
59
|
</mermaid_syntax>
|
|
60
60
|
|
|
61
|
-
<begin_plan_mode/>
|
|
62
61
|
</system_reminder>
|
|
@@ -18,7 +18,6 @@ Image Support:
|
|
|
18
18
|
PDF Support:
|
|
19
19
|
- PDF files are converted into text content automatically (subject to the same character limits as other files).`;
|
|
20
20
|
const MAX_RENDER_PATH_CHARS = 120;
|
|
21
|
-
const MAX_COLLAPSED_RESULT_LINES = 5;
|
|
22
21
|
const readSchema = Type.Object({
|
|
23
22
|
path: Type.String({ description: "The absolute path of the file to read." }),
|
|
24
23
|
offset: Type.Optional(Type.Number({
|
|
@@ -112,19 +111,6 @@ function prefixLineNumbers(text, startLine, details) {
|
|
|
112
111
|
.join("\n");
|
|
113
112
|
return notice ? `${numberedText}\n\n${notice}` : numberedText;
|
|
114
113
|
}
|
|
115
|
-
function getCollapsedResultText(text, expanded) {
|
|
116
|
-
if (text.length === 0) {
|
|
117
|
-
return { output: text, remaining: 0 };
|
|
118
|
-
}
|
|
119
|
-
const lines = text.split("\n");
|
|
120
|
-
if (expanded || lines.length <= MAX_COLLAPSED_RESULT_LINES) {
|
|
121
|
-
return { output: text, remaining: 0 };
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
output: lines.slice(0, MAX_COLLAPSED_RESULT_LINES).join("\n"),
|
|
125
|
-
remaining: lines.length - MAX_COLLAPSED_RESULT_LINES,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
114
|
export default function (pi) {
|
|
129
115
|
// System prompt injection is handled centrally by system-prompt extension.
|
|
130
116
|
pi.registerTool({
|
|
@@ -157,14 +143,17 @@ export default function (pi) {
|
|
|
157
143
|
if (!textContent) {
|
|
158
144
|
return new Text("", 0, 0);
|
|
159
145
|
}
|
|
160
|
-
const
|
|
161
|
-
|
|
146
|
+
const fullText = textContent.text;
|
|
147
|
+
const lineCount = fullText.split("\n").length;
|
|
148
|
+
if (!expanded) {
|
|
149
|
+
const summary = `${lineCount} lines (click or ${keyHint("expandTools", "to expand")})`;
|
|
150
|
+
return new Text(theme.fg("muted", summary), 0, 0);
|
|
151
|
+
}
|
|
152
|
+
let text = fullText
|
|
162
153
|
.split("\n")
|
|
163
154
|
.map((line) => theme.fg("toolOutput", line))
|
|
164
155
|
.join("\n");
|
|
165
|
-
|
|
166
|
-
text += `${theme.fg("muted", `\n... (${remaining} more lines,`)} ${keyHint("expandTools", "to expand")})`;
|
|
167
|
-
}
|
|
156
|
+
text += theme.fg("muted", `\n(click or ${keyHint("expandTools", "to collapse")})`);
|
|
168
157
|
return new Text(text, 0, 0);
|
|
169
158
|
},
|
|
170
159
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
@@ -298,21 +298,6 @@ function shellQuoteArg(value) {
|
|
|
298
298
|
return value;
|
|
299
299
|
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
300
300
|
}
|
|
301
|
-
function getCollapsedResultText(text, expanded) {
|
|
302
|
-
if (text.length === 0) {
|
|
303
|
-
return { output: text, remaining: 0 };
|
|
304
|
-
}
|
|
305
|
-
const lines = text.split("\n");
|
|
306
|
-
// Use 20 lines as the standard collapse threshold
|
|
307
|
-
const MAX_COLLAPSED_RESULT_LINES = 20;
|
|
308
|
-
if (expanded || lines.length <= MAX_COLLAPSED_RESULT_LINES) {
|
|
309
|
-
return { output: text, remaining: 0 };
|
|
310
|
-
}
|
|
311
|
-
return {
|
|
312
|
-
output: lines.slice(0, MAX_COLLAPSED_RESULT_LINES).join("\n"),
|
|
313
|
-
remaining: lines.length - MAX_COLLAPSED_RESULT_LINES,
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
301
|
export const __test__ = {
|
|
317
302
|
applyPagination,
|
|
318
303
|
buildRgArgs,
|
|
@@ -380,15 +365,20 @@ export default function (pi) {
|
|
|
380
365
|
if (!textBlock || typeof textBlock.text !== "string") {
|
|
381
366
|
return new Text(theme.fg("error", "No text result returned."), 0, 0);
|
|
382
367
|
}
|
|
383
|
-
const
|
|
368
|
+
const fullText = textBlock.text;
|
|
369
|
+
const lineCount = fullText.split("\n").length;
|
|
370
|
+
const details = result.details;
|
|
371
|
+
const matchCount = details?.returned_entries ?? lineCount;
|
|
372
|
+
if (!expanded) {
|
|
373
|
+
const summary = `${matchCount} matches, ${lineCount} lines (click or ${keyHint("expandTools", "to expand")})`;
|
|
374
|
+
return new Text(theme.fg("muted", summary), 0, 0);
|
|
375
|
+
}
|
|
384
376
|
const isErrorResult = result.isError === true || result.details?.is_error === true;
|
|
385
|
-
let text =
|
|
377
|
+
let text = fullText
|
|
386
378
|
.split("\n")
|
|
387
379
|
.map((line) => (isErrorResult ? theme.fg("error", line) : theme.fg("toolOutput", line)))
|
|
388
380
|
.join("\n");
|
|
389
|
-
|
|
390
|
-
text += `${theme.fg("muted", `\n... (${remaining} more lines,`)} ${keyHint("expandTools", "to expand")})`;
|
|
391
|
-
}
|
|
381
|
+
text += theme.fg("muted", `\n(click or ${keyHint("expandTools", "to collapse")})`);
|
|
392
382
|
return new Text(text, 0, 0);
|
|
393
383
|
},
|
|
394
384
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { closeSync, createWriteStream, existsSync, mkdirSync, openSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync, writeSync, } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
3
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
4
|
import { fileURLToPath } from "node:url";
|
|
6
5
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, getShellConfig, keyHint, truncateTail, } from "@mariozechner/pi-coding-agent";
|
|
7
6
|
import { Text } from "@mariozechner/pi-tui";
|
|
8
7
|
import { Type } from "@sinclair/typebox";
|
|
8
|
+
import { deriveAgentId, getAgentTerminalsDir } from "../agents-paths.js";
|
|
9
9
|
// Tool docs are surfaced via system-prompt extension functions namespace.
|
|
10
10
|
const DEFAULT_BLOCK_UNTIL_MS = 30_000;
|
|
11
11
|
const UPDATE_RUNNING_SECONDS_EVERY_MS = 5_000;
|
|
12
12
|
const OUTPUT_CAPTURE_LIMIT_BYTES = DEFAULT_MAX_BYTES * 2;
|
|
13
13
|
const MAX_RENDER_COMMAND_CHARS = 180;
|
|
14
|
-
const MAX_COLLAPSED_RESULT_LINES = 5;
|
|
15
14
|
const DESCRIPTION = readFileSync(fileURLToPath(new URL("./shell-description.md", import.meta.url)), "utf-8").trim();
|
|
16
15
|
const shellSchema = Type.Object({
|
|
17
16
|
command: Type.String({ description: "The command to execute" }),
|
|
@@ -32,24 +31,10 @@ function compactCommandForRender(command) {
|
|
|
32
31
|
}
|
|
33
32
|
return `${singleLine.slice(0, MAX_RENDER_COMMAND_CHARS - 1)}…`;
|
|
34
33
|
}
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.replace(/^-+/, "");
|
|
40
|
-
}
|
|
41
|
-
function getTerminalsDir(workspaceCwd) {
|
|
42
|
-
const workspaceKey = encodeWorkspacePath(workspaceCwd);
|
|
43
|
-
const primary = join(resolve(workspaceCwd), ".pi", "terminals");
|
|
44
|
-
try {
|
|
45
|
-
mkdirSync(primary, { recursive: true });
|
|
46
|
-
return primary;
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
const fallback = join(tmpdir(), "pi-shell", workspaceKey, "terminals");
|
|
50
|
-
mkdirSync(fallback, { recursive: true });
|
|
51
|
-
return fallback;
|
|
52
|
-
}
|
|
34
|
+
function getTerminalsDir(agentId, sessionId) {
|
|
35
|
+
const dir = getAgentTerminalsDir(agentId, sessionId);
|
|
36
|
+
mkdirSync(dir, { recursive: true });
|
|
37
|
+
return dir;
|
|
53
38
|
}
|
|
54
39
|
function getNextTerminalId(terminalsDir) {
|
|
55
40
|
const entries = readdirSync(terminalsDir, { withFileTypes: true });
|
|
@@ -84,21 +69,6 @@ function parseEnvSnapshot(snapshot) {
|
|
|
84
69
|
}
|
|
85
70
|
return parsed;
|
|
86
71
|
}
|
|
87
|
-
function getCollapsedResultText(text, expanded) {
|
|
88
|
-
if (text.length === 0) {
|
|
89
|
-
return { output: text, remaining: 0 };
|
|
90
|
-
}
|
|
91
|
-
const lines = text.split("\n");
|
|
92
|
-
if (expanded || lines.length <= MAX_COLLAPSED_RESULT_LINES) {
|
|
93
|
-
return { output: text, remaining: 0 };
|
|
94
|
-
}
|
|
95
|
-
// Show the *last* 20 lines for shell output (tail), since errors and final output usually appear at the end.
|
|
96
|
-
// For backgrounded or partial it's fine, but typically we want the end of the log.
|
|
97
|
-
return {
|
|
98
|
-
output: lines.slice(-MAX_COLLAPSED_RESULT_LINES).join("\n"),
|
|
99
|
-
remaining: lines.length - MAX_COLLAPSED_RESULT_LINES,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
72
|
function updateRunningSecondsInHeader(session) {
|
|
103
73
|
const runningSeconds = Math.floor((Date.now() - session.startedAtMs) / 1000);
|
|
104
74
|
const runningLine = `running_for_seconds: ${String(runningSeconds).padStart(10, "0")}\n`;
|
|
@@ -427,15 +397,20 @@ export default function (pi) {
|
|
|
427
397
|
if (!textBlock || typeof textBlock.text !== "string") {
|
|
428
398
|
return new Text("", 0, 0);
|
|
429
399
|
}
|
|
430
|
-
const
|
|
431
|
-
|
|
400
|
+
const fullText = textBlock.text;
|
|
401
|
+
const lineCount = fullText.split("\n").length;
|
|
402
|
+
const details = result.details;
|
|
403
|
+
const exitCode = details?.exit_code;
|
|
404
|
+
const exitInfo = exitCode != null && exitCode !== 0 ? `, exit ${exitCode}` : "";
|
|
405
|
+
if (!expanded) {
|
|
406
|
+
const summary = `${lineCount} lines${exitInfo} (click or ${keyHint("expandTools", "to expand")})`;
|
|
407
|
+
return new Text(theme.fg(exitCode != null && exitCode !== 0 ? "error" : "muted", summary), 0, 0);
|
|
408
|
+
}
|
|
409
|
+
let text = fullText
|
|
432
410
|
.split("\n")
|
|
433
411
|
.map((line) => theme.fg("toolOutput", line))
|
|
434
412
|
.join("\n");
|
|
435
|
-
|
|
436
|
-
// Since we tail the output, the remaining lines are *before* the shown ones.
|
|
437
|
-
text = `${theme.fg("muted", `(... ${remaining} earlier lines, ${keyHint("expandTools", "to expand")})`)}\n${text}`;
|
|
438
|
-
}
|
|
413
|
+
text += theme.fg("muted", `\n(click or ${keyHint("expandTools", "to collapse")})`);
|
|
439
414
|
return new Text(text, 0, 0);
|
|
440
415
|
},
|
|
441
416
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
@@ -450,7 +425,9 @@ export default function (pi) {
|
|
|
450
425
|
const defaultWorkingDirectory = resolveWorkingDirectory(runtimeState.cwd, ctx.cwd);
|
|
451
426
|
const workingDirectory = resolveWorkingDirectory(params.working_directory ?? defaultWorkingDirectory, ctx.cwd);
|
|
452
427
|
const blockUntilMs = normalizeBlockUntilMs(params.block_until_ms);
|
|
453
|
-
const
|
|
428
|
+
const agentId = deriveAgentId(ctx.cwd);
|
|
429
|
+
const sessionId = ctx.sessionManager?.getSessionId?.() ?? "default";
|
|
430
|
+
const terminalsDir = getTerminalsDir(agentId, sessionId);
|
|
454
431
|
const session = createTerminalSession(terminalsDir, command, workingDirectory, runtimeState, activeSessions);
|
|
455
432
|
const waitResult = await waitForeground(session, blockUntilMs, signal);
|
|
456
433
|
if (!waitResult.completed || !waitResult.completion) {
|