@cueloop/schema 0.1.0-alpha.10 → 0.1.0-alpha.100
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/package.json +17 -17
- package/src/agent-comment.test.ts +26 -0
- package/src/agent-comment.ts +17 -0
- package/src/agent-harness.ts +71 -0
- package/src/agent-input.test.ts +9 -0
- package/src/agent-input.ts +9 -0
- package/src/agent-submission.test.ts +15 -0
- package/src/agent-submission.ts +38 -0
- package/src/anchor.test.ts +340 -40
- package/src/anchor.ts +374 -43
- package/src/diff.test.ts +42 -25
- package/src/diff.ts +112 -79
- package/src/feedback.test.ts +318 -41
- package/src/feedback.ts +218 -55
- package/src/fuzzy.test.ts +110 -0
- package/src/fuzzy.ts +129 -0
- package/src/harness-output-routing.test.ts +18 -0
- package/src/harness-output-routing.ts +12 -0
- package/src/herdr.test.ts +50 -0
- package/src/herdr.ts +54 -0
- package/src/history.test.ts +401 -0
- package/src/history.ts +413 -0
- package/src/index.ts +18 -0
- package/src/inline.test.ts +195 -0
- package/src/inline.ts +234 -0
- package/src/markdown.test.ts +138 -22
- package/src/markdown.ts +332 -86
- package/src/participants.test.ts +105 -0
- package/src/participants.ts +51 -0
- package/src/path-view.test.ts +233 -0
- package/src/path-view.ts +105 -0
- package/src/share-access.test.ts +29 -0
- package/src/share-access.ts +14 -0
- package/src/thread-agent.ts +92 -0
- package/src/thread-surface.test.ts +6 -0
- package/src/thread-surface.ts +6 -0
- package/src/types.test.ts +66 -5
- package/src/types.ts +260 -33
- package/src/working-copy.test.ts +209 -24
- package/src/working-copy.ts +148 -12
package/src/working-copy.ts
CHANGED
|
@@ -1,15 +1,95 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
1
|
+
/** Working-copy source surgery for block and character cuts plus block restoration. */
|
|
2
|
+
|
|
3
|
+
import { parseBlocks, sourceOffsetAt, type Block } from "./markdown";
|
|
4
|
+
import type { TextCut } from "./types";
|
|
5
|
+
|
|
6
|
+
/** Add one source range and normalize overlaps without copying on a no-op. */
|
|
7
|
+
export function mergeTextCut(
|
|
8
|
+
source: string,
|
|
9
|
+
cuts: readonly TextCut[],
|
|
10
|
+
start: number,
|
|
11
|
+
end: number,
|
|
12
|
+
): TextCut[] {
|
|
13
|
+
const boundedStart = Math.max(0, Math.min(start, source.length));
|
|
14
|
+
const boundedEnd = Math.max(boundedStart, Math.min(end, source.length));
|
|
15
|
+
|
|
16
|
+
if (boundedEnd === boundedStart) {
|
|
17
|
+
// SAFETY: a no-op returns the caller's array unchanged; callers never mutate the result.
|
|
18
|
+
return cuts as TextCut[];
|
|
19
|
+
}
|
|
20
|
+
const ranges = [
|
|
21
|
+
...cuts.map((cut) => ({ start: cut.start, end: cut.end })),
|
|
22
|
+
{ start: boundedStart, end: boundedEnd },
|
|
23
|
+
]
|
|
24
|
+
.map((range) => ({
|
|
25
|
+
start: Math.max(0, Math.min(range.start, source.length)),
|
|
26
|
+
end: Math.max(0, Math.min(range.end, source.length)),
|
|
27
|
+
}))
|
|
28
|
+
.filter((range) => range.end > range.start)
|
|
29
|
+
.toSorted((left, right) => left.start - right.start || left.end - right.end);
|
|
30
|
+
const merged: Array<{ start: number; end: number }> = [];
|
|
31
|
+
|
|
32
|
+
for (const range of ranges) {
|
|
33
|
+
const previous = merged.at(-1);
|
|
34
|
+
|
|
35
|
+
if (previous && range.start <= previous.end) previous.end = Math.max(previous.end, range.end);
|
|
36
|
+
else merged.push(range);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return merged.map((range) => ({
|
|
40
|
+
...range,
|
|
41
|
+
quote: source.slice(range.start, range.end),
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Restore a selected part of one contiguous character Cut. */
|
|
46
|
+
export function restoreTextCut(
|
|
47
|
+
source: string,
|
|
48
|
+
cuts: readonly TextCut[],
|
|
49
|
+
start: number,
|
|
50
|
+
end: number,
|
|
51
|
+
): TextCut[] | null {
|
|
52
|
+
const cutIndex = cuts.findIndex((cut) => cut.start <= start && end <= cut.end);
|
|
7
53
|
|
|
8
|
-
|
|
54
|
+
if (cutIndex === -1 || end <= start) return null;
|
|
55
|
+
const cut = cuts[cutIndex]!;
|
|
56
|
+
const replacements: TextCut[] = [];
|
|
57
|
+
|
|
58
|
+
if (cut.start < start) {
|
|
59
|
+
replacements.push({ start: cut.start, end: start, quote: source.slice(cut.start, start) });
|
|
60
|
+
}
|
|
61
|
+
if (end < cut.end) {
|
|
62
|
+
replacements.push({ start: end, end: cut.end, quote: source.slice(end, cut.end) });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return [...cuts.slice(0, cutIndex), ...replacements, ...cuts.slice(cutIndex + 1)];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Apply valid source ranges in source order, ignoring stale or overlapping records. */
|
|
69
|
+
export function applyTextCuts(source: string, cuts: readonly TextCut[]): string {
|
|
70
|
+
if (cuts.length === 0) return source;
|
|
71
|
+
let cursor = 0;
|
|
72
|
+
const pieces: string[] = [];
|
|
73
|
+
|
|
74
|
+
for (const cut of cuts.toSorted(
|
|
75
|
+
(left, right) => left.start - right.start || left.end - right.end,
|
|
76
|
+
)) {
|
|
77
|
+
if (cut.start < cursor || cut.start < 0 || cut.end > source.length || cut.end <= cut.start)
|
|
78
|
+
continue;
|
|
79
|
+
if (source.slice(cut.start, cut.end) !== cut.quote) continue;
|
|
80
|
+
|
|
81
|
+
pieces.push(source.slice(cursor, cut.start));
|
|
82
|
+
cursor = cut.end;
|
|
83
|
+
}
|
|
84
|
+
pieces.push(source.slice(cursor));
|
|
85
|
+
|
|
86
|
+
return pieces.join("");
|
|
87
|
+
}
|
|
9
88
|
|
|
10
89
|
/** Chunk of the base source a block occupies (for restore and display). */
|
|
11
90
|
export function sourceChunk(base: string, block: Block): string {
|
|
12
91
|
const lines = base.split("\n");
|
|
92
|
+
|
|
13
93
|
return lines.slice(block.lineStart, block.lineEnd + 1).join("\n");
|
|
14
94
|
}
|
|
15
95
|
|
|
@@ -18,10 +98,50 @@ export function cutBlock(working: string, block: Block): string {
|
|
|
18
98
|
const lines = working.split("\n");
|
|
19
99
|
const before = lines.slice(0, block.lineStart);
|
|
20
100
|
const after = lines.slice(block.lineEnd + 1);
|
|
101
|
+
|
|
21
102
|
while (before.length && before[before.length - 1]!.trim() === "") before.pop();
|
|
103
|
+
|
|
22
104
|
return [...before, ...after].join("\n");
|
|
23
105
|
}
|
|
24
106
|
|
|
107
|
+
/** Source interval removed by a whole-block Cut, including its leading blank-line padding. */
|
|
108
|
+
export function blockCutSourceRange(source: string, block: Block) {
|
|
109
|
+
const lines = source.split("\n");
|
|
110
|
+
let startLine = block.lineStart;
|
|
111
|
+
|
|
112
|
+
while (startLine > 0 && lines[startLine - 1]!.trim() === "") startLine--;
|
|
113
|
+
const lineStarts = [0];
|
|
114
|
+
|
|
115
|
+
for (let index = 0; index < source.length; index++) {
|
|
116
|
+
if (source.charCodeAt(index) === 10) lineStarts.push(index + 1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
start: lineStarts[startLine] ?? source.length,
|
|
121
|
+
end: lineStarts[block.lineEnd + 1] ?? source.length,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Remove exactly the selected block-text range while retaining surrounding
|
|
127
|
+
* Markdown markers. A cross-block range also removes the source between its
|
|
128
|
+
* endpoint characters.
|
|
129
|
+
*/
|
|
130
|
+
export function cutTextRange(
|
|
131
|
+
working: string,
|
|
132
|
+
startBlock: Block,
|
|
133
|
+
start: number,
|
|
134
|
+
endBlock: Block,
|
|
135
|
+
end: number,
|
|
136
|
+
): string {
|
|
137
|
+
const sourceStart = sourceOffsetAt(working, startBlock, start) ?? -1;
|
|
138
|
+
const sourceEnd = sourceOffsetAt(working, endBlock, end) ?? -1;
|
|
139
|
+
|
|
140
|
+
if (sourceStart < 0 || sourceEnd <= sourceStart) return working;
|
|
141
|
+
|
|
142
|
+
return working.slice(0, sourceStart) + working.slice(sourceEnd);
|
|
143
|
+
}
|
|
144
|
+
|
|
25
145
|
/** The line a restored block re-enters at: the next surviving block's start. */
|
|
26
146
|
export function restoreLine(next: Block | undefined, workingLineCount: number): number {
|
|
27
147
|
return next ? next.lineStart : workingLineCount;
|
|
@@ -34,10 +154,24 @@ export function restoreLine(next: Block | undefined, workingLineCount: number):
|
|
|
34
154
|
*/
|
|
35
155
|
function signature(text: string): string {
|
|
36
156
|
return parseBlocks(text)
|
|
37
|
-
.map((
|
|
157
|
+
.map((block) => block.kind + " " + block.text)
|
|
38
158
|
.join("\0");
|
|
39
159
|
}
|
|
40
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Whether a base block is missing from the working source: the working copy
|
|
163
|
+
* holds fewer blocks with its kind and text than the base does. Only such a
|
|
164
|
+
* block can be restored without duplicating content.
|
|
165
|
+
*/
|
|
166
|
+
export function isBlockCut(base: string, working: string, block: Block): boolean {
|
|
167
|
+
const matches = (text: string) =>
|
|
168
|
+
parseBlocks(text).filter(
|
|
169
|
+
(candidate) => candidate.kind === block.kind && candidate.text === block.text,
|
|
170
|
+
).length;
|
|
171
|
+
|
|
172
|
+
return matches(working) < matches(base);
|
|
173
|
+
}
|
|
174
|
+
|
|
41
175
|
/**
|
|
42
176
|
* Re-insert a cut base block into the working source before `beforeLine`.
|
|
43
177
|
* Returns undefined when the block structure round-trips to the base content
|
|
@@ -53,9 +187,11 @@ export function restoreBlock(
|
|
|
53
187
|
const lines = working.split("\n");
|
|
54
188
|
const before = lines.slice(0, beforeLine);
|
|
55
189
|
const after = lines.slice(beforeLine);
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
190
|
+
const insertedLines = sourceChunk(base, block).split("\n");
|
|
191
|
+
|
|
192
|
+
if (before.length && before[before.length - 1]!.trim() !== "") insertedLines.unshift("");
|
|
193
|
+
if (after.length && after[0]!.trim() !== "") insertedLines.push("");
|
|
194
|
+
const restored = [...before, ...insertedLines, ...after].join("\n");
|
|
195
|
+
|
|
60
196
|
return signature(restored) === signature(base) ? undefined : restored;
|
|
61
197
|
}
|