@osovv/vv-opencode 0.21.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 (75) 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/{code-reviewer.md → vv-code-reviewer.md} +12 -4
  74. package/templates/agents/{implementer.md → vv-implementer.md} +14 -8
  75. package/templates/agents/{spec-reviewer.md → vv-spec-reviewer.md} +13 -5
@@ -0,0 +1,114 @@
1
+ // FILE: src/plugins/hashline-edit/edit-operation-primitives.ts
2
+ // VERSION: 0.1.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Apply validated hashline edit operations to an in-memory file snapshot one mutation at a time.
5
+ // SCOPE: Single-line replace, range replace, anchored insert-before/after, and BOF/EOF insert helpers.
6
+ // DEPENDS: [src/plugins/hashline-edit/autocorrect-replacement-lines.ts, src/plugins/hashline-edit/edit-text-normalization.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
+ // applySetLine - Replace or delete a single anchored line.
14
+ // applyReplaceLines - Replace or delete an inclusive anchored line range.
15
+ // applyInsertAfter - Insert lines after an anchored line.
16
+ // applyInsertBefore - Insert lines before an anchored line.
17
+ // applyAppend - Insert lines at EOF, creating content for an empty file.
18
+ // applyPrepend - Insert lines at BOF, creating content for an empty file.
19
+ // END_MODULE_MAP
20
+ import { autocorrectReplacementLines } from "./autocorrect-replacement-lines.js";
21
+ import { restoreLeadingIndent, stripInsertAnchorEcho, stripInsertBeforeEcho, stripRangeBoundaryEcho, toNewLines, } from "./edit-text-normalization.js";
22
+ import { parseLineRef, validateLineRef } from "./validation.js";
23
+ function shouldValidate(options) {
24
+ return options?.skipValidation !== true;
25
+ }
26
+ export function applySetLine(lines, anchor, newText, options) {
27
+ if (shouldValidate(options)) {
28
+ validateLineRef(lines, anchor);
29
+ }
30
+ const { line } = parseLineRef(anchor);
31
+ const result = [...lines];
32
+ const originalLine = lines[line - 1] ?? "";
33
+ const normalized = newText === null ? [] : toNewLines(newText);
34
+ const corrected = autocorrectReplacementLines([originalLine], normalized);
35
+ const replacement = corrected.map((entry, index) => {
36
+ if (index !== 0) {
37
+ return entry;
38
+ }
39
+ return restoreLeadingIndent(originalLine, entry);
40
+ });
41
+ result.splice(line - 1, 1, ...replacement);
42
+ return result;
43
+ }
44
+ export function applyReplaceLines(lines, startAnchor, endAnchor, newText, options) {
45
+ if (shouldValidate(options)) {
46
+ validateLineRef(lines, startAnchor);
47
+ validateLineRef(lines, endAnchor);
48
+ }
49
+ const { line: startLine } = parseLineRef(startAnchor);
50
+ const { line: endLine } = parseLineRef(endAnchor);
51
+ if (startLine > endLine) {
52
+ throw new Error(`Invalid range: start line ${startLine} cannot be greater than end line ${endLine}`);
53
+ }
54
+ const result = [...lines];
55
+ const originalRange = lines.slice(startLine - 1, endLine);
56
+ const normalized = newText === null ? [] : toNewLines(newText);
57
+ const stripped = stripRangeBoundaryEcho(lines, startLine, endLine, normalized);
58
+ const corrected = autocorrectReplacementLines(originalRange, stripped);
59
+ const restored = corrected.map((entry, index) => {
60
+ if (index !== 0) {
61
+ return entry;
62
+ }
63
+ return restoreLeadingIndent(lines[startLine - 1] ?? "", entry);
64
+ });
65
+ result.splice(startLine - 1, endLine - startLine + 1, ...restored);
66
+ return result;
67
+ }
68
+ export function applyInsertAfter(lines, anchor, text, options) {
69
+ if (shouldValidate(options)) {
70
+ validateLineRef(lines, anchor);
71
+ }
72
+ const { line } = parseLineRef(anchor);
73
+ const result = [...lines];
74
+ const newLines = stripInsertAnchorEcho(lines[line - 1] ?? "", toNewLines(text));
75
+ if (newLines.length === 0) {
76
+ throw new Error(`append (anchored) requires non-empty text for ${anchor}`);
77
+ }
78
+ result.splice(line, 0, ...newLines);
79
+ return result;
80
+ }
81
+ export function applyInsertBefore(lines, anchor, text, options) {
82
+ if (shouldValidate(options)) {
83
+ validateLineRef(lines, anchor);
84
+ }
85
+ const { line } = parseLineRef(anchor);
86
+ const result = [...lines];
87
+ const newLines = stripInsertBeforeEcho(lines[line - 1] ?? "", toNewLines(text));
88
+ if (newLines.length === 0) {
89
+ throw new Error(`prepend (anchored) requires non-empty text for ${anchor}`);
90
+ }
91
+ result.splice(line - 1, 0, ...newLines);
92
+ return result;
93
+ }
94
+ export function applyAppend(lines, text) {
95
+ const normalized = toNewLines(text);
96
+ if (normalized.length === 0) {
97
+ throw new Error("append requires non-empty text");
98
+ }
99
+ if (lines.length === 1 && lines[0] === "") {
100
+ return [...normalized];
101
+ }
102
+ return [...lines, ...normalized];
103
+ }
104
+ export function applyPrepend(lines, text) {
105
+ const normalized = toNewLines(text);
106
+ if (normalized.length === 0) {
107
+ throw new Error("prepend requires non-empty text");
108
+ }
109
+ if (lines.length === 1 && lines[0] === "") {
110
+ return [...normalized];
111
+ }
112
+ return [...normalized, ...lines];
113
+ }
114
+ //# sourceMappingURL=edit-operation-primitives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-operation-primitives.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/edit-operation-primitives.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { HashlineEdit } from "./types.js";
2
+ export interface HashlineApplyReport {
3
+ content: string;
4
+ noopEdits: number;
5
+ deduplicatedEdits: number;
6
+ }
7
+ export declare function applyHashlineEditsWithReport(content: string, edits: HashlineEdit[]): HashlineApplyReport;
@@ -0,0 +1,168 @@
1
+ // FILE: src/plugins/hashline-edit/edit-operations.ts
2
+ // VERSION: 0.1.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Validate, order, deduplicate, and apply a batch of hashline edit operations against a file snapshot.
5
+ // SCOPE: Batch anchor collection, overlap detection, exact-edit deduplication, bottom-up application ordering, and no-op reporting.
6
+ // DEPENDS: [src/plugins/hashline-edit/edit-operation-primitives.ts, src/plugins/hashline-edit/types.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
+ // HashlineApplyReport - Result shape returned after applying a batch of hashline edits.
14
+ // applyHashlineEditsWithReport - Validate and apply a batch of edits while reporting no-ops and deduplicated operations.
15
+ // END_MODULE_MAP
16
+ import { applyAppend, applyInsertAfter, applyInsertBefore, applyPrepend, applyReplaceLines, applySetLine, } from "./edit-operation-primitives.js";
17
+ import { normalizeLineRef, parseLineRef, validateLineRefs } from "./validation.js";
18
+ function arraysEqual(left, right) {
19
+ if (left.length !== right.length) {
20
+ return false;
21
+ }
22
+ for (let index = 0; index < left.length; index += 1) {
23
+ if ((left[index] ?? "") !== (right[index] ?? "")) {
24
+ return false;
25
+ }
26
+ }
27
+ return true;
28
+ }
29
+ function toLinePayload(lines) {
30
+ if (lines === null) {
31
+ return "<delete>";
32
+ }
33
+ return Array.isArray(lines) ? lines.join("\n") : lines;
34
+ }
35
+ function getEditLineNumber(edit) {
36
+ switch (edit.op) {
37
+ case "replace":
38
+ return parseLineRef(edit.end ?? edit.pos).line;
39
+ case "append":
40
+ case "prepend":
41
+ return edit.pos ? parseLineRef(edit.pos).line : Number.NEGATIVE_INFINITY;
42
+ }
43
+ }
44
+ function collectLineRefs(edits) {
45
+ return edits.flatMap((edit) => {
46
+ switch (edit.op) {
47
+ case "replace":
48
+ return edit.end ? [edit.pos, edit.end] : [edit.pos];
49
+ case "append":
50
+ case "prepend":
51
+ return edit.pos ? [edit.pos] : [];
52
+ }
53
+ });
54
+ }
55
+ function detectOverlappingRanges(edits) {
56
+ const ranges = [];
57
+ for (let index = 0; index < edits.length; index += 1) {
58
+ const edit = edits[index];
59
+ if (!edit || edit.op !== "replace" || !edit.end) {
60
+ continue;
61
+ }
62
+ ranges.push({
63
+ start: parseLineRef(edit.pos).line,
64
+ end: parseLineRef(edit.end).line,
65
+ index,
66
+ });
67
+ }
68
+ if (ranges.length < 2) {
69
+ return null;
70
+ }
71
+ ranges.sort((left, right) => left.start - right.start || left.end - right.end);
72
+ for (let index = 1; index < ranges.length; index += 1) {
73
+ const previous = ranges[index - 1];
74
+ const current = ranges[index];
75
+ if (current.start <= previous.end) {
76
+ return `Overlapping range edits detected: edit ${previous.index + 1} (lines ${previous.start}-${previous.end}) overlaps with edit ${current.index + 1} (lines ${current.start}-${current.end}).`;
77
+ }
78
+ }
79
+ return null;
80
+ }
81
+ function dedupeEdits(edits) {
82
+ const seen = new Set();
83
+ const deduped = [];
84
+ let deduplicatedEdits = 0;
85
+ for (const edit of edits) {
86
+ const key = JSON.stringify({
87
+ op: edit.op,
88
+ pos: edit.pos ? normalizeLineRef(edit.pos) : undefined,
89
+ end: "end" in edit && edit.end ? normalizeLineRef(edit.end) : undefined,
90
+ lines: toLinePayload(edit.lines),
91
+ });
92
+ if (seen.has(key)) {
93
+ deduplicatedEdits += 1;
94
+ continue;
95
+ }
96
+ seen.add(key);
97
+ deduped.push(edit);
98
+ }
99
+ return { edits: deduped, deduplicatedEdits };
100
+ }
101
+ export function applyHashlineEditsWithReport(content, edits) {
102
+ if (edits.length === 0) {
103
+ return {
104
+ content,
105
+ noopEdits: 0,
106
+ deduplicatedEdits: 0,
107
+ };
108
+ }
109
+ const dedupeResult = dedupeEdits(edits);
110
+ const editPrecedence = {
111
+ replace: 0,
112
+ append: 1,
113
+ prepend: 2,
114
+ };
115
+ const sortedEdits = dedupeResult.edits
116
+ .map((edit, index) => ({ edit, index }))
117
+ .sort((left, right) => {
118
+ const lineDelta = getEditLineNumber(right.edit) - getEditLineNumber(left.edit);
119
+ if (lineDelta !== 0) {
120
+ return lineDelta;
121
+ }
122
+ const precedenceDelta = editPrecedence[left.edit.op] - editPrecedence[right.edit.op];
123
+ if (precedenceDelta !== 0) {
124
+ return precedenceDelta;
125
+ }
126
+ return left.index - right.index;
127
+ })
128
+ .map((entry) => entry.edit);
129
+ const overlapError = detectOverlappingRanges(sortedEdits);
130
+ if (overlapError) {
131
+ throw new Error(overlapError);
132
+ }
133
+ const refs = collectLineRefs(sortedEdits);
134
+ let lines = content.length === 0 ? [] : content.split("\n");
135
+ validateLineRefs(lines, refs);
136
+ let noopEdits = 0;
137
+ for (const edit of sortedEdits) {
138
+ let next = lines;
139
+ switch (edit.op) {
140
+ case "replace":
141
+ next = edit.end
142
+ ? applyReplaceLines(lines, edit.pos, edit.end, edit.lines, { skipValidation: true })
143
+ : applySetLine(lines, edit.pos, edit.lines, { skipValidation: true });
144
+ break;
145
+ case "append":
146
+ next = edit.pos
147
+ ? applyInsertAfter(lines, edit.pos, edit.lines, { skipValidation: true })
148
+ : applyAppend(lines, edit.lines);
149
+ break;
150
+ case "prepend":
151
+ next = edit.pos
152
+ ? applyInsertBefore(lines, edit.pos, edit.lines, { skipValidation: true })
153
+ : applyPrepend(lines, edit.lines);
154
+ break;
155
+ }
156
+ if (arraysEqual(next, lines)) {
157
+ noopEdits += 1;
158
+ continue;
159
+ }
160
+ lines = next;
161
+ }
162
+ return {
163
+ content: lines.join("\n"),
164
+ noopEdits,
165
+ deduplicatedEdits: dedupeResult.deduplicatedEdits,
166
+ };
167
+ }
168
+ //# sourceMappingURL=edit-operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-operations.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/edit-operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function stripLinePrefixes(lines: string[]): string[];
2
+ export declare function toNewLines(input: string | string[]): string[];
3
+ export declare function restoreLeadingIndent(templateLine: string, line: string): string;
4
+ export declare function stripInsertAnchorEcho(anchorLine: string, newLines: string[]): string[];
5
+ export declare function stripInsertBeforeEcho(anchorLine: string, newLines: string[]): string[];
6
+ export declare function stripRangeBoundaryEcho(lines: string[], startLine: number, endLine: number, newLines: string[]): string[];
@@ -0,0 +1,123 @@
1
+ // FILE: src/plugins/hashline-edit/edit-text-normalization.ts
2
+ // VERSION: 0.1.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Normalize edit payload text so copied hashline rows and accidental diff markers do not corrupt replacements.
5
+ // SCOPE: Prefix stripping, line splitting, indentation restoration, and echo-line trimming for insert/replace payloads.
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
+ // stripLinePrefixes - Remove copied hashline or diff prefixes when most payload lines include them.
14
+ // toNewLines - Normalize string or string[] payloads into plain content lines.
15
+ // restoreLeadingIndent - Reapply the template line indentation for obvious unindented replacements.
16
+ // stripInsertAnchorEcho - Remove duplicated anchor echoes from append payloads.
17
+ // stripInsertBeforeEcho - Remove duplicated anchor echoes from prepend payloads.
18
+ // stripRangeBoundaryEcho - Remove duplicated surrounding lines accidentally included in replace payloads.
19
+ // END_MODULE_MAP
20
+ const HASHLINE_PREFIX_RE = /^\s*(?:>>>|>>)?\s*\d+\s*#\s*[ZPMQVRWSNKTXJBYH]{2}\|/;
21
+ const DIFF_PLUS_RE = /^[+](?![+])/;
22
+ function equalsIgnoringWhitespace(left, right) {
23
+ if (left === right) {
24
+ return true;
25
+ }
26
+ return left.replace(/\s+/g, "") === right.replace(/\s+/g, "");
27
+ }
28
+ function leadingWhitespace(text) {
29
+ return text.match(/^\s*/)?.[0] ?? "";
30
+ }
31
+ export function stripLinePrefixes(lines) {
32
+ let hashPrefixCount = 0;
33
+ let diffPlusCount = 0;
34
+ let nonEmpty = 0;
35
+ for (const line of lines) {
36
+ if (line.length === 0) {
37
+ continue;
38
+ }
39
+ nonEmpty += 1;
40
+ if (HASHLINE_PREFIX_RE.test(line)) {
41
+ hashPrefixCount += 1;
42
+ }
43
+ if (DIFF_PLUS_RE.test(line)) {
44
+ diffPlusCount += 1;
45
+ }
46
+ }
47
+ if (nonEmpty === 0) {
48
+ return lines;
49
+ }
50
+ const stripHash = hashPrefixCount > 0 && hashPrefixCount >= nonEmpty * 0.5;
51
+ const stripPlus = !stripHash && diffPlusCount > 0 && diffPlusCount >= nonEmpty * 0.5;
52
+ if (!stripHash && !stripPlus) {
53
+ return lines;
54
+ }
55
+ return lines.map((line) => {
56
+ if (stripHash) {
57
+ return line.replace(HASHLINE_PREFIX_RE, "");
58
+ }
59
+ if (stripPlus) {
60
+ return line.replace(DIFF_PLUS_RE, "");
61
+ }
62
+ return line;
63
+ });
64
+ }
65
+ export function toNewLines(input) {
66
+ if (Array.isArray(input)) {
67
+ return stripLinePrefixes(input);
68
+ }
69
+ return stripLinePrefixes(input.split("\n"));
70
+ }
71
+ export function restoreLeadingIndent(templateLine, line) {
72
+ if (line.length === 0) {
73
+ return line;
74
+ }
75
+ const templateIndent = leadingWhitespace(templateLine);
76
+ if (templateIndent.length === 0) {
77
+ return line;
78
+ }
79
+ if (leadingWhitespace(line).length > 0) {
80
+ return line;
81
+ }
82
+ if (templateLine.trim() === line.trim()) {
83
+ return line;
84
+ }
85
+ return `${templateIndent}${line}`;
86
+ }
87
+ export function stripInsertAnchorEcho(anchorLine, newLines) {
88
+ if (newLines.length === 0) {
89
+ return newLines;
90
+ }
91
+ if (equalsIgnoringWhitespace(newLines[0] ?? "", anchorLine)) {
92
+ return newLines.slice(1);
93
+ }
94
+ return newLines;
95
+ }
96
+ export function stripInsertBeforeEcho(anchorLine, newLines) {
97
+ if (newLines.length <= 1) {
98
+ return newLines;
99
+ }
100
+ if (equalsIgnoringWhitespace(newLines[newLines.length - 1] ?? "", anchorLine)) {
101
+ return newLines.slice(0, -1);
102
+ }
103
+ return newLines;
104
+ }
105
+ export function stripRangeBoundaryEcho(lines, startLine, endLine, newLines) {
106
+ const replacedCount = endLine - startLine + 1;
107
+ if (newLines.length <= 1 || newLines.length <= replacedCount) {
108
+ return newLines;
109
+ }
110
+ let output = newLines;
111
+ const beforeIndex = startLine - 2;
112
+ if (beforeIndex >= 0 && equalsIgnoringWhitespace(output[0] ?? "", lines[beforeIndex] ?? "")) {
113
+ output = output.slice(1);
114
+ }
115
+ const afterIndex = endLine;
116
+ if (afterIndex < lines.length &&
117
+ output.length > 0 &&
118
+ equalsIgnoringWhitespace(output[output.length - 1] ?? "", lines[afterIndex] ?? "")) {
119
+ output = output.slice(0, -1);
120
+ }
121
+ return output;
122
+ }
123
+ //# sourceMappingURL=edit-text-normalization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-text-normalization.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/edit-text-normalization.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface FileTextEnvelope {
2
+ content: string;
3
+ hadBom: boolean;
4
+ lineEnding: "\n" | "\r\n";
5
+ }
6
+ export declare function canonicalizeFileText(content: string): FileTextEnvelope;
7
+ export declare function restoreFileText(content: string, envelope: FileTextEnvelope): string;
@@ -0,0 +1,52 @@
1
+ // FILE: src/plugins/hashline-edit/file-text-canonicalization.ts
2
+ // VERSION: 0.1.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Canonicalize file text for anchor validation while preserving BOM and original line endings on write-back.
5
+ // SCOPE: BOM stripping, line-ending normalization, and restoration of the original text envelope after edits.
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
+ // FileTextEnvelope - Captures the canonical content plus original BOM and line-ending style.
14
+ // canonicalizeFileText - Normalize file text to LF without losing BOM or line-ending metadata.
15
+ // restoreFileText - Reapply the original line-ending style and BOM to canonical content.
16
+ // END_MODULE_MAP
17
+ function detectLineEnding(content) {
18
+ const crlfIndex = content.indexOf("\r\n");
19
+ const lfIndex = content.indexOf("\n");
20
+ if (lfIndex === -1 || crlfIndex === -1) {
21
+ return "\n";
22
+ }
23
+ return crlfIndex < lfIndex ? "\r\n" : "\n";
24
+ }
25
+ function stripBom(content) {
26
+ if (!content.startsWith("\uFEFF")) {
27
+ return { content, hadBom: false };
28
+ }
29
+ return { content: content.slice(1), hadBom: true };
30
+ }
31
+ function normalizeToLf(content) {
32
+ return content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
33
+ }
34
+ function restoreLineEndings(content, lineEnding) {
35
+ if (lineEnding === "\n") {
36
+ return content;
37
+ }
38
+ return content.replace(/\n/g, "\r\n");
39
+ }
40
+ export function canonicalizeFileText(content) {
41
+ const stripped = stripBom(content);
42
+ return {
43
+ content: normalizeToLf(stripped.content),
44
+ hadBom: stripped.hadBom,
45
+ lineEnding: detectLineEnding(stripped.content),
46
+ };
47
+ }
48
+ export function restoreFileText(content, envelope) {
49
+ const withLineEnding = restoreLineEndings(content, envelope.lineEnding);
50
+ return envelope.hadBom ? `\uFEFF${withLineEnding}` : withLineEnding;
51
+ }
52
+ //# sourceMappingURL=file-text-canonicalization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-text-canonicalization.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/file-text-canonicalization.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,iBAAiB;AACjB,wBAAwB;AACxB,wHAAwH;AACxH,gHAAgH;AAChH,gBAAgB;AAChB,oCAAoC;AACpC,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,+FAA+F;AAC/F,iGAAiG;AACjG,2FAA2F;AAC3F,iBAAiB;AAQjB,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAC/B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACrD,CAAC;AAED,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAe,EAAE,UAAyB;IACpE,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO;QACL,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC;QACxC,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,QAA0B;IACzE,MAAM,cAAc,GAAG,kBAAkB,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IACxE,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,cAAc,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC;AACtE,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function computeLineHash(lineNumber: number, content: string): string;
2
+ export declare function computeLegacyLineHash(lineNumber: number, content: string): string;
3
+ export declare function formatHashLine(lineNumber: number, content: string): string;
@@ -0,0 +1,34 @@
1
+ // FILE: src/plugins/hashline-edit/hash-computation.ts
2
+ // VERSION: 0.1.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Compute stable short line hashes used by hashline read output and edit anchors.
5
+ // SCOPE: Current and legacy line hash computation plus formatting helpers for rendered hashline rows.
6
+ // DEPENDS: [src/plugins/hashline-edit/constants.ts]
7
+ // LINKS: [M-PLUGIN-HASHLINE-EDIT]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // computeLineHash - Compute the current two-character hash for a line using trailing-whitespace-insensitive content.
14
+ // computeLegacyLineHash - Compute the previous whitespace-insensitive hash used for compatibility with earlier anchors.
15
+ // formatHashLine - Render a `line#hash|content` row for read-output enhancement.
16
+ // END_MODULE_MAP
17
+ import { HASHLINE_DICT } from "./constants.js";
18
+ const RE_SIGNIFICANT = /[\p{L}\p{N}]/u;
19
+ function computeNormalizedLineHash(lineNumber, normalizedContent) {
20
+ const seed = RE_SIGNIFICANT.test(normalizedContent) ? 0 : lineNumber;
21
+ const hash = Bun.hash.xxHash32(normalizedContent, seed);
22
+ const index = hash % 256;
23
+ return HASHLINE_DICT[index] ?? HASHLINE_DICT[0];
24
+ }
25
+ export function computeLineHash(lineNumber, content) {
26
+ return computeNormalizedLineHash(lineNumber, content.replace(/\r/g, "").trimEnd());
27
+ }
28
+ export function computeLegacyLineHash(lineNumber, content) {
29
+ return computeNormalizedLineHash(lineNumber, content.replace(/\r/g, "").replace(/\s+/g, ""));
30
+ }
31
+ export function formatHashLine(lineNumber, content) {
32
+ return `${lineNumber}#${computeLineHash(lineNumber, content)}|${content}`;
33
+ }
34
+ //# sourceMappingURL=hash-computation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash-computation.js","sourceRoot":"","sources":["../../../src/plugins/hashline-edit/hash-computation.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,iBAAiB;AACjB,wBAAwB;AACxB,6FAA6F;AAC7F,wGAAwG;AACxG,sDAAsD;AACtD,oCAAoC;AACpC,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,uHAAuH;AACvH,0HAA0H;AAC1H,mFAAmF;AACnF,iBAAiB;AAEjB,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,cAAc,GAAG,eAAe,CAAC;AAEvC,SAAS,yBAAyB,CAAC,UAAkB,EAAE,iBAAyB;IAC9E,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACrE,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,IAAI,GAAG,GAAG,CAAC;IACzB,OAAO,aAAa,CAAC,KAAK,CAAC,IAAI,aAAa,CAAC,CAAC,CAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,UAAkB,EAAE,OAAe;IACjE,OAAO,yBAAyB,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,UAAkB,EAAE,OAAe;IACvE,OAAO,yBAAyB,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAkB,EAAE,OAAe;IAChE,OAAO,GAAG,UAAU,IAAI,eAAe,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,OAAO,EAAE,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { type Plugin } from "@opencode-ai/plugin";
2
+ export declare const HashlineEditPlugin: Plugin;