jeopi-hashline 16.2.13
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/CHANGELOG.md +343 -0
- package/README.md +82 -0
- package/dist/types/apply.d.ts +10 -0
- package/dist/types/block.d.ts +39 -0
- package/dist/types/diff-preview.d.ts +14 -0
- package/dist/types/format.d.ts +83 -0
- package/dist/types/fs.d.ts +109 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/input.d.ts +110 -0
- package/dist/types/messages.d.ts +127 -0
- package/dist/types/mismatch.d.ts +44 -0
- package/dist/types/normalize.d.ts +20 -0
- package/dist/types/parser.d.ts +27 -0
- package/dist/types/patcher.d.ts +118 -0
- package/dist/types/prefixes.d.ts +42 -0
- package/dist/types/recovery.d.ts +44 -0
- package/dist/types/snapshots.d.ts +127 -0
- package/dist/types/stream.d.ts +2 -0
- package/dist/types/tokenizer.d.ts +73 -0
- package/dist/types/types.d.ts +172 -0
- package/package.json +64 -0
- package/src/apply.ts +1281 -0
- package/src/block.ts +168 -0
- package/src/diff-preview.ts +124 -0
- package/src/format.ts +141 -0
- package/src/fs.ts +246 -0
- package/src/grammar.lark +29 -0
- package/src/index.ts +17 -0
- package/src/input.ts +462 -0
- package/src/messages.ts +267 -0
- package/src/mismatch.ts +118 -0
- package/src/normalize.ts +38 -0
- package/src/parser.ts +456 -0
- package/src/patcher.ts +608 -0
- package/src/prefixes.ts +142 -0
- package/src/prompt.md +172 -0
- package/src/recovery.ts +418 -0
- package/src/snapshots.ts +282 -0
- package/src/stream.ts +132 -0
- package/src/tokenizer.ts +557 -0
- package/src/types.ts +172 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One full-file version observed at a point in time. The tag the model sees is
|
|
3
|
+
* {@link Snapshot.hash}; recovery replays edits against {@link Snapshot.text}.
|
|
4
|
+
*/
|
|
5
|
+
export interface Snapshot {
|
|
6
|
+
/** Canonical path this version belongs to. */
|
|
7
|
+
readonly path: string;
|
|
8
|
+
/** Full normalized (LF, no BOM) file text as observed. */
|
|
9
|
+
readonly text: string;
|
|
10
|
+
/** Content-derived tag for {@link Snapshot.text} (see {@link computeFileHash}). */
|
|
11
|
+
readonly hash: string;
|
|
12
|
+
/** Timestamp (ms since epoch) the version was recorded. */
|
|
13
|
+
recordedAt: number;
|
|
14
|
+
/**
|
|
15
|
+
* 1-indexed file lines a producer (read/search) actually *displayed* under
|
|
16
|
+
* this tag. A partial read (range, or a structural summary that collapsed
|
|
17
|
+
* bodies) leaves this sparse; a whole-file read fills every line. Multiple
|
|
18
|
+
* reads of the same content union into one set. `undefined` means "no
|
|
19
|
+
* provenance recorded" — the patcher then skips the seen-line check and
|
|
20
|
+
* applies as before. Mutated in place as more of the same content is read.
|
|
21
|
+
*/
|
|
22
|
+
seenLines?: Set<number>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Storage seam for full-file version snapshots. The patcher calls {@link head}
|
|
26
|
+
* for the latest version of a path and {@link byHashExact} when it needs the
|
|
27
|
+
* specific historical version a section's stale tag names.
|
|
28
|
+
*/
|
|
29
|
+
export declare abstract class SnapshotStore {
|
|
30
|
+
/** Most-recently recorded version for `path`, or `null` if none. */
|
|
31
|
+
abstract head(path: string): Snapshot | null;
|
|
32
|
+
/**
|
|
33
|
+
* Recorded version for `path` whose tag equals `hash`, or `null`. When two
|
|
34
|
+
* distinct texts collide on the 16-bit tag, returns the most-recently
|
|
35
|
+
* recorded one; callers that treat the tag as content identity must use
|
|
36
|
+
* {@link byHashExact} (or verify {@link Snapshot.text} via {@link byContent}).
|
|
37
|
+
*/
|
|
38
|
+
abstract byHash(path: string, hash: string): Snapshot | null;
|
|
39
|
+
/**
|
|
40
|
+
* Collision-safe {@link byHash}: the single retained version for `path`
|
|
41
|
+
* whose tag equals `hash`, or `null` when none is retained OR when two or
|
|
42
|
+
* more distinct texts collide on the tag. In the collision case there is
|
|
43
|
+
* no way to know which retained text the model's line anchors were minted
|
|
44
|
+
* against, so consumers that replay anchors (recovery, previews) must
|
|
45
|
+
* refuse rather than pick one.
|
|
46
|
+
*/
|
|
47
|
+
abstract byHashExact(path: string, hash: string): Snapshot | null;
|
|
48
|
+
/**
|
|
49
|
+
* Recorded version for `path` whose {@link Snapshot.text} equals `fullText`,
|
|
50
|
+
* or `null`. Disambiguates hash collisions where two distinct file states
|
|
51
|
+
* share the same 4-hex tag: the patcher consults this before taking the
|
|
52
|
+
* no-drift path so a colliding live text is never accepted as the exact
|
|
53
|
+
* snapshot the model's line anchors were minted against.
|
|
54
|
+
*/
|
|
55
|
+
abstract byContent(path: string, fullText: string): Snapshot | null;
|
|
56
|
+
/**
|
|
57
|
+
* Every retained version whose tag equals `hash`, across all tracked
|
|
58
|
+
* paths. The patcher uses this to recover the intended file when a section
|
|
59
|
+
* names a path that does not exist on disk but carries a tag the store
|
|
60
|
+
* minted — the model mistyped the path of a file it read this session.
|
|
61
|
+
*
|
|
62
|
+
* The base returns no matches (recovery disabled); stores that can
|
|
63
|
+
* enumerate their contents override it to enable tag-based path recovery.
|
|
64
|
+
*/
|
|
65
|
+
findByHash(_hash: string): Snapshot[];
|
|
66
|
+
/**
|
|
67
|
+
* Record the full normalized text of `path` and return its content tag.
|
|
68
|
+
* `seenLines` (optional) are the 1-indexed lines the producer displayed;
|
|
69
|
+
* they merge into {@link Snapshot.seenLines} across reads of identical text.
|
|
70
|
+
*/
|
|
71
|
+
abstract record(path: string, fullText: string, seenLines?: Iterable<number>): string;
|
|
72
|
+
/**
|
|
73
|
+
* Merge `lines` into the {@link Snapshot.seenLines} of the version whose tag
|
|
74
|
+
* equals `hash`. No-op when no such version is retained (the content aged
|
|
75
|
+
* out or was overwritten). Lets producers attach displayed lines after the
|
|
76
|
+
* tag was already minted (the body is formatted after the hash is computed).
|
|
77
|
+
*/
|
|
78
|
+
abstract recordSeenLines(path: string, hash: string, lines: Iterable<number>): void;
|
|
79
|
+
/** Drop the version history for a single path. */
|
|
80
|
+
abstract invalidate(path: string): void;
|
|
81
|
+
/**
|
|
82
|
+
* Move retained version history (and read provenance) from `from` to `to`.
|
|
83
|
+
* No-op when `from` has no history. Used by file moves so tags minted from
|
|
84
|
+
* reads of the source path stay valid at the destination.
|
|
85
|
+
*/
|
|
86
|
+
abstract relocate(from: string, to: string): void;
|
|
87
|
+
/** Drop every version history. */
|
|
88
|
+
abstract clear(): void;
|
|
89
|
+
}
|
|
90
|
+
export interface InMemorySnapshotStoreOptions {
|
|
91
|
+
/** Maximum number of distinct paths tracked at once (default 30). LRU eviction. */
|
|
92
|
+
maxPaths?: number;
|
|
93
|
+
/** Maximum full-file versions retained per path (default 4). Oldest dropped first. */
|
|
94
|
+
maxVersionsPerPath?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Global ceiling on retained snapshot text summed across every path's
|
|
97
|
+
* version history, measured in UTF-16 code units (default 64 MiB).
|
|
98
|
+
* Least-recently-used path histories are evicted to stay under it.
|
|
99
|
+
*/
|
|
100
|
+
maxTotalBytes?: number;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* In-memory {@link SnapshotStore} backed by `lru-cache`. Per-path history is a
|
|
104
|
+
* short ring of full-file versions (oldest dropped first); per-session path
|
|
105
|
+
* tracking is LRU-bounded so cold paths age out automatically.
|
|
106
|
+
*
|
|
107
|
+
* Recording byte-identical content again refreshes recency and reuses the
|
|
108
|
+
* existing tag (read fusion); recording new content unshifts a fresh version
|
|
109
|
+
* onto the front of the path history. Two distinct texts that collide on the
|
|
110
|
+
* short 4-hex tag are retained as separate versions so callers can still tell
|
|
111
|
+
* them apart via {@link Snapshot.text} — the tag is only a fast index, never
|
|
112
|
+
* the identity.
|
|
113
|
+
*/
|
|
114
|
+
export declare class InMemorySnapshotStore extends SnapshotStore {
|
|
115
|
+
#private;
|
|
116
|
+
constructor(options?: InMemorySnapshotStoreOptions);
|
|
117
|
+
head(path: string): Snapshot | null;
|
|
118
|
+
byHash(path: string, hash: string): Snapshot | null;
|
|
119
|
+
byHashExact(path: string, hash: string): Snapshot | null;
|
|
120
|
+
byContent(path: string, fullText: string): Snapshot | null;
|
|
121
|
+
findByHash(hash: string): Snapshot[];
|
|
122
|
+
record(path: string, fullText: string, seenLines?: Iterable<number>): string;
|
|
123
|
+
recordSeenLines(path: string, hash: string, lines: Iterable<number>): void;
|
|
124
|
+
invalidate(path: string): void;
|
|
125
|
+
relocate(from: string, to: string): void;
|
|
126
|
+
clear(): void;
|
|
127
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { Anchor, Cursor, ParsedRange } from "./types";
|
|
2
|
+
export declare function splitHashlineLines(text: string): string[];
|
|
3
|
+
export declare function cloneCursor(cursor: Cursor): Cursor;
|
|
4
|
+
/** Parse a bare line-number anchor. Throws on malformed input. */
|
|
5
|
+
export declare function parseLid(raw: string, lineNum: number): Anchor;
|
|
6
|
+
export type BlockTarget = {
|
|
7
|
+
kind: "replace";
|
|
8
|
+
range: ParsedRange;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "block";
|
|
11
|
+
anchor: Anchor;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "delete";
|
|
14
|
+
range: ParsedRange;
|
|
15
|
+
} | {
|
|
16
|
+
kind: "delete_block";
|
|
17
|
+
anchor: Anchor;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "insert_before";
|
|
20
|
+
anchor: Anchor;
|
|
21
|
+
} | {
|
|
22
|
+
kind: "insert_after";
|
|
23
|
+
anchor: Anchor;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "insert_after_block";
|
|
26
|
+
anchor: Anchor;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "rem";
|
|
29
|
+
} | {
|
|
30
|
+
kind: "move";
|
|
31
|
+
dest: string;
|
|
32
|
+
} | {
|
|
33
|
+
kind: "bof";
|
|
34
|
+
} | {
|
|
35
|
+
kind: "eof";
|
|
36
|
+
};
|
|
37
|
+
interface TokenBase {
|
|
38
|
+
lineNum: number;
|
|
39
|
+
}
|
|
40
|
+
export type Token = (TokenBase & {
|
|
41
|
+
kind: "blank";
|
|
42
|
+
}) | (TokenBase & {
|
|
43
|
+
kind: "envelope-begin";
|
|
44
|
+
}) | (TokenBase & {
|
|
45
|
+
kind: "envelope-end";
|
|
46
|
+
}) | (TokenBase & {
|
|
47
|
+
kind: "abort";
|
|
48
|
+
}) | (TokenBase & {
|
|
49
|
+
kind: "header";
|
|
50
|
+
path: string;
|
|
51
|
+
fileHash?: string;
|
|
52
|
+
}) | (TokenBase & {
|
|
53
|
+
kind: "op-block";
|
|
54
|
+
target: BlockTarget;
|
|
55
|
+
}) | (TokenBase & {
|
|
56
|
+
kind: "payload-literal";
|
|
57
|
+
text: string;
|
|
58
|
+
}) | (TokenBase & {
|
|
59
|
+
kind: "raw";
|
|
60
|
+
text: string;
|
|
61
|
+
});
|
|
62
|
+
export declare class Tokenizer {
|
|
63
|
+
#private;
|
|
64
|
+
feed(chunk: string): Token[];
|
|
65
|
+
end(): Token[];
|
|
66
|
+
reset(): void;
|
|
67
|
+
tokenizeAll(text: string): Token[];
|
|
68
|
+
tokenize(line: string, lineNum?: number): Token;
|
|
69
|
+
isOp(line: string): boolean;
|
|
70
|
+
isHeader(line: string): boolean;
|
|
71
|
+
isEnvelopeMarker(line: string): boolean;
|
|
72
|
+
}
|
|
73
|
+
export type { ParsedRange } from "./types";
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure data types shared across the hashline parser, applier, and patcher.
|
|
3
|
+
* Nothing in this file references a filesystem, agent runtime, or schema
|
|
4
|
+
* library — keep it that way.
|
|
5
|
+
*/
|
|
6
|
+
/** A line-number anchor (1-indexed). */
|
|
7
|
+
export interface Anchor {
|
|
8
|
+
line: number;
|
|
9
|
+
}
|
|
10
|
+
/** Where an `insert` edit should land relative to existing content. */
|
|
11
|
+
export type Cursor = {
|
|
12
|
+
kind: "bof";
|
|
13
|
+
} | {
|
|
14
|
+
kind: "eof";
|
|
15
|
+
} | {
|
|
16
|
+
kind: "before_anchor";
|
|
17
|
+
anchor: Anchor;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "after_anchor";
|
|
20
|
+
anchor: Anchor;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* A single low-level edit produced by the parser and consumed by the applier.
|
|
24
|
+
* Multi-line replacements decompose to one `insert` per replacement line plus
|
|
25
|
+
* one `delete` per consumed line. Replacement payloads are tagged so the
|
|
26
|
+
* applier can distinguish literal insertion from new content for a deleted
|
|
27
|
+
* line.
|
|
28
|
+
*/
|
|
29
|
+
export type Edit = {
|
|
30
|
+
kind: "insert";
|
|
31
|
+
cursor: Cursor;
|
|
32
|
+
text: string;
|
|
33
|
+
lineNum: number;
|
|
34
|
+
index: number;
|
|
35
|
+
mode?: "replacement";
|
|
36
|
+
/**
|
|
37
|
+
* Present on inserts lowered from `insert_after_block N:`: the
|
|
38
|
+
* resolved block's first line. Lets the applier slide a body that
|
|
39
|
+
* claims a depth inside the block back across the block's trailing
|
|
40
|
+
* closer lines (never above this line).
|
|
41
|
+
*/
|
|
42
|
+
blockStart?: number;
|
|
43
|
+
} | {
|
|
44
|
+
kind: "delete";
|
|
45
|
+
anchor: Anchor;
|
|
46
|
+
lineNum: number;
|
|
47
|
+
index: number;
|
|
48
|
+
oldAssertion?: string;
|
|
49
|
+
} | {
|
|
50
|
+
/**
|
|
51
|
+
* Deferred block edit (`replace_block N:` / `delete_block N` /
|
|
52
|
+
* `insert_after_block N:`). The exact line span is unknown at parse
|
|
53
|
+
* time — it is computed by {@link resolveBlockEdits} once file text +
|
|
54
|
+
* path (→ language) are available, then expanded into concrete edits:
|
|
55
|
+
* a non-empty `payloads` without `mode` (from `replace_block`) becomes
|
|
56
|
+
* the same `replacement` inserts + deletes that `replace start.=end:`
|
|
57
|
+
* produces; an empty `payloads` (from `delete_block`) becomes a pure
|
|
58
|
+
* range deletion; `mode: "insert_after"` becomes plain `after_anchor`
|
|
59
|
+
* inserts at the block's last line. `applyEdits` never sees this
|
|
60
|
+
* variant.
|
|
61
|
+
*/
|
|
62
|
+
kind: "block";
|
|
63
|
+
anchor: Anchor;
|
|
64
|
+
payloads: string[];
|
|
65
|
+
mode?: "insert_after";
|
|
66
|
+
lineNum: number;
|
|
67
|
+
index: number;
|
|
68
|
+
};
|
|
69
|
+
/** File-level operation parsed from a section body (`REM` / `MV`). */
|
|
70
|
+
export type FileOp = {
|
|
71
|
+
kind: "rem";
|
|
72
|
+
} | {
|
|
73
|
+
kind: "move";
|
|
74
|
+
dest: string;
|
|
75
|
+
};
|
|
76
|
+
/** Result of applying a parsed set of edits to a text body. */
|
|
77
|
+
export interface ApplyResult {
|
|
78
|
+
/** Post-edit text body. */
|
|
79
|
+
text: string;
|
|
80
|
+
/** First line number (1-indexed) that changed, or `undefined` for a no-op apply. */
|
|
81
|
+
firstChangedLine?: number;
|
|
82
|
+
/** Diagnostic warnings collected by the parser, patcher, or recovery. */
|
|
83
|
+
warnings?: string[];
|
|
84
|
+
/**
|
|
85
|
+
* Resolved spans for each `replace_block`/`delete_block` op in this apply,
|
|
86
|
+
* in patch order. Present only when the apply matched the tagged content
|
|
87
|
+
* (the common no-drift path), so the line numbers line up with what the
|
|
88
|
+
* caller read. Absent when there were no block ops.
|
|
89
|
+
*/
|
|
90
|
+
blockResolutions?: BlockResolution[];
|
|
91
|
+
}
|
|
92
|
+
/** A parsed `[A.=B]` line range. */
|
|
93
|
+
export interface ParsedRange {
|
|
94
|
+
start: Anchor;
|
|
95
|
+
end: Anchor;
|
|
96
|
+
}
|
|
97
|
+
/** Optional hints for {@link splitPatchInput}. */
|
|
98
|
+
export interface SplitOptions {
|
|
99
|
+
/** Resolves absolute paths inside hashline headers to cwd-relative form. */
|
|
100
|
+
cwd?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Fallback path used when the input lacks a `[PATH]` header but contains
|
|
103
|
+
* recognizable hashline operations. Lets streaming previews work before
|
|
104
|
+
* the model has written the header.
|
|
105
|
+
*/
|
|
106
|
+
path?: string;
|
|
107
|
+
}
|
|
108
|
+
/** Streaming-formatter knobs for {@link streamHashLines}. */
|
|
109
|
+
export interface StreamOptions {
|
|
110
|
+
/** First line number to use when formatting (1-indexed, default 1). */
|
|
111
|
+
startLine?: number;
|
|
112
|
+
/** Maximum formatted lines per yielded chunk (default 200). */
|
|
113
|
+
maxChunkLines?: number;
|
|
114
|
+
/** Maximum UTF-8 bytes per yielded chunk (default 64 KiB). */
|
|
115
|
+
maxChunkBytes?: number;
|
|
116
|
+
}
|
|
117
|
+
/** Result of {@link buildCompactDiffPreview}. */
|
|
118
|
+
export interface CompactDiffPreview {
|
|
119
|
+
preview: string;
|
|
120
|
+
addedLines: number;
|
|
121
|
+
removedLines: number;
|
|
122
|
+
}
|
|
123
|
+
/** Optional knobs for {@link buildCompactDiffPreview}. */
|
|
124
|
+
export interface CompactDiffOptions {
|
|
125
|
+
/** Added lines kept on each side of a long added-run elision (default 2). */
|
|
126
|
+
maxAddedRunContext?: number;
|
|
127
|
+
/** Back-compat alias for {@link maxAddedRunContext}. */
|
|
128
|
+
maxUnchangedRun?: number;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Resolved 1-indexed inclusive line span of a `replace_block N:` target.
|
|
132
|
+
*/
|
|
133
|
+
export interface BlockSpan {
|
|
134
|
+
/** First line of the block (1-indexed, inclusive). */
|
|
135
|
+
start: number;
|
|
136
|
+
/** Last line of the block (1-indexed, inclusive). */
|
|
137
|
+
end: number;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* One `replace_block N:` / `delete_block N` / `insert_after_block N:` anchor
|
|
141
|
+
* resolved to its concrete line span. Surfaced on {@link ApplyResult} so the
|
|
142
|
+
* host can echo "block N → lines start.=end" and let the model catch a wrong
|
|
143
|
+
* opener — e.g. a decorator or doc-comment that sits in a separate node
|
|
144
|
+
* outside the resolved block.
|
|
145
|
+
*/
|
|
146
|
+
export interface BlockResolution {
|
|
147
|
+
/** The 1-indexed line the block op was anchored on (the `N`). */
|
|
148
|
+
anchorLine: number;
|
|
149
|
+
/** First line of the resolved span (1-indexed, inclusive). */
|
|
150
|
+
start: number;
|
|
151
|
+
/** Last line of the resolved span (1-indexed, inclusive). */
|
|
152
|
+
end: number;
|
|
153
|
+
/** Which block op produced this resolution. */
|
|
154
|
+
op: "replace" | "delete" | "insert_after";
|
|
155
|
+
}
|
|
156
|
+
/** Request handed to a {@link BlockResolver} to resolve one `replace_block N:` anchor. */
|
|
157
|
+
export interface BlockResolverRequest {
|
|
158
|
+
/** Target file path (used to infer language by extension). */
|
|
159
|
+
path: string;
|
|
160
|
+
/** Full text the block must be resolved against (the snapshot the tag names). */
|
|
161
|
+
text: string;
|
|
162
|
+
/** 1-indexed line the block must begin on. */
|
|
163
|
+
line: number;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Resolves a `replace_block N:` anchor to the line span of the syntactic block
|
|
167
|
+
* that begins on line N. Returns `null` when no block can be resolved
|
|
168
|
+
* (unrecognized language, blank/out-of-range line, no node begins there, or the
|
|
169
|
+
* resolved subtree has a syntax error). Pure seam: the hashline core declares
|
|
170
|
+
* the contract; the host injects a tree-sitter-backed implementation.
|
|
171
|
+
*/
|
|
172
|
+
export type BlockResolver = (request: BlockResolverRequest) => BlockSpan | null;
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "module",
|
|
3
|
+
"name": "jeopi-hashline",
|
|
4
|
+
"version": "16.2.13",
|
|
5
|
+
"description": "Hashline: a compact, line-anchored patch language and applier. Pluggable FS/IO so it works over disk, in-memory, or any custom backend.",
|
|
6
|
+
"homepage": "https://github.com/akillness/jeopi",
|
|
7
|
+
"author": "Can Boluk",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/akillness/jeopi.git",
|
|
12
|
+
"directory": "packages/hashline"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/akillness/jeopi/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"patch",
|
|
19
|
+
"diff",
|
|
20
|
+
"edit",
|
|
21
|
+
"hashline",
|
|
22
|
+
"agent",
|
|
23
|
+
"llm"
|
|
24
|
+
],
|
|
25
|
+
"main": "./src/index.ts",
|
|
26
|
+
"types": "./dist/types/index.d.ts",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"check": "biome check . && bun run check:types",
|
|
29
|
+
"check:types": "tsgo -p tsconfig.json --noEmit",
|
|
30
|
+
"lint": "biome lint .",
|
|
31
|
+
"test": "bun test --parallel",
|
|
32
|
+
"fix": "biome check --write --unsafe .",
|
|
33
|
+
"fmt": "biome format --write ."
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"diff": "^9.0.0",
|
|
37
|
+
"lru-cache": "11.5.1"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/bun": "^1.3.14"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"bun": ">=1.3.14"
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"src",
|
|
47
|
+
"README.md",
|
|
48
|
+
"CHANGELOG.md",
|
|
49
|
+
"dist/types"
|
|
50
|
+
],
|
|
51
|
+
"exports": {
|
|
52
|
+
".": {
|
|
53
|
+
"types": "./dist/types/index.d.ts",
|
|
54
|
+
"import": "./src/index.ts"
|
|
55
|
+
},
|
|
56
|
+
"./grammar.lark": "./src/grammar.lark",
|
|
57
|
+
"./prompt.md": "./src/prompt.md",
|
|
58
|
+
"./*": {
|
|
59
|
+
"types": "./dist/types/*.d.ts",
|
|
60
|
+
"import": "./src/*.ts"
|
|
61
|
+
},
|
|
62
|
+
"./*.js": "./src/*.ts"
|
|
63
|
+
}
|
|
64
|
+
}
|