@aragon-agent/cli 0.5.8 → 0.5.9
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 +279 -0
- package/README.md +1429 -1163
- package/dist/agent/coalesce.d.ts +13 -0
- package/dist/agent/coalesce.js +50 -11
- package/dist/agent/controller.d.ts +141 -2
- package/dist/agent/controller.js +396 -4
- package/dist/agent/headless.d.ts +8 -0
- package/dist/agent/headless.js +40 -0
- package/dist/agent/reducer.d.ts +245 -3
- package/dist/agent/reducer.js +490 -17
- package/dist/agent/retry-view.d.ts +68 -0
- package/dist/agent/retry-view.js +95 -0
- package/dist/agent/system-prompt.d.ts +11 -0
- package/dist/agent/system-prompt.js +2 -0
- package/dist/cli.js +86 -2
- package/dist/commands/builtins.d.ts +1 -1
- package/dist/commands/builtins.js +308 -2
- package/dist/config/cli-commands.d.ts +53 -2
- package/dist/config/cli-commands.js +136 -3
- package/dist/config/env.d.ts +6 -3
- package/dist/config/env.js +103 -3
- package/dist/config/load.d.ts +49 -0
- package/dist/config/load.js +83 -1
- package/dist/config/schema.d.ts +212 -2
- package/dist/config/schema.js +207 -1
- package/dist/config/store.js +20 -1
- package/dist/fast/critique.d.ts +43 -0
- package/dist/fast/critique.js +62 -0
- package/dist/fast/digest.d.ts +42 -0
- package/dist/fast/digest.js +85 -0
- package/dist/fast/frames.d.ts +99 -0
- package/dist/fast/frames.js +180 -0
- package/dist/fast/limits.d.ts +98 -0
- package/dist/fast/limits.js +98 -0
- package/dist/fast/prompt.d.ts +72 -0
- package/dist/fast/prompt.js +94 -0
- package/dist/fast/resolve.d.ts +43 -0
- package/dist/fast/resolve.js +105 -0
- package/dist/fast/review-call.d.ts +99 -0
- package/dist/fast/review-call.js +130 -0
- package/dist/fast/reviewer.d.ts +248 -0
- package/dist/fast/reviewer.js +664 -0
- package/dist/fast/types.d.ts +128 -0
- package/dist/fast/types.js +14 -0
- package/dist/fast/wiring.d.ts +170 -0
- package/dist/fast/wiring.js +316 -0
- package/dist/logging/install.d.ts +15 -1
- package/dist/logging/install.js +37 -4
- package/dist/logging/logger.d.ts +1 -1
- package/dist/session/persist.js +57 -1
- package/dist/team/normalize.d.ts +26 -1
- package/dist/team/normalize.js +23 -3
- package/dist/team/prompt.d.ts +11 -0
- package/dist/team/prompt.js +10 -0
- package/dist/team/report.d.ts +18 -0
- package/dist/team/report.js +27 -1
- package/dist/team/runtime.d.ts +13 -2
- package/dist/team/runtime.js +33 -6
- package/dist/team/subagent.d.ts +19 -1
- package/dist/team/subagent.js +72 -10
- package/dist/team/task-tool.d.ts +26 -0
- package/dist/team/task-tool.js +48 -4
- package/dist/team/types.d.ts +80 -1
- package/dist/tools/bash-tool.js +19 -3
- package/dist/tools/diff.d.ts +25 -5
- package/dist/tools/diff.js +72 -41
- package/dist/tools/file-change-store.d.ts +34 -0
- package/dist/tools/file-change-store.js +57 -0
- package/dist/tools/fs-tools.d.ts +26 -0
- package/dist/tools/fs-tools.js +62 -5
- package/dist/tools/index.d.ts +31 -0
- package/dist/tools/index.js +7 -1
- package/dist/tools/patch.d.ts +115 -0
- package/dist/tools/patch.js +453 -0
- package/dist/tools/terminal-output.d.ts +107 -0
- package/dist/tools/terminal-output.js +198 -0
- package/dist/tools/tool-output-store.d.ts +68 -0
- package/dist/tools/tool-output-store.js +102 -0
- package/dist/ui/ActivityLine.d.ts +48 -0
- package/dist/ui/ActivityLine.js +22 -0
- package/dist/ui/App.d.ts +1 -4
- package/dist/ui/App.js +273 -37
- package/dist/ui/BottomStatusRow.d.ts +43 -0
- package/dist/ui/BottomStatusRow.js +14 -0
- package/dist/ui/Composer.d.ts +1 -6
- package/dist/ui/Composer.js +2 -2
- package/dist/ui/PromptInput.d.ts +1 -15
- package/dist/ui/PromptInput.js +1 -38
- package/dist/ui/StatusBar.d.ts +37 -0
- package/dist/ui/StatusBar.js +5 -3
- package/dist/ui/TeamPanel.d.ts +5 -4
- package/dist/ui/TeamPanel.js +1 -1
- package/dist/ui/TodoPanel.d.ts +5 -4
- package/dist/ui/Transcript.d.ts +26 -3
- package/dist/ui/Transcript.js +76 -10
- package/dist/ui/activity-phrases.d.ts +33 -0
- package/dist/ui/activity-phrases.js +50 -0
- package/dist/ui/entries/AssistantEntry.d.ts +20 -0
- package/dist/ui/entries/AssistantEntry.js +3 -2
- package/dist/ui/entries/DiffView.d.ts +67 -0
- package/dist/ui/entries/DiffView.js +103 -0
- package/dist/ui/entries/FastCard.d.ts +53 -0
- package/dist/ui/entries/FastCard.js +87 -0
- package/dist/ui/entries/RetryCard.d.ts +56 -0
- package/dist/ui/entries/RetryCard.js +60 -0
- package/dist/ui/entries/TeamCard.js +6 -1
- package/dist/ui/entries/ToolCard.d.ts +38 -1
- package/dist/ui/entries/ToolCard.js +68 -5
- package/dist/ui/glyphs.d.ts +9 -0
- package/dist/ui/glyphs.js +2 -0
- package/dist/ui/layout/AppShell.d.ts +13 -22
- package/dist/ui/layout/AppShell.js +3 -38
- package/dist/ui/layout/virtual-window.d.ts +1 -1
- package/dist/ui/layout/virtual-window.js +109 -5
- package/dist/ui/overlays/HelpOverlay.js +16 -2
- package/dist/ui/overlays/SettingsScreen.d.ts +82 -1
- package/dist/ui/overlays/SettingsScreen.js +147 -1
- package/dist/ui/transcript-text.js +27 -0
- package/dist/ui/use-wheel-routing.d.ts +16 -32
- package/dist/ui/use-wheel-routing.js +21 -38
- package/package.json +2 -2
- package/dist/ui/layout/regions.d.ts +0 -55
- package/dist/ui/layout/regions.js +0 -52
package/dist/tools/fs-tools.js
CHANGED
|
@@ -10,6 +10,7 @@ import { promises as fs } from 'node:fs';
|
|
|
10
10
|
import { isAbsolute, join, resolve, dirname } from 'node:path';
|
|
11
11
|
import { defineTool, errorResult, textResult, } from '@aragon-agent/core';
|
|
12
12
|
import { renderUnifiedDiff } from './diff.js';
|
|
13
|
+
import { PATCH_LIMITS, buildPatch } from './patch.js';
|
|
13
14
|
function resolvePath(cwd, p) {
|
|
14
15
|
return isAbsolute(p) ? p : resolve(cwd, p);
|
|
15
16
|
}
|
|
@@ -78,13 +79,20 @@ export function makeWriteFile(deps) {
|
|
|
78
79
|
},
|
|
79
80
|
required: ['path', 'content'],
|
|
80
81
|
},
|
|
81
|
-
async execute(
|
|
82
|
+
async execute(id, rawParams) {
|
|
82
83
|
const params = rawParams;
|
|
83
84
|
const target = resolvePath(deps.getCwd(), params.path);
|
|
84
85
|
try {
|
|
86
|
+
// BEFORE the write, and only when somebody is listening. `readOldSide`
|
|
87
|
+
// swallows every failure itself, so a presentation feature can never
|
|
88
|
+
// prevent or delay the operation it presents (D-14 / R-6).
|
|
89
|
+
const oldSide = deps.recordChange ? await readOldSide(target) : null;
|
|
85
90
|
await fs.mkdir(dirname(target), { recursive: true });
|
|
86
91
|
await fs.writeFile(target, params.content, 'utf-8');
|
|
92
|
+
if (oldSide)
|
|
93
|
+
recordFileChange(deps, id, oldSide, params.content, params.path);
|
|
87
94
|
const bytes = Buffer.byteLength(params.content, 'utf-8');
|
|
95
|
+
// BYTE-IDENTICAL model-facing text: the diff costs zero extra tokens.
|
|
88
96
|
return textResult(`Wrote ${bytes} bytes to ${params.path}`);
|
|
89
97
|
}
|
|
90
98
|
catch (err) {
|
|
@@ -116,7 +124,7 @@ export function makeEditFile(deps) {
|
|
|
116
124
|
},
|
|
117
125
|
required: ['path', 'old_string', 'new_string'],
|
|
118
126
|
},
|
|
119
|
-
async execute(
|
|
127
|
+
async execute(id, rawParams) {
|
|
120
128
|
const params = rawParams;
|
|
121
129
|
const target = resolvePath(deps.getCwd(), params.path);
|
|
122
130
|
try {
|
|
@@ -138,6 +146,10 @@ export function makeEditFile(deps) {
|
|
|
138
146
|
? original.split(params.old_string).join(params.new_string)
|
|
139
147
|
: original.replace(params.old_string, () => params.new_string);
|
|
140
148
|
await fs.writeFile(target, updated, 'utf-8');
|
|
149
|
+
// The same sentence, from the same data: the card's structured patch and
|
|
150
|
+
// the model's text are built from `original` / `updated` by one algorithm
|
|
151
|
+
// at two context widths (D-10 / D-20).
|
|
152
|
+
recordFileChange(deps, id, { text: original }, updated, params.path);
|
|
141
153
|
const diff = renderUnifiedDiff(original, updated, { path: params.path });
|
|
142
154
|
return textResult(`Applied edit to ${params.path}:\n${diff}`);
|
|
143
155
|
}
|
|
@@ -189,9 +201,54 @@ export function makeListDir(deps) {
|
|
|
189
201
|
},
|
|
190
202
|
});
|
|
191
203
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Best-effort read of the file `write_file` is about to overwrite.
|
|
206
|
+
*
|
|
207
|
+
* NEVER THROWS AND NEVER REPORTS AN ERROR TO THE MODEL. Every outcome is a
|
|
208
|
+
* `FilePatch` the card can render honestly:
|
|
209
|
+
*
|
|
210
|
+
* ENOENT -> null, no reason -> a `create` diff
|
|
211
|
+
* size > readMaxBytes -> null, `too-large` -> an `update` we declined to read
|
|
212
|
+
* binary sniff fails -> null, `binary` -> ditto
|
|
213
|
+
* any other throw -> null, `unreadable` -> ditto
|
|
214
|
+
*/
|
|
215
|
+
async function readOldSide(target) {
|
|
216
|
+
try {
|
|
217
|
+
const stat = await fs.stat(target);
|
|
218
|
+
if (stat.size > PATCH_LIMITS.readMaxBytes)
|
|
219
|
+
return { text: null, degraded: 'too-large' };
|
|
220
|
+
const buf = await fs.readFile(target);
|
|
221
|
+
if (looksBinary(buf))
|
|
222
|
+
return { text: null, degraded: 'binary' };
|
|
223
|
+
return { text: buf.toString('utf-8') };
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
if (err.code === 'ENOENT')
|
|
227
|
+
return { text: null };
|
|
228
|
+
return { text: null, degraded: 'unreadable' };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Build and hand over the patch, if anyone asked for one.
|
|
233
|
+
*
|
|
234
|
+
* WRAPPED, because `recordChange` is a caller-supplied closure and a display
|
|
235
|
+
* callback must not be able to fail a write that has already happened.
|
|
236
|
+
* `buildPatch` itself is total.
|
|
237
|
+
*/
|
|
238
|
+
function recordFileChange(deps, toolCallId, oldSide, newText, path) {
|
|
239
|
+
if (!deps.recordChange)
|
|
240
|
+
return;
|
|
241
|
+
try {
|
|
242
|
+
deps.recordChange(toolCallId, buildPatch(oldSide.text, newText, {
|
|
243
|
+
path,
|
|
244
|
+
context: PATCH_LIMITS.context,
|
|
245
|
+
...(oldSide.degraded ? { degraded: oldSide.degraded } : {}),
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
// Presentation only. The file is already on disk.
|
|
250
|
+
}
|
|
251
|
+
}
|
|
195
252
|
function countOccurrences(haystack, needle) {
|
|
196
253
|
if (needle.length === 0)
|
|
197
254
|
return 0;
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { type AgentTool, type ToolPolicyDecision, type ToolPolicyVerdict } from '@aragon-agent/core';
|
|
12
12
|
import type { AgentMode } from '../agent/agent-mode.js';
|
|
13
|
+
import type { FilePatch } from './patch.js';
|
|
13
14
|
export interface ConfirmRequest {
|
|
14
15
|
tool: string;
|
|
15
16
|
summary: string;
|
|
@@ -29,6 +30,36 @@ export interface ConfirmRequest {
|
|
|
29
30
|
}
|
|
30
31
|
export interface BuiltinToolsOptions {
|
|
31
32
|
getCwd: () => string;
|
|
33
|
+
/**
|
|
34
|
+
* Hand `write_file` / `edit_file` a place to leave a structured `FilePatch`
|
|
35
|
+
* (agent-activity-presentation §3.3.5), already bound to its owner.
|
|
36
|
+
*
|
|
37
|
+
* THE FIELD IS NEEDED IN TWO INTERFACES, NOT ONE. This bag is the factory's;
|
|
38
|
+
* `ToolDeps` is what the `make*` functions receive, and it is built below from
|
|
39
|
+
* exactly the fields named there. Adding it to `ToolDeps` alone type-checks and
|
|
40
|
+
* forwards nothing — the tools simply never record, and every card falls back
|
|
41
|
+
* to `ToolPreview` with no error anywhere (P1-3).
|
|
42
|
+
*
|
|
43
|
+
* Omitting it — every existing test, every headless run, and every subagent
|
|
44
|
+
* this round — leaves the tools byte-identical to today, which is the same
|
|
45
|
+
* opt-in shape `skillTools` / `planTools` / `todoTools` already use.
|
|
46
|
+
*/
|
|
47
|
+
recordChange?: (toolCallId: string, patch: FilePatch) => void;
|
|
48
|
+
/**
|
|
49
|
+
* Hand `bash` a place to leave its raw output chunks
|
|
50
|
+
* (agent-activity-presentation-live §3.1.2), already bound to its owner.
|
|
51
|
+
*
|
|
52
|
+
* THE TWO-INTERFACE RULE ABOVE APPLIES VERBATIM (P1-1), and it applies because
|
|
53
|
+
* round 1 made this exact mistake once already with `recordChange`: adding the
|
|
54
|
+
* field to `ToolDeps` alone type-checks and forwards nothing, so `bash` never
|
|
55
|
+
* records, every running card stays the single `running` row it is today, and
|
|
56
|
+
* NOTHING ANYWHERE ERRORS.
|
|
57
|
+
*
|
|
58
|
+
* The conditional spread below is also what makes AC-31 true at this layer:
|
|
59
|
+
* with `liveToolOutput` off the controller passes no key, so no property is
|
|
60
|
+
* added and `deps` is the object it is today.
|
|
61
|
+
*/
|
|
62
|
+
recordOutput?: (toolCallId: string, chunk: string) => void;
|
|
32
63
|
/** When true (and `confirm` is provided), mutating tools are gated. */
|
|
33
64
|
confirmTools?: boolean;
|
|
34
65
|
/** Awaited before a mutating tool runs; resolve `false` to cancel. */
|
package/dist/tools/index.js
CHANGED
|
@@ -215,7 +215,13 @@ function withPlanModeGate(tool, getMode) {
|
|
|
215
215
|
};
|
|
216
216
|
}
|
|
217
217
|
export function createBuiltinTools(options) {
|
|
218
|
-
const deps = {
|
|
218
|
+
const deps = {
|
|
219
|
+
getCwd: options.getCwd,
|
|
220
|
+
// The forward half of the two-interface note on `recordChange` above.
|
|
221
|
+
...(options.recordChange ? { recordChange: options.recordChange } : {}),
|
|
222
|
+
// Added in the same shape and for the same reason (P1-1).
|
|
223
|
+
...(options.recordOutput ? { recordOutput: options.recordOutput } : {}),
|
|
224
|
+
};
|
|
219
225
|
let tools = [
|
|
220
226
|
makeReadFile(deps),
|
|
221
227
|
makeWriteFile(deps),
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured file patches (agent-activity-presentation §3.3).
|
|
3
|
+
*
|
|
4
|
+
* PURE, NO I/O, NO REACT, ASCII-ONLY MARKERS. `glyphs.test.ts`'s static scan
|
|
5
|
+
* walks ALL of `src/` (skipping only `__tests__/` and two exempt files), so this
|
|
6
|
+
* module sits inside that guard rail directly rather than by analogy. The
|
|
7
|
+
* substantive reason is the one `reducer.ts` gives for `PREVIEW_TRUNCATION_MARK`:
|
|
8
|
+
* a string produced outside `src/ui/**` has no `TermCapabilities` in scope and
|
|
9
|
+
* must be safe on a legacy `cmd.exe`.
|
|
10
|
+
*
|
|
11
|
+
* The ladder is ANCHORED SPLIT -> BOUNDED LCS -> BLOCK REPLACE, and every
|
|
12
|
+
* recursion path terminates in one of three leaf returns. `blockReplace` is
|
|
13
|
+
* exactly what `renderUnifiedDiff` produced before this round — every old row as
|
|
14
|
+
* `del`, then every new row as `add` — kept as the explicit, bounded fallback so
|
|
15
|
+
* a pathological input degrades to today's behaviour rather than hanging.
|
|
16
|
+
*
|
|
17
|
+
* `buildPatch` is TOTAL: it never throws, for any pair of strings.
|
|
18
|
+
*/
|
|
19
|
+
export type PatchLineKind = 'ctx' | 'add' | 'del';
|
|
20
|
+
export interface PatchLine {
|
|
21
|
+
kind: PatchLineKind;
|
|
22
|
+
/** 1-based line number in the OLD file; absent on an `add`. */
|
|
23
|
+
oldLine?: number;
|
|
24
|
+
/** 1-based line number in the NEW file; absent on a `del`. */
|
|
25
|
+
newLine?: number;
|
|
26
|
+
/** Rendered text. A trailing CR is stripped; long lines are truncated. */
|
|
27
|
+
text: string;
|
|
28
|
+
}
|
|
29
|
+
export interface PatchHunk {
|
|
30
|
+
oldStart: number;
|
|
31
|
+
oldCount: number;
|
|
32
|
+
newStart: number;
|
|
33
|
+
newCount: number;
|
|
34
|
+
lines: PatchLine[];
|
|
35
|
+
}
|
|
36
|
+
export interface FilePatch {
|
|
37
|
+
/** As the model wrote it — relative when the call was relative. */
|
|
38
|
+
path: string;
|
|
39
|
+
kind: 'create' | 'update';
|
|
40
|
+
added: number;
|
|
41
|
+
removed: number;
|
|
42
|
+
hunks: PatchHunk[];
|
|
43
|
+
/** Budget was hit; the tail of the change is not in `hunks`. */
|
|
44
|
+
truncated: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Total rendered rows across every hunk (summary and separators excluded).
|
|
47
|
+
*
|
|
48
|
+
* PRECOMPUTED so `entryRevision` stays O(1) (I-L3-1 forbids hashing, and
|
|
49
|
+
* summing `hunks[].lines.length` per entry per frame is exactly the cost the
|
|
50
|
+
* height cache exists to remove).
|
|
51
|
+
*/
|
|
52
|
+
lineCount: number;
|
|
53
|
+
/** Set when the old side could not be read: too large, binary, or unreadable. */
|
|
54
|
+
degraded?: 'binary' | 'too-large' | 'unreadable';
|
|
55
|
+
}
|
|
56
|
+
export declare const PATCH_LIMITS: {
|
|
57
|
+
/**
|
|
58
|
+
* Context rows kept either side of a change, FOR THE UI.
|
|
59
|
+
*
|
|
60
|
+
* The text renderer does NOT use this (D-20): `renderUnifiedDiff` keeps its
|
|
61
|
+
* own `CONTEXT_LINES = 2` default so the model-facing diff does not silently
|
|
62
|
+
* widen by two rows on every single-region edit. One algorithm, two widths,
|
|
63
|
+
* chosen by the caller.
|
|
64
|
+
*/
|
|
65
|
+
readonly context: 3;
|
|
66
|
+
/**
|
|
67
|
+
* Hunks separated by this many context rows or fewer are merged into one.
|
|
68
|
+
*
|
|
69
|
+
* MUST STAY `>= 2 * context` FOR EVERY CALLER'S CONTEXT WIDTH, or two adjacent
|
|
70
|
+
* hunks expanded by `context` would overlap and the same row would be rendered
|
|
71
|
+
* twice with two different line numbers. 6 covers both widths in use (3 and 2).
|
|
72
|
+
*/
|
|
73
|
+
readonly mergeGap: 6;
|
|
74
|
+
/** Rendered rows a patch may carry, across all hunks. */
|
|
75
|
+
readonly maxLines: 200;
|
|
76
|
+
/** Total characters across all `PatchLine.text`. Mirrors STORED_PREVIEW_CHARS. */
|
|
77
|
+
readonly maxChars: 8000;
|
|
78
|
+
/** A single row is truncated past this, with `TRUNCATION_MARK`. */
|
|
79
|
+
readonly maxLineChars: 500;
|
|
80
|
+
/** Above this cell count the LCS leaf is refused; the segment becomes a block replace. */
|
|
81
|
+
readonly lcsCellBudget: 160000;
|
|
82
|
+
/** Recursion depth ceiling for the anchor split. */
|
|
83
|
+
readonly maxDepth: 32;
|
|
84
|
+
/** Old-side bytes above which `write_file` does not read for a diff. */
|
|
85
|
+
readonly readMaxBytes: number;
|
|
86
|
+
/** Model-facing diff text ceiling — a bound `edit_file` does not have today. */
|
|
87
|
+
readonly modelDiffMaxChars: 4000;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Appended to a row clipped at `maxLineChars`.
|
|
91
|
+
*
|
|
92
|
+
* SPELLED HERE RATHER THAN IMPORTED from `agent/reducer.ts`, so that `tools/`
|
|
93
|
+
* does not take a runtime dependency on the view model for one three-character
|
|
94
|
+
* string. `patch.test.ts` asserts the two spellings are equal, so the pair
|
|
95
|
+
* cannot drift silently — which is the property the import would have bought.
|
|
96
|
+
*/
|
|
97
|
+
export declare const TRUNCATION_MARK = "...";
|
|
98
|
+
/** The note emitted when exactly one side ends with a newline. */
|
|
99
|
+
export declare const NO_NEWLINE_NOTE = "(no newline at end of file)";
|
|
100
|
+
export interface BuildPatchOptions {
|
|
101
|
+
/** As the model wrote it; carried onto the patch verbatim. */
|
|
102
|
+
path: string;
|
|
103
|
+
/** Context rows either side of a change. Defaults to `PATCH_LIMITS.context`. */
|
|
104
|
+
context?: number;
|
|
105
|
+
/**
|
|
106
|
+
* Why the old side is `null`.
|
|
107
|
+
*
|
|
108
|
+
* It also decides `kind`: a missing old side with no reason is a CREATE, and a
|
|
109
|
+
* missing old side WITH one is an UPDATE whose old half could not be read. The
|
|
110
|
+
* distinction matters because "created a file" and "overwrote a 5 MB file we
|
|
111
|
+
* declined to read" are different events and the card names them differently.
|
|
112
|
+
*/
|
|
113
|
+
degraded?: FilePatch['degraded'];
|
|
114
|
+
}
|
|
115
|
+
export declare function buildPatch(oldText: string | null, newText: string, options: BuildPatchOptions): FilePatch;
|