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
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { homedir } from "node:os";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
1
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, keyHint, truncateTail, } from "@mariozechner/pi-coding-agent";
|
|
4
2
|
import { Text } from "@mariozechner/pi-tui";
|
|
5
3
|
import { Type } from "@sinclair/typebox";
|
|
6
|
-
import {
|
|
4
|
+
import { McpServerError, resolveTargetServer } from "../mcp/servers.js";
|
|
5
|
+
import { createRpcRequestId, formatJsonRpcError, initializeMcpSession, postJsonRpcRequest } from "../mcp/protocol.js";
|
|
6
|
+
import { formatErrorMessage, getHeaderKeys, isRecord, toBoolean, toNonEmptyString } from "../mcp/config.js";
|
|
7
7
|
const DESCRIPTION = `Call an MCP tool by server identifier and tool name with arbitrary JSON arguments. IMPORTANT: Always read the tool's schema/descriptor BEFORE calling to ensure correct parameters.
|
|
8
8
|
|
|
9
9
|
Example:
|
|
@@ -45,10 +45,7 @@ async function callRemoteMcpTool(options) {
|
|
|
45
45
|
if (!callBody || callBody.result === undefined) {
|
|
46
46
|
throw new Error("MCP tools/call returned no result.");
|
|
47
47
|
}
|
|
48
|
-
return {
|
|
49
|
-
result: callBody.result,
|
|
50
|
-
sessionId,
|
|
51
|
-
};
|
|
48
|
+
return { result: callBody.result, sessionId };
|
|
52
49
|
}
|
|
53
50
|
function normalizeServerName(value) {
|
|
54
51
|
const normalized = value.trim();
|
|
@@ -142,27 +139,7 @@ function formatToolCallResultOutput(server, toolName, result) {
|
|
|
142
139
|
lines.push(JSON.stringify(result, null, 2));
|
|
143
140
|
lines.push("```");
|
|
144
141
|
}
|
|
145
|
-
return {
|
|
146
|
-
text: lines.join("\n"),
|
|
147
|
-
contentItems,
|
|
148
|
-
isError,
|
|
149
|
-
hasStructuredContent,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
function getCollapsedResultText(text, expanded) {
|
|
153
|
-
if (text.length === 0) {
|
|
154
|
-
return { output: text, remaining: 0 };
|
|
155
|
-
}
|
|
156
|
-
const lines = text.split("\n");
|
|
157
|
-
// Use 20 lines as the standard collapse threshold
|
|
158
|
-
const MAX_COLLAPSED_RESULT_LINES = 20;
|
|
159
|
-
if (expanded || lines.length <= MAX_COLLAPSED_RESULT_LINES) {
|
|
160
|
-
return { output: text, remaining: 0 };
|
|
161
|
-
}
|
|
162
|
-
return {
|
|
163
|
-
output: lines.slice(0, MAX_COLLAPSED_RESULT_LINES).join("\n"),
|
|
164
|
-
remaining: lines.length - MAX_COLLAPSED_RESULT_LINES,
|
|
165
|
-
};
|
|
142
|
+
return { text: lines.join("\n"), contentItems, isError, hasStructuredContent };
|
|
166
143
|
}
|
|
167
144
|
export default function callMcpToolExtension(pi) {
|
|
168
145
|
pi.registerTool({
|
|
@@ -171,10 +148,16 @@ export default function callMcpToolExtension(pi) {
|
|
|
171
148
|
description: DESCRIPTION,
|
|
172
149
|
parameters: callMcpToolSchema,
|
|
173
150
|
renderCall(args, theme) {
|
|
174
|
-
const
|
|
175
|
-
const
|
|
151
|
+
const input = args;
|
|
152
|
+
const server = typeof input.server === "string" && input.server.trim() ? input.server.trim() : "(missing server)";
|
|
153
|
+
const toolName = typeof input.toolName === "string" && input.toolName.trim() ? input.toolName.trim() : "(missing tool)";
|
|
154
|
+
const commandArgs = [server, toolName];
|
|
155
|
+
if (input.arguments && typeof input.arguments === "object" && Object.keys(input.arguments).length > 0) {
|
|
156
|
+
const json = JSON.stringify(input.arguments);
|
|
157
|
+
commandArgs.push(json.length > 120 ? `${json.slice(0, 119)}…` : json);
|
|
158
|
+
}
|
|
176
159
|
let text = theme.fg("toolTitle", theme.bold("CallMcpTool"));
|
|
177
|
-
text += ` ${theme.fg("toolOutput",
|
|
160
|
+
text += ` ${theme.fg("toolOutput", commandArgs.join(" "))}`;
|
|
178
161
|
return new Text(text, 0, 0);
|
|
179
162
|
},
|
|
180
163
|
renderResult(result, { expanded, isPartial }, theme) {
|
|
@@ -185,15 +168,18 @@ export default function callMcpToolExtension(pi) {
|
|
|
185
168
|
if (!textBlock || typeof textBlock.text !== "string") {
|
|
186
169
|
return new Text(theme.fg("error", "No text result returned."), 0, 0);
|
|
187
170
|
}
|
|
188
|
-
const
|
|
171
|
+
const fullText = textBlock.text;
|
|
172
|
+
const lineCount = fullText.split("\n").length;
|
|
189
173
|
const isErrorResult = result.isError === true || result.details?.is_error === true;
|
|
190
|
-
|
|
174
|
+
if (!expanded) {
|
|
175
|
+
const summary = `${lineCount} lines (click or ${keyHint("expandTools", "to expand")})`;
|
|
176
|
+
return new Text(theme.fg(isErrorResult ? "error" : "muted", summary), 0, 0);
|
|
177
|
+
}
|
|
178
|
+
let text = fullText
|
|
191
179
|
.split("\n")
|
|
192
180
|
.map((line) => (isErrorResult ? theme.fg("error", line) : theme.fg("toolOutput", line)))
|
|
193
181
|
.join("\n");
|
|
194
|
-
|
|
195
|
-
text += `${theme.fg("muted", `\n... (${remaining} more lines,`)} ${keyHint("expandTools", "to expand")})`;
|
|
196
|
-
}
|
|
182
|
+
text += theme.fg("muted", `\n(click or ${keyHint("expandTools", "to collapse")})`);
|
|
197
183
|
return new Text(text, 0, 0);
|
|
198
184
|
},
|
|
199
185
|
async execute(toolCallId, params, signal, _onUpdate, ctx) {
|
|
@@ -217,75 +203,21 @@ export default function callMcpToolExtension(pi) {
|
|
|
217
203
|
isError: true,
|
|
218
204
|
};
|
|
219
205
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const workspaceCandidate = resolve(ctx.cwd, MCP_CONFIG_RELATIVE_PATH);
|
|
223
|
-
const homeCandidate = resolve(homedir(), MCP_CONFIG_RELATIVE_PATH);
|
|
224
|
-
const message = `MCP config not found. Checked:\n- ${workspaceCandidate}\n- ${homeCandidate}`;
|
|
225
|
-
return {
|
|
226
|
-
content: [{ type: "text", text: message }],
|
|
227
|
-
details: {
|
|
228
|
-
server: serverName,
|
|
229
|
-
tool_name: toolName,
|
|
230
|
-
error: message,
|
|
231
|
-
},
|
|
232
|
-
isError: true,
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
let servers;
|
|
206
|
+
let server;
|
|
207
|
+
let configPaths;
|
|
236
208
|
try {
|
|
237
|
-
|
|
209
|
+
const result = await resolveTargetServer(ctx.cwd, serverName);
|
|
210
|
+
server = result.server;
|
|
211
|
+
configPaths = result.configPaths;
|
|
238
212
|
}
|
|
239
213
|
catch (error) {
|
|
240
214
|
const message = formatErrorMessage(error);
|
|
215
|
+
const transport = error instanceof McpServerError ? error.transport : undefined;
|
|
216
|
+
const paths = error instanceof McpServerError ? error.configPaths : undefined;
|
|
241
217
|
return {
|
|
242
218
|
content: [{ type: "text", text: message }],
|
|
243
219
|
details: {
|
|
244
|
-
|
|
245
|
-
server: serverName,
|
|
246
|
-
tool_name: toolName,
|
|
247
|
-
error: message,
|
|
248
|
-
},
|
|
249
|
-
isError: true,
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
const serverConfig = servers[serverName];
|
|
253
|
-
if (!serverConfig) {
|
|
254
|
-
const message = `MCP server '${serverName}' not found in ${configPath}.`;
|
|
255
|
-
return {
|
|
256
|
-
content: [{ type: "text", text: message }],
|
|
257
|
-
details: {
|
|
258
|
-
config_path: configPath,
|
|
259
|
-
server: serverName,
|
|
260
|
-
tool_name: toolName,
|
|
261
|
-
error: message,
|
|
262
|
-
},
|
|
263
|
-
isError: true,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
if (!isServerEnabled(serverConfig)) {
|
|
267
|
-
const message = `MCP server '${serverName}' is disabled in config.`;
|
|
268
|
-
return {
|
|
269
|
-
content: [{ type: "text", text: message }],
|
|
270
|
-
details: {
|
|
271
|
-
config_path: configPath,
|
|
272
|
-
server: serverName,
|
|
273
|
-
tool_name: toolName,
|
|
274
|
-
transport: inferTransport(serverConfig),
|
|
275
|
-
error: message,
|
|
276
|
-
},
|
|
277
|
-
isError: true,
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
const transport = inferTransport(serverConfig);
|
|
281
|
-
if (transport === "stdio") {
|
|
282
|
-
const command = toNonEmptyString(serverConfig.command);
|
|
283
|
-
const message = `MCP stdio transport is not supported yet in CallMcpTool.` +
|
|
284
|
-
(command ? ` Configured command: ${command}` : "");
|
|
285
|
-
return {
|
|
286
|
-
content: [{ type: "text", text: message }],
|
|
287
|
-
details: {
|
|
288
|
-
config_path: configPath,
|
|
220
|
+
config_paths: paths,
|
|
289
221
|
server: serverName,
|
|
290
222
|
tool_name: toolName,
|
|
291
223
|
transport,
|
|
@@ -294,26 +226,10 @@ export default function callMcpToolExtension(pi) {
|
|
|
294
226
|
isError: true,
|
|
295
227
|
};
|
|
296
228
|
}
|
|
297
|
-
const serverUrl = toNonEmptyString(serverConfig.url);
|
|
298
|
-
if (!serverUrl) {
|
|
299
|
-
const message = `MCP server '${serverName}' is missing a remote URL.`;
|
|
300
|
-
return {
|
|
301
|
-
content: [{ type: "text", text: message }],
|
|
302
|
-
details: {
|
|
303
|
-
config_path: configPath,
|
|
304
|
-
server: serverName,
|
|
305
|
-
tool_name: toolName,
|
|
306
|
-
transport,
|
|
307
|
-
error: message,
|
|
308
|
-
},
|
|
309
|
-
isError: true,
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
const headers = extractStringHeaders(serverConfig.headers);
|
|
313
229
|
try {
|
|
314
230
|
const remoteResult = await callRemoteMcpTool({
|
|
315
|
-
serverUrl,
|
|
316
|
-
serverHeaders: headers,
|
|
231
|
+
serverUrl: server.url,
|
|
232
|
+
serverHeaders: server.headers,
|
|
317
233
|
toolName,
|
|
318
234
|
argumentsValue,
|
|
319
235
|
signal,
|
|
@@ -331,12 +247,12 @@ export default function callMcpToolExtension(pi) {
|
|
|
331
247
|
return {
|
|
332
248
|
content: [{ type: "text", text: output }],
|
|
333
249
|
details: {
|
|
334
|
-
|
|
250
|
+
config_paths: configPaths,
|
|
335
251
|
server: serverName,
|
|
336
252
|
tool_name: toolName,
|
|
337
|
-
transport,
|
|
338
|
-
server_url:
|
|
339
|
-
header_keys: getHeaderKeys(headers),
|
|
253
|
+
transport: "remote",
|
|
254
|
+
server_url: server.url,
|
|
255
|
+
header_keys: getHeaderKeys(server.headers),
|
|
340
256
|
session_id: remoteResult.sessionId,
|
|
341
257
|
content_items: formatted.contentItems,
|
|
342
258
|
is_error: formatted.isError,
|
|
@@ -351,12 +267,12 @@ export default function callMcpToolExtension(pi) {
|
|
|
351
267
|
return {
|
|
352
268
|
content: [{ type: "text", text: `CallMcpTool failed: ${message}` }],
|
|
353
269
|
details: {
|
|
354
|
-
|
|
270
|
+
config_paths: configPaths,
|
|
355
271
|
server: serverName,
|
|
356
272
|
tool_name: toolName,
|
|
357
|
-
transport,
|
|
358
|
-
server_url:
|
|
359
|
-
header_keys: getHeaderKeys(headers),
|
|
273
|
+
transport: "remote",
|
|
274
|
+
server_url: server.url,
|
|
275
|
+
header_keys: getHeaderKeys(server.headers),
|
|
360
276
|
error: message,
|
|
361
277
|
},
|
|
362
278
|
isError: true,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Use this tool to edit files with codex-style patch syntax.
|
|
2
|
+
|
|
3
|
+
Patch envelope:
|
|
4
|
+
|
|
5
|
+
*** Begin Patch
|
|
6
|
+
[ one or more file sections ]
|
|
7
|
+
*** End Patch
|
|
8
|
+
|
|
9
|
+
Each file section starts with one header:
|
|
10
|
+
|
|
11
|
+
*** Add File: <path>
|
|
12
|
+
*** Delete File: <path>
|
|
13
|
+
*** Update File: <path>
|
|
14
|
+
|
|
15
|
+
For update sections, you can optionally rename with:
|
|
16
|
+
|
|
17
|
+
*** Move to: <new path>
|
|
18
|
+
|
|
19
|
+
Then include one or more chunks introduced by `@@` (optionally followed by a context header):
|
|
20
|
+
|
|
21
|
+
@@
|
|
22
|
+
@@ class MyClass
|
|
23
|
+
@@ def my_function(...)
|
|
24
|
+
|
|
25
|
+
Inside each update chunk, every line must start with one of:
|
|
26
|
+
|
|
27
|
+
- ` ` (space): context line
|
|
28
|
+
- `-`: removed line
|
|
29
|
+
- `+`: added line
|
|
30
|
+
|
|
31
|
+
Optional EOF anchor:
|
|
32
|
+
|
|
33
|
+
*** End of File
|
|
34
|
+
|
|
35
|
+
Grammar:
|
|
36
|
+
|
|
37
|
+
Patch := Begin { FileOp } End
|
|
38
|
+
Begin := "*** Begin Patch" NEWLINE
|
|
39
|
+
End := "*** End Patch" NEWLINE
|
|
40
|
+
FileOp := AddFile | DeleteFile | UpdateFile
|
|
41
|
+
AddFile := "*** Add File: " path NEWLINE { "+" line NEWLINE }
|
|
42
|
+
DeleteFile := "*** Delete File: " path NEWLINE
|
|
43
|
+
UpdateFile := "*** Update File: " path NEWLINE [ MoveTo ] { Chunk }
|
|
44
|
+
MoveTo := "*** Move to: " path NEWLINE
|
|
45
|
+
Chunk := "@@" [ header ] NEWLINE { ChunkLine } [ "*** End of File" NEWLINE ]
|
|
46
|
+
ChunkLine := (" " | "-" | "+") text NEWLINE
|
|
47
|
+
|
|
48
|
+
Important constraints:
|
|
49
|
+
|
|
50
|
+
- Paths must be relative (absolute paths are rejected)
|
|
51
|
+
- `*** Begin Patch` and `*** End Patch` are required
|
|
52
|
+
- Multiple file operations are supported in a single patch
|