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 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...) a development-only panel that shows the same chat through
182
- `startEmbeddedWeb` from `genaicode/ui`; the in-app agent (`genaicode/app-agent` with
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 plugin serves this function's source (`mountOverlay.toString()`) as a module, so it must
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=overlay.js.map
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;AAyErD;;;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;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"}
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"}
@@ -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;
@@ -1,9 +1,8 @@
1
1
  import { createRequire } from 'node:module';
2
2
  import { defaultAgents } from '../agents/defaults.js';
3
- import { mountOverlay } from './overlay.js';
4
- const API = '/__genaicode';
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
- const log = server.config.logger;
28
- started = (async () => {
27
+ started = startOverlayUi(async () => {
29
28
  const ui = await (options.loadUi ?? loadBundledUi)();
30
- try {
31
- return await ui.startEmbeddedWeb({
32
- agents: options.agents ?? defaultAgents(),
33
- agent: options.agent,
34
- cwd: server.config.root,
35
- model: options.model,
36
- effort: options.effort,
37
- approveAll: options.approveAll,
38
- version: packageVersion(),
39
- port: options.port,
40
- frameAncestors: () => pageOrigins(server, seen),
41
- });
42
- }
43
- catch (error) {
44
- if (!(error instanceof ui.NoAgentError))
45
- throw error;
46
- log.warn(`[genaicode] ${error.message} The overlay is off.`);
47
- return undefined;
48
- }
49
- })().then((ui) => {
50
- if (ui)
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
- const config = { api: API, captureErrors: options.captureErrors ?? true };
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;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"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"}
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. It also keeps its shell commands few, since each one may need approval.
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.1",
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 panel without Vite** (`genaicode/ui`): the same chat for apps on webpack, Next.js,
22
- Express, Fastify, Remix, Astro or any other Node dev server. The dev server process
23
- starts the chat on 127.0.0.1 with `startEmbeddedWeb`, and a development-only component
24
- on the page shows it in a frame. A few more lines than the plugin, same result.
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 and injects the panel into the HTML it serves, and an
35
- npm script to start it. The files on disk and the build output stay untouched, so size
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**: what you changed, file by file, and how to try it (the dev command, where
82
- to click). Say that the agent uses its own CLI login and billing.
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 panel without Vite
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
- // The origins the app was opened at; the chat lets only these frame it, read per request.
121
- const origins = new Set<string>();
122
- let panel: Promise<{ url: string }> | undefined;
123
- export function genaicodePanel() {
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
- - `frameAncestors` is read per request and must list every origin the app is opened at in
149
- development (`http://localhost:3000`, `http://127.0.0.1:3000`...); the chat refuses other
150
- frames. Collect them as above rather than capturing the first one. Behind a dev host name
151
- (`app.localhost`, https), allow that name explicitly.
152
- `startEmbeddedWeb` binds to 127.0.0.1 on a free port (`port` to fix one) and takes
153
- `agent`, `model`, `effort`, `approveAll` like the Vite plugin.
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 promise on `globalThis` so a reload does not start a second chat.
156
- - Where to hook the route:
157
- - Express / Connect / node:http dev server: before the app's routes, behind
158
- `process.env.NODE_ENV !== 'production'`.
159
- - webpack-dev-server: `devServer.setupMiddlewares(middlewares, devServer)`, push a
160
- middleware for `/__genaicode/session`.
161
- - Next.js: a route handler such as `app/api/genaicode/route.ts` (folders starting with
162
- `_` are private in the app router) that returns 404 unless
163
- `process.env.NODE_ENV === 'development'`. It has no socket address, so check that the
164
- `Host` header is `localhost` / `127.0.0.1` / `[::1]` with a port and that
165
- `sec-fetch-site` is `same-origin`. Start the chat from the route on first use (Node
166
- runtime: `export const runtime = 'nodejs'`), cached on `globalThis`.
167
- - Fastify: a route under `if (dev)`; Koa: a middleware under `if (dev)`.
168
-
169
- Page side, a component rendered only in development (`process.env.NODE_ENV === 'development'`,
170
- `import.meta.env.DEV`...), loaded so the production bundle drops it (a dynamic `import()`
171
- behind that check, or the framework's dev-only slot):
172
-
173
- ```tsx
174
- import { useEffect, useState } from 'react';
175
-
176
- export function GenaicodePanel() {
177
- const [url, setUrl] = useState<string>();
178
- const [open, setOpen] = useState(false);
179
- useEffect(() => {
180
- fetch('/__genaicode/session')
181
- .then((r) => (r.ok ? r.json() : undefined))
182
- .then((s) => setUrl(s?.url));
183
- }, []);
184
- if (!url) return null;
185
- return (
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 panel injected into HTML.
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 { startEmbeddedWeb } from 'genaicode/ui';
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 origins = new Set([`http://localhost:${port}`, `http://127.0.0.1:${port}`]);
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
- const url = new URL(req.url ?? '/', 'http://x');
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' ? injectPanel(body.toString()) : body);
274
- }).listen(port, '127.0.0.1', () =>
275
- console.log(`http://localhost:${port} (genaicode panel: the button in the corner)`),
276
- );
277
-
278
- function injectPanel(html) {
279
- return html.includes('</body>') ? html.replace('</body>', `${PANEL}</body>`) : html + PANEL;
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
- `PANEL_SCRIPT` is the page side as plain DOM, the same as the React component in the
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
- - Optional, for the agent to see what breaks: in `PANEL_SCRIPT`, collect `error` and
294
- `unhandledrejection` events and offer a "Fix N errors" button that POSTs them to a
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
 
@@ -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;
@@ -1 +0,0 @@
1
- {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/vite/overlay.ts"],"names":[],"mappings":"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"}