@loompad/cli 0.1.0

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.
Files changed (177) hide show
  1. package/ARCHITECTURE.md +211 -0
  2. package/CHANGELOG.md +470 -0
  3. package/LICENSE +21 -0
  4. package/README.md +630 -0
  5. package/dist/adapters/base.d.ts +71 -0
  6. package/dist/adapters/base.js +187 -0
  7. package/dist/adapters/base.js.map +1 -0
  8. package/dist/adapters/bridges/antigravity.d.ts +53 -0
  9. package/dist/adapters/bridges/antigravity.js +106 -0
  10. package/dist/adapters/bridges/antigravity.js.map +1 -0
  11. package/dist/adapters/bridges/cdp.d.ts +82 -0
  12. package/dist/adapters/bridges/cdp.js +222 -0
  13. package/dist/adapters/bridges/cdp.js.map +1 -0
  14. package/dist/adapters/bridges/gui-chat.d.ts +113 -0
  15. package/dist/adapters/bridges/gui-chat.js +498 -0
  16. package/dist/adapters/bridges/gui-chat.js.map +1 -0
  17. package/dist/adapters/bridges/kiro.d.ts +19 -0
  18. package/dist/adapters/bridges/kiro.js +22 -0
  19. package/dist/adapters/bridges/kiro.js.map +1 -0
  20. package/dist/adapters/bridges/profiles.d.ts +82 -0
  21. package/dist/adapters/bridges/profiles.js +125 -0
  22. package/dist/adapters/bridges/profiles.js.map +1 -0
  23. package/dist/adapters/claude-code.d.ts +26 -0
  24. package/dist/adapters/claude-code.js +209 -0
  25. package/dist/adapters/claude-code.js.map +1 -0
  26. package/dist/adapters/codex.d.ts +51 -0
  27. package/dist/adapters/codex.js +291 -0
  28. package/dist/adapters/codex.js.map +1 -0
  29. package/dist/adapters/echo.d.ts +20 -0
  30. package/dist/adapters/echo.js +79 -0
  31. package/dist/adapters/echo.js.map +1 -0
  32. package/dist/adapters/grok.d.ts +61 -0
  33. package/dist/adapters/grok.js +217 -0
  34. package/dist/adapters/grok.js.map +1 -0
  35. package/dist/adapters/index.d.ts +9 -0
  36. package/dist/adapters/index.js +33 -0
  37. package/dist/adapters/index.js.map +1 -0
  38. package/dist/adapters/opencode.d.ts +64 -0
  39. package/dist/adapters/opencode.js +426 -0
  40. package/dist/adapters/opencode.js.map +1 -0
  41. package/dist/cli/common.d.ts +11 -0
  42. package/dist/cli/common.js +40 -0
  43. package/dist/cli/common.js.map +1 -0
  44. package/dist/cli/doctor.d.ts +12 -0
  45. package/dist/cli/doctor.js +181 -0
  46. package/dist/cli/doctor.js.map +1 -0
  47. package/dist/cli/index.d.ts +8 -0
  48. package/dist/cli/index.js +641 -0
  49. package/dist/cli/index.js.map +1 -0
  50. package/dist/cli/tui-model.d.ts +73 -0
  51. package/dist/cli/tui-model.js +312 -0
  52. package/dist/cli/tui-model.js.map +1 -0
  53. package/dist/cli/tui.d.ts +15 -0
  54. package/dist/cli/tui.js +451 -0
  55. package/dist/cli/tui.js.map +1 -0
  56. package/dist/cli/ui.d.ts +10 -0
  57. package/dist/cli/ui.js +135 -0
  58. package/dist/cli/ui.js.map +1 -0
  59. package/dist/core/ades.d.ts +79 -0
  60. package/dist/core/ades.js +130 -0
  61. package/dist/core/ades.js.map +1 -0
  62. package/dist/core/baton.d.ts +37 -0
  63. package/dist/core/baton.js +92 -0
  64. package/dist/core/baton.js.map +1 -0
  65. package/dist/core/brain-extract.d.ts +111 -0
  66. package/dist/core/brain-extract.js +248 -0
  67. package/dist/core/brain-extract.js.map +1 -0
  68. package/dist/core/brain-index.d.ts +128 -0
  69. package/dist/core/brain-index.js +338 -0
  70. package/dist/core/brain-index.js.map +1 -0
  71. package/dist/core/brain.d.ts +214 -0
  72. package/dist/core/brain.js +425 -0
  73. package/dist/core/brain.js.map +1 -0
  74. package/dist/core/claude-cli.d.ts +12 -0
  75. package/dist/core/claude-cli.js +47 -0
  76. package/dist/core/claude-cli.js.map +1 -0
  77. package/dist/core/distill.d.ts +19 -0
  78. package/dist/core/distill.js +88 -0
  79. package/dist/core/distill.js.map +1 -0
  80. package/dist/core/eventlog.d.ts +43 -0
  81. package/dist/core/eventlog.js +211 -0
  82. package/dist/core/eventlog.js.map +1 -0
  83. package/dist/core/git.d.ts +203 -0
  84. package/dist/core/git.js +460 -0
  85. package/dist/core/git.js.map +1 -0
  86. package/dist/core/logbook.d.ts +59 -0
  87. package/dist/core/logbook.js +118 -0
  88. package/dist/core/logbook.js.map +1 -0
  89. package/dist/core/memory.d.ts +34 -0
  90. package/dist/core/memory.js +124 -0
  91. package/dist/core/memory.js.map +1 -0
  92. package/dist/core/notify.d.ts +11 -0
  93. package/dist/core/notify.js +30 -0
  94. package/dist/core/notify.js.map +1 -0
  95. package/dist/core/projection.d.ts +20 -0
  96. package/dist/core/projection.js +96 -0
  97. package/dist/core/projection.js.map +1 -0
  98. package/dist/core/registry.d.ts +76 -0
  99. package/dist/core/registry.js +147 -0
  100. package/dist/core/registry.js.map +1 -0
  101. package/dist/core/router.d.ts +42 -0
  102. package/dist/core/router.js +99 -0
  103. package/dist/core/router.js.map +1 -0
  104. package/dist/core/routes.d.ts +93 -0
  105. package/dist/core/routes.js +399 -0
  106. package/dist/core/routes.js.map +1 -0
  107. package/dist/core/search.d.ts +63 -0
  108. package/dist/core/search.js +0 -0
  109. package/dist/core/search.js.map +1 -0
  110. package/dist/core/setup.d.ts +70 -0
  111. package/dist/core/setup.js +250 -0
  112. package/dist/core/setup.js.map +1 -0
  113. package/dist/core/suggestions.d.ts +15 -0
  114. package/dist/core/suggestions.js +38 -0
  115. package/dist/core/suggestions.js.map +1 -0
  116. package/dist/core/worktree.d.ts +32 -0
  117. package/dist/core/worktree.js +83 -0
  118. package/dist/core/worktree.js.map +1 -0
  119. package/dist/daemon/app-page.d.ts +32 -0
  120. package/dist/daemon/app-page.js +6363 -0
  121. package/dist/daemon/app-page.js.map +1 -0
  122. package/dist/daemon/auth.d.ts +51 -0
  123. package/dist/daemon/auth.js +135 -0
  124. package/dist/daemon/auth.js.map +1 -0
  125. package/dist/daemon/board.d.ts +117 -0
  126. package/dist/daemon/board.js +202 -0
  127. package/dist/daemon/board.js.map +1 -0
  128. package/dist/daemon/brand-icons.d.ts +29 -0
  129. package/dist/daemon/brand-icons.js +44 -0
  130. package/dist/daemon/brand-icons.js.map +1 -0
  131. package/dist/daemon/client.d.ts +127 -0
  132. package/dist/daemon/client.js +237 -0
  133. package/dist/daemon/client.js.map +1 -0
  134. package/dist/daemon/geist-font.d.ts +10 -0
  135. package/dist/daemon/geist-font.js +783 -0
  136. package/dist/daemon/geist-font.js.map +1 -0
  137. package/dist/daemon/guards.d.ts +18 -0
  138. package/dist/daemon/guards.js +40 -0
  139. package/dist/daemon/guards.js.map +1 -0
  140. package/dist/daemon/linear.d.ts +59 -0
  141. package/dist/daemon/linear.js +117 -0
  142. package/dist/daemon/linear.js.map +1 -0
  143. package/dist/daemon/push.d.ts +22 -0
  144. package/dist/daemon/push.js +58 -0
  145. package/dist/daemon/push.js.map +1 -0
  146. package/dist/daemon/runtime.d.ts +299 -0
  147. package/dist/daemon/runtime.js +1016 -0
  148. package/dist/daemon/runtime.js.map +1 -0
  149. package/dist/daemon/server.d.ts +125 -0
  150. package/dist/daemon/server.js +1728 -0
  151. package/dist/daemon/server.js.map +1 -0
  152. package/dist/daemon/tasks.d.ts +153 -0
  153. package/dist/daemon/tasks.js +264 -0
  154. package/dist/daemon/tasks.js.map +1 -0
  155. package/dist/daemon/terminals.d.ts +82 -0
  156. package/dist/daemon/terminals.js +372 -0
  157. package/dist/daemon/terminals.js.map +1 -0
  158. package/dist/index.d.ts +20 -0
  159. package/dist/index.js +20 -0
  160. package/dist/index.js.map +1 -0
  161. package/dist/sdk.d.ts +17 -0
  162. package/dist/sdk.js +17 -0
  163. package/dist/sdk.js.map +1 -0
  164. package/dist/types.d.ts +236 -0
  165. package/dist/types.js +18 -0
  166. package/dist/types.js.map +1 -0
  167. package/docs/SETUP.md +265 -0
  168. package/docs/adapters.md +132 -0
  169. package/docs/design-system.md +245 -0
  170. package/docs/img/board-linear.png +0 -0
  171. package/docs/img/board-projects.png +0 -0
  172. package/docs/img/brain.png +0 -0
  173. package/docs/img/settings.png +0 -0
  174. package/docs/img/workspace.png +0 -0
  175. package/docs/integration-notes.md +76 -0
  176. package/docs/proposals/brain.md +262 -0
  177. package/package.json +84 -0
