chivgent 0.7.0 → 0.7.1
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 +1 -0
- package/README.zh-CN.md +1 -0
- package/dist/workspace/read.d.ts +2 -0
- package/dist/workspace/read.d.ts.map +1 -1
- package/dist/workspace/read.js +5 -1
- package/dist/workspace/read.js.map +1 -1
- package/dist/workspace/text.d.ts +15 -0
- package/dist/workspace/text.d.ts.map +1 -1
- package/dist/workspace/text.js +21 -2
- package/dist/workspace/text.js.map +1 -1
- package/dist/workspace/write.d.ts.map +1 -1
- package/dist/workspace/write.js +38 -11
- package/dist/workspace/write.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ to study before adding production-harness complexity.
|
|
|
37
37
|
- Ranged `read_file` output with continuation hints and bounded tool results.
|
|
38
38
|
- Read-only by default; `--allow-writes` adds `write_file` and `edit_file`.
|
|
39
39
|
- Exact-match `edit_file` that refuses missing or ambiguous edits.
|
|
40
|
+
- Edits preserve the file's own byte order mark and CRLF line endings.
|
|
40
41
|
- Atomic writes: a crash mid-write leaves the original file intact.
|
|
41
42
|
- Safe workspace access with traversal and symlink-escape protection.
|
|
42
43
|
- Root `.gitignore`, generated-directory, and sensitive-path filtering.
|
package/README.zh-CN.md
CHANGED
package/dist/workspace/read.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type ReadTextFileOptions, type TextFileSlice, type WorkspaceLimits } from "./types.js";
|
|
2
|
+
import { type Utf8FileContents } from "./text.js";
|
|
2
3
|
export declare function readFullTextFile(limits: WorkspaceLimits, relativePath: string): Promise<string>;
|
|
3
4
|
export declare function readTextFile(limits: WorkspaceLimits, relativePath: string, options?: ReadTextFileOptions): Promise<TextFileSlice>;
|
|
5
|
+
export declare function readFullTextFileWithBom(limits: WorkspaceLimits, relativePath: string): Promise<Utf8FileContents>;
|
|
4
6
|
//# sourceMappingURL=read.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/workspace/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/workspace/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,WAAW,CAAC;AAEnB,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,aAAa,CAAC,CAuCxB;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAO3B"}
|
package/dist/workspace/read.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_READ_LINE_COUNT, MAX_READ_LINE_COUNT, invalidRange, } from "./types.js";
|
|
2
2
|
import { resolveExistingPath } from "./paths.js";
|
|
3
|
-
import { boundedPositiveInteger, readUtf8File, splitLinesPreservingEndings, } from "./text.js";
|
|
3
|
+
import { boundedPositiveInteger, readUtf8File, readUtf8FileWithBom, splitLinesPreservingEndings, } from "./text.js";
|
|
4
4
|
export async function readFullTextFile(limits, relativePath) {
|
|
5
5
|
const resolved = await resolveExistingPath(limits.root, relativePath);
|
|
6
6
|
return readUtf8File(resolved.realTarget, relativePath, limits.maxFileBytes);
|
|
@@ -34,4 +34,8 @@ export async function readTextFile(limits, relativePath, options = {}) {
|
|
|
34
34
|
truncated: endLine < lines.length,
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
+
export async function readFullTextFileWithBom(limits, relativePath) {
|
|
38
|
+
const resolved = await resolveExistingPath(limits.root, relativePath);
|
|
39
|
+
return readUtf8FileWithBom(resolved.realTarget, relativePath, limits.maxFileBytes);
|
|
40
|
+
}
|
|
37
41
|
//# sourceMappingURL=read.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/workspace/read.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,GAIb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,2BAA2B,
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/workspace/read.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,GAIb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,mBAAmB,EACnB,2BAA2B,GAE5B,MAAM,WAAW,CAAC;AAEnB,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAuB,EACvB,YAAoB;IAEpB,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACtE,OAAO,YAAY,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAuB,EACvB,YAAoB,EACpB,OAAO,GAAwB,EAAE;IAEjC,MAAM,SAAS,GAAG,sBAAsB,CACtC,OAAO,CAAC,SAAS,IAAI,CAAC,EACtB,WAAW,EACX,MAAM,CAAC,gBAAgB,CACxB,CAAC;IACF,MAAM,SAAS,GAAG,sBAAsB,CACtC,OAAO,CAAC,SAAS,IAAI,uBAAuB,EAC5C,WAAW,EACX,mBAAmB,CACpB,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,2BAA2B,CAAC,QAAQ,CAAC,CAAC;IAEpD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;YACpB,MAAM,YAAY,CAAC,YAAY,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QACjD,CAAC;QACD,OAAO;YACL,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC;YACV,UAAU,EAAE,CAAC;YACb,SAAS,EAAE,KAAK;SACjB,CAAC;IACJ,CAAC;IAED,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,YAAY,CAAC,YAAY,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC;IAClE,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QACrD,SAAS;QACT,OAAO;QACP,UAAU,EAAE,KAAK,CAAC,MAAM;QACxB,SAAS,EAAE,OAAO,GAAG,KAAK,CAAC,MAAM;KAClC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,MAAuB,EACvB,YAAoB;IAEpB,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACtE,OAAO,mBAAmB,CACxB,QAAQ,CAAC,UAAU,EACnB,YAAY,EACZ,MAAM,CAAC,YAAY,CACpB,CAAC;AACJ,CAAC"}
|
package/dist/workspace/text.d.ts
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
export declare const UTF8_BOM = "\uFEFF";
|
|
2
|
+
export interface Utf8FileContents {
|
|
3
|
+
readonly contents: string;
|
|
4
|
+
/** True when the file began with a UTF-8 byte order mark. */
|
|
5
|
+
readonly hadBom: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Reads a file and reports whether it carried a byte order mark.
|
|
9
|
+
*
|
|
10
|
+
* `TextDecoder` swallows the BOM by default, which is what readers want but
|
|
11
|
+
* loses information a writer needs: decoding and writing back would silently
|
|
12
|
+
* drop the mark. Decoding with `ignoreBOM` keeps it visible so the caller can
|
|
13
|
+
* strip it deliberately and restore it afterwards.
|
|
14
|
+
*/
|
|
15
|
+
export declare function readUtf8FileWithBom(absolutePath: string, displayPath: string, maxFileBytes: number): Promise<Utf8FileContents>;
|
|
1
16
|
export declare function readUtf8File(absolutePath: string, displayPath: string, maxFileBytes: number): Promise<string>;
|
|
2
17
|
export declare function validateSearchQuery(query: string): void;
|
|
3
18
|
export declare function positiveSafeInteger(value: number, name: string): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/workspace/text.ts"],"names":[],"mappings":"AAGA,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/workspace/text.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,QAAQ,WAAW,CAAC;AAEjC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,gBAAgB,CAAC,CA6C3B;AAED,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAavD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvE;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,MAAM,CAMR;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAStE;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAIrD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAqCtE"}
|
package/dist/workspace/text.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { lstat, readFile } from "node:fs/promises";
|
|
2
2
|
import { MAX_PREVIEW_CHARACTERS, MAX_QUERY_CHARACTERS, WorkspaceError } from "./types.js";
|
|
3
|
-
export
|
|
3
|
+
export const UTF8_BOM = "\uFEFF";
|
|
4
|
+
/**
|
|
5
|
+
* Reads a file and reports whether it carried a byte order mark.
|
|
6
|
+
*
|
|
7
|
+
* `TextDecoder` swallows the BOM by default, which is what readers want but
|
|
8
|
+
* loses information a writer needs: decoding and writing back would silently
|
|
9
|
+
* drop the mark. Decoding with `ignoreBOM` keeps it visible so the caller can
|
|
10
|
+
* strip it deliberately and restore it afterwards.
|
|
11
|
+
*/
|
|
12
|
+
export async function readUtf8FileWithBom(absolutePath, displayPath, maxFileBytes) {
|
|
4
13
|
const stats = await lstat(absolutePath);
|
|
5
14
|
if (!stats.isFile()) {
|
|
6
15
|
throw new WorkspaceError("not_a_file", `Path is not a regular file: ${displayPath}`);
|
|
@@ -15,12 +24,22 @@ export async function readUtf8File(absolutePath, displayPath, maxFileBytes) {
|
|
|
15
24
|
if (contents.includes(0)) {
|
|
16
25
|
throw new WorkspaceError("binary_file", `File appears to be binary: ${displayPath}`);
|
|
17
26
|
}
|
|
27
|
+
let decoded;
|
|
18
28
|
try {
|
|
19
|
-
|
|
29
|
+
decoded = new TextDecoder("utf-8", {
|
|
30
|
+
fatal: true,
|
|
31
|
+
ignoreBOM: true,
|
|
32
|
+
}).decode(contents);
|
|
20
33
|
}
|
|
21
34
|
catch (error) {
|
|
22
35
|
throw new WorkspaceError("invalid_utf8", `File is not valid UTF-8: ${displayPath}`, { cause: error });
|
|
23
36
|
}
|
|
37
|
+
const hadBom = decoded.startsWith(UTF8_BOM);
|
|
38
|
+
return { contents: hadBom ? decoded.slice(UTF8_BOM.length) : decoded, hadBom };
|
|
39
|
+
}
|
|
40
|
+
export async function readUtf8File(absolutePath, displayPath, maxFileBytes) {
|
|
41
|
+
const { contents } = await readUtf8FileWithBom(absolutePath, displayPath, maxFileBytes);
|
|
42
|
+
return contents;
|
|
24
43
|
}
|
|
25
44
|
export function validateSearchQuery(query) {
|
|
26
45
|
if (typeof query !== "string" ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/workspace/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE1F,MAAM,CAAC,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/workspace/text.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/workspace/write.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACzB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/workspace/write.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACzB,MAAM,YAAY,CAAC;AA0EpB,wBAAsB,aAAa,CACjC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,mBAAmB,CAAC,CAiB9B;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAiE7B"}
|
package/dist/workspace/write.js
CHANGED
|
@@ -2,8 +2,26 @@ import { mkdir, rename, unlink, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { WorkspaceError, } from "./types.js";
|
|
4
4
|
import { resolveWritePath } from "./paths.js";
|
|
5
|
-
import {
|
|
6
|
-
import { splitLinesPreservingEndings } from "./text.js";
|
|
5
|
+
import { readFullTextFileWithBom } from "./read.js";
|
|
6
|
+
import { splitLinesPreservingEndings, UTF8_BOM } from "./text.js";
|
|
7
|
+
/**
|
|
8
|
+
* A file whose every newline is a CRLF pair can be matched against LF text and
|
|
9
|
+
* converted back afterwards. A file that mixes both styles cannot: rewriting it
|
|
10
|
+
* in one style would touch lines the edit never asked about, so mixed files
|
|
11
|
+
* keep strict byte-for-byte matching instead.
|
|
12
|
+
*/
|
|
13
|
+
function usesUniformCrlf(contents) {
|
|
14
|
+
const carriageReturns = contents.split("\r").length - 1;
|
|
15
|
+
const newlines = contents.split("\n").length - 1;
|
|
16
|
+
const pairs = contents.split("\r\n").length - 1;
|
|
17
|
+
return pairs > 0 && carriageReturns === pairs && newlines === pairs;
|
|
18
|
+
}
|
|
19
|
+
function toLf(value) {
|
|
20
|
+
return value.split("\r\n").join("\n");
|
|
21
|
+
}
|
|
22
|
+
function toCrlf(value) {
|
|
23
|
+
return value.split("\n").join("\r\n");
|
|
24
|
+
}
|
|
7
25
|
/**
|
|
8
26
|
* Writes are staged into a sibling temp file and then renamed over the target.
|
|
9
27
|
* `rename` within one directory is atomic, so a crash midway leaves the
|
|
@@ -54,30 +72,39 @@ export async function editTextFile(limits, relativePath, options) {
|
|
|
54
72
|
if (typeof newText !== "string") {
|
|
55
73
|
throw new TypeError("new_text must be a string.");
|
|
56
74
|
}
|
|
57
|
-
if (oldText === newText) {
|
|
75
|
+
if (toLf(oldText) === toLf(newText)) {
|
|
58
76
|
throw new WorkspaceError("invalid_range", "old_text and new_text are identical, so the edit would change nothing.");
|
|
59
77
|
}
|
|
60
78
|
// Reading first proves the file exists, is a regular file, is valid UTF-8,
|
|
61
79
|
// and is within the size limit, reusing the read path's guarantees.
|
|
62
|
-
const original = await
|
|
80
|
+
const { contents: original, hadBom } = await readFullTextFileWithBom(limits, relativePath);
|
|
63
81
|
const resolved = await resolveWritePath(limits.root, relativePath);
|
|
64
|
-
|
|
82
|
+
// Models routinely normalise CRLF to LF when they echo text back, so a
|
|
83
|
+
// uniformly-CRLF file is matched in LF and converted back before writing.
|
|
84
|
+
const crlf = usesUniformCrlf(original);
|
|
85
|
+
const haystack = crlf ? toLf(original) : original;
|
|
86
|
+
const needle = crlf ? toLf(oldText) : oldText;
|
|
87
|
+
const replacement = crlf ? toLf(newText) : newText;
|
|
88
|
+
const firstIndex = haystack.indexOf(needle);
|
|
65
89
|
if (firstIndex === -1) {
|
|
66
90
|
throw new WorkspaceError("no_match", `old_text does not appear in ${relativePath}. Read the file again and copy the exact text, including indentation.`);
|
|
67
91
|
}
|
|
68
|
-
if (
|
|
92
|
+
if (haystack.indexOf(needle, firstIndex + 1) !== -1) {
|
|
69
93
|
throw new WorkspaceError("ambiguous_match", `old_text appears more than once in ${relativePath}. Include enough surrounding context to make it unique.`);
|
|
70
94
|
}
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
95
|
+
const edited = haystack.slice(0, firstIndex) +
|
|
96
|
+
replacement +
|
|
97
|
+
haystack.slice(firstIndex + needle.length);
|
|
98
|
+
// Restore the file's own shape: the edit changed content, not encoding.
|
|
99
|
+
const restored = crlf ? toCrlf(edited) : edited;
|
|
100
|
+
const updated = hadBom ? `${UTF8_BOM}${restored}` : restored;
|
|
74
101
|
const bytesWritten = validateContents(updated, limits.maxFileBytes, relativePath);
|
|
75
102
|
await writeAtomically(resolved.lexicalTarget, updated);
|
|
76
103
|
return {
|
|
77
104
|
path: resolved.relativePath,
|
|
78
|
-
line: splitLinesPreservingEndings(
|
|
105
|
+
line: splitLinesPreservingEndings(haystack.slice(0, firstIndex)).length + 1,
|
|
79
106
|
bytesWritten,
|
|
80
|
-
totalLines: splitLinesPreservingEndings(
|
|
107
|
+
totalLines: splitLinesPreservingEndings(restored).length,
|
|
81
108
|
};
|
|
82
109
|
}
|
|
83
110
|
//# sourceMappingURL=write.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/workspace/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,cAAc,GAKf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/workspace/write.ts"],"names":[],"mappings":"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"}
|