@osovv/vv-opencode 0.19.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +45 -9
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +9 -5
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/managed-agents.d.ts +3 -3
  6. package/dist/lib/managed-agents.js +14 -13
  7. package/dist/lib/managed-agents.js.map +1 -1
  8. package/dist/lib/model-roles.d.ts +3 -3
  9. package/dist/lib/model-roles.js +5 -4
  10. package/dist/lib/model-roles.js.map +1 -1
  11. package/dist/lib/opencode.js +100 -5
  12. package/dist/lib/opencode.js.map +1 -1
  13. package/dist/lib/vvoc-config.js +5 -4
  14. package/dist/lib/vvoc-config.js.map +1 -1
  15. package/dist/plugins/hashline-edit/autocorrect-replacement-lines.d.ts +1 -0
  16. package/dist/plugins/hashline-edit/autocorrect-replacement-lines.js +184 -0
  17. package/dist/plugins/hashline-edit/autocorrect-replacement-lines.js.map +1 -0
  18. package/dist/plugins/hashline-edit/constants.d.ts +4 -0
  19. package/dist/plugins/hashline-edit/constants.js +26 -0
  20. package/dist/plugins/hashline-edit/constants.js.map +1 -0
  21. package/dist/plugins/hashline-edit/edit-operation-primitives.d.ts +10 -0
  22. package/dist/plugins/hashline-edit/edit-operation-primitives.js +114 -0
  23. package/dist/plugins/hashline-edit/edit-operation-primitives.js.map +1 -0
  24. package/dist/plugins/hashline-edit/edit-operations.d.ts +7 -0
  25. package/dist/plugins/hashline-edit/edit-operations.js +168 -0
  26. package/dist/plugins/hashline-edit/edit-operations.js.map +1 -0
  27. package/dist/plugins/hashline-edit/edit-text-normalization.d.ts +6 -0
  28. package/dist/plugins/hashline-edit/edit-text-normalization.js +123 -0
  29. package/dist/plugins/hashline-edit/edit-text-normalization.js.map +1 -0
  30. package/dist/plugins/hashline-edit/file-text-canonicalization.d.ts +7 -0
  31. package/dist/plugins/hashline-edit/file-text-canonicalization.js +52 -0
  32. package/dist/plugins/hashline-edit/file-text-canonicalization.js.map +1 -0
  33. package/dist/plugins/hashline-edit/hash-computation.d.ts +3 -0
  34. package/dist/plugins/hashline-edit/hash-computation.js +34 -0
  35. package/dist/plugins/hashline-edit/hash-computation.js.map +1 -0
  36. package/dist/plugins/hashline-edit/index.d.ts +2 -0
  37. package/dist/plugins/hashline-edit/index.js +246 -0
  38. package/dist/plugins/hashline-edit/index.js.map +1 -0
  39. package/dist/plugins/hashline-edit/normalize-edits.d.ts +10 -0
  40. package/dist/plugins/hashline-edit/normalize-edits.js +82 -0
  41. package/dist/plugins/hashline-edit/normalize-edits.js.map +1 -0
  42. package/dist/plugins/hashline-edit/tool-description.d.ts +1 -0
  43. package/dist/plugins/hashline-edit/tool-description.js +35 -0
  44. package/dist/plugins/hashline-edit/tool-description.js.map +1 -0
  45. package/dist/plugins/hashline-edit/types.d.ts +17 -0
  46. package/dist/plugins/hashline-edit/types.js +19 -0
  47. package/dist/plugins/hashline-edit/types.js.map +1 -0
  48. package/dist/plugins/hashline-edit/validation.d.ts +20 -0
  49. package/dist/plugins/hashline-edit/validation.js +160 -0
  50. package/dist/plugins/hashline-edit/validation.js.map +1 -0
  51. package/dist/plugins/system-context-injection/index.js +65 -2
  52. package/dist/plugins/system-context-injection/index.js.map +1 -1
  53. package/dist/plugins/workflow/index.d.ts +2 -0
  54. package/dist/plugins/workflow/index.js +411 -0
  55. package/dist/plugins/workflow/index.js.map +1 -0
  56. package/dist/plugins/workflow/protocol.d.ts +33 -0
  57. package/dist/plugins/workflow/protocol.js +188 -0
  58. package/dist/plugins/workflow/protocol.js.map +1 -0
  59. package/dist/plugins/workflow/state.d.ts +79 -0
  60. package/dist/plugins/workflow/state.js +307 -0
  61. package/dist/plugins/workflow/state.js.map +1 -0
  62. package/dist/plugins/workflow/system-instruction.md +14 -0
  63. package/dist/plugins/workflow/tooling.d.ts +26 -0
  64. package/dist/plugins/workflow/tooling.js +161 -0
  65. package/dist/plugins/workflow/tooling.js.map +1 -0
  66. package/dist/plugins/workflow/transitions.d.ts +7 -0
  67. package/dist/plugins/workflow/transitions.js +102 -0
  68. package/dist/plugins/workflow/transitions.js.map +1 -0
  69. package/package.json +11 -3
  70. package/schemas/vvoc/v1.json +1 -1
  71. package/schemas/vvoc/v2.json +1 -1
  72. package/schemas/vvoc/v3.json +1 -1
  73. package/templates/agents/enhancer.md +54 -21
  74. package/templates/agents/investitagor.md +18 -6
  75. package/templates/agents/vv-code-reviewer.md +57 -0
  76. package/templates/agents/vv-implementer.md +78 -0
  77. package/templates/agents/vv-spec-reviewer.md +62 -0
  78. package/templates/agents/code-reviewer.md +0 -37
  79. package/templates/agents/implementer.md +0 -53
  80. package/templates/agents/spec-reviewer.md +0 -41
@@ -0,0 +1,246 @@
1
+ // FILE: src/plugins/hashline-edit/index.ts
2
+ // VERSION: 0.1.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Override OpenCode's default `edit` tool with a hash-anchored edit implementation and hash-aware read output.
5
+ // SCOPE: Hashline-backed edit tool registration, read-output transformation, anchor validation, file mutation execution, and success metadata emission.
6
+ // DEPENDS: [@opencode-ai/plugin, src/plugins/hashline-edit/edit-operations.ts, src/plugins/hashline-edit/file-text-canonicalization.ts, src/plugins/hashline-edit/hash-computation.ts, src/plugins/hashline-edit/normalize-edits.ts, src/plugins/hashline-edit/tool-description.ts, src/plugins/hashline-edit/validation.ts]
7
+ // LINKS: [M-PLUGIN-HASHLINE-EDIT]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // HashlineEditPlugin - Registers the hash-anchored `edit` tool override and post-read output enhancer.
14
+ // END_MODULE_MAP
15
+ //
16
+ // START_CHANGE_SUMMARY
17
+ // LAST_CHANGE: [v0.1.0 - Added a default-on hash-anchored edit override that rewrites Read output to `line#hash|content` and rejects stale anchors on edit.]
18
+ // END_CHANGE_SUMMARY
19
+ import { tool } from "@opencode-ai/plugin";
20
+ import { applyHashlineEditsWithReport } from "./edit-operations.js";
21
+ import { canonicalizeFileText, restoreFileText } from "./file-text-canonicalization.js";
22
+ import { computeLineHash } from "./hash-computation.js";
23
+ import { normalizeHashlineEdits } from "./normalize-edits.js";
24
+ import { HASHLINE_EDIT_DESCRIPTION } from "./tool-description.js";
25
+ import { HashlineMismatchError } from "./validation.js";
26
+ const z = tool.schema;
27
+ const CONTENT_OPEN_TAG = "<content>";
28
+ const CONTENT_CLOSE_TAG = "</content>";
29
+ const FILE_OPEN_TAG = "<file>";
30
+ const FILE_CLOSE_TAG = "</file>";
31
+ const OPENCODE_LINE_TRUNCATION_SUFFIX = "... (line truncated to 2000 chars)";
32
+ const COLON_READ_LINE_PATTERN = /^\s*(\d+): ?(.*)$/;
33
+ const PIPE_READ_LINE_PATTERN = /^\s*(\d+)\| ?(.*)$/;
34
+ function canCreateFromMissingFile(edits) {
35
+ if (edits.length === 0) {
36
+ return false;
37
+ }
38
+ return edits.every((edit) => (edit.op === "append" || edit.op === "prepend") && edit.pos === undefined);
39
+ }
40
+ function findFirstChangedLine(beforeContent, afterContent) {
41
+ const beforeLines = beforeContent.split("\n");
42
+ const afterLines = afterContent.split("\n");
43
+ const maxLength = Math.max(beforeLines.length, afterLines.length);
44
+ for (let index = 0; index < maxLength; index += 1) {
45
+ if ((beforeLines[index] ?? "") !== (afterLines[index] ?? "")) {
46
+ return index + 1;
47
+ }
48
+ }
49
+ return undefined;
50
+ }
51
+ function publishSuccessMetadata(args) {
52
+ args.context.metadata({
53
+ title: args.filePath,
54
+ metadata: {
55
+ filePath: args.filePath,
56
+ path: args.filePath,
57
+ file: args.filePath,
58
+ noopEdits: args.noopEdits,
59
+ deduplicatedEdits: args.deduplicatedEdits,
60
+ firstChangedLine: findFirstChangedLine(args.beforeContent, args.afterContent),
61
+ filediff: {
62
+ file: args.filePath,
63
+ path: args.filePath,
64
+ filePath: args.filePath,
65
+ before: args.beforeContent,
66
+ after: args.afterContent,
67
+ },
68
+ },
69
+ });
70
+ }
71
+ function isReadTool(toolName) {
72
+ return toolName.toLowerCase() === "read";
73
+ }
74
+ function isTextFileOutput(output) {
75
+ const firstLine = output.split("\n")[0] ?? "";
76
+ return COLON_READ_LINE_PATTERN.test(firstLine) || PIPE_READ_LINE_PATTERN.test(firstLine);
77
+ }
78
+ function parseReadLine(line) {
79
+ const colonMatch = COLON_READ_LINE_PATTERN.exec(line);
80
+ if (colonMatch) {
81
+ return {
82
+ lineNumber: Number.parseInt(colonMatch[1] ?? "0", 10),
83
+ content: colonMatch[2] ?? "",
84
+ };
85
+ }
86
+ const pipeMatch = PIPE_READ_LINE_PATTERN.exec(line);
87
+ if (pipeMatch) {
88
+ return {
89
+ lineNumber: Number.parseInt(pipeMatch[1] ?? "0", 10),
90
+ content: pipeMatch[2] ?? "",
91
+ };
92
+ }
93
+ return null;
94
+ }
95
+ function transformReadLine(line) {
96
+ const parsed = parseReadLine(line);
97
+ if (!parsed) {
98
+ return line;
99
+ }
100
+ if (parsed.content.endsWith(OPENCODE_LINE_TRUNCATION_SUFFIX)) {
101
+ return line;
102
+ }
103
+ return `${parsed.lineNumber}#${computeLineHash(parsed.lineNumber, parsed.content)}|${parsed.content}`;
104
+ }
105
+ function transformReadOutput(output) {
106
+ if (!output) {
107
+ return output;
108
+ }
109
+ const lines = output.split("\n");
110
+ const contentStart = lines.findIndex((line) => line === CONTENT_OPEN_TAG || line.startsWith(CONTENT_OPEN_TAG));
111
+ const contentEnd = lines.indexOf(CONTENT_CLOSE_TAG);
112
+ const fileStart = lines.findIndex((line) => line === FILE_OPEN_TAG || line.startsWith(FILE_OPEN_TAG));
113
+ const fileEnd = lines.indexOf(FILE_CLOSE_TAG);
114
+ const blockStart = contentStart !== -1 ? contentStart : fileStart;
115
+ const blockEnd = contentStart !== -1 ? contentEnd : fileEnd;
116
+ const openTag = contentStart !== -1 ? CONTENT_OPEN_TAG : FILE_OPEN_TAG;
117
+ if (blockStart !== -1 && blockEnd !== -1 && blockEnd > blockStart) {
118
+ const openLine = lines[blockStart] ?? "";
119
+ const inlineFirst = openLine.startsWith(openTag) && openLine !== openTag ? openLine.slice(openTag.length) : null;
120
+ const fileLines = inlineFirst !== null
121
+ ? [inlineFirst, ...lines.slice(blockStart + 1, blockEnd)]
122
+ : lines.slice(blockStart + 1, blockEnd);
123
+ if (!isTextFileOutput(fileLines[0] ?? "")) {
124
+ return output;
125
+ }
126
+ const result = [];
127
+ for (const line of fileLines) {
128
+ if (!parseReadLine(line)) {
129
+ result.push(...fileLines.slice(result.length));
130
+ break;
131
+ }
132
+ result.push(transformReadLine(line));
133
+ }
134
+ const prefixLines = inlineFirst !== null
135
+ ? [...lines.slice(0, blockStart), openTag]
136
+ : lines.slice(0, blockStart + 1);
137
+ return [...prefixLines, ...result, ...lines.slice(blockEnd)].join("\n");
138
+ }
139
+ if (!isTextFileOutput(lines[0] ?? "")) {
140
+ return output;
141
+ }
142
+ const result = [];
143
+ for (const line of lines) {
144
+ if (!parseReadLine(line)) {
145
+ result.push(...lines.slice(result.length));
146
+ break;
147
+ }
148
+ result.push(transformReadLine(line));
149
+ }
150
+ return result.join("\n");
151
+ }
152
+ async function executeHashlineEdit(args, context) {
153
+ try {
154
+ const { filePath, rename, delete: deleteMode } = args;
155
+ if (deleteMode && rename) {
156
+ return "Error: delete and rename cannot be used together";
157
+ }
158
+ if (deleteMode && args.edits.length > 0) {
159
+ return "Error: delete mode requires edits to be an empty array";
160
+ }
161
+ if (!deleteMode && (!Array.isArray(args.edits) || args.edits.length === 0)) {
162
+ return "Error: edits parameter must be a non-empty array";
163
+ }
164
+ const edits = deleteMode ? [] : normalizeHashlineEdits(args.edits);
165
+ const file = Bun.file(filePath);
166
+ const exists = await file.exists();
167
+ if (!exists && !deleteMode && !canCreateFromMissingFile(edits)) {
168
+ return `Error: File not found: ${filePath}`;
169
+ }
170
+ if (deleteMode) {
171
+ if (!exists) {
172
+ return `Error: File not found: ${filePath}`;
173
+ }
174
+ await file.delete();
175
+ return `Successfully deleted ${filePath}`;
176
+ }
177
+ const rawOldContent = exists ? Buffer.from(await file.arrayBuffer()).toString("utf8") : "";
178
+ const oldEnvelope = canonicalizeFileText(rawOldContent);
179
+ const applyResult = applyHashlineEditsWithReport(oldEnvelope.content, edits);
180
+ const canonicalNewContent = applyResult.content;
181
+ if (canonicalNewContent === oldEnvelope.content && !rename) {
182
+ let diagnostic = `No changes made to ${filePath}. The edits produced identical content.`;
183
+ if (applyResult.noopEdits > 0) {
184
+ diagnostic += ` No-op edits: ${applyResult.noopEdits}. Re-read the file and provide content that differs from the current lines.`;
185
+ }
186
+ return `Error: ${diagnostic}`;
187
+ }
188
+ const writeContent = restoreFileText(canonicalNewContent, oldEnvelope);
189
+ await Bun.write(filePath, writeContent);
190
+ if (rename && rename !== filePath) {
191
+ await Bun.write(rename, writeContent);
192
+ await Bun.file(filePath).delete();
193
+ }
194
+ const effectivePath = rename && rename !== filePath ? rename : filePath;
195
+ publishSuccessMetadata({
196
+ context,
197
+ filePath: effectivePath,
198
+ beforeContent: oldEnvelope.content,
199
+ afterContent: canonicalNewContent,
200
+ noopEdits: applyResult.noopEdits,
201
+ deduplicatedEdits: applyResult.deduplicatedEdits,
202
+ });
203
+ return rename && rename !== filePath
204
+ ? `Moved ${filePath} to ${rename}`
205
+ : `Updated ${effectivePath}`;
206
+ }
207
+ catch (error) {
208
+ const message = error instanceof Error ? error.message : String(error);
209
+ if (error instanceof HashlineMismatchError) {
210
+ return `Error: hash mismatch - ${message}\nTip: reuse LINE#ID entries from the latest read output or mismatch snippet, or batch related edits in one call.`;
211
+ }
212
+ return `Error: ${message}`;
213
+ }
214
+ }
215
+ export const HashlineEditPlugin = async () => {
216
+ return {
217
+ "tool.execute.after": async (input, output) => {
218
+ if (!isReadTool(input.tool) || typeof output.output !== "string") {
219
+ return;
220
+ }
221
+ output.output = transformReadOutput(output.output);
222
+ },
223
+ tool: {
224
+ edit: tool({
225
+ description: HASHLINE_EDIT_DESCRIPTION,
226
+ args: {
227
+ filePath: z.string().describe("Absolute path to the file to edit"),
228
+ delete: z.boolean().optional().describe("Delete the file instead of editing it"),
229
+ rename: z.string().optional().describe("Rename the file after edits are applied"),
230
+ edits: z
231
+ .array(z.object({
232
+ op: z.enum(["replace", "append", "prepend"]),
233
+ pos: z.string().optional().describe("Primary anchor in LINE#HASH format"),
234
+ end: z.string().optional().describe("Inclusive range end in LINE#HASH format"),
235
+ lines: z
236
+ .union([z.array(z.string()), z.string(), z.null()])
237
+ .describe("Replacement or inserted lines as plain text content"),
238
+ }))
239
+ .describe("Hash-anchored edit operations to apply to the file"),
240
+ },
241
+ execute: (args, context) => executeHashlineEdit(args, context),
242
+ }),
243
+ },
244
+ };
245
+ };
246
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { HashlineEdit } from "./types.js";
2
+ type HashlineToolOp = "replace" | "append" | "prepend";
3
+ export interface RawHashlineEdit {
4
+ op?: HashlineToolOp;
5
+ pos?: string;
6
+ end?: string;
7
+ lines?: string | string[] | null;
8
+ }
9
+ export declare function normalizeHashlineEdits(rawEdits: RawHashlineEdit[]): HashlineEdit[];
10
+ export {};
@@ -0,0 +1,82 @@
1
+ // FILE: src/plugins/hashline-edit/normalize-edits.ts
2
+ // VERSION: 0.1.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Validate and normalize raw hashline tool arguments into strongly-typed edit operations.
5
+ // SCOPE: Raw edit input shape, anchor trimming, required-field validation, and replace/append/prepend normalization.
6
+ // DEPENDS: [src/plugins/hashline-edit/types.ts]
7
+ // LINKS: [M-PLUGIN-HASHLINE-EDIT]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // RawHashlineEdit - Tool-facing edit input before validation and normalization.
14
+ // normalizeHashlineEdits - Convert raw tool args into validated HashlineEdit operations.
15
+ // END_MODULE_MAP
16
+ function normalizeAnchor(value) {
17
+ if (typeof value !== "string") {
18
+ return undefined;
19
+ }
20
+ const trimmed = value.trim();
21
+ return trimmed === "" ? undefined : trimmed;
22
+ }
23
+ function requireLines(edit, index) {
24
+ if (edit.lines === undefined) {
25
+ throw new Error(`Edit ${index}: lines is required for ${edit.op ?? "unknown"}`);
26
+ }
27
+ return edit.lines;
28
+ }
29
+ function requireAnchor(anchor, index, op) {
30
+ if (!anchor) {
31
+ throw new Error(`Edit ${index}: ${op} requires at least one anchor line reference (pos or end)`);
32
+ }
33
+ return anchor;
34
+ }
35
+ function normalizeReplaceEdit(edit, index) {
36
+ const pos = normalizeAnchor(edit.pos);
37
+ const end = normalizeAnchor(edit.end);
38
+ const anchor = requireAnchor(pos ?? end, index, "replace");
39
+ const lines = requireLines(edit, index);
40
+ const normalized = {
41
+ op: "replace",
42
+ pos: anchor,
43
+ lines,
44
+ };
45
+ if (end) {
46
+ normalized.end = end;
47
+ }
48
+ return normalized;
49
+ }
50
+ function normalizeInsertEdit(edit, index, op) {
51
+ const pos = normalizeAnchor(edit.pos);
52
+ const end = normalizeAnchor(edit.end);
53
+ const anchor = pos ?? end;
54
+ const lines = requireLines(edit, index);
55
+ if (lines === null) {
56
+ throw new Error(`Edit ${index}: ${op} does not support lines=null`);
57
+ }
58
+ const normalized = {
59
+ op,
60
+ lines,
61
+ };
62
+ if (anchor) {
63
+ normalized.pos = anchor;
64
+ }
65
+ return normalized;
66
+ }
67
+ export function normalizeHashlineEdits(rawEdits) {
68
+ return rawEdits.map((rawEdit, index) => {
69
+ const edit = rawEdit ?? {};
70
+ switch (edit.op) {
71
+ case "replace":
72
+ return normalizeReplaceEdit(edit, index);
73
+ case "append":
74
+ return normalizeInsertEdit(edit, index, "append");
75
+ case "prepend":
76
+ return normalizeInsertEdit(edit, index, "prepend");
77
+ default:
78
+ throw new Error(`Edit ${index}: unsupported op "${String(edit.op)}". Use replace, append, or prepend.`);
79
+ }
80
+ });
81
+ }
82
+ //# sourceMappingURL=normalize-edits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-edits.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/normalize-edits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const HASHLINE_EDIT_DESCRIPTION = "Edit files using exact hash-anchored line references from the latest Read output.\n\nWorkflow:\n1. Read the file and copy anchors in `{line}#{hash}` form from rows like `42#VK|content`.\n2. Submit one `edit` call per file with the smallest possible set of replace/append/prepend operations.\n3. If the same file needs another call after a successful edit, re-read it first.\n\nRules:\n- Every anchored edit must use exact current `{line}#{hash}` values from the latest Read output.\n- All edits in one call target the ORIGINAL file snapshot; do not adjust line numbers for earlier edits in the same batch.\n- `replace` with `pos` only replaces one line.\n- `replace` with `pos` and `end` replaces the inclusive range `pos..end`.\n- `append` inserts after the anchor, or at EOF when no anchor is provided.\n- `prepend` inserts before the anchor, or at BOF when no anchor is provided.\n- `lines: null` or `lines: []` with `replace` deletes the targeted line or range.\n- `lines` must contain plain replacement content only, not copied `line#hash|content` rows.\n- Prefer one operation per logical mutation site instead of a single oversized replace.\n\nRecovery:\n- If you get a hash mismatch error, copy the updated anchors shown in that error or re-read the file before retrying.";
@@ -0,0 +1,35 @@
1
+ // FILE: src/plugins/hashline-edit/tool-description.ts
2
+ // VERSION: 0.1.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Provide the LLM-facing tool description for the hash-anchored edit override.
5
+ // SCOPE: Stable instructions for read-then-edit workflow, anchor usage, operation choice, and stale-anchor recovery.
6
+ // DEPENDS: []
7
+ // LINKS: [M-PLUGIN-HASHLINE-EDIT]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // HASHLINE_EDIT_DESCRIPTION - Canonical LLM-facing description for the hashline-backed `edit` tool.
14
+ // END_MODULE_MAP
15
+ export const HASHLINE_EDIT_DESCRIPTION = `Edit files using exact hash-anchored line references from the latest Read output.
16
+
17
+ Workflow:
18
+ 1. Read the file and copy anchors in \`{line}#{hash}\` form from rows like \`42#VK|content\`.
19
+ 2. Submit one \`edit\` call per file with the smallest possible set of replace/append/prepend operations.
20
+ 3. If the same file needs another call after a successful edit, re-read it first.
21
+
22
+ Rules:
23
+ - Every anchored edit must use exact current \`{line}#{hash}\` values from the latest Read output.
24
+ - All edits in one call target the ORIGINAL file snapshot; do not adjust line numbers for earlier edits in the same batch.
25
+ - \`replace\` with \`pos\` only replaces one line.
26
+ - \`replace\` with \`pos\` and \`end\` replaces the inclusive range \`pos..end\`.
27
+ - \`append\` inserts after the anchor, or at EOF when no anchor is provided.
28
+ - \`prepend\` inserts before the anchor, or at BOF when no anchor is provided.
29
+ - \`lines: null\` or \`lines: []\` with \`replace\` deletes the targeted line or range.
30
+ - \`lines\` must contain plain replacement content only, not copied \`line#hash|content\` rows.
31
+ - Prefer one operation per logical mutation site instead of a single oversized replace.
32
+
33
+ Recovery:
34
+ - If you get a hash mismatch error, copy the updated anchors shown in that error or re-read the file before retrying.`;
35
+ //# sourceMappingURL=tool-description.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-description.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/tool-description.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,iBAAiB;AACjB,wBAAwB;AACxB,0FAA0F;AAC1F,uHAAuH;AACvH,gBAAgB;AAChB,oCAAoC;AACpC,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,sGAAsG;AACtG,iBAAiB;AAEjB,MAAM,CAAC,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;;sHAmB6E,CAAC"}
@@ -0,0 +1,17 @@
1
+ export interface ReplaceEdit {
2
+ op: "replace";
3
+ pos: string;
4
+ end?: string;
5
+ lines: string | string[] | null;
6
+ }
7
+ export interface AppendEdit {
8
+ op: "append";
9
+ pos?: string;
10
+ lines: string | string[];
11
+ }
12
+ export interface PrependEdit {
13
+ op: "prepend";
14
+ pos?: string;
15
+ lines: string | string[];
16
+ }
17
+ export type HashlineEdit = ReplaceEdit | AppendEdit | PrependEdit;
@@ -0,0 +1,19 @@
1
+ // FILE: src/plugins/hashline-edit/types.ts
2
+ // VERSION: 0.1.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Define the normalized edit operation shapes accepted by the hash-anchored edit executor.
5
+ // SCOPE: Replace, append, and prepend operation contracts plus the shared HashlineEdit union.
6
+ // DEPENDS: []
7
+ // LINKS: [M-PLUGIN-HASHLINE-EDIT]
8
+ // ROLE: TYPES
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // ReplaceEdit - Replace or delete a single line or inclusive range anchored by hashline references.
14
+ // AppendEdit - Insert content after an optional anchor or at EOF when no anchor is provided.
15
+ // PrependEdit - Insert content before an optional anchor or at BOF when no anchor is provided.
16
+ // HashlineEdit - Union of all normalized hashline edit operations.
17
+ // END_MODULE_MAP
18
+ export {};
19
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/types.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,iBAAiB;AACjB,wBAAwB;AACxB,sGAAsG;AACtG,gGAAgG;AAChG,gBAAgB;AAChB,oCAAoC;AACpC,gBAAgB;AAChB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,sGAAsG;AACtG,+FAA+F;AAC/F,iGAAiG;AACjG,qEAAqE;AACrE,iBAAiB"}
@@ -0,0 +1,20 @@
1
+ export interface LineRef {
2
+ line: number;
3
+ hash: string;
4
+ }
5
+ interface HashMismatch {
6
+ line: number;
7
+ expected: string;
8
+ }
9
+ export declare function normalizeLineRef(ref: string): string;
10
+ export declare function parseLineRef(ref: string): LineRef;
11
+ export declare class HashlineMismatchError extends Error {
12
+ private readonly mismatches;
13
+ private readonly fileLines;
14
+ readonly remaps: ReadonlyMap<string, string>;
15
+ constructor(mismatches: HashMismatch[], fileLines: string[]);
16
+ static formatMessage(mismatches: HashMismatch[], fileLines: string[]): string;
17
+ }
18
+ export declare function validateLineRef(lines: string[], ref: string): void;
19
+ export declare function validateLineRefs(lines: string[], refs: string[]): void;
20
+ export {};
@@ -0,0 +1,160 @@
1
+ // FILE: src/plugins/hashline-edit/validation.ts
2
+ // VERSION: 0.1.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Parse and validate hashline references against the current file snapshot before edits are applied.
5
+ // SCOPE: Anchor normalization, line reference parsing, full-batch validation, mismatch diagnostics, and compatibility fallback for legacy hashes.
6
+ // DEPENDS: [src/plugins/hashline-edit/constants.ts, src/plugins/hashline-edit/hash-computation.ts]
7
+ // LINKS: [M-PLUGIN-HASHLINE-EDIT]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // LineRef - Parsed `{ line, hash }` structure for a normalized hashline anchor.
14
+ // normalizeLineRef - Strip copied prefixes and inline content from a raw anchor string.
15
+ // parseLineRef - Parse a normalized hashline anchor and fail loudly on malformed references.
16
+ // validateLineRef - Validate a single anchor against the current file lines.
17
+ // validateLineRefs - Validate a batch of anchors and aggregate mismatches.
18
+ // HashlineMismatchError - Rich mismatch error that includes updated surrounding anchors.
19
+ // END_MODULE_MAP
20
+ import { HASHLINE_REF_PATTERN } from "./constants.js";
21
+ import { computeLegacyLineHash, computeLineHash } from "./hash-computation.js";
22
+ const MISMATCH_CONTEXT = 2;
23
+ const LINE_REF_EXTRACT_PATTERN = /([0-9]+#[ZPMQVRWSNKTXJBYH]{2})/;
24
+ function isCompatibleLineHash(line, content, hash) {
25
+ return computeLineHash(line, content) === hash || computeLegacyLineHash(line, content) === hash;
26
+ }
27
+ export function normalizeLineRef(ref) {
28
+ const originalTrimmed = ref.trim();
29
+ let trimmed = originalTrimmed;
30
+ trimmed = trimmed.replace(/^(?:>>>|[+-])\s*/, "");
31
+ trimmed = trimmed.replace(/\s*#\s*/, "#");
32
+ trimmed = trimmed.replace(/\|.*$/, "");
33
+ trimmed = trimmed.trim();
34
+ if (HASHLINE_REF_PATTERN.test(trimmed)) {
35
+ return trimmed;
36
+ }
37
+ const extracted = trimmed.match(LINE_REF_EXTRACT_PATTERN);
38
+ if (extracted) {
39
+ return extracted[1];
40
+ }
41
+ return originalTrimmed;
42
+ }
43
+ export function parseLineRef(ref) {
44
+ const normalized = normalizeLineRef(ref);
45
+ const match = normalized.match(HASHLINE_REF_PATTERN);
46
+ if (match) {
47
+ return {
48
+ line: Number.parseInt(match[1], 10),
49
+ hash: match[2],
50
+ };
51
+ }
52
+ const hashIndex = normalized.indexOf("#");
53
+ if (hashIndex > 0) {
54
+ const prefix = normalized.slice(0, hashIndex);
55
+ const suffix = normalized.slice(hashIndex + 1);
56
+ if (!/^\d+$/.test(prefix) && /^[ZPMQVRWSNKTXJBYH]{2}$/.test(suffix)) {
57
+ throw new Error(`Invalid line reference: "${ref}". "${prefix}" is not a line number. Use the exact line number from the latest read output.`);
58
+ }
59
+ }
60
+ throw new Error(`Invalid line reference format: "${ref}". Expected format: "{line_number}#{hash_id}"`);
61
+ }
62
+ export class HashlineMismatchError extends Error {
63
+ mismatches;
64
+ fileLines;
65
+ remaps;
66
+ constructor(mismatches, fileLines) {
67
+ super(HashlineMismatchError.formatMessage(mismatches, fileLines));
68
+ this.mismatches = mismatches;
69
+ this.fileLines = fileLines;
70
+ this.name = "HashlineMismatchError";
71
+ const remaps = new Map();
72
+ for (const mismatch of mismatches) {
73
+ const actual = computeLineHash(mismatch.line, fileLines[mismatch.line - 1] ?? "");
74
+ remaps.set(`${mismatch.line}#${mismatch.expected}`, `${mismatch.line}#${actual}`);
75
+ }
76
+ this.remaps = remaps;
77
+ }
78
+ static formatMessage(mismatches, fileLines) {
79
+ const mismatchByLine = new Map();
80
+ for (const mismatch of mismatches) {
81
+ mismatchByLine.set(mismatch.line, mismatch);
82
+ }
83
+ const displayLines = new Set();
84
+ for (const mismatch of mismatches) {
85
+ const low = Math.max(1, mismatch.line - MISMATCH_CONTEXT);
86
+ const high = Math.min(fileLines.length, mismatch.line + MISMATCH_CONTEXT);
87
+ for (let line = low; line <= high; line += 1) {
88
+ displayLines.add(line);
89
+ }
90
+ }
91
+ const sortedLines = [...displayLines].sort((left, right) => left - right);
92
+ const output = [];
93
+ output.push(`${mismatches.length} line${mismatches.length > 1 ? "s have" : " has"} changed since last read. Use updated {line_number}#{hash_id} references below (>>> marks changed lines).`);
94
+ output.push("");
95
+ let previousLine = -1;
96
+ for (const line of sortedLines) {
97
+ if (previousLine !== -1 && line > previousLine + 1) {
98
+ output.push(" ...");
99
+ }
100
+ previousLine = line;
101
+ const content = fileLines[line - 1] ?? "";
102
+ const hash = computeLineHash(line, content);
103
+ const formatted = `${line}#${hash}|${content}`;
104
+ output.push(mismatchByLine.has(line) ? `>>> ${formatted}` : ` ${formatted}`);
105
+ }
106
+ return output.join("\n");
107
+ }
108
+ }
109
+ function suggestLineForHash(ref, lines) {
110
+ const hashMatch = ref.trim().match(/#([ZPMQVRWSNKTXJBYH]{2})$/);
111
+ if (!hashMatch) {
112
+ return null;
113
+ }
114
+ const hash = hashMatch[1];
115
+ for (let index = 0; index < lines.length; index += 1) {
116
+ if (isCompatibleLineHash(index + 1, lines[index] ?? "", hash)) {
117
+ return `Did you mean "${index + 1}#${computeLineHash(index + 1, lines[index] ?? "")}"?`;
118
+ }
119
+ }
120
+ return null;
121
+ }
122
+ function parseLineRefWithHint(ref, lines) {
123
+ try {
124
+ return parseLineRef(ref);
125
+ }
126
+ catch (error) {
127
+ const hint = suggestLineForHash(ref, lines);
128
+ if (hint && error instanceof Error) {
129
+ throw new Error(`${error.message} ${hint}`);
130
+ }
131
+ throw error;
132
+ }
133
+ }
134
+ export function validateLineRef(lines, ref) {
135
+ const { line, hash } = parseLineRefWithHint(ref, lines);
136
+ if (line < 1 || line > lines.length) {
137
+ throw new Error(`Line number ${line} out of bounds. File has ${lines.length} lines.`);
138
+ }
139
+ const content = lines[line - 1] ?? "";
140
+ if (!isCompatibleLineHash(line, content, hash)) {
141
+ throw new HashlineMismatchError([{ line, expected: hash }], lines);
142
+ }
143
+ }
144
+ export function validateLineRefs(lines, refs) {
145
+ const mismatches = [];
146
+ for (const ref of refs) {
147
+ const { line, hash } = parseLineRefWithHint(ref, lines);
148
+ if (line < 1 || line > lines.length) {
149
+ throw new Error(`Line number ${line} out of bounds (file has ${lines.length} lines)`);
150
+ }
151
+ const content = lines[line - 1] ?? "";
152
+ if (!isCompatibleLineHash(line, content, hash)) {
153
+ mismatches.push({ line, expected: hash });
154
+ }
155
+ }
156
+ if (mismatches.length > 0) {
157
+ throw new HashlineMismatchError(mismatches, lines);
158
+ }
159
+ }
160
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/validation.ts"],"names":[],"mappings":"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"}