genaicode 2.18.1 → 2.18.3
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 +16 -2
- package/dist/overlay/client.d.ts +25 -0
- package/dist/{vite/overlay.js → overlay/client.js} +69 -3
- package/dist/overlay/client.js.map +1 -0
- package/dist/overlay/server.d.ts +89 -0
- package/dist/overlay/server.js +197 -0
- package/dist/overlay/server.js.map +1 -0
- package/dist/ui.d.ts +31 -0
- package/dist/ui.js +21 -0
- package/dist/ui.js.map +1 -1
- package/dist/vite/plugin.d.ts +3 -16
- package/dist/vite/plugin.js +26 -131
- package/dist/vite/plugin.js.map +1 -1
- package/docs/CHANGELOG.md +6 -1
- package/package.json +1 -1
- package/skills/genaicode-embed/SKILL.md +82 -142
- package/dist/vite/overlay.d.ts +0 -19
- package/dist/vite/overlay.js.map +0 -1
package/README.md
CHANGED
|
@@ -178,8 +178,8 @@ npx genaicode embed --print | pbcopy # just the instructions, for any other
|
|
|
178
178
|
`genaicode embed` does not inspect your project itself. It starts your agent with
|
|
179
179
|
instructions on how to embed genaicode, and the agent reads the project and picks the way
|
|
180
180
|
in: the Vite overlay below for an app on Vite; for any other Node dev server (webpack,
|
|
181
|
-
Next.js, Express...)
|
|
182
|
-
|
|
181
|
+
Next.js, Express...) the same overlay through `createDevOverlay` from `genaicode/ui`; for
|
|
182
|
+
pages with no dev server at all, a small dev-only server of its own with that overlay; the in-app agent (`genaicode/app-agent` with
|
|
183
183
|
`<AppAgentChat>`) when the agent should act on the app itself; and `npx genaicode ui` next
|
|
184
184
|
to the dev server when there is no Node process to host it. Words after `embed` go to the
|
|
185
185
|
agent as your request. You watch and answer in the same chat as `genaicode chat` (`--ui`
|
|
@@ -221,6 +221,20 @@ Builds are untouched. The chat runs on its own port on 127.0.0.1 even when Vite
|
|
|
221
221
|
`--host`, lets only the app's origins frame it, and hands its token (and takes "fix" requests)
|
|
222
222
|
only from the app's own pages on this machine.
|
|
223
223
|
|
|
224
|
+
Any other Node dev server (Express, webpack-dev-server, a script that serves static files)
|
|
225
|
+
gets the same overlay from `createDevOverlay` in `genaicode/ui`:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
import { createDevOverlay } from 'genaicode/ui';
|
|
229
|
+
|
|
230
|
+
const overlay = createDevOverlay(); // same options as the plugin, plus `cwd`
|
|
231
|
+
app.use(overlay.middleware); // Express; or `if (await overlay.handle(req, res)) return;`
|
|
232
|
+
// ...and in the HTML it serves: overlay.injectHtml(html), or the overlay.script tag.
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Development only. The token goes only to pages opened at `localhost`, `*.localhost`,
|
|
236
|
+
`127.0.0.1` or `[::1]`, and without an agent CLI the overlay stays off.
|
|
237
|
+
|
|
224
238
|
### In your own React app
|
|
225
239
|
|
|
226
240
|
`genaicode/react` is the same chat as a component. It draws a `SessionState` your app gives
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** What the dev server tells the overlay. */
|
|
2
|
+
export interface OverlayConfig {
|
|
3
|
+
/** Path of the overlay's endpoints on the dev server, e.g. `/__genaicode`. */
|
|
4
|
+
api: string;
|
|
5
|
+
/** Collect errors from the page and offer to send them to the agent. */
|
|
6
|
+
captureErrors: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** The part of Vite's `import.meta.hot` the overlay listens to. */
|
|
9
|
+
export interface OverlayHot {
|
|
10
|
+
on(event: string, callback: (payload: unknown) => void): void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Runs as a classic inline script ahead of the page's own scripts, which run before any
|
|
14
|
+
* module (the overlay is one), and keeps their errors for the overlay to pick up. Served as
|
|
15
|
+
* source like `mountOverlay`, so it must not use anything from outside its own body.
|
|
16
|
+
*/
|
|
17
|
+
export declare function collectEarlyErrors(): void;
|
|
18
|
+
/**
|
|
19
|
+
* The dev-server overlay: a wolf in the corner of the app that opens the genaicode UI in a
|
|
20
|
+
* panel, and collects the page's errors so one click sends them to the agent.
|
|
21
|
+
*
|
|
22
|
+
* The dev server serves this function's source (`mountOverlay.toString()`) as a module (see
|
|
23
|
+
* `overlayModule` in ./server.ts), so it must not use anything from outside its own body.
|
|
24
|
+
*/
|
|
25
|
+
export declare function mountOverlay(config: OverlayConfig, hot: OverlayHot | undefined): void;
|
|
@@ -1,9 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs as a classic inline script ahead of the page's own scripts, which run before any
|
|
3
|
+
* module (the overlay is one), and keeps their errors for the overlay to pick up. Served as
|
|
4
|
+
* source like `mountOverlay`, so it must not use anything from outside its own body.
|
|
5
|
+
*/
|
|
6
|
+
export function collectEarlyErrors() {
|
|
7
|
+
const target = window;
|
|
8
|
+
if (target.__genaicodeEarly)
|
|
9
|
+
return;
|
|
10
|
+
const consoleError = console.error;
|
|
11
|
+
const early = {
|
|
12
|
+
errors: [],
|
|
13
|
+
restore: () => {
|
|
14
|
+
if (console.error === report)
|
|
15
|
+
console.error = consoleError;
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
target.__genaicodeEarly = early;
|
|
19
|
+
const keep = (error) => {
|
|
20
|
+
if (!early.done && early.errors.length < 20)
|
|
21
|
+
early.errors.push(error);
|
|
22
|
+
};
|
|
23
|
+
const text = (value) => {
|
|
24
|
+
if (value instanceof Error)
|
|
25
|
+
return value.message;
|
|
26
|
+
if (typeof value === 'string')
|
|
27
|
+
return value;
|
|
28
|
+
try {
|
|
29
|
+
return JSON.stringify(value) ?? String(value);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return Object.prototype.toString.call(value);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
window.addEventListener('error', (event) => {
|
|
36
|
+
const where = event.filename ? ` (${event.filename}:${event.lineno}:${event.colno})` : '';
|
|
37
|
+
keep({ source: 'error', message: `${event.message}${where}`, stack: event.error?.stack });
|
|
38
|
+
});
|
|
39
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
40
|
+
keep({ source: 'rejection', message: text(event.reason), stack: event.reason?.stack });
|
|
41
|
+
});
|
|
42
|
+
const report = (...args) => {
|
|
43
|
+
consoleError.apply(console, args);
|
|
44
|
+
try {
|
|
45
|
+
keep({
|
|
46
|
+
source: 'console',
|
|
47
|
+
message: args.map(text).join(' '),
|
|
48
|
+
stack: args.find((arg) => arg instanceof Error)?.stack,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Ignore values that cannot be described.
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
console.error = report;
|
|
56
|
+
}
|
|
1
57
|
/**
|
|
2
58
|
* The dev-server overlay: a wolf in the corner of the app that opens the genaicode UI in a
|
|
3
59
|
* panel, and collects the page's errors so one click sends them to the agent.
|
|
4
60
|
*
|
|
5
|
-
* The
|
|
6
|
-
* not use anything from outside its own body.
|
|
61
|
+
* The dev server serves this function's source (`mountOverlay.toString()`) as a module (see
|
|
62
|
+
* `overlayModule` in ./server.ts), so it must not use anything from outside its own body.
|
|
7
63
|
*/
|
|
8
64
|
export function mountOverlay(config, hot) {
|
|
9
65
|
if (document.querySelector('genaicode-overlay'))
|
|
@@ -262,7 +318,17 @@ iframe { flex: 1; width: 100%; border: 0; background: #f7f7f5; }
|
|
|
262
318
|
errors = [...errors, error].slice(-MAX_ERRORS);
|
|
263
319
|
render();
|
|
264
320
|
};
|
|
321
|
+
// What `collectEarlyErrors` caught before this module ran: the page's classic scripts.
|
|
322
|
+
const early = window.__genaicodeEarly;
|
|
323
|
+
if (early) {
|
|
324
|
+
early.done = true;
|
|
325
|
+
early.restore();
|
|
326
|
+
}
|
|
265
327
|
if (config.captureErrors) {
|
|
328
|
+
for (const error of early?.errors ?? []) {
|
|
329
|
+
if (error && typeof error.message === 'string' && typeof error.source === 'string')
|
|
330
|
+
add(error);
|
|
331
|
+
}
|
|
266
332
|
window.addEventListener('error', (event) => {
|
|
267
333
|
const where = event.filename ? ` (${event.filename}:${event.lineno}:${event.colno})` : '';
|
|
268
334
|
add({ source: 'error', message: `${event.message}${where}`, stack: event.error?.stack });
|
|
@@ -311,4 +377,4 @@ iframe { flex: 1; width: 100%; border: 0; background: #f7f7f5; }
|
|
|
311
377
|
wolf.append(badge);
|
|
312
378
|
});
|
|
313
379
|
}
|
|
314
|
-
//# sourceMappingURL=
|
|
380
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/overlay/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { type OverlayConfig } from './client.js';
|
|
3
|
+
/**
|
|
4
|
+
* The server side of the dev overlay (the wolf in the page's corner), shared by the Vite
|
|
5
|
+
* plugin (`genaicode/vite`) and `createDevOverlay` (`genaicode/ui`) for any other dev server.
|
|
6
|
+
*/
|
|
7
|
+
/** Where the overlay's endpoints live on the dev server. */
|
|
8
|
+
export declare const API = "/__genaicode";
|
|
9
|
+
/** The genaicode UI the overlay shows: what `startEmbeddedWeb` returns. */
|
|
10
|
+
export interface OverlayUi {
|
|
11
|
+
url: string;
|
|
12
|
+
controller: {
|
|
13
|
+
submit(text: string): unknown;
|
|
14
|
+
get(): {
|
|
15
|
+
session: {
|
|
16
|
+
agent: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export interface OverlayLog {
|
|
23
|
+
info(message: string): void;
|
|
24
|
+
warn(message: string): void;
|
|
25
|
+
error(message: string): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Start the UI for the overlay. Never rejects: without an agent CLI, or when the UI fails to
|
|
29
|
+
* start, it says so in the log and resolves to undefined, and the app runs on without it.
|
|
30
|
+
*/
|
|
31
|
+
export declare function startOverlayUi<Ui extends OverlayUi>(start: () => Promise<Ui>, log: OverlayLog): Promise<Ui | undefined>;
|
|
32
|
+
/** The overlay for a dev server: its routes, and the tag that puts it in a page. */
|
|
33
|
+
export interface Overlay<Ui extends OverlayUi = OverlayUi> {
|
|
34
|
+
/** The chat once it runs; undefined when no agent CLI is installed or it failed (see `log`). */
|
|
35
|
+
readonly ready: Promise<Ui | undefined>;
|
|
36
|
+
/**
|
|
37
|
+
* Answers the overlay's routes under `/__genaicode/`; resolves to false for anything else,
|
|
38
|
+
* so the server goes on to its own routes. Mount it before them.
|
|
39
|
+
*/
|
|
40
|
+
handle(req: IncomingMessage, res: ServerResponse): Promise<boolean>;
|
|
41
|
+
/** `handle` as Express / Connect middleware. */
|
|
42
|
+
middleware(req: IncomingMessage, res: ServerResponse, next: (error?: unknown) => void): void;
|
|
43
|
+
/**
|
|
44
|
+
* The overlay's tags for the app's HTML: an inline error collector for the page's own
|
|
45
|
+
* scripts, then `<script type="module" src="/__genaicode/overlay.js">`.
|
|
46
|
+
*/
|
|
47
|
+
readonly script: string;
|
|
48
|
+
/** Adds `script` to an HTML page, as early as possible; unchanged when the overlay is off. */
|
|
49
|
+
injectHtml(html: string): string;
|
|
50
|
+
close(): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The overlay for any Node dev server (`createDevOverlay` in src/ui.ts). `start` gets the
|
|
54
|
+
* origins that may frame the chat: the app's pages that asked for the session.
|
|
55
|
+
*/
|
|
56
|
+
export declare function createOverlay<Ui extends OverlayUi>(start: (frameAncestors: () => readonly string[]) => Promise<Ui>, { captureErrors, log }: {
|
|
57
|
+
captureErrors: boolean;
|
|
58
|
+
log: OverlayLog;
|
|
59
|
+
}): Overlay<Ui>;
|
|
60
|
+
export interface OverlayRequestContext {
|
|
61
|
+
/** The UI, or undefined when it is off. */
|
|
62
|
+
ui: Promise<OverlayUi | undefined> | undefined;
|
|
63
|
+
/** Called with the origin of each app page that asks for the session, for frame-ancestors. */
|
|
64
|
+
onPage(origin: string): void;
|
|
65
|
+
/** Serve the overlay module at `/__genaicode/overlay.js` with these settings. */
|
|
66
|
+
overlay: OverlayConfig;
|
|
67
|
+
/** Whether the app is served over https. Default: whether this request came over TLS. */
|
|
68
|
+
https?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Hand the UI's token only to pages opened at a loopback name (localhost, *.localhost,
|
|
71
|
+
* 127.0.0.1, [::1]), which stops DNS-rebinding pages. Vite checks the Host itself.
|
|
72
|
+
*/
|
|
73
|
+
loopbackHosts: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The overlay's endpoints: the overlay module, the UI link, and "fix these errors". Resolves
|
|
77
|
+
* to false for any other URL, so the dev server goes on to its own routes.
|
|
78
|
+
*/
|
|
79
|
+
export declare function handleOverlayRequest(req: IncomingMessage, res: ServerResponse, context: OverlayRequestContext): Promise<boolean>;
|
|
80
|
+
/** The overlay as an ES module. `hot` is the expression for Vite's HMR client, if any. */
|
|
81
|
+
export declare function overlayModule(config: OverlayConfig, hot?: string): string;
|
|
82
|
+
/** The prompt for "Fix N errors", or undefined when the body is not a list of errors. */
|
|
83
|
+
export declare function fixPrompt(body: unknown): string | undefined;
|
|
84
|
+
/** 127.0.0.0/8 and ::1, also as IPv4-mapped IPv6 addresses. */
|
|
85
|
+
export declare function isLoopback(address: string | undefined): boolean;
|
|
86
|
+
/** A Host header naming this machine: localhost, *.localhost, 127.x.x.x or [::1], any port. */
|
|
87
|
+
export declare function isLoopbackHost(host: string | undefined): boolean;
|
|
88
|
+
/** The origin a same-origin request came from, by its Host header. */
|
|
89
|
+
export declare function pageOrigin(host: string | undefined, https: boolean): string | undefined;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { collectEarlyErrors, mountOverlay } from './client.js';
|
|
2
|
+
/**
|
|
3
|
+
* The server side of the dev overlay (the wolf in the page's corner), shared by the Vite
|
|
4
|
+
* plugin (`genaicode/vite`) and `createDevOverlay` (`genaicode/ui`) for any other dev server.
|
|
5
|
+
*/
|
|
6
|
+
/** Where the overlay's endpoints live on the dev server. */
|
|
7
|
+
export const API = '/__genaicode';
|
|
8
|
+
const MAX_BODY = 256 * 1024;
|
|
9
|
+
/**
|
|
10
|
+
* Start the UI for the overlay. Never rejects: without an agent CLI, or when the UI fails to
|
|
11
|
+
* start, it says so in the log and resolves to undefined, and the app runs on without it.
|
|
12
|
+
*/
|
|
13
|
+
export async function startOverlayUi(start, log) {
|
|
14
|
+
try {
|
|
15
|
+
const ui = await start();
|
|
16
|
+
log.info(` ➜ genaicode: ${ui.controller.get().session.agent} in the page, or open ${ui.url}`);
|
|
17
|
+
return ui;
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
// By name: the error class lives in the lazily loaded UI bundle.
|
|
21
|
+
if (error?.name === 'NoAgentError') {
|
|
22
|
+
log.warn(`[genaicode] ${error.message} The overlay is off.`);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
log.error(`[genaicode] The UI did not start: ${error?.message ?? String(error)}`);
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The overlay for any Node dev server (`createDevOverlay` in src/ui.ts). `start` gets the
|
|
32
|
+
* origins that may frame the chat: the app's pages that asked for the session.
|
|
33
|
+
*/
|
|
34
|
+
export function createOverlay(start, { captureErrors, log }) {
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
let ui = startOverlayUi(() => start(() => [...seen]), log);
|
|
37
|
+
let off = false;
|
|
38
|
+
void ui.then((started) => (off = !started));
|
|
39
|
+
// The page's classic scripts run before any module: an inline collector keeps their errors.
|
|
40
|
+
const script = (captureErrors ? `<script>(${collectEarlyErrors.toString()})()</script>` : '') +
|
|
41
|
+
`<script type="module" src="${API}/overlay.js"></script>`;
|
|
42
|
+
const handle = (req, res) => handleOverlayRequest(req, res, {
|
|
43
|
+
ui,
|
|
44
|
+
onPage: (origin) => seen.add(origin),
|
|
45
|
+
overlay: { api: API, captureErrors },
|
|
46
|
+
loopbackHosts: true,
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
get ready() {
|
|
50
|
+
return ui ?? Promise.resolve(undefined);
|
|
51
|
+
},
|
|
52
|
+
handle,
|
|
53
|
+
middleware(req, res, next) {
|
|
54
|
+
handle(req, res).then((done) => done || next(), next);
|
|
55
|
+
},
|
|
56
|
+
script,
|
|
57
|
+
injectHtml(html) {
|
|
58
|
+
if (off || html.includes(script))
|
|
59
|
+
return html;
|
|
60
|
+
// In <head> (else <body>, else <html>), so it loads before the app's own modules.
|
|
61
|
+
const open = ['head', 'body', 'html']
|
|
62
|
+
.map((tag) => new RegExp(`<${tag}(\\s[^>]*)?>`, 'i').exec(html))
|
|
63
|
+
.find((match) => match);
|
|
64
|
+
// Without those optional tags, after the doctype: before it, the page would be in quirks mode.
|
|
65
|
+
const at = open ? open.index + open[0].length : (/^\s*<!doctype[^>]*>/i.exec(html)?.[0].length ?? 0);
|
|
66
|
+
return html.slice(0, at) + script + html.slice(at);
|
|
67
|
+
},
|
|
68
|
+
async close() {
|
|
69
|
+
const started = await ui;
|
|
70
|
+
ui = undefined;
|
|
71
|
+
off = true;
|
|
72
|
+
await started?.close();
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The overlay's endpoints: the overlay module, the UI link, and "fix these errors". Resolves
|
|
78
|
+
* to false for any other URL, so the dev server goes on to its own routes.
|
|
79
|
+
*/
|
|
80
|
+
export async function handleOverlayRequest(req, res, context) {
|
|
81
|
+
const path = (req.url ?? '/').split('?')[0];
|
|
82
|
+
if (path !== API && !path.startsWith(`${API}/`))
|
|
83
|
+
return false;
|
|
84
|
+
const send = (status, body) => {
|
|
85
|
+
res.writeHead(status, { 'content-type': 'application/json', 'cache-control': 'no-store' });
|
|
86
|
+
res.end(JSON.stringify(body));
|
|
87
|
+
return true;
|
|
88
|
+
};
|
|
89
|
+
// The overlay itself holds nothing secret.
|
|
90
|
+
if (req.method === 'GET' && path === `${API}/overlay.js`) {
|
|
91
|
+
res.writeHead(200, { 'content-type': 'text/javascript', 'cache-control': 'no-store' });
|
|
92
|
+
res.end(overlayModule(context.overlay));
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
// Only this machine: a dev server listening beyond loopback also answers the network, and
|
|
96
|
+
// Sec-Fetch-Site is just a header a client there could send. Then only the app's own pages:
|
|
97
|
+
// another site open in the browser must not read the UI's token or start the agent.
|
|
98
|
+
if (!isLoopback(req.socket.remoteAddress))
|
|
99
|
+
return send(403, { error: 'this machine only' });
|
|
100
|
+
if (context.loopbackHosts && !isLoopbackHost(req.headers.host))
|
|
101
|
+
return send(403, { error: 'localhost only' });
|
|
102
|
+
if (req.headers['sec-fetch-site'] !== 'same-origin')
|
|
103
|
+
return send(403, { error: 'same-origin only' });
|
|
104
|
+
const ui = await context.ui;
|
|
105
|
+
if (!ui)
|
|
106
|
+
return send(503, { error: 'genaicode is off; see the dev server terminal' });
|
|
107
|
+
if (req.method === 'GET' && path === `${API}/session`) {
|
|
108
|
+
const origin = pageOrigin(req.headers.host, context.https ?? !!req.socket.encrypted);
|
|
109
|
+
if (origin)
|
|
110
|
+
context.onPage(origin);
|
|
111
|
+
return send(200, { url: ui.url, agent: ui.controller.get().session.agent });
|
|
112
|
+
}
|
|
113
|
+
if (req.method === 'POST' && path === `${API}/fix`) {
|
|
114
|
+
if (!String(req.headers['content-type'] ?? '').startsWith('application/json')) {
|
|
115
|
+
return send(415, { error: 'expected JSON' });
|
|
116
|
+
}
|
|
117
|
+
let prompt;
|
|
118
|
+
try {
|
|
119
|
+
prompt = fixPrompt(JSON.parse(await readBody(req)));
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
prompt = undefined;
|
|
123
|
+
}
|
|
124
|
+
if (!prompt)
|
|
125
|
+
return send(400, { error: 'bad request' });
|
|
126
|
+
ui.controller.submit(prompt);
|
|
127
|
+
return send(200, { ok: true });
|
|
128
|
+
}
|
|
129
|
+
return send(404, { error: 'not found' });
|
|
130
|
+
}
|
|
131
|
+
/** The overlay as an ES module. `hot` is the expression for Vite's HMR client, if any. */
|
|
132
|
+
export function overlayModule(config, hot = 'undefined') {
|
|
133
|
+
return `(${mountOverlay.toString()})(${JSON.stringify(config)}, ${hot});\n`;
|
|
134
|
+
}
|
|
135
|
+
const SOURCES = {
|
|
136
|
+
vite: 'build error',
|
|
137
|
+
error: 'uncaught error',
|
|
138
|
+
rejection: 'unhandled rejection',
|
|
139
|
+
console: 'console.error',
|
|
140
|
+
};
|
|
141
|
+
/** The prompt for "Fix N errors", or undefined when the body is not a list of errors. */
|
|
142
|
+
export function fixPrompt(body) {
|
|
143
|
+
if (!body || typeof body !== 'object')
|
|
144
|
+
return undefined;
|
|
145
|
+
const { page, errors } = body;
|
|
146
|
+
if (!Array.isArray(errors) || errors.length === 0)
|
|
147
|
+
return undefined;
|
|
148
|
+
const items = [];
|
|
149
|
+
for (const error of errors.slice(0, 20)) {
|
|
150
|
+
if (!error || typeof error !== 'object')
|
|
151
|
+
return undefined;
|
|
152
|
+
const { source, message, stack } = error;
|
|
153
|
+
if (typeof message !== 'string' || typeof source !== 'string' || !Object.hasOwn(SOURCES, source))
|
|
154
|
+
return undefined;
|
|
155
|
+
const trace = typeof stack === 'string' && stack && !message.includes(stack) ? `\n${stack.slice(0, 4000)}` : '';
|
|
156
|
+
items.push(`${items.length + 1}. [${SOURCES[source]}] ${message.slice(0, 4000)}${trace}`);
|
|
157
|
+
}
|
|
158
|
+
const where = typeof page === 'string' && /^https?:\/\//.test(page) ? ` at ${page.slice(0, 500)}` : '';
|
|
159
|
+
return (`The app running in the dev server${where} reports ${items.length === 1 ? 'this error' : 'these errors'} ` +
|
|
160
|
+
`in the browser. Find the cause in the code and fix it.\n\n` +
|
|
161
|
+
'```\n' +
|
|
162
|
+
items.join('\n\n').replace(/```/g, "'''") +
|
|
163
|
+
'\n```');
|
|
164
|
+
}
|
|
165
|
+
/** 127.0.0.0/8 and ::1, also as IPv4-mapped IPv6 addresses. */
|
|
166
|
+
export function isLoopback(address) {
|
|
167
|
+
if (!address)
|
|
168
|
+
return false;
|
|
169
|
+
const v4 = address.startsWith('::ffff:') ? address.slice(7) : address;
|
|
170
|
+
return address === '::1' || /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v4);
|
|
171
|
+
}
|
|
172
|
+
/** A Host header naming this machine: localhost, *.localhost, 127.x.x.x or [::1], any port. */
|
|
173
|
+
export function isLoopbackHost(host) {
|
|
174
|
+
const match = /^(\[::1\]|[\w.-]+)(:\d+)?$/.exec(host ?? '');
|
|
175
|
+
if (!match)
|
|
176
|
+
return false;
|
|
177
|
+
const name = match[1].toLowerCase();
|
|
178
|
+
return name === '[::1]' || name === 'localhost' || name.endsWith('.localhost') || isLoopback(name);
|
|
179
|
+
}
|
|
180
|
+
/** The origin a same-origin request came from, by its Host header. */
|
|
181
|
+
export function pageOrigin(host, https) {
|
|
182
|
+
if (!host || !/^[\w.-]+(:\d+)?$|^\[[\da-f:.]+\](:\d+)?$/i.test(host))
|
|
183
|
+
return undefined;
|
|
184
|
+
return `${https ? 'https' : 'http'}://${host.toLowerCase()}`;
|
|
185
|
+
}
|
|
186
|
+
async function readBody(req) {
|
|
187
|
+
let size = 0;
|
|
188
|
+
const chunks = [];
|
|
189
|
+
for await (const chunk of req) {
|
|
190
|
+
size += chunk.length;
|
|
191
|
+
if (size > MAX_BODY)
|
|
192
|
+
throw new Error('Request too large');
|
|
193
|
+
chunks.push(chunk);
|
|
194
|
+
}
|
|
195
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/overlay/server.ts"],"names":[],"mappings":"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"}
|
package/dist/ui.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentSession, SessionState } from './agents/session.js';
|
|
2
2
|
import type { AgentTask, ApprovalDecision, CodingAgent } from './agents/types.js';
|
|
3
|
+
import { type Overlay, type OverlayLog } from './overlay/server.js';
|
|
3
4
|
/**
|
|
4
5
|
* `genaicode/ui`: the `genaicode ui` chat served on 127.0.0.1 for a host that shows it in its
|
|
5
6
|
* own page (an iframe) and wants a say in the session: MCP servers, env, a prompt prefix.
|
|
@@ -7,6 +8,9 @@ import type { AgentTask, ApprovalDecision, CodingAgent } from './agents/types.js
|
|
|
7
8
|
* The UI itself (React, Ink) is bundled in `dist/ui/` and loaded only when
|
|
8
9
|
* `startEmbeddedWeb` runs, so importing this module pulls no UI code. For a chat drawn by the
|
|
9
10
|
* host's own React tree, use `genaicode/react` instead.
|
|
11
|
+
*
|
|
12
|
+
* `createDevOverlay` puts the same chat into any Node dev server the way `genaicode/vite` does
|
|
13
|
+
* for Vite: the genaicode wolf in the page's corner, with the page's errors in its badge.
|
|
10
14
|
*/
|
|
11
15
|
export interface EmbeddedWebOptions {
|
|
12
16
|
/** Directory the agent works in. */
|
|
@@ -69,3 +73,30 @@ export type EmbeddedWebBundleOptions = EmbeddedWebOptions & {
|
|
|
69
73
|
* `NoAgentError` when no agent CLI is installed (or `agent` is unknown).
|
|
70
74
|
*/
|
|
71
75
|
export declare function startEmbeddedWeb(options: EmbeddedWebOptions): Promise<EmbeddedWeb>;
|
|
76
|
+
export interface DevOverlayOptions extends Omit<EmbeddedWebOptions, 'cwd' | 'frameAncestors'> {
|
|
77
|
+
/** Directory the agent works in. Default: `process.cwd()`. */
|
|
78
|
+
cwd?: string;
|
|
79
|
+
/** Collect the page's errors and offer to send them to the agent. Default true. */
|
|
80
|
+
captureErrors?: boolean;
|
|
81
|
+
/** Where the overlay says it started, or why not. Default: `console`. */
|
|
82
|
+
log?: OverlayLog;
|
|
83
|
+
}
|
|
84
|
+
/** The genaicode overlay for a dev server: its routes, and the tag that puts it in a page. */
|
|
85
|
+
export type DevOverlay = Overlay<EmbeddedWeb>;
|
|
86
|
+
/**
|
|
87
|
+
* The genaicode overlay for a dev server other than Vite (Express, webpack-dev-server, a
|
|
88
|
+
* script that serves static files...): the wolf in the corner opens the chat with the agent
|
|
89
|
+
* working in `cwd`, its badge counts the page's errors, and "Fix N errors" sends them to the
|
|
90
|
+
* agent. Development only.
|
|
91
|
+
*
|
|
92
|
+
* ```js
|
|
93
|
+
* const overlay = createDevOverlay();
|
|
94
|
+
* app.use(overlay.middleware); // Express, before the app's routes
|
|
95
|
+
* // ...and overlay.script in the dev HTML, or overlay.injectHtml(html) where HTML is served.
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* The chat starts in the background on 127.0.0.1. Its token goes only to the app's own pages
|
|
99
|
+
* (same-origin), on this machine, opened at a loopback name (localhost, *.localhost,
|
|
100
|
+
* 127.0.0.1, [::1]). Without an agent CLI the overlay stays off and the app runs on.
|
|
101
|
+
*/
|
|
102
|
+
export declare function createDevOverlay(options?: DevOverlayOptions): DevOverlay;
|
package/dist/ui.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
2
|
import { defaultAgents } from './agents/defaults.js';
|
|
3
|
+
import { createOverlay } from './overlay/server.js';
|
|
3
4
|
/**
|
|
4
5
|
* Start the chat UI on 127.0.0.1 for the host's page. Rejects with an error named
|
|
5
6
|
* `NoAgentError` when no agent CLI is installed (or `agent` is unknown).
|
|
@@ -13,6 +14,26 @@ export async function startEmbeddedWeb(options) {
|
|
|
13
14
|
frameAncestors: options.frameAncestors ?? (() => []),
|
|
14
15
|
});
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* The genaicode overlay for a dev server other than Vite (Express, webpack-dev-server, a
|
|
19
|
+
* script that serves static files...): the wolf in the corner opens the chat with the agent
|
|
20
|
+
* working in `cwd`, its badge counts the page's errors, and "Fix N errors" sends them to the
|
|
21
|
+
* agent. Development only.
|
|
22
|
+
*
|
|
23
|
+
* ```js
|
|
24
|
+
* const overlay = createDevOverlay();
|
|
25
|
+
* app.use(overlay.middleware); // Express, before the app's routes
|
|
26
|
+
* // ...and overlay.script in the dev HTML, or overlay.injectHtml(html) where HTML is served.
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* The chat starts in the background on 127.0.0.1. Its token goes only to the app's own pages
|
|
30
|
+
* (same-origin), on this machine, opened at a loopback name (localhost, *.localhost,
|
|
31
|
+
* 127.0.0.1, [::1]). Without an agent CLI the overlay stays off and the app runs on.
|
|
32
|
+
*/
|
|
33
|
+
export function createDevOverlay(options = {}) {
|
|
34
|
+
const { captureErrors = true, log = console, ...web } = options;
|
|
35
|
+
return createOverlay((frameAncestors) => startEmbeddedWeb({ ...web, cwd: web.cwd ?? process.cwd(), frameAncestors }), { captureErrors, log });
|
|
36
|
+
}
|
|
16
37
|
/** The front ends are bundled into dist/ui by scripts/build-ui.mjs; the path is kept opaque to tsc. */
|
|
17
38
|
function loadBundledUi() {
|
|
18
39
|
const bundle = new URL('./ui/index.js', import.meta.url).href;
|
package/dist/ui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAiC,MAAM,qBAAqB,CAAC;AA0EnF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAA2B;IAChE,MAAM,EAAE,GAAG,MAAM,aAAa,EAAE,CAAC;IACjC,OAAO,EAAE,CAAC,gBAAgB,CAAC;QACzB,GAAG,OAAO;QACV,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,aAAa,EAAE;QACzC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,cAAc,EAAE;QAC5C,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;KACrD,CAAC,CAAC;AACL,CAAC;AAcD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAA6B,EAAE;IAC9D,MAAM,EAAE,aAAa,GAAG,IAAI,EAAE,GAAG,GAAG,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC;IAChE,OAAO,aAAa,CAClB,CAAC,cAAc,EAAE,EAAE,CAAC,gBAAgB,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,CAAC,EAC/F,EAAE,aAAa,EAAE,GAAG,EAAE,CACvB,CAAC;AACJ,CAAC;AAED,uGAAuG;AACvG,SAAS,aAAa;IACpB,MAAM,MAAM,GAAW,IAAI,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IACtE,OAAO,MAAM,CAAC,MAAM,CAAsB,CAAC;AAC7C,CAAC;AAED,SAAS,cAAc;IACrB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,OAAQ,OAAO,CAAC,iBAAiB,CAAyB,CAAC,OAAO,CAAC;AACrE,CAAC"}
|
package/dist/vite/plugin.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
2
|
import type { CodingAgent } from '../agents/types.js';
|
|
3
|
+
import { type OverlayUi } from '../overlay/server.js';
|
|
4
|
+
export { fixPrompt, isLoopback } from '../overlay/server.js';
|
|
3
5
|
export interface GenaicodeViteOptions {
|
|
4
6
|
/** Agent to start with. Default: the first installed one. */
|
|
5
7
|
agent?: string;
|
|
@@ -29,18 +31,7 @@ export interface EmbeddedUiModule {
|
|
|
29
31
|
version: string;
|
|
30
32
|
port?: number;
|
|
31
33
|
frameAncestors: () => readonly string[];
|
|
32
|
-
}): Promise<
|
|
33
|
-
url: string;
|
|
34
|
-
controller: {
|
|
35
|
-
submit(text: string): unknown;
|
|
36
|
-
get(): {
|
|
37
|
-
session: {
|
|
38
|
-
agent: string;
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
close(): Promise<void>;
|
|
43
|
-
}>;
|
|
34
|
+
}): Promise<OverlayUi>;
|
|
44
35
|
}
|
|
45
36
|
/**
|
|
46
37
|
* `genaicode/vite`: the genaicode UI inside a Vite dev server. The page gets a wolf in the
|
|
@@ -51,7 +42,3 @@ export interface EmbeddedUiModule {
|
|
|
51
42
|
* server started with `--host` does not expose the agent to the network.
|
|
52
43
|
*/
|
|
53
44
|
export declare function genaicode(options?: GenaicodeViteOptions): Plugin;
|
|
54
|
-
/** The prompt for "Fix N errors", or undefined when the body is not a list of errors. */
|
|
55
|
-
export declare function fixPrompt(body: unknown): string | undefined;
|
|
56
|
-
/** 127.0.0.0/8 and ::1, also as IPv4-mapped IPv6 addresses. */
|
|
57
|
-
export declare function isLoopback(address: string | undefined): boolean;
|
package/dist/vite/plugin.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
2
|
import { defaultAgents } from '../agents/defaults.js';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { API, handleOverlayRequest, overlayModule, startOverlayUi } from '../overlay/server.js';
|
|
4
|
+
export { fixPrompt, isLoopback } from '../overlay/server.js';
|
|
5
5
|
const OVERLAY_ID = 'virtual:genaicode-overlay';
|
|
6
|
-
const MAX_BODY = 256 * 1024;
|
|
7
6
|
/**
|
|
8
7
|
* `genaicode/vite`: the genaicode UI inside a Vite dev server. The page gets a wolf in the
|
|
9
8
|
* corner that opens the chat with a coding agent working in the project, and its errors
|
|
@@ -14,6 +13,7 @@ const MAX_BODY = 256 * 1024;
|
|
|
14
13
|
*/
|
|
15
14
|
export function genaicode(options = {}) {
|
|
16
15
|
let started;
|
|
16
|
+
const overlay = { api: API, captureErrors: options.captureErrors ?? true };
|
|
17
17
|
let base = '/';
|
|
18
18
|
// Origins the app's pages were actually opened at (e.g. app.localhost), for frame-ancestors.
|
|
19
19
|
const seen = new Set();
|
|
@@ -24,38 +24,29 @@ export function genaicode(options = {}) {
|
|
|
24
24
|
base = config.base;
|
|
25
25
|
},
|
|
26
26
|
configureServer(server) {
|
|
27
|
-
|
|
28
|
-
started = (async () => {
|
|
27
|
+
started = startOverlayUi(async () => {
|
|
29
28
|
const ui = await (options.loadUi ?? loadBundledUi)();
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
log.info(` ➜ genaicode: ${ui.controller.get().session.agent} in the page, or open ${ui.url}`);
|
|
52
|
-
return ui;
|
|
53
|
-
}, (error) => {
|
|
54
|
-
log.error(`[genaicode] The UI did not start: ${error.message}`);
|
|
55
|
-
return undefined;
|
|
56
|
-
});
|
|
57
|
-
server.middlewares.use(API, (req, res, next) => {
|
|
58
|
-
handleApi(req, res, started, (origin) => seen.add(origin), !!server.config.server.https).catch(next);
|
|
29
|
+
return ui.startEmbeddedWeb({
|
|
30
|
+
agents: options.agents ?? defaultAgents(),
|
|
31
|
+
agent: options.agent,
|
|
32
|
+
cwd: server.config.root,
|
|
33
|
+
model: options.model,
|
|
34
|
+
effort: options.effort,
|
|
35
|
+
approveAll: options.approveAll,
|
|
36
|
+
version: packageVersion(),
|
|
37
|
+
port: options.port,
|
|
38
|
+
frameAncestors: () => pageOrigins(server, seen),
|
|
39
|
+
});
|
|
40
|
+
}, server.config.logger);
|
|
41
|
+
server.middlewares.use((req, res, next) => {
|
|
42
|
+
handleOverlayRequest(req, res, {
|
|
43
|
+
ui: started,
|
|
44
|
+
onPage: (origin) => seen.add(origin),
|
|
45
|
+
overlay,
|
|
46
|
+
https: !!server.config.server.https,
|
|
47
|
+
// Vite checks the Host itself (server.allowedHosts).
|
|
48
|
+
loopbackHosts: false,
|
|
49
|
+
}).then((done) => done || next(), next);
|
|
59
50
|
});
|
|
60
51
|
},
|
|
61
52
|
resolveId(id) {
|
|
@@ -65,8 +56,7 @@ export function genaicode(options = {}) {
|
|
|
65
56
|
load(id) {
|
|
66
57
|
if (id !== `\0${OVERLAY_ID}`)
|
|
67
58
|
return;
|
|
68
|
-
|
|
69
|
-
return `(${mountOverlay.toString()})(${JSON.stringify(config)}, import.meta.hot);\n`;
|
|
59
|
+
return overlayModule(overlay, 'import.meta.hot');
|
|
70
60
|
},
|
|
71
61
|
async transformIndexHtml() {
|
|
72
62
|
if (!(await started))
|
|
@@ -88,90 +78,6 @@ export function genaicode(options = {}) {
|
|
|
88
78
|
},
|
|
89
79
|
};
|
|
90
80
|
}
|
|
91
|
-
/** The dev server's own endpoints for the overlay: the UI link, and "fix these errors". */
|
|
92
|
-
async function handleApi(req, res, started, onPage, https) {
|
|
93
|
-
const send = (status, body) => {
|
|
94
|
-
res.writeHead(status, { 'content-type': 'application/json', 'cache-control': 'no-store' });
|
|
95
|
-
res.end(JSON.stringify(body));
|
|
96
|
-
};
|
|
97
|
-
// Only this machine: with --host the dev server also answers the network, and Sec-Fetch-Site
|
|
98
|
-
// is just a header a client there could send. Then only the app's own pages: another site
|
|
99
|
-
// open in the browser must not read the UI's token or start the agent.
|
|
100
|
-
if (!isLoopback(req.socket.remoteAddress))
|
|
101
|
-
return send(403, { error: 'this machine only' });
|
|
102
|
-
if (req.headers['sec-fetch-site'] !== 'same-origin')
|
|
103
|
-
return send(403, { error: 'same-origin only' });
|
|
104
|
-
const ui = await started;
|
|
105
|
-
if (!ui)
|
|
106
|
-
return send(503, { error: 'genaicode is off; see the dev server terminal' });
|
|
107
|
-
const path = (req.url ?? '/').split('?')[0];
|
|
108
|
-
if (req.method === 'GET' && path === '/session') {
|
|
109
|
-
const origin = pageOrigin(req.headers.host, https);
|
|
110
|
-
if (origin)
|
|
111
|
-
onPage(origin);
|
|
112
|
-
return send(200, { url: ui.url, agent: ui.controller.get().session.agent });
|
|
113
|
-
}
|
|
114
|
-
if (req.method === 'POST' && path === '/fix') {
|
|
115
|
-
if (!String(req.headers['content-type'] ?? '').startsWith('application/json')) {
|
|
116
|
-
return send(415, { error: 'expected JSON' });
|
|
117
|
-
}
|
|
118
|
-
let prompt;
|
|
119
|
-
try {
|
|
120
|
-
prompt = fixPrompt(JSON.parse(await readBody(req)));
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
123
|
-
prompt = undefined;
|
|
124
|
-
}
|
|
125
|
-
if (!prompt)
|
|
126
|
-
return send(400, { error: 'bad request' });
|
|
127
|
-
ui.controller.submit(prompt);
|
|
128
|
-
return send(200, { ok: true });
|
|
129
|
-
}
|
|
130
|
-
send(404, { error: 'not found' });
|
|
131
|
-
}
|
|
132
|
-
const SOURCES = {
|
|
133
|
-
vite: 'build error',
|
|
134
|
-
error: 'uncaught error',
|
|
135
|
-
rejection: 'unhandled rejection',
|
|
136
|
-
console: 'console.error',
|
|
137
|
-
};
|
|
138
|
-
/** The prompt for "Fix N errors", or undefined when the body is not a list of errors. */
|
|
139
|
-
export function fixPrompt(body) {
|
|
140
|
-
if (!body || typeof body !== 'object')
|
|
141
|
-
return undefined;
|
|
142
|
-
const { page, errors } = body;
|
|
143
|
-
if (!Array.isArray(errors) || errors.length === 0)
|
|
144
|
-
return undefined;
|
|
145
|
-
const items = [];
|
|
146
|
-
for (const error of errors.slice(0, 20)) {
|
|
147
|
-
if (!error || typeof error !== 'object')
|
|
148
|
-
return undefined;
|
|
149
|
-
const { source, message, stack } = error;
|
|
150
|
-
if (typeof message !== 'string' || typeof source !== 'string' || !Object.hasOwn(SOURCES, source))
|
|
151
|
-
return undefined;
|
|
152
|
-
const trace = typeof stack === 'string' && stack && !message.includes(stack) ? `\n${stack.slice(0, 4000)}` : '';
|
|
153
|
-
items.push(`${items.length + 1}. [${SOURCES[source]}] ${message.slice(0, 4000)}${trace}`);
|
|
154
|
-
}
|
|
155
|
-
const where = typeof page === 'string' && /^https?:\/\//.test(page) ? ` at ${page.slice(0, 500)}` : '';
|
|
156
|
-
return (`The app running in the Vite dev server${where} reports ${items.length === 1 ? 'this error' : 'these errors'} ` +
|
|
157
|
-
`in the browser. Find the cause in the code and fix it.\n\n` +
|
|
158
|
-
'```\n' +
|
|
159
|
-
items.join('\n\n').replace(/```/g, "'''") +
|
|
160
|
-
'\n```');
|
|
161
|
-
}
|
|
162
|
-
/** 127.0.0.0/8 and ::1, also as IPv4-mapped IPv6 addresses. */
|
|
163
|
-
export function isLoopback(address) {
|
|
164
|
-
if (!address)
|
|
165
|
-
return false;
|
|
166
|
-
const v4 = address.startsWith('::ffff:') ? address.slice(7) : address;
|
|
167
|
-
return address === '::1' || /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v4);
|
|
168
|
-
}
|
|
169
|
-
/** The origin a same-origin request came from, by its Host header. */
|
|
170
|
-
function pageOrigin(host, https) {
|
|
171
|
-
if (!host || !/^[\w.-]+(:\d+)?$|^\[[\da-f:.]+\](:\d+)?$/i.test(host))
|
|
172
|
-
return undefined;
|
|
173
|
-
return `${https ? 'https' : 'http'}://${host.toLowerCase()}`;
|
|
174
|
-
}
|
|
175
81
|
/** Where the app's pages come from, allowed to show the UI in a frame. */
|
|
176
82
|
function pageOrigins(server, seen) {
|
|
177
83
|
const urls = [...(server.resolvedUrls?.local ?? []), ...(server.resolvedUrls?.network ?? [])];
|
|
@@ -191,17 +97,6 @@ function pageOrigins(server, seen) {
|
|
|
191
97
|
}
|
|
192
98
|
return [...origins];
|
|
193
99
|
}
|
|
194
|
-
async function readBody(req) {
|
|
195
|
-
let size = 0;
|
|
196
|
-
const chunks = [];
|
|
197
|
-
for await (const chunk of req) {
|
|
198
|
-
size += chunk.length;
|
|
199
|
-
if (size > MAX_BODY)
|
|
200
|
-
throw new Error('Request too large');
|
|
201
|
-
chunks.push(chunk);
|
|
202
|
-
}
|
|
203
|
-
return Buffer.concat(chunks).toString('utf8');
|
|
204
|
-
}
|
|
205
100
|
/** The front ends are bundled into dist/ui by scripts/build-ui.mjs; the path is kept opaque to tsc. */
|
|
206
101
|
function loadBundledUi() {
|
|
207
102
|
const bundle = new URL('../ui/index.js', import.meta.url).href;
|
package/dist/vite/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"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"}
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -9,7 +9,12 @@
|
|
|
9
9
|
`/auto off` asks again. `-y` starts with it on.
|
|
10
10
|
- `genaicode embed` makes projects without a dev server work too: the agent writes a small
|
|
11
11
|
dev-only server that serves the pages with the panel injected, leaving the files and the
|
|
12
|
-
build untouched.
|
|
12
|
+
build untouched. That server opens the browser, and the agent's report starts with the one
|
|
13
|
+
command to run. It also keeps its shell commands few, since each one may need approval.
|
|
14
|
+
- `createDevOverlay()` in `genaicode/ui`: the Vite plugin's overlay (the wolf, its error
|
|
15
|
+
badge, "Fix N errors", the resizable panel) for any other Node dev server, as
|
|
16
|
+
`handle(req, res)` / `middleware` plus `injectHtml(html)`. `genaicode embed` now uses it
|
|
17
|
+
for non-Vite dev servers and for the dev server it writes, instead of a hand-made button.
|
|
13
18
|
|
|
14
19
|
## 2.18.0
|
|
15
20
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genaicode",
|
|
3
|
-
"version": "2.18.
|
|
3
|
+
"version": "2.18.3",
|
|
4
4
|
"description": "Drive the coding-agent CLIs you already have (Claude Code, Codex, Copilot, Cursor, Gemini, opencode...) behind one API and one CLI, plus a thin provider-neutral LLM layer.",
|
|
5
5
|
"author": "Grzegorz Tańczyk",
|
|
6
6
|
"repository": {
|
|
@@ -18,10 +18,10 @@ the project has HTML pages a browser can open.
|
|
|
18
18
|
in `vite dev` the page gets a wolf button that opens a chat with the agent working in
|
|
19
19
|
the project root, and the page's errors can be sent to the agent with one click.
|
|
20
20
|
Builds are untouched, nothing reaches production.
|
|
21
|
-
2. **Dev
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
2. **Dev overlay without Vite** (`createDevOverlay` from `genaicode/ui`): the same overlay
|
|
22
|
+
(the wolf, the error badge, "Fix N errors") for apps on webpack, Next.js, Express,
|
|
23
|
+
Fastify, Koa or any other Node dev server. The dev server mounts its routes, the page
|
|
24
|
+
loads one script in development. A few more lines than the plugin, same result.
|
|
25
25
|
3. **In-app agent** (`genaicode/app-agent` on the server, `<AppAgentChat>` from
|
|
26
26
|
`genaicode/react` on the page): for a local app with its own Node server (an admin
|
|
27
27
|
console, an internal tool, an editor) whose users want the agent to act on the app's
|
|
@@ -31,9 +31,9 @@ the project has HTML pages a browser can open.
|
|
|
31
31
|
4. **A dev server of your own**: the project has pages but nothing serves them in
|
|
32
32
|
development (static HTML, files opened from `file://`, a build script that writes
|
|
33
33
|
`index.html`, a game jam entry with a size budget...). Write a small Node script that
|
|
34
|
-
serves those files on localhost
|
|
35
|
-
npm script to start it. The files on disk and the build output stay
|
|
36
|
-
budgets and release builds are not affected.
|
|
34
|
+
serves those files on localhost with the overlay from option 2 injected into the HTML
|
|
35
|
+
it serves, and an npm script to start it. The files on disk and the build output stay
|
|
36
|
+
untouched, so size budgets and release builds are not affected.
|
|
37
37
|
5. **Last resort**: no Node at all in the project and no HTML to serve (a Rails, Django or
|
|
38
38
|
Go app whose server you cannot change safely): tell the user to run `npx genaicode ui`
|
|
39
39
|
(browser) or `npx genaicode` (terminal) next to their dev server, and say why.
|
|
@@ -78,8 +78,12 @@ allow, batch what must run into few commands, and do not run the dev server just
|
|
|
78
78
|
production build. For options 1, 2 and 4 the production output must not contain
|
|
79
79
|
genaicode. Fix what you broke; do not "fix" unrelated failures. Remove build output
|
|
80
80
|
you created that the project does not track.
|
|
81
|
-
6. **Report
|
|
82
|
-
to
|
|
81
|
+
6. **Report**, starting with how to see it, before anything else: one line with the exact
|
|
82
|
+
command to run and what happens next, e.g. "Run `npm run agent`: the game opens in your
|
|
83
|
+
browser with the genaicode wolf in the bottom-right corner." The developer may not know
|
|
84
|
+
the project's scripts or that a new one exists, so never leave this for the end of a
|
|
85
|
+
long summary. Then what you changed, file by file, briefly. Say that the agent uses its
|
|
86
|
+
own CLI login and billing.
|
|
83
87
|
|
|
84
88
|
## Recipe: Vite overlay
|
|
85
89
|
|
|
@@ -109,109 +113,63 @@ export default defineConfig({
|
|
|
109
113
|
- The chat runs on its own 127.0.0.1 port, only the app's own pages can frame it, and it
|
|
110
114
|
takes requests only from the same machine. No env vars or secrets are needed.
|
|
111
115
|
|
|
112
|
-
## Recipe: dev
|
|
116
|
+
## Recipe: dev overlay without Vite
|
|
117
|
+
|
|
118
|
+
`createDevOverlay()` from `genaicode/ui` is the Vite plugin's overlay for any Node dev
|
|
119
|
+
server: the genaicode wolf in the page's bottom-right corner opens the chat, its badge
|
|
120
|
+
counts the page's errors, and "Fix N errors" sends them to the agent. Do not write your own
|
|
121
|
+
button, panel or session route: use this.
|
|
113
122
|
|
|
114
123
|
Server side, in the Node process that serves the app in development, and only there:
|
|
115
124
|
|
|
116
125
|
```ts
|
|
117
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
118
|
-
|
|
119
126
|
// Development only: production never imports genaicode.
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
panel ??= import('genaicode/ui').then(({ startEmbeddedWeb }) =>
|
|
125
|
-
startEmbeddedWeb({ cwd: process.cwd(), frameAncestors: () => [...origins] }),
|
|
126
|
-
);
|
|
127
|
-
return panel;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// GET /__genaicode/session -> { url }. The url carries the chat's access token: hand it only
|
|
131
|
-
// to the app's own pages on this machine.
|
|
132
|
-
export async function genaicodeSession(req: IncomingMessage, res: ServerResponse) {
|
|
133
|
-
const address = req.socket.remoteAddress ?? '';
|
|
134
|
-
const local = address === '::1' || address.startsWith('127.') || address.startsWith('::ffff:127.');
|
|
135
|
-
const host = req.headers.host ?? '';
|
|
136
|
-
const loopbackHost = /^(localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/.test(host);
|
|
137
|
-
if (!local || !loopbackHost || req.headers['sec-fetch-site'] !== 'same-origin') {
|
|
138
|
-
res.writeHead(403).end();
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
origins.add(`http://${host}`); // localhost and 127.0.0.1 can both frame it, without a restart
|
|
142
|
-
const { url } = await genaicodePanel();
|
|
143
|
-
res.writeHead(200, { 'content-type': 'application/json', 'cache-control': 'no-store' });
|
|
144
|
-
res.end(JSON.stringify({ url }));
|
|
127
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
128
|
+
const { createDevOverlay } = await import('genaicode/ui');
|
|
129
|
+
const overlay = createDevOverlay(); // the agent works in process.cwd(); `cwd` to change
|
|
130
|
+
app.use(overlay.middleware); // before the app's own routes
|
|
145
131
|
}
|
|
146
132
|
```
|
|
147
133
|
|
|
148
|
-
- `
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
134
|
+
- `overlay.handle(req, res)` answers everything under `/__genaicode/` and resolves to
|
|
135
|
+
`false` for other URLs; `overlay.middleware` is the same for Express / Connect. Options:
|
|
136
|
+
`cwd`, `agent`, `model`, `effort`, `approveAll` (only if asked), `port`,
|
|
137
|
+
`captureErrors: false`, like the Vite plugin.
|
|
138
|
+
- The chat starts in the background on 127.0.0.1. Its token goes only to the app's own
|
|
139
|
+
pages, on this machine, opened at `localhost`, `*.localhost`, `127.0.0.1` or `[::1]`.
|
|
140
|
+
Without an agent CLI it logs why and the app runs on.
|
|
154
141
|
- Start it once per process. Dev servers that reload server code (Next.js, nodemon...)
|
|
155
|
-
re-run modules: keep the
|
|
156
|
-
- Where to hook
|
|
157
|
-
- Express / Connect
|
|
158
|
-
|
|
159
|
-
- webpack-dev-server: `
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
`
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
`
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
<>
|
|
187
|
-
<button onClick={() => setOpen(!open)} style={{ position: 'fixed', right: 16, bottom: 16, zIndex: 2147483647 }}>
|
|
188
|
-
Agent
|
|
189
|
-
</button>
|
|
190
|
-
{open && (
|
|
191
|
-
<iframe
|
|
192
|
-
src={url}
|
|
193
|
-
title="genaicode"
|
|
194
|
-
style={{
|
|
195
|
-
position: 'fixed',
|
|
196
|
-
right: 16,
|
|
197
|
-
bottom: 64,
|
|
198
|
-
width: 420,
|
|
199
|
-
height: '70vh',
|
|
200
|
-
zIndex: 2147483647,
|
|
201
|
-
border: 0,
|
|
202
|
-
borderRadius: 12,
|
|
203
|
-
boxShadow: '0 8px 32px #0004',
|
|
204
|
-
}}
|
|
205
|
-
/>
|
|
206
|
-
)}
|
|
207
|
-
</>
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
Not React? The same in the app's own framework or plain DOM: fetch the session, then a
|
|
213
|
-
fixed button that toggles a fixed iframe. Keep the token URL out of logs, `localStorage`
|
|
214
|
-
and anything the page sends elsewhere.
|
|
142
|
+
re-run modules: keep the overlay on `globalThis` so a reload does not start a second chat.
|
|
143
|
+
- Where to hook it:
|
|
144
|
+
- Express / Connect: `app.use(overlay.middleware)` before the routes.
|
|
145
|
+
- node:http: `if (await overlay.handle(req, res)) return;` at the top of the handler.
|
|
146
|
+
- webpack-dev-server: `setupMiddlewares: (middlewares) => [{ name: 'genaicode', middleware: overlay.middleware }, ...middlewares]`.
|
|
147
|
+
- Fastify: an `onRequest` hook that, for URLs under `/__genaicode/`, calls
|
|
148
|
+
`reply.hijack()` and `overlay.handle(request.raw, reply.raw)`. Koa: a middleware that
|
|
149
|
+
sets `ctx.respond = false` when `await overlay.handle(ctx.req, ctx.res)` is true.
|
|
150
|
+
- Next.js: a rewrite in `next.config` from `/__genaicode/:path*` to
|
|
151
|
+
`/api/genaicode/:path*` (development only), and a pages-router route
|
|
152
|
+
`pages/api/genaicode/[...path].ts` with `export const config = { api: { bodyParser: false } }`
|
|
153
|
+
that returns 404 outside development, sets
|
|
154
|
+
`req.url = '/__genaicode/' + [req.query.path].flat().join('/')` and calls
|
|
155
|
+
`overlay.handle(req, res)`.
|
|
156
|
+
|
|
157
|
+
Page side, the overlay script in development only:
|
|
158
|
+
|
|
159
|
+
- Where the server renders or serves the HTML: `overlay.injectHtml(html)`, or
|
|
160
|
+
`overlay.script` (an inline error collector plus
|
|
161
|
+
`<script type="module" src="/__genaicode/overlay.js"></script>`) at the top of the dev
|
|
162
|
+
template's `<head>`.
|
|
163
|
+
- Otherwise, in the app's entry, behind the bundler's dev flag so production drops it:
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
if (process.env.NODE_ENV === 'development') {
|
|
167
|
+
const script = document.createElement('script');
|
|
168
|
+
script.type = 'module';
|
|
169
|
+
script.src = '/__genaicode/overlay.js';
|
|
170
|
+
document.head.append(script);
|
|
171
|
+
}
|
|
172
|
+
```
|
|
215
173
|
|
|
216
174
|
## Recipe: a dev server of your own
|
|
217
175
|
|
|
@@ -220,17 +178,17 @@ project's folder for scripts), plus `"agent": "node tools/agent-dev.mjs"` (or a
|
|
|
220
178
|
fits next to the existing scripts) in `package.json`:
|
|
221
179
|
|
|
222
180
|
```js
|
|
223
|
-
// Development only: serves <dir> on 127.0.0.1 with the genaicode
|
|
181
|
+
// Development only: serves <dir> on 127.0.0.1 with the genaicode overlay injected into HTML.
|
|
224
182
|
// The files on disk are not changed.
|
|
183
|
+
import { spawn } from 'node:child_process';
|
|
225
184
|
import { createServer } from 'node:http';
|
|
226
185
|
import { readFile, stat } from 'node:fs/promises';
|
|
227
186
|
import { extname, join, normalize, resolve, sep } from 'node:path';
|
|
228
|
-
import {
|
|
187
|
+
import { createDevOverlay } from 'genaicode/ui';
|
|
229
188
|
|
|
230
189
|
const root = resolve(process.argv[2] ?? 'build');
|
|
231
190
|
const port = Number(process.env.PORT ?? 5173);
|
|
232
|
-
const
|
|
233
|
-
const chat = await startEmbeddedWeb({ cwd: process.cwd(), frameAncestors: () => [...origins] });
|
|
191
|
+
const overlay = createDevOverlay();
|
|
234
192
|
const TYPES = {
|
|
235
193
|
'.html': 'text/html',
|
|
236
194
|
'.js': 'text/javascript',
|
|
@@ -241,26 +199,12 @@ const TYPES = {
|
|
|
241
199
|
'.svg': 'image/svg+xml',
|
|
242
200
|
'.wasm': 'application/wasm',
|
|
243
201
|
};
|
|
244
|
-
const PANEL = `<script type="module" src="/__genaicode/panel.js"></script>`;
|
|
245
202
|
|
|
246
203
|
createServer(async (req, res) => {
|
|
247
|
-
|
|
248
|
-
if (url.pathname === '/__genaicode/session') {
|
|
249
|
-
// The token: only this machine (a loopback Host, which stops DNS rebinding), only the
|
|
250
|
-
// app's own pages.
|
|
251
|
-
if (!origins.has(`http://${req.headers.host}`) || req.headers['sec-fetch-site'] !== 'same-origin') {
|
|
252
|
-
return res.writeHead(403).end();
|
|
253
|
-
}
|
|
254
|
-
res.writeHead(200, { 'content-type': 'application/json', 'cache-control': 'no-store' });
|
|
255
|
-
return res.end(JSON.stringify({ url: chat.url }));
|
|
256
|
-
}
|
|
257
|
-
if (url.pathname === '/__genaicode/panel.js') {
|
|
258
|
-
res.writeHead(200, { 'content-type': 'text/javascript' });
|
|
259
|
-
return res.end(PANEL_SCRIPT);
|
|
260
|
-
}
|
|
204
|
+
if (await overlay.handle(req, res)) return;
|
|
261
205
|
let file;
|
|
262
206
|
try {
|
|
263
|
-
file = normalize(join(root, decodeURIComponent(url.pathname)));
|
|
207
|
+
file = normalize(join(root, decodeURIComponent(new URL(req.url ?? '/', 'http://x').pathname)));
|
|
264
208
|
} catch {
|
|
265
209
|
return res.writeHead(400).end();
|
|
266
210
|
}
|
|
@@ -270,30 +214,26 @@ createServer(async (req, res) => {
|
|
|
270
214
|
if (!body) return res.writeHead(404).end('not found');
|
|
271
215
|
const type = TYPES[extname(file)] ?? 'application/octet-stream';
|
|
272
216
|
res.writeHead(200, { 'content-type': type, 'cache-control': 'no-store' });
|
|
273
|
-
res.end(type === 'text/html' ?
|
|
274
|
-
}).listen(port, '127.0.0.1', () =>
|
|
275
|
-
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
217
|
+
res.end(type === 'text/html' ? overlay.injectHtml(body.toString()) : body);
|
|
218
|
+
}).listen(port, '127.0.0.1', () => {
|
|
219
|
+
const page = `http://localhost:${port}/`;
|
|
220
|
+
console.log(`${page} (genaicode: the wolf in the bottom-right corner)`);
|
|
221
|
+
// Open it like `vite --open` does; NO_OPEN=1 to skip.
|
|
222
|
+
if (!process.env.NO_OPEN && !process.env.CI) {
|
|
223
|
+
const opener = { darwin: 'open', win32: 'explorer' }[process.platform] ?? 'xdg-open';
|
|
224
|
+
spawn(opener, [page], { stdio: 'ignore', detached: true })
|
|
225
|
+
.on('error', () => {})
|
|
226
|
+
.unref();
|
|
227
|
+
}
|
|
228
|
+
});
|
|
281
229
|
```
|
|
282
230
|
|
|
283
|
-
|
|
284
|
-
recipe above: fetch `/__genaicode/session`, then a fixed button in a corner that toggles a
|
|
285
|
-
fixed iframe with `src` set to the session `url`. Keep it out of the app's own code.
|
|
286
|
-
|
|
287
|
-
- Listen on `127.0.0.1` only, and hand out the token only for a loopback `Host` and
|
|
288
|
-
`Sec-Fetch-Site: same-origin`. Together they keep the token on this machine and away from
|
|
289
|
-
other sites, including DNS-rebinding pages.
|
|
231
|
+
- Listen on `127.0.0.1` only.
|
|
290
232
|
- Serve what the developer actually opens: the build output folder if the project builds
|
|
291
233
|
one (start or chain its build or watch script when it has one, e.g. with `--watch` or a
|
|
292
234
|
second process), otherwise the source folder with the HTML.
|
|
293
|
-
-
|
|
294
|
-
|
|
295
|
-
`/__genaicode/fix` route (same checks as the session route) which calls
|
|
296
|
-
`chat.controller.submit('Fix these errors in the page …' + details)`.
|
|
235
|
+
- Open the browser on start (as above), at the page the developer works on when there is
|
|
236
|
+
one obvious page (e.g. `/fireball/`), not a folder listing.
|
|
297
237
|
- A page that reloads itself on change (a watch build) is the developer's own; do not
|
|
298
238
|
add a live-reload system for this.
|
|
299
239
|
|
package/dist/vite/overlay.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/** What the plugin tells the overlay. */
|
|
2
|
-
export interface OverlayConfig {
|
|
3
|
-
/** Path of the plugin's endpoints on the dev server, e.g. `/__genaicode`. */
|
|
4
|
-
api: string;
|
|
5
|
-
/** Collect errors from the page and offer to send them to the agent. */
|
|
6
|
-
captureErrors: boolean;
|
|
7
|
-
}
|
|
8
|
-
/** The part of Vite's `import.meta.hot` the overlay listens to. */
|
|
9
|
-
export interface OverlayHot {
|
|
10
|
-
on(event: string, callback: (payload: unknown) => void): void;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* The dev-server overlay: a wolf in the corner of the app that opens the genaicode UI in a
|
|
14
|
-
* panel, and collects the page's errors so one click sends them to the agent.
|
|
15
|
-
*
|
|
16
|
-
* The plugin serves this function's source (`mountOverlay.toString()`) as a module, so it must
|
|
17
|
-
* not use anything from outside its own body.
|
|
18
|
-
*/
|
|
19
|
-
export declare function mountOverlay(config: OverlayConfig, hot: OverlayHot | undefined): void;
|
package/dist/vite/overlay.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/vite/overlay.ts"],"names":[],"mappings":"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"}
|