genaicode 2.8.0 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
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;
@@ -0,0 +1,180 @@
1
+ /**
2
+ * The dev-server overlay: a wolf in the corner of the app that opens the genaicode UI in a
3
+ * panel, and collects the page's errors so one click sends them to the agent.
4
+ *
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.
7
+ */
8
+ export function mountOverlay(config, hot) {
9
+ if (document.querySelector('genaicode-overlay'))
10
+ return;
11
+ const MAX_ERRORS = 20;
12
+ const MAX_TEXT = 4000;
13
+ let errors = [];
14
+ let session;
15
+ const host = document.createElement('genaicode-overlay');
16
+ host.style.cssText = 'position:fixed;z-index:2147483647;right:0;bottom:0;';
17
+ const root = host.attachShadow({ mode: 'open' });
18
+ root.innerHTML = `<style>
19
+ :host { all: initial; }
20
+ * { box-sizing: border-box; font: 13px/1.4 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; }
21
+ .wolf { position: fixed; right: 18px; bottom: 18px; width: 52px; height: 52px; border-radius: 50%; border: 1px solid #e4e4df;
22
+ background: #fff center / 34px no-repeat; box-shadow: 0 2px 10px rgba(0,0,0,.18); cursor: pointer; padding: 0; font-size: 26px; }
23
+ .wolf:hover { transform: scale(1.06); }
24
+ .badge { position: absolute; top: -4px; right: -4px; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 10px;
25
+ background: #c92a2a; color: #fff; font-size: 11px; font-weight: 700; line-height: 20px; text-align: center; }
26
+ .badge[hidden], .panel[hidden], .fix[hidden] { display: none; }
27
+ .panel { position: fixed; right: 18px; bottom: 82px; width: min(460px, calc(100vw - 36px)); height: min(680px, calc(100vh - 110px));
28
+ display: flex; flex-direction: column; background: #fff; border: 1px solid #e4e4df; border-radius: 14px; overflow: hidden;
29
+ box-shadow: 0 8px 40px rgba(0,0,0,.22); }
30
+ .head { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid #e4e4df; background: #f7f7f5; color: #1d1d1b; }
31
+ .head b { flex: 1; }
32
+ .head button { border: 1px solid #e4e4df; background: #fff; color: #1d1d1b; border-radius: 8px; padding: 4px 10px; cursor: pointer; }
33
+ .head .fix { background: #c92a2a; border-color: #c92a2a; color: #fff; font-weight: 600; }
34
+ iframe { flex: 1; width: 100%; border: 0; background: #f7f7f5; }
35
+ .note { padding: 16px; color: #6b6b66; }
36
+ @media (prefers-color-scheme: dark) {
37
+ .wolf, .panel { background-color: #1d1d1c; border-color: #2e2e2c; }
38
+ .head { background: #141414; border-color: #2e2e2c; color: #ececea; }
39
+ .head button { background: #1d1d1c; border-color: #2e2e2c; color: #ececea; }
40
+ iframe { background: #141414; }
41
+ }
42
+ </style>
43
+ <div class="panel" hidden>
44
+ <div class="head"><b>genaicode</b><button class="fix" hidden></button><button class="close" title="Hide">✕</button></div>
45
+ </div>
46
+ <button class="wolf" title="genaicode"><span class="badge" hidden></span></button>`;
47
+ const $ = (selector) => root.querySelector(selector);
48
+ const wolf = $('.wolf');
49
+ const badge = $('.badge');
50
+ const panel = $('.panel');
51
+ const fix = $('.fix');
52
+ let frame;
53
+ const render = () => {
54
+ badge.hidden = errors.length === 0;
55
+ badge.textContent = String(errors.length);
56
+ fix.hidden = errors.length === 0;
57
+ fix.textContent = `Fix ${errors.length} error${errors.length === 1 ? '' : 's'}`;
58
+ const label = errors.length
59
+ ? `genaicode: ${errors.length} error${errors.length === 1 ? '' : 's'} on this page`
60
+ : `genaicode${session ? ` (${session.agent})` : ''}`;
61
+ wolf.title = label;
62
+ wolf.setAttribute('aria-label', label);
63
+ };
64
+ const loadSession = async () => {
65
+ if (session)
66
+ return session;
67
+ const response = await fetch(`${config.api}/session`, { credentials: 'same-origin' });
68
+ if (!response.ok)
69
+ throw new Error(`genaicode: ${response.status}`);
70
+ session = (await response.json());
71
+ wolf.style.backgroundImage = `url(${new URL('/assets/wolf-64.png', session.url).href})`;
72
+ render();
73
+ return session;
74
+ };
75
+ // One frame, even when the wolf and "Fix" are clicked before the session has loaded.
76
+ const open = () => {
77
+ panel.hidden = false;
78
+ frame ??= loadSession().then(({ url }) => {
79
+ const iframe = document.createElement('iframe');
80
+ iframe.src = url;
81
+ iframe.title = 'genaicode';
82
+ panel.append(iframe);
83
+ }, (error) => {
84
+ const note = document.createElement('div');
85
+ note.className = 'note';
86
+ note.textContent = `The genaicode UI is not available: ${error.message}. See the dev server's terminal.`;
87
+ panel.append(note);
88
+ });
89
+ return frame;
90
+ };
91
+ wolf.addEventListener('click', () => (panel.hidden ? void open() : (panel.hidden = true)));
92
+ $('.close').addEventListener('click', () => (panel.hidden = true));
93
+ fix.addEventListener('click', async () => {
94
+ const sent = errors;
95
+ errors = [];
96
+ render();
97
+ await open();
98
+ const response = await fetch(`${config.api}/fix`, {
99
+ method: 'POST',
100
+ credentials: 'same-origin',
101
+ headers: { 'content-type': 'application/json' },
102
+ body: JSON.stringify({ page: location.origin + location.pathname, errors: sent }),
103
+ }).catch(() => undefined);
104
+ if (!response?.ok) {
105
+ errors = [...sent, ...errors].slice(-MAX_ERRORS);
106
+ render();
107
+ }
108
+ });
109
+ const text = (value) => {
110
+ if (value instanceof Error)
111
+ return value.message;
112
+ if (typeof value === 'string')
113
+ return value;
114
+ try {
115
+ return JSON.stringify(value) ?? String(value);
116
+ }
117
+ catch {
118
+ try {
119
+ return String(value);
120
+ }
121
+ catch {
122
+ return Object.prototype.toString.call(value);
123
+ }
124
+ }
125
+ };
126
+ const add = (error) => {
127
+ error.message = error.message.slice(0, MAX_TEXT);
128
+ if (error.stack)
129
+ error.stack = error.stack.slice(0, MAX_TEXT);
130
+ if (errors.some((seen) => seen.message === error.message && seen.source === error.source))
131
+ return;
132
+ errors = [...errors, error].slice(-MAX_ERRORS);
133
+ render();
134
+ };
135
+ if (config.captureErrors) {
136
+ window.addEventListener('error', (event) => {
137
+ const where = event.filename ? ` (${event.filename}:${event.lineno}:${event.colno})` : '';
138
+ add({ source: 'error', message: `${event.message}${where}`, stack: event.error?.stack });
139
+ });
140
+ window.addEventListener('unhandledrejection', (event) => {
141
+ add({ source: 'rejection', message: text(event.reason), stack: event.reason?.stack });
142
+ });
143
+ const consoleError = console.error.bind(console);
144
+ console.error = (...args) => {
145
+ consoleError(...args);
146
+ // Collecting the error must never break the app's own logging.
147
+ try {
148
+ add({
149
+ source: 'console',
150
+ message: args.map(text).join(' '),
151
+ stack: args.find((arg) => arg instanceof Error)?.stack,
152
+ });
153
+ }
154
+ catch {
155
+ // Ignore values that cannot be described.
156
+ }
157
+ };
158
+ hot?.on('vite:error', (payload) => {
159
+ const err = payload.err;
160
+ if (!err)
161
+ return;
162
+ const file = err.id ? `\n${err.id}` : '';
163
+ add({ source: 'vite', message: `${err.message ?? 'Vite error'}${file}${err.frame ? `\n${err.frame}` : ''}` });
164
+ });
165
+ // A successful update means the build errors are gone; keep what the running page reported.
166
+ hot?.on('vite:afterUpdate', () => {
167
+ const before = errors.length;
168
+ errors = errors.filter((error) => error.source !== 'vite');
169
+ if (errors.length !== before)
170
+ render();
171
+ });
172
+ }
173
+ document.body.append(host);
174
+ render();
175
+ void loadSession().catch(() => {
176
+ wolf.textContent = '🐺';
177
+ wolf.append(badge);
178
+ });
179
+ }
180
+ //# sourceMappingURL=overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/vite/overlay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import type { Plugin } from 'vite';
2
+ import type { CodingAgent } from '../agents/types.js';
3
+ export interface GenaicodeViteOptions {
4
+ /** Agent to start with. Default: the first installed one. */
5
+ agent?: string;
6
+ model?: string;
7
+ effort?: string;
8
+ /** Approve every permission request without asking. */
9
+ approveAll?: boolean;
10
+ /** Agents to offer. Default: the same headless drivers as `genaicode ui`. */
11
+ agents?: readonly CodingAgent[];
12
+ /** Collect the page's errors and offer to send them to the agent. Default true. */
13
+ captureErrors?: boolean;
14
+ /** Port of the genaicode UI on 127.0.0.1. Default: a free port. */
15
+ port?: number;
16
+ /** Loads the bundled front ends. Defaults to `dist/ui/index.js`; tests pass the sources. */
17
+ loadUi?(): Promise<EmbeddedUiModule>;
18
+ }
19
+ /** What the plugin needs from the bundled front ends (see `startEmbeddedWeb` in src/ui/index.tsx). */
20
+ export interface EmbeddedUiModule {
21
+ NoAgentError: new (...args: never[]) => Error;
22
+ startEmbeddedWeb(options: {
23
+ agents: readonly CodingAgent[];
24
+ agent?: string;
25
+ cwd: string;
26
+ model?: string;
27
+ effort?: string;
28
+ approveAll?: boolean;
29
+ version: string;
30
+ port?: number;
31
+ 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
+ }>;
44
+ }
45
+ /**
46
+ * `genaicode/vite`: the genaicode UI inside a Vite dev server. The page gets a wolf in the
47
+ * corner that opens the chat with a coding agent working in the project, and its errors
48
+ * (build errors, uncaught exceptions, console.error) go to the agent with one click.
49
+ *
50
+ * Only `vite dev`: builds are untouched. The UI runs on its own port on 127.0.0.1, so a dev
51
+ * server started with `--host` does not expose the agent to the network.
52
+ */
53
+ 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;
@@ -0,0 +1,214 @@
1
+ import { createRequire } from 'node:module';
2
+ import { defaultAgents } from '../agents/defaults.js';
3
+ import { mountOverlay } from './overlay.js';
4
+ const API = '/__genaicode';
5
+ const OVERLAY_ID = 'virtual:genaicode-overlay';
6
+ const MAX_BODY = 256 * 1024;
7
+ /**
8
+ * `genaicode/vite`: the genaicode UI inside a Vite dev server. The page gets a wolf in the
9
+ * corner that opens the chat with a coding agent working in the project, and its errors
10
+ * (build errors, uncaught exceptions, console.error) go to the agent with one click.
11
+ *
12
+ * Only `vite dev`: builds are untouched. The UI runs on its own port on 127.0.0.1, so a dev
13
+ * server started with `--host` does not expose the agent to the network.
14
+ */
15
+ export function genaicode(options = {}) {
16
+ let started;
17
+ let base = '/';
18
+ // Origins the app's pages were actually opened at (e.g. app.localhost), for frame-ancestors.
19
+ const seen = new Set();
20
+ return {
21
+ name: 'genaicode',
22
+ apply: 'serve',
23
+ configResolved(config) {
24
+ base = config.base;
25
+ },
26
+ configureServer(server) {
27
+ const log = server.config.logger;
28
+ started = (async () => {
29
+ 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);
59
+ });
60
+ },
61
+ resolveId(id) {
62
+ if (id === OVERLAY_ID)
63
+ return `\0${OVERLAY_ID}`;
64
+ },
65
+ load(id) {
66
+ if (id !== `\0${OVERLAY_ID}`)
67
+ return;
68
+ const config = { api: API, captureErrors: options.captureErrors ?? true };
69
+ return `(${mountOverlay.toString()})(${JSON.stringify(config)}, import.meta.hot);\n`;
70
+ },
71
+ async transformIndexHtml() {
72
+ if (!(await started))
73
+ return;
74
+ return [
75
+ {
76
+ tag: 'script',
77
+ attrs: { type: 'module', src: `${base}@id/__x00__${OVERLAY_ID}` },
78
+ // First, so the app's own startup errors are caught too. Module scripts are deferred.
79
+ injectTo: 'head-prepend',
80
+ },
81
+ ];
82
+ },
83
+ // Vite calls this when the dev server closes or restarts.
84
+ async buildEnd() {
85
+ const ui = await started;
86
+ started = undefined;
87
+ await ui?.close();
88
+ },
89
+ };
90
+ }
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
+ /** Where the app's pages come from, allowed to show the UI in a frame. */
176
+ function pageOrigins(server, seen) {
177
+ const urls = [...(server.resolvedUrls?.local ?? []), ...(server.resolvedUrls?.network ?? [])];
178
+ const origins = new Set(seen);
179
+ for (const url of urls) {
180
+ try {
181
+ origins.add(new URL(url).origin);
182
+ }
183
+ catch {
184
+ // Not a URL: skip it.
185
+ }
186
+ }
187
+ if (origins.size === 0) {
188
+ // Middleware mode, or not listening yet: any local port.
189
+ for (const origin of ['http://localhost:*', 'http://127.0.0.1:*', 'http://[::1]:*'])
190
+ origins.add(origin);
191
+ }
192
+ return [...origins];
193
+ }
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
+ /** The front ends are bundled into dist/ui by scripts/build-ui.mjs; the path is kept opaque to tsc. */
206
+ function loadBundledUi() {
207
+ const bundle = new URL('../ui/index.js', import.meta.url).href;
208
+ return import(bundle);
209
+ }
210
+ function packageVersion() {
211
+ const require = createRequire(import.meta.url);
212
+ return require('../../package.json').version;
213
+ }
214
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/vite/plugin.ts"],"names":[],"mappings":"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"}
package/dist/vite.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `genaicode/vite`: chat with a coding agent from inside the app in `vite dev`.
3
+ *
4
+ * ```ts
5
+ * import { defineConfig } from 'vite';
6
+ * import genaicode from 'genaicode/vite';
7
+ *
8
+ * export default defineConfig({ plugins: [genaicode()] });
9
+ * ```
10
+ */
11
+ export { genaicode, genaicode as default, type GenaicodeViteOptions } from './vite/plugin.js';
package/dist/vite.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `genaicode/vite`: chat with a coding agent from inside the app in `vite dev`.
3
+ *
4
+ * ```ts
5
+ * import { defineConfig } from 'vite';
6
+ * import genaicode from 'genaicode/vite';
7
+ *
8
+ * export default defineConfig({ plugins: [genaicode()] });
9
+ * ```
10
+ */
11
+ export { genaicode, genaicode as default } from './vite/plugin.js';
12
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.js","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,SAAS,EAAE,SAAS,IAAI,OAAO,EAA6B,MAAM,kBAAkB,CAAC"}
package/docs/pivot.md CHANGED
@@ -47,7 +47,9 @@ and it adds no agent loop, prompts, or repository tools of its own. See [agents.
47
47
  The `genaicode` bin (`npx genaicode run`, `chat`, `ui`) is a thin front end to those drivers,
48
48
  under the same rule: it parses flags, shows events, and adds nothing the library does not
49
49
  already do. Its terminal and browser chat are bundled (Ink, React) into `dist/ui` and load
50
- only for those commands, so the library keeps no UI dependencies.
50
+ only for those commands, so the library keeps no UI dependencies. `genaicode/vite` brings
51
+ back a Vite dev plugin in the same shape: it shows that browser chat inside the app and
52
+ hands the page's errors to the external agent as a prompt; it does not generate code itself.
51
53
 
52
54
  This is a major-version break. The old implementation remains available in git history
53
55
  and in the 1.x npm line.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genaicode",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "description": "A small, provider-neutral TypeScript toolkit for calling LLMs from backend code.",
5
5
  "author": "Grzegorz Tańczyk",
6
6
  "repository": {
@@ -15,7 +15,8 @@
15
15
  "prompt",
16
16
  "toolkit",
17
17
  "coding-agent",
18
- "cli"
18
+ "cli",
19
+ "vite-plugin"
19
20
  ],
20
21
  "type": "module",
21
22
  "bin": {
@@ -45,6 +46,10 @@
45
46
  "./agents": {
46
47
  "types": "./dist/agents.d.ts",
47
48
  "import": "./dist/agents.js"
49
+ },
50
+ "./vite": {
51
+ "types": "./dist/vite.d.ts",
52
+ "import": "./dist/vite.js"
48
53
  }
49
54
  },
50
55
  "scripts": {
@@ -64,6 +69,14 @@
64
69
  "@google/genai": "^1.30.0",
65
70
  "openai": "^5.16.0"
66
71
  },
72
+ "peerDependencies": {
73
+ "vite": ">=5"
74
+ },
75
+ "peerDependenciesMeta": {
76
+ "vite": {
77
+ "optional": true
78
+ }
79
+ },
67
80
  "devDependencies": {
68
81
  "@types/node": "^20.0.0",
69
82
  "@types/react": "^19.3.0",
@@ -81,7 +94,7 @@
81
94
  "react": "^19.3.0",
82
95
  "react-dom": "^19.3.0",
83
96
  "typescript": "^5.0.0",
84
- "vite": "^6.4.1",
97
+ "vite": "^6.4.3",
85
98
  "vitest": "^3.0.7"
86
99
  },
87
100
  "lint-staged": {
@@ -1,6 +0,0 @@
1
- import type { CodingAgent } from '../agents/types.js';
2
- /**
3
- * Headless drivers the CLI can run, in the order `run` picks the first installed one.
4
- * Live drivers are left out: the CLI has no approval prompt, so they would deny everything.
5
- */
6
- export declare function defaultAgents(): CodingAgent[];
@@ -1,17 +0,0 @@
1
- import { antigravity } from '../agents/drivers/antigravity.js';
2
- import { claude } from '../agents/drivers/claude.js';
3
- import { codex } from '../agents/drivers/codex.js';
4
- import { copilot } from '../agents/drivers/copilot.js';
5
- import { cursor } from '../agents/drivers/cursor.js';
6
- import { gemini } from '../agents/drivers/gemini.js';
7
- import { muse } from '../agents/drivers/muse.js';
8
- import { opencode } from '../agents/drivers/opencode.js';
9
- import { vibe } from '../agents/drivers/vibe.js';
10
- /**
11
- * Headless drivers the CLI can run, in the order `run` picks the first installed one.
12
- * Live drivers are left out: the CLI has no approval prompt, so they would deny everything.
13
- */
14
- export function defaultAgents() {
15
- return [claude(), codex(), copilot(), cursor(), gemini(), opencode(), vibe(), antigravity(), muse()];
16
- }
17
- //# sourceMappingURL=agents.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/cli/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAGjD;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;AACvG,CAAC"}