@oh-my-pi/hashline 15.5.7 → 15.5.8
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 +24 -24
- package/dist/types/apply.d.ts +4 -5
- package/dist/types/format.d.ts +30 -34
- package/dist/types/input.d.ts +8 -8
- package/dist/types/messages.d.ts +33 -11
- package/dist/types/mismatch.d.ts +1 -1
- package/dist/types/parser.d.ts +20 -20
- package/dist/types/patcher.d.ts +16 -26
- package/dist/types/recovery.d.ts +4 -4
- package/dist/types/snapshots.d.ts +100 -41
- package/dist/types/tokenizer.d.ts +14 -12
- package/dist/types/types.d.ts +13 -18
- package/package.json +3 -3
- package/src/apply.ts +63 -605
- package/src/format.ts +34 -47
- package/src/grammar.lark +15 -14
- package/src/input.ts +77 -22
- package/src/messages.ts +39 -14
- package/src/mismatch.ts +4 -4
- package/src/parser.ts +269 -128
- package/src/patcher.ts +71 -67
- package/src/prefixes.ts +1 -1
- package/src/prompt.md +67 -109
- package/src/recovery.ts +45 -35
- package/src/snapshots.ts +247 -108
- package/src/tokenizer.ts +167 -105
- package/src/types.ts +15 -21
package/README.md
CHANGED
|
@@ -19,15 +19,15 @@ import {
|
|
|
19
19
|
} from "@oh-my-pi/hashline";
|
|
20
20
|
|
|
21
21
|
const fs = new InMemoryFilesystem();
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const patcher = new Patcher({ fs });
|
|
28
|
-
const patch = Patch.parse(String.raw`¶hello.ts
|
|
29
|
-
1
|
|
30
|
-
|
|
22
|
+
const snapshots = new InMemorySnapshotStore();
|
|
23
|
+
const before = `const greeting = "hi";\nexport { greeting };\n`;
|
|
24
|
+
await fs.writeText("hello.ts", before);
|
|
25
|
+
|
|
26
|
+
const tag = snapshots.recordContiguous("hello.ts", 1, before.split("\n"), { fullText: before });
|
|
27
|
+
const patcher = new Patcher({ fs, snapshots });
|
|
28
|
+
const patch = Patch.parse(String.raw`¶hello.ts#${tag}
|
|
29
|
+
@@ 1..1 @@
|
|
30
|
+
+const greeting = "hello";`);
|
|
31
31
|
const result = await patcher.apply(patch);
|
|
32
32
|
|
|
33
33
|
console.log(result.sections[0].op); // "update"
|
|
@@ -39,19 +39,19 @@ console.log(await fs.readText("hello.ts"));
|
|
|
39
39
|
See [`src/prompt.md`](./src/prompt.md) for the user-facing description and
|
|
40
40
|
[`src/grammar.lark`](./src/grammar.lark) for the formal grammar.
|
|
41
41
|
|
|
42
|
-
Each
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
session-aware
|
|
42
|
+
Each file section starts with `¶PATH#TAG`. The tag is a 3-hex opaque
|
|
43
|
+
pointer into the `SnapshotStore` that minted it; it is not content-derived
|
|
44
|
+
and is not meaningful outside that store. The patcher protects against
|
|
45
|
+
stale anchors by resolving the tag, verifying the recorded snapshot lines
|
|
46
|
+
against live file content, and refusing or attempting session-aware
|
|
47
|
+
recovery on mismatch.
|
|
47
48
|
|
|
48
|
-
Inside a
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
- `
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
- `↓TEXT` — insert after B (`EOF:` treats `↑`/`↓` equivalently).
|
|
49
|
+
Inside a section:
|
|
50
|
+
- `@@ A..B @@` — open a hunk on lines A..B (use `@@ A,A @@` for a single line; bare `@@ A @@` is also accepted).
|
|
51
|
+
- `@@ BOF @@` / `@@ EOF @@` — virtual hunks at the beginning/end of file.
|
|
52
|
+
- `+TEXT` — literal body row (use `+` alone for a blank line).
|
|
53
|
+
- `&A..B` — repeat original file lines A..B inline (`&A` for one line).
|
|
54
|
+
- Empty body — delete the selected range.
|
|
55
55
|
|
|
56
56
|
## Abstractions
|
|
57
57
|
|
|
@@ -67,9 +67,9 @@ text-document protocol, a Git tree, anything.
|
|
|
67
67
|
|
|
68
68
|
### `SnapshotStore`
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
Required. Hashline tags are opaque store pointers, so `Patcher` must receive
|
|
71
|
+
the store that minted them. Recovery replays edits against the cached pre-edit
|
|
72
|
+
snapshot and 3-way-merges onto current content when the live file diverged.
|
|
73
73
|
|
|
74
74
|
### `Patcher`
|
|
75
75
|
|
package/dist/types/apply.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ApplyResult, Edit } from "./types";
|
|
2
2
|
/**
|
|
3
3
|
* Apply a parsed list of edits to a text body. Pure function — no I/O.
|
|
4
4
|
*
|
|
5
|
-
* Returns the post-edit text
|
|
6
|
-
*
|
|
7
|
-
* structural-boundary delete check. Throws if an anchor is out of bounds.
|
|
5
|
+
* Returns the post-edit text and the first changed line number (1-indexed).
|
|
6
|
+
* Throws if an anchor is out of bounds.
|
|
8
7
|
*/
|
|
9
|
-
export declare function applyEdits(text: string, edits: Edit[]
|
|
8
|
+
export declare function applyEdits(text: string, edits: Edit[]): ApplyResult;
|
package/dist/types/format.d.ts
CHANGED
|
@@ -1,61 +1,57 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Hashline format primitives: sigils, separators, regex fragments, and
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Hashline format primitives: sigils, separators, regex fragments, and
|
|
3
|
+
* display helpers. These are the single source of truth for the parser, the
|
|
4
|
+
* tokenizer, the prompt, and the formal grammar.
|
|
5
5
|
*/
|
|
6
|
-
/**
|
|
7
|
-
export declare const HL_OP_REPLACE = ":";
|
|
8
|
-
/** Payload sigil for lines that replace the anchored range in place. */
|
|
9
|
-
export declare const HL_PAYLOAD_REPLACE = "|";
|
|
10
|
-
/** Payload sigil for lines inserted before the anchored range. */
|
|
11
|
-
export declare const HL_PAYLOAD_ABOVE = "\u2191";
|
|
12
|
-
/** Payload sigil for lines inserted after the anchored range. */
|
|
13
|
-
export declare const HL_PAYLOAD_BELOW = "\u2193";
|
|
14
|
-
/** All hashline payload sigils, concatenated for fast membership tests. */
|
|
15
|
-
export declare const HL_PAYLOAD_CHARS = "|\u2191\u2193";
|
|
16
|
-
/** Hashline edit file-section header marker. */
|
|
6
|
+
/** File-section header prefix: `¶path#hash`. */
|
|
17
7
|
export declare const HL_FILE_PREFIX = "\u00B6";
|
|
18
|
-
/**
|
|
8
|
+
/** Payload sigil for literal body rows. */
|
|
9
|
+
export declare const HL_PAYLOAD_REPLACE = "+";
|
|
10
|
+
/** Payload sigil for body rows that repeat original file lines. */
|
|
11
|
+
export declare const HL_PAYLOAD_REPEAT = "&";
|
|
12
|
+
/** All hashline payload sigils, concatenated for fast membership tests. */
|
|
13
|
+
export declare const HL_PAYLOAD_CHARS = "+&";
|
|
14
|
+
/** Separator between a hashline file path and its opaque snapshot tag. */
|
|
19
15
|
export declare const HL_FILE_HASH_SEP = "#";
|
|
16
|
+
/** Separator between two line numbers in a range, e.g. `5..10`. */
|
|
17
|
+
export declare const HL_RANGE_SEP = "..";
|
|
20
18
|
/** Separator between a line number and displayed line content in hashline mode. */
|
|
21
19
|
export declare const HL_LINE_BODY_SEP = ":";
|
|
22
20
|
/**
|
|
23
21
|
* Decoration prefix that may precede a line number in tool output:
|
|
24
|
-
* `>` (context line in grep)
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* `*` (match line), `>` (context line in grep). Any combination, in any
|
|
23
|
+
* order, surrounded by optional whitespace. Output formatters emit at most
|
|
24
|
+
* one decoration per line; the parser stays liberal because it accepts
|
|
25
|
+
* whatever the model echoes back.
|
|
28
26
|
*/
|
|
29
|
-
export declare const HL_ANCHOR_DECORATION_RE_RAW = "\\s*[
|
|
27
|
+
export declare const HL_ANCHOR_DECORATION_RE_RAW = "\\s*[>*]*\\s*";
|
|
30
28
|
/** Capture-group regex source for a decorated bare line-number anchor. */
|
|
31
|
-
export declare const HL_ANCHOR_RE_RAW = "\\s*[
|
|
29
|
+
export declare const HL_ANCHOR_RE_RAW = "\\s*[>*]*\\s*(\\d+)";
|
|
32
30
|
/** Bare positive line-number Lid (no decorations, no captures, no anchors). */
|
|
33
31
|
export declare const HL_LINE_RE_RAW = "[1-9]\\d*";
|
|
34
32
|
/** Capture-group form of {@link HL_LINE_RE_RAW}. */
|
|
35
33
|
export declare const HL_LINE_CAPTURE_RE_RAW = "([1-9]\\d*)";
|
|
36
|
-
/**
|
|
37
|
-
export declare const
|
|
34
|
+
/** Regex for repeat payload rows (`&A..B`). */
|
|
35
|
+
export declare const HL_PAYLOAD_REPEAT_RE: RegExp;
|
|
36
|
+
/** Number of hex characters in an opaque snapshot tag. */
|
|
37
|
+
export declare const HL_FILE_HASH_LENGTH = 3;
|
|
38
|
+
/** Canonical uppercase hexadecimal opaque snapshot tag carried by a hashline section header. */
|
|
39
|
+
export declare const HL_FILE_HASH_RE_RAW = "[0-9A-F]{3}";
|
|
38
40
|
/** Capture-group form of {@link HL_FILE_HASH_RE_RAW}. */
|
|
39
|
-
export declare const HL_FILE_HASH_CAPTURE_RE_RAW = "([0-
|
|
41
|
+
export declare const HL_FILE_HASH_CAPTURE_RE_RAW = "([0-9A-F]{3})";
|
|
40
42
|
/** Regex-escaped form of {@link HL_LINE_BODY_SEP}, safe for embedding inside a regex. */
|
|
41
43
|
export declare const HL_LINE_BODY_SEP_RE_RAW: string;
|
|
42
44
|
/**
|
|
43
|
-
* Representative
|
|
44
|
-
* examples.
|
|
45
|
+
* Representative snapshot tags for use in user-facing error messages and
|
|
46
|
+
* prompt examples.
|
|
45
47
|
*/
|
|
46
|
-
export declare const HL_FILE_HASH_EXAMPLES: readonly ["
|
|
48
|
+
export declare const HL_FILE_HASH_EXAMPLES: readonly ["0A3", "1F7", "3C9"];
|
|
47
49
|
/**
|
|
48
50
|
* Format a comma-separated list of example anchors with an optional line-number
|
|
49
51
|
* prefix, quoted for inclusion in error messages: `"160", "42", "7"`.
|
|
50
52
|
*/
|
|
51
53
|
export declare function describeAnchorExamples(linePrefix?: string): string;
|
|
52
|
-
/**
|
|
53
|
-
* Compute the 4-hex-character hash carried by a hashline section header. The
|
|
54
|
-
* hash normalizes CR characters and trailing whitespace before hashing so
|
|
55
|
-
* platform line endings and display-trimmed lines do not invalidate anchors.
|
|
56
|
-
*/
|
|
57
|
-
export declare function computeFileHash(text: string): string;
|
|
58
|
-
/** Format a hashline section header for a file path and file hash. */
|
|
54
|
+
/** Format a hashline section header for a file path and snapshot tag. */
|
|
59
55
|
export declare function formatHashlineHeader(filePath: string, fileHash: string): string;
|
|
60
56
|
/** Formats a single numbered line as `LINE:TEXT`. */
|
|
61
57
|
export declare function formatNumberedLine(lineNumber: number, line: string): string;
|
package/dist/types/input.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ApplyResult, Edit, SplitOptions } from "./types";
|
|
2
2
|
interface RawSection {
|
|
3
3
|
path: string;
|
|
4
4
|
fileHash?: string;
|
|
@@ -36,21 +36,21 @@ export declare class PatchSection {
|
|
|
36
36
|
/** Warnings emitted during parsing of this section. */
|
|
37
37
|
get warnings(): readonly string[];
|
|
38
38
|
/**
|
|
39
|
-
* True when at least one edit anchors to
|
|
40
|
-
*
|
|
41
|
-
*
|
|
39
|
+
* True when at least one edit anchors to concrete file content. Pure BOF/EOF
|
|
40
|
+
* literal inserts do not count: those are safe to apply to files that don't
|
|
41
|
+
* yet exist.
|
|
42
42
|
*/
|
|
43
43
|
get hasAnchorScopedEdit(): boolean;
|
|
44
44
|
/** Anchor lines touched by this section, sorted ascending and deduplicated. */
|
|
45
45
|
collectAnchorLines(): readonly number[];
|
|
46
46
|
/**
|
|
47
47
|
* Apply this section's edits to `text` and return the post-edit result.
|
|
48
|
-
* Pure: does no I/O, does not validate the section
|
|
49
|
-
* {@link Patcher} owns
|
|
48
|
+
* Pure: does no I/O, does not validate the section snapshot tag. The
|
|
49
|
+
* {@link Patcher} owns tag validation and recovery; reach for this
|
|
50
50
|
* method directly when you've already validated the file content and
|
|
51
51
|
* just want the result.
|
|
52
52
|
*/
|
|
53
|
-
applyTo(text: string
|
|
53
|
+
applyTo(text: string): ApplyResult;
|
|
54
54
|
/**
|
|
55
55
|
* Streaming-tolerant counterpart to {@link applyTo}. Uses
|
|
56
56
|
* {@link parsePatchStreaming} so a trailing in-flight op (no payload yet,
|
|
@@ -58,7 +58,7 @@ export declare class PatchSection {
|
|
|
58
58
|
* empty-payload edit. Intended for incremental diff previews; the writer
|
|
59
59
|
* path should always use {@link applyTo}.
|
|
60
60
|
*/
|
|
61
|
-
applyPartialTo(text: string
|
|
61
|
+
applyPartialTo(text: string): ApplyResult;
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
64
|
* A parsed hashline patch — zero or more {@link PatchSection}s, each rooted
|
package/dist/types/messages.d.ts
CHANGED
|
@@ -13,21 +13,43 @@ export declare const END_PATCH_MARKER = "*** End Patch";
|
|
|
13
13
|
/**
|
|
14
14
|
* Recovery sentinel emitted by an agent loop when a contaminated tool-call
|
|
15
15
|
* stream is truncated mid-call. Behaves like {@link END_PATCH_MARKER} for
|
|
16
|
-
* parsing — terminates the line loop — and
|
|
17
|
-
* so the caller knows to re-issue any remaining edits.
|
|
16
|
+
* parsing — terminates the line loop — and does not surface a warning.
|
|
18
17
|
*/
|
|
19
18
|
export declare const ABORT_MARKER = "*** Abort";
|
|
20
|
-
/** Warning text appended to the tool result when {@link ABORT_MARKER} terminates parsing. */
|
|
21
|
-
export declare const ABORT_WARNING = "Tool stream truncated mid-call due to detected output corruption. Applied ops above are valid. Re-issue any remaining edits.";
|
|
22
19
|
/**
|
|
23
|
-
* Warning text appended when two consecutive
|
|
24
|
-
* concrete range. The second
|
|
20
|
+
* Warning text appended when two consecutive hunks target the exact same
|
|
21
|
+
* concrete range. The second hunk wins; the first is discarded.
|
|
25
22
|
*/
|
|
26
|
-
export declare const REPLACE_PAIR_COALESCED_WARNING = "Detected two identical-range hashline
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
export declare const REPLACE_PAIR_COALESCED_WARNING = "Detected two identical-range hashline hunks; kept only the second hunk. Issue ONE hunk per range \u2014 payload is the final desired content, never both old and new.";
|
|
24
|
+
/**
|
|
25
|
+
* Warning text appended when a bare hunk header (`A B` with no body)
|
|
26
|
+
* is followed by an overlapping concrete hunk. The earlier bare hunk is
|
|
27
|
+
* dropped on the assumption that the model expressed an old/new pair across
|
|
28
|
+
* two hunks; only the second hunk's payload is applied.
|
|
29
|
+
*/
|
|
30
|
+
export declare const REPLACE_PAIR_COALESCED_OVERLAP_WARNING = "Detected an overlapping bare hashline hunk immediately followed by a concrete hunk; dropped the earlier bare hunk. Issue ONE hunk per range \u2014 payload is the final desired content, never both old and new.";
|
|
31
|
+
/**
|
|
32
|
+
* Warning text appended when bare body rows (no `+` / `&` prefix) follow a
|
|
33
|
+
* hunk header and the parser auto-converts them to `+literal` rows because
|
|
34
|
+
* no `+`/`&` row was present in the hunk. Helps the model learn the
|
|
35
|
+
* canonical body-row syntax while keeping the patch applying.
|
|
36
|
+
*/
|
|
37
|
+
export declare const BARE_BODY_AUTO_PIPED_WARNING = "Auto-prefixed bare body row(s) with `+`. Always start payload rows with `+TEXT` (literal) or `&A..B` (repeat) \u2014 pasting raw code as payload is not a portable shape.";
|
|
38
|
+
/**
|
|
39
|
+
* Warning text emitted when a body row begins with `+&A..B` — the model
|
|
40
|
+
* mistakenly prefixed a repeat row with the `+` literal sigil. We reroute
|
|
41
|
+
* the row as a `&A..B` repeat so the patch still applies, then surface this
|
|
42
|
+
* warning so the model sees the mistake on the next turn.
|
|
43
|
+
*/
|
|
44
|
+
export declare const PLUS_PREFIXED_REPEAT_WARNING = "A body row started with `+&A..B`. `+` (literal text) and `&A..B` (repeat) are sibling row kinds \u2014 a row uses exactly one of them. Treated as `&A..B`; remove the leading `+` next time.";
|
|
45
|
+
/**
|
|
46
|
+
* Warning text emitted when a hunk body contains unified-diff-style rows
|
|
47
|
+
* (`-old`, ` context`) and the parser silently converts them: `-` rows are
|
|
48
|
+
* dropped (the hunk header's range already deletes those lines), and the
|
|
49
|
+
* leading metadata-space on context rows is stripped once unified-diff
|
|
50
|
+
* mode is detected. Bare body rows are auto-prefixed with `+` regardless.
|
|
51
|
+
*/
|
|
52
|
+
export declare const UNIFIED_DIFF_BODY_AUTO_CONVERT_WARNING = "Hunk body contained unified-diff-style rows (`-old`, ` context`). The `-` rows were dropped (the hunk header's range already deletes those lines); context rows were treated as `+TEXT` literals. Use `+TEXT` (literal) or `&A..B` (repeat) directly next time.";
|
|
31
53
|
/** Warning text emitted by `Recovery` when an external write fits a cached snapshot. */
|
|
32
54
|
export declare const RECOVERY_EXTERNAL_WARNING = "Recovered from a stale file hash using a previous read snapshot (file changed externally between read and edit).";
|
|
33
55
|
/** Warning text emitted by `Recovery` when a prior in-session edit advanced the hash. */
|
package/dist/types/mismatch.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export interface MismatchDetails {
|
|
|
12
12
|
anchorLines?: readonly number[];
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Raised when a hashline section's
|
|
15
|
+
* Raised when a hashline section's snapshot tag doesn't match the live file's
|
|
16
16
|
* content (and recovery, if configured, declined the merge). Carries the
|
|
17
17
|
* file lines plus anchored lines so renderers can produce a richer
|
|
18
18
|
* diagnostic via {@link MismatchError.displayMessage}.
|
package/dist/types/parser.d.ts
CHANGED
|
@@ -4,10 +4,10 @@ import type { Edit } from "./types";
|
|
|
4
4
|
* Token-driven state machine that turns a stream of {@link Token}s into a
|
|
5
5
|
* flat list of {@link Edit}s.
|
|
6
6
|
*
|
|
7
|
-
* `feed()` accepts tokens one at a time;
|
|
8
|
-
* the next
|
|
9
|
-
* true (on `envelope-end` or `abort`) subsequent feeds are silently
|
|
10
|
-
* so callers can keep draining their tokenizer.
|
|
7
|
+
* `feed()` accepts tokens one at a time; hunk body rows accumulate until
|
|
8
|
+
* the next hunk header or {@link end} flushes them. After `terminated`
|
|
9
|
+
* flips true (on `envelope-end` or `abort`) subsequent feeds are silently
|
|
10
|
+
* ignored so callers can keep draining their tokenizer.
|
|
11
11
|
*/
|
|
12
12
|
export declare class Executor {
|
|
13
13
|
#private;
|
|
@@ -20,13 +20,13 @@ export declare class Executor {
|
|
|
20
20
|
*/
|
|
21
21
|
feed(token: Token): void;
|
|
22
22
|
/**
|
|
23
|
-
* Flush any open pending
|
|
24
|
-
* warnings. The executor is single-use; {@link reset} is required for
|
|
23
|
+
* Flush any open pending hunk and return the accumulated edits and
|
|
24
|
+
* warnings. The executor is single-use; {@link reset} is required for
|
|
25
|
+
* reuse.
|
|
25
26
|
*
|
|
26
|
-
* Throws if two
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* validator.
|
|
27
|
+
* Throws if two hunks target the same line with non-identical ranges.
|
|
28
|
+
* Identical-range hunks in the same patch are coalesced last-wins by
|
|
29
|
+
* `feed()` with a warning, so they never reach the validator.
|
|
30
30
|
*/
|
|
31
31
|
end(): {
|
|
32
32
|
edits: Edit[];
|
|
@@ -34,9 +34,9 @@ export declare class Executor {
|
|
|
34
34
|
};
|
|
35
35
|
/**
|
|
36
36
|
* Streaming-tolerant variant of {@link end}. Identical, except a pending
|
|
37
|
-
*
|
|
38
|
-
* in flight and dropped instead of flushed (which would otherwise
|
|
39
|
-
* destructive
|
|
37
|
+
* hunk whose body has not yet accumulated any rows is treated as still
|
|
38
|
+
* in flight and dropped instead of flushed (which would otherwise commit
|
|
39
|
+
* a destructive delete while the model may still be typing payload).
|
|
40
40
|
*/
|
|
41
41
|
endStreaming(): {
|
|
42
42
|
edits: Edit[];
|
|
@@ -61,14 +61,14 @@ export declare function parsePatch(diff: string): {
|
|
|
61
61
|
* parsed successfully when the diff is still being typed:
|
|
62
62
|
*
|
|
63
63
|
* - per-token feed errors stop the drain but preserve the edits already
|
|
64
|
-
* collected (the trailing
|
|
65
|
-
* chunk),
|
|
66
|
-
* - the trailing pending
|
|
67
|
-
* destructive bare-delete preview while payload may still be coming).
|
|
64
|
+
* collected (the trailing hunk is malformed mid-stream — wait for the
|
|
65
|
+
* next chunk),
|
|
66
|
+
* - the trailing pending hunk is dropped if it has no payload yet (avoids
|
|
67
|
+
* a destructive bare-delete preview while payload may still be coming).
|
|
68
68
|
*
|
|
69
|
-
* Throws only on the cross-
|
|
70
|
-
* shapes (two
|
|
71
|
-
*
|
|
69
|
+
* Throws only on the cross-hunk overlap validator, which catches conflicting
|
|
70
|
+
* shapes (two hunks hitting the same anchor). Streaming preview callers
|
|
71
|
+
* should treat any throw here as "no preview this tick".
|
|
72
72
|
*/
|
|
73
73
|
export declare function parsePatchStreaming(diff: string): {
|
|
74
74
|
edits: Edit[];
|
package/dist/types/patcher.d.ts
CHANGED
|
@@ -3,21 +3,12 @@ import type { Patch, PatchSection } from "./input";
|
|
|
3
3
|
import { type LineEnding } from "./normalize";
|
|
4
4
|
import { Recovery } from "./recovery";
|
|
5
5
|
import type { SnapshotStore } from "./snapshots";
|
|
6
|
-
import type {
|
|
6
|
+
import type { ApplyResult } from "./types";
|
|
7
7
|
export interface PatcherOptions {
|
|
8
8
|
/** Storage backend used for all reads and writes. */
|
|
9
9
|
fs: Filesystem;
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
* section with a stale hash tries a 3-way merge against a cached
|
|
13
|
-
* snapshot before the apply fails with {@link MismatchError}.
|
|
14
|
-
*/
|
|
15
|
-
snapshots?: SnapshotStore;
|
|
16
|
-
/**
|
|
17
|
-
* Optional default {@link ApplyOptions} forwarded to every section.
|
|
18
|
-
* Per-call overrides win on a key-by-key basis.
|
|
19
|
-
*/
|
|
20
|
-
applyOptions?: ApplyOptions;
|
|
10
|
+
/** Snapshot store that minted and resolves hashline section tags. Required. */
|
|
11
|
+
snapshots: SnapshotStore;
|
|
21
12
|
}
|
|
22
13
|
/** Per-section result returned by {@link Patcher.apply} / {@link Patcher.commit}. */
|
|
23
14
|
export interface PatchSectionResult {
|
|
@@ -35,9 +26,9 @@ export interface PatchSectionResult {
|
|
|
35
26
|
persisted: string;
|
|
36
27
|
/** Final text that the {@link Filesystem} actually wrote (may differ if the FS transformed it). */
|
|
37
28
|
written: string;
|
|
38
|
-
/**
|
|
29
|
+
/** 3-hex opaque snapshot tag for `after`. Use to anchor follow-up edits. */
|
|
39
30
|
fileHash: string;
|
|
40
|
-
/** Hashline section header (`¶path#
|
|
31
|
+
/** Hashline section header (`¶path#tag`) of the post-edit content. */
|
|
41
32
|
header: string;
|
|
42
33
|
/** 1-indexed first changed line in `after`, or `undefined` for noops. */
|
|
43
34
|
firstChangedLine?: number;
|
|
@@ -68,7 +59,7 @@ export declare class PreparedSection {
|
|
|
68
59
|
get isNoop(): boolean;
|
|
69
60
|
}
|
|
70
61
|
/**
|
|
71
|
-
* High-level patcher. Wires a {@link Filesystem} and
|
|
62
|
+
* High-level patcher. Wires a {@link Filesystem} and a required
|
|
72
63
|
* {@link SnapshotStore} together with the parsing + applying core.
|
|
73
64
|
*
|
|
74
65
|
* Construct once per FS configuration; reuse across patches.
|
|
@@ -76,9 +67,8 @@ export declare class PreparedSection {
|
|
|
76
67
|
export declare class Patcher {
|
|
77
68
|
#private;
|
|
78
69
|
readonly fs: Filesystem;
|
|
79
|
-
readonly snapshots: SnapshotStore
|
|
80
|
-
readonly recovery: Recovery
|
|
81
|
-
readonly applyOptions: ApplyOptions;
|
|
70
|
+
readonly snapshots: SnapshotStore;
|
|
71
|
+
readonly recovery: Recovery;
|
|
82
72
|
constructor(options: PatcherOptions);
|
|
83
73
|
/**
|
|
84
74
|
* Apply every section in `patch`. `prepare` runs the full apply for each
|
|
@@ -86,27 +76,27 @@ export declare class Patcher {
|
|
|
86
76
|
* multi-section batch is naturally all-or-nothing. Returns one
|
|
87
77
|
* {@link PatchSectionResult} per section in the original patch order.
|
|
88
78
|
*/
|
|
89
|
-
apply(patch: Patch
|
|
79
|
+
apply(patch: Patch): Promise<PatcherApplyResult>;
|
|
90
80
|
/**
|
|
91
81
|
* Run the preflight pass only: read, parse, validate, apply-in-memory.
|
|
92
82
|
* No writes hit the filesystem. Use for CI checks and dry runs.
|
|
93
83
|
*/
|
|
94
|
-
preflight(patch: Patch
|
|
84
|
+
preflight(patch: Patch): Promise<void>;
|
|
95
85
|
/**
|
|
96
|
-
* Read a section's target file, parse the section, validate the
|
|
97
|
-
*
|
|
86
|
+
* Read a section's target file, parse the section, validate the snapshot
|
|
87
|
+
* tag (with recovery), and apply the edits in memory. Returns a
|
|
98
88
|
* {@link PreparedSection} which can be fed to {@link commit} to land
|
|
99
89
|
* the result on the filesystem.
|
|
100
90
|
*
|
|
101
91
|
* Throws on parse error, missing-file-for-anchored-edit, or unrecovered
|
|
102
|
-
*
|
|
92
|
+
* tag mismatch ({@link MismatchError}).
|
|
103
93
|
*/
|
|
104
|
-
prepare(section: PatchSection
|
|
94
|
+
prepare(section: PatchSection): Promise<PreparedSection>;
|
|
105
95
|
/**
|
|
106
96
|
* Commit a previously {@link prepare}d section to the filesystem.
|
|
107
97
|
* Restores line endings and BOM, writes via the {@link Filesystem}, and
|
|
108
|
-
* records a fresh snapshot in the {@link SnapshotStore}
|
|
109
|
-
*
|
|
98
|
+
* records a fresh snapshot in the {@link SnapshotStore} keyed by the
|
|
99
|
+
* filesystem-canonical path.
|
|
110
100
|
*/
|
|
111
101
|
commit(prepared: PreparedSection): Promise<PatchSectionResult>;
|
|
112
102
|
}
|
package/dist/types/recovery.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { SnapshotStore } from "./snapshots";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Edit } from "./types";
|
|
3
3
|
export interface RecoveryArgs {
|
|
4
4
|
path: string;
|
|
5
5
|
currentText: string;
|
|
6
6
|
fileHash: string;
|
|
7
7
|
edits: readonly Edit[];
|
|
8
|
-
options?: ApplyOptions;
|
|
9
8
|
}
|
|
10
9
|
export interface RecoveryResult {
|
|
11
10
|
/** Post-recovery text. */
|
|
@@ -28,8 +27,9 @@ export interface RecoveryResult {
|
|
|
28
27
|
* a dedicated {@link RECOVERY_SESSION_REPLAY_WARNING} because even with
|
|
29
28
|
* both guards a coincidental insert+delete pair on duplicate rows can
|
|
30
29
|
* still land the edit on the wrong row; see {@link replaySessionChainOnCurrent}.
|
|
31
|
-
* 3. Reconstruct from a sparse snapshot (lines map only),
|
|
32
|
-
*
|
|
30
|
+
* 3. Reconstruct from a sparse snapshot (lines map only), then 3-way-merge.
|
|
31
|
+
* Sparse snapshots that still match the live file are direct-apply cases
|
|
32
|
+
* owned by the patcher, so recovery declines them.
|
|
33
33
|
*/
|
|
34
34
|
export declare class Recovery {
|
|
35
35
|
readonly store: SnapshotStore;
|