@@ -0,0 +1,222 @@
1
+ /**
2
+ * A small Chrome DevTools Protocol client — enough to drive an Electron agent
3
+ * app, and nothing more.
4
+ *
5
+ * Antigravity and Kiro are Electron apps. Launched with a debugging port they
6
+ * speak CDP, which is the only interface either of them offers: no API, no
7
+ * headless mode, no way in but the one the browser gives us. The approach is
8
+ * the same one krishnakanthb13/antigravity_phone_chat uses to put Antigravity
9
+ * on a phone — connect over CDP, read the DOM, drive the real widgets.
10
+ *
11
+ * Typing goes through Input.insertText rather than assigning to `.value`.
12
+ * These UIs are React and Monaco: an assignment updates the DOM and the
13
+ * framework never hears about it, so the app still believes its composer is
14
+ * empty and sends nothing. insertText enters through the same pipeline a
15
+ * keyboard does, so the app cannot tell the difference.
16
+ */
17
+ import WebSocket from "ws";
18
+ import { fetchJson } from "../base.js";
19
+ /** Is anything listening for CDP at host:port? */
20
+ export async function cdpUp(endpoint, timeoutMs = 2000) {
21
+ try {
22
+ await fetchJson(`${endpoint}/json/version`, undefined, timeoutMs);
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ export async function cdpTargets(endpoint, timeoutMs = 3000) {
30
+ return fetchJson(`${endpoint}/json`, undefined, timeoutMs).catch(() => []);
31
+ }
32
+ /**
33
+ * The window that holds the app, not its splash screen.
34
+ *
35
+ * Antigravity shows a `data:` URL loader for the first seconds after launch and
36
+ * the workbench arrives later on a different target; picking the first page
37
+ * gets you an animated ellipsis with no chat in it.
38
+ */
39
+ export function workbenchTarget(targets) {
40
+ return chatTargets(targets)[0] ?? null;
41
+ }
42
+ /**
43
+ * Every target that could hold a chat, best first.
44
+ *
45
+ * A page is not enough. Kiro keeps its chat in a `vscode-webview` target — a
46
+ * separate CDP target of type `iframe` — so a page-only filter finds the
47
+ * workbench, reports "no chat panel", and is wrong about the whole app.
48
+ * Antigravity keeps its chat in its page. Both have to be reachable, so this
49
+ * returns candidates and the driver asks each one whether a chat is in it.
50
+ *
51
+ * Ordering, not exclusion, is the tool here. AntiGravity-AutoAccept drops
52
+ * http(s) targets outright, because Antigravity's *Manager* is an https page
53
+ * behind a sign-in with no chat in it — a real trap, and it cost an afternoon.
54
+ * But "no chat" is a question the driver already asks, and answering it by URL
55
+ * scheme also throws away any app that legitimately serves its UI over http.
56
+ * So the Manager sorts last and eliminates itself by having no composer, which
57
+ * is both true and non-fatal.
58
+ *
59
+ * Workers are dropped for real: there is no DOM in one.
60
+ */
61
+ export function chatTargets(targets) {
62
+ const usable = targets.filter((t) => {
63
+ if (!t.webSocketDebuggerUrl)
64
+ return false;
65
+ const url = String(t.url ?? "");
66
+ if (!url || url === "about:blank")
67
+ return false;
68
+ if (t.type === "service_worker" || t.type === "worker" || t.type === "shared_worker")
69
+ return false;
70
+ return t.type === "page" || t.type === "iframe" || url.includes("webview");
71
+ });
72
+ const rank = (t) => {
73
+ const url = String(t.url ?? "");
74
+ if (url.startsWith("data:"))
75
+ return 4; // a splash screen
76
+ if (url.startsWith("http://") || url.startsWith("https://"))
77
+ return 3; // probably a Manager
78
+ if (url.includes("webview"))
79
+ return 1; // where a panel's chat tends to live
80
+ return 0;
81
+ };
82
+ return [...usable].sort((a, b) => rank(a) - rank(b));
83
+ }
84
+ /** One CDP session against one target. */
85
+ export class CdpSession {
86
+ url;
87
+ ws = null;
88
+ nextId = 1;
89
+ pending = new Map();
90
+ constructor(url) {
91
+ this.url = url;
92
+ }
93
+ static async open(target, timeoutMs = 5000) {
94
+ if (!target.webSocketDebuggerUrl)
95
+ throw new Error("target has no debugger url");
96
+ const session = new CdpSession(target.webSocketDebuggerUrl);
97
+ await session.connect(timeoutMs);
98
+ return session;
99
+ }
100
+ connect(timeoutMs) {
101
+ return new Promise((resolve, reject) => {
102
+ const ws = new WebSocket(this.url, { maxPayload: 64 * 1024 * 1024 });
103
+ this.ws = ws;
104
+ const timer = setTimeout(() => {
105
+ ws.terminate();
106
+ reject(new Error("timed out connecting to the app's debugger"));
107
+ }, timeoutMs);
108
+ ws.on("open", () => {
109
+ clearTimeout(timer);
110
+ resolve();
111
+ });
112
+ ws.on("error", (err) => {
113
+ clearTimeout(timer);
114
+ reject(err instanceof Error ? err : new Error(String(err)));
115
+ });
116
+ ws.on("message", (raw) => this.onMessage(String(raw)));
117
+ ws.on("close", () => {
118
+ // Nothing else is coming; don't leave callers hanging forever.
119
+ for (const [, p] of this.pending)
120
+ p.reject(new Error("debugger connection closed"));
121
+ this.pending.clear();
122
+ });
123
+ });
124
+ }
125
+ onMessage(raw) {
126
+ let msg;
127
+ try {
128
+ msg = JSON.parse(raw);
129
+ }
130
+ catch {
131
+ return;
132
+ }
133
+ if (typeof msg.id !== "number")
134
+ return; // an event, not our reply
135
+ const p = this.pending.get(msg.id);
136
+ if (!p)
137
+ return;
138
+ this.pending.delete(msg.id);
139
+ if (msg.error)
140
+ p.reject(new Error(msg.error.message ?? "cdp error"));
141
+ else
142
+ p.resolve(msg.result);
143
+ }
144
+ send(method, params = {}, timeoutMs = 15_000) {
145
+ const ws = this.ws;
146
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
147
+ return Promise.reject(new Error("debugger not connected"));
148
+ }
149
+ const id = this.nextId++;
150
+ return new Promise((resolve, reject) => {
151
+ const timer = setTimeout(() => {
152
+ this.pending.delete(id);
153
+ reject(new Error(`${method} timed out`));
154
+ }, timeoutMs);
155
+ this.pending.set(id, {
156
+ resolve: (v) => {
157
+ clearTimeout(timer);
158
+ resolve(v);
159
+ },
160
+ reject: (e) => {
161
+ clearTimeout(timer);
162
+ reject(e);
163
+ },
164
+ });
165
+ ws.send(JSON.stringify({ id, method, params }));
166
+ });
167
+ }
168
+ /** Evaluate an expression in the page and return it by value. */
169
+ async evaluate(expression, timeoutMs = 15_000) {
170
+ const res = await this.send("Runtime.evaluate", { expression, returnByValue: true, awaitPromise: true }, timeoutMs);
171
+ if (res.exceptionDetails) {
172
+ const detail = res.exceptionDetails.exception?.description ?? res.exceptionDetails.text;
173
+ throw new Error(`page threw: ${String(detail).slice(0, 300)}`);
174
+ }
175
+ return res.result?.value;
176
+ }
177
+ /** Type text into whatever currently has focus, the way a keyboard would. */
178
+ async insertText(text) {
179
+ await this.send("Input.insertText", { text });
180
+ }
181
+ /**
182
+ * Click where a person would.
183
+ *
184
+ * `el.focus()` is a request the page can decline — a re-render, an overlay, a
185
+ * framework that manages focus itself — and when it's declined, Input.insertText
186
+ * types into whatever else has focus, which is nowhere useful. A real mouse
187
+ * event at real coordinates is how a human gets the caret into a box, and it
188
+ * doesn't ask.
189
+ */
190
+ async clickAt(x, y) {
191
+ const base = { x, y, button: "left", clickCount: 1 };
192
+ await this.send("Input.dispatchMouseEvent", { ...base, type: "mousePressed" });
193
+ await this.send("Input.dispatchMouseEvent", { ...base, type: "mouseReleased" });
194
+ }
195
+ async pressEnter() {
196
+ for (const type of ["keyDown", "keyUp"]) {
197
+ await this.send("Input.dispatchKeyEvent", {
198
+ type,
199
+ key: "Enter",
200
+ code: "Enter",
201
+ windowsVirtualKeyCode: 13,
202
+ nativeVirtualKeyCode: 13,
203
+ text: type === "keyDown" ? "\r" : undefined,
204
+ });
205
+ }
206
+ }
207
+ close() {
208
+ const ws = this.ws;
209
+ this.ws = null;
210
+ if (!ws)
211
+ return;
212
+ try {
213
+ ws.removeAllListeners();
214
+ ws.on("error", () => { });
215
+ ws.terminate();
216
+ }
217
+ catch {
218
+ /* already gone */
219
+ }
220
+ }
221
+ }
222
+ //# sourceMappingURL=cdp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp.js","sourceRoot":"","sources":["../../../src/adapters/bridges/cdp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Driving a GUI agent's chat box over CDP.
3
+ *
4
+ * Shared by the Antigravity and Kiro bridges, because the problem is identical:
5
+ * an Electron app with a chat panel, no API, and a DOM we can reach.
6
+ *
7
+ * The approach — and most of the hard-won detail — comes from two projects that
8
+ * do this for real every day: krishnakanthb13/antigravity_phone_chat for the
9
+ * shape of the chat, yazanbaker94/AntiGravity-AutoAccept for how to attach.
10
+ * Both MIT. Connect over CDP, find the composer inside the chat panel, type
11
+ * through the browser's own input pipeline, click the app's own submit button.
12
+ * Never touch the provider APIs, never lift a token: drive the app that's
13
+ * already signed in, the way a person would.
14
+ *
15
+ * ## Why Input.insertText and not `el.textContent = …`
16
+ *
17
+ * Antigravity's composer is a Lexical editor; Kiro's is React. Both keep their
18
+ * own model of the text and only update it when the browser tells them about an
19
+ * edit. Assigning to the DOM changes what you see and nothing else — the app
20
+ * still believes the box is empty and submits nothing.
21
+ *
22
+ * CDP's `Input.insertText` is what's used, and the choice was measured rather
23
+ * than assumed. In a real Chromium:
24
+ *
25
+ * document.execCommand("insertText") → fires `input` only
26
+ * Input.insertText (CDP) → fires `beforeinput` AND `input`
27
+ *
28
+ * `beforeinput` is the one an editor builds its model from, so execCommand is
29
+ * the worse tool despite being the obvious one — it fills the box while leaving
30
+ * the app convinced it's empty, which then looks like a send bug. It survives
31
+ * only as a fallback, after synthesising the events by hand.
32
+ *
33
+ * ## Why it refuses
34
+ *
35
+ * Both apps are VS Code family, and Monaco — the editor holding YOUR SOURCE
36
+ * FILE — is a `contenteditable`. A driver that hunts the document for something
37
+ * editable will eventually find that one, type a prompt into your code and press
38
+ * Enter. No error message repairs that afterwards.
39
+ *
40
+ * So the composer is only ever looked for *inside* the chat panel
41
+ * (profiles.ts), never in the document at large; anything under `.monaco-editor`
42
+ * is excluded even then; and no match, or an ambiguous one, is a refusal that
43
+ * names the fix. Not sending is a bad outcome. Sending into the wrong box is a
44
+ * worse one.
45
+ */
46
+ export interface GuiChatSelectors {
47
+ /** CSS selector for the chat input. Set this when discovery can't. */
48
+ composer?: string;
49
+ /** CSS selector for the submit button. Falls back to pressing Enter. */
50
+ send?: string;
51
+ /** CSS selector for the transcript container, to read replies from. */
52
+ transcript?: string;
53
+ }
54
+ export interface GuiChatOptions {
55
+ host?: string;
56
+ debugPort?: number;
57
+ selectors?: GuiChatSelectors;
58
+ /** How long a reply may take before we stop waiting. */
59
+ replyTimeoutMs?: number;
60
+ /** Quiet time that means "it stopped typing". */
61
+ settleMs?: number;
62
+ }
63
+ export declare class GuiChatDriver {
64
+ private readonly options;
65
+ private profile;
66
+ private readonly appName;
67
+ /** The target that had the chat last time; tried first, never trusted. */
68
+ private lastTargetId;
69
+ constructor(appName: string, options: GuiChatOptions, kind?: string);
70
+ get endpoint(): string;
71
+ /** How to start this app with a debugger, on this OS. */
72
+ get launchHint(): string;
73
+ reachable(): Promise<boolean>;
74
+ /**
75
+ * A session on the target that actually has the chat in it.
76
+ *
77
+ * There is usually more than one candidate and the right one isn't
78
+ * predictable from the app: Antigravity's chat is in its page, Kiro's is in a
79
+ * webview target. So every candidate is asked "is there a composer here?" and
80
+ * the first that says yes wins. The answer is remembered — the targets don't
81
+ * move around between two calls a second apart — but it's re-derived whenever
82
+ * that target has gone.
83
+ */
84
+ private session;
85
+ /**
86
+ * Can we actually drive it right now? Reachable is not enough: a signed-out
87
+ * Antigravity answers CDP happily and has no chat in it at all.
88
+ */
89
+ driveable(): Promise<{
90
+ ok: boolean;
91
+ reason?: string;
92
+ }>;
93
+ /**
94
+ * Type a prompt into the app, submit it, and wait for the panel to stop
95
+ * growing.
96
+ *
97
+ * What comes back is the panel's text, not the model's response object —
98
+ * these apps render their conversation, they don't hand it out. Same trade
99
+ * the phone-chat project makes: mirror what's on screen rather than pretend
100
+ * to have something structured.
101
+ */
102
+ ask(text: string, onProgress?: (partial: string) => void): Promise<string>;
103
+ /** Poll until the transcript stops changing, or we run out of patience. */
104
+ private waitForReply;
105
+ }
106
+ /**
107
+ * What the panel gained.
108
+ *
109
+ * Not a real diff: the transcript is a rendered panel that scrolls, collapses
110
+ * and reflows. When `after` simply grew, the tail is the new part; when it
111
+ * changed shape, the common prefix is the best we can honestly do.
112
+ */
113
+ export declare function delta(before: string, after: string): string;