genaicode 2.18.0 → 2.18.1
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 +3 -1
- package/dist/ui/index.js +52 -52
- package/dist/ui/web-client.js +9 -9
- package/docs/CHANGELOG.md +11 -0
- package/package.json +1 -1
- package/skills/genaicode-embed/SKILL.md +105 -9
package/docs/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
### Added
|
|
6
6
|
|
|
7
|
+
- Auto-approve in `genaicode chat` and `genaicode ui`: `a` on a permission request (or
|
|
8
|
+
`/auto`, or the Auto-approve chip in the browser) approves it and everything after it;
|
|
9
|
+
`/auto off` asks again. `-y` starts with it on.
|
|
10
|
+
- `genaicode embed` makes projects without a dev server work too: the agent writes a small
|
|
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.
|
|
13
|
+
|
|
14
|
+
## 2.18.0
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
7
18
|
- `genaicode embed [request]`: your own agent adds genaicode to the project in the current
|
|
8
19
|
directory. It gets instructions (the Vite overlay; a development-only panel through
|
|
9
20
|
`genaicode/ui` for webpack, Next.js, Express and other Node dev servers; the in-app agent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genaicode",
|
|
3
|
-
"version": "2.18.
|
|
3
|
+
"version": "2.18.1",
|
|
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": {
|
|
@@ -10,8 +10,9 @@ already has installed (Claude Code, Codex, Copilot CLI, Cursor, Gemini, opencode
|
|
|
10
10
|
one API. Your job is to wire it into the project in the current directory so the
|
|
11
11
|
project's developers can talk to their agent from inside the running app.
|
|
12
12
|
|
|
13
|
-
There are
|
|
14
|
-
more impressive.
|
|
13
|
+
There are four ways in, plus a last resort. Pick by what the project is, not by what is
|
|
14
|
+
more impressive. Always end with a working way in: "it doesn't fit" is not a result while
|
|
15
|
+
the project has HTML pages a browser can open.
|
|
15
16
|
|
|
16
17
|
1. **Vite dev overlay** (`genaicode/vite`): for any app built with Vite. One plugin line;
|
|
17
18
|
in `vite dev` the page gets a wolf button that opens a chat with the agent working in
|
|
@@ -27,15 +28,25 @@ more impressive.
|
|
|
27
28
|
data. The agent works the app through tools the app serves over MCP, every write waits
|
|
28
29
|
for the user's Approve, and an optional `dev` mode lets the agent edit the app's own
|
|
29
30
|
code and propose a commit.
|
|
30
|
-
4. **
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
4. **A dev server of your own**: the project has pages but nothing serves them in
|
|
32
|
+
development (static HTML, files opened from `file://`, a build script that writes
|
|
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.
|
|
37
|
+
5. **Last resort**: no Node at all in the project and no HTML to serve (a Rails, Django or
|
|
38
|
+
Go app whose server you cannot change safely): tell the user to run `npx genaicode ui`
|
|
39
|
+
(browser) or `npx genaicode` (terminal) next to their dev server, and say why.
|
|
33
40
|
|
|
34
41
|
The agent CLI always runs on the machine that runs the server, with that machine's
|
|
35
|
-
login and files. Options 1 and
|
|
42
|
+
login and files. Options 1, 2 and 4 exist only in development. The in-app agent is for apps
|
|
36
43
|
that run on the developer's own machine (or a trusted internal host behind real auth).
|
|
37
44
|
Never wire any of them into a public production site, and never expose them without auth.
|
|
38
45
|
|
|
46
|
+
Work with as few shell commands as you can: the user approves each one unless they turned
|
|
47
|
+
on auto-approve. Read files instead of listing them through the shell where your tools
|
|
48
|
+
allow, batch what must run into few commands, and do not run the dev server just to look.
|
|
49
|
+
|
|
39
50
|
## Steps
|
|
40
51
|
|
|
41
52
|
1. **Look before you change anything.** Read `package.json` (dependencies, scripts,
|
|
@@ -50,10 +61,11 @@ Never wire any of them into a public production site, and never expose them with
|
|
|
50
61
|
- The user wants the agent to use the app itself (its data, its actions), or the app
|
|
51
62
|
is an internal tool with a Node server and a React UI: option 3, alone or next to
|
|
52
63
|
option 1 or 2.
|
|
53
|
-
-
|
|
64
|
+
- Pages but no dev server: option 4.
|
|
65
|
+
- Otherwise: option 5. Say why.
|
|
54
66
|
- If genaicode is already wired in, extend or fix what is there instead of adding a
|
|
55
67
|
second copy.
|
|
56
|
-
3. **Install** `genaicode` as a dev dependency for options 1 and
|
|
68
|
+
3. **Install** `genaicode` as a dev dependency for options 1, 2 and 4, as a regular
|
|
57
69
|
dependency when the server imports `genaicode/app-agent`. Use the project's package
|
|
58
70
|
manager (lockfile: `package-lock.json` npm, `pnpm-lock.yaml` pnpm, `yarn.lock` yarn,
|
|
59
71
|
`bun.lockb`/`bun.lock` bun). If you may not run the install, add the dependency to
|
|
@@ -63,7 +75,7 @@ Never wire any of them into a public production site, and never expose them with
|
|
|
63
75
|
4. **Wire it in** (recipes below), matching the project's style: TypeScript or
|
|
64
76
|
JavaScript, ESM or CJS, its formatter, its folder layout.
|
|
65
77
|
5. **Check it**: run the project's type check, lint and tests if it has them, and a
|
|
66
|
-
production build. For options 1 and
|
|
78
|
+
production build. For options 1, 2 and 4 the production output must not contain
|
|
67
79
|
genaicode. Fix what you broke; do not "fix" unrelated failures. Remove build output
|
|
68
80
|
you created that the project does not track.
|
|
69
81
|
6. **Report**: what you changed, file by file, and how to try it (the dev command, where
|
|
@@ -201,6 +213,90 @@ Not React? The same in the app's own framework or plain DOM: fetch the session,
|
|
|
201
213
|
fixed button that toggles a fixed iframe. Keep the token URL out of logs, `localStorage`
|
|
202
214
|
and anything the page sends elsewhere.
|
|
203
215
|
|
|
216
|
+
## Recipe: a dev server of your own
|
|
217
|
+
|
|
218
|
+
For a project with pages but no dev server. One file, e.g. `tools/agent-dev.mjs` (match the
|
|
219
|
+
project's folder for scripts), plus `"agent": "node tools/agent-dev.mjs"` (or a name that
|
|
220
|
+
fits next to the existing scripts) in `package.json`:
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
// Development only: serves <dir> on 127.0.0.1 with the genaicode panel injected into HTML.
|
|
224
|
+
// The files on disk are not changed.
|
|
225
|
+
import { createServer } from 'node:http';
|
|
226
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
227
|
+
import { extname, join, normalize, resolve, sep } from 'node:path';
|
|
228
|
+
import { startEmbeddedWeb } from 'genaicode/ui';
|
|
229
|
+
|
|
230
|
+
const root = resolve(process.argv[2] ?? 'build');
|
|
231
|
+
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] });
|
|
234
|
+
const TYPES = {
|
|
235
|
+
'.html': 'text/html',
|
|
236
|
+
'.js': 'text/javascript',
|
|
237
|
+
'.mjs': 'text/javascript',
|
|
238
|
+
'.css': 'text/css',
|
|
239
|
+
'.json': 'application/json',
|
|
240
|
+
'.png': 'image/png',
|
|
241
|
+
'.svg': 'image/svg+xml',
|
|
242
|
+
'.wasm': 'application/wasm',
|
|
243
|
+
};
|
|
244
|
+
const PANEL = `<script type="module" src="/__genaicode/panel.js"></script>`;
|
|
245
|
+
|
|
246
|
+
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
|
+
}
|
|
261
|
+
let file;
|
|
262
|
+
try {
|
|
263
|
+
file = normalize(join(root, decodeURIComponent(url.pathname)));
|
|
264
|
+
} catch {
|
|
265
|
+
return res.writeHead(400).end();
|
|
266
|
+
}
|
|
267
|
+
if (file !== root && !file.startsWith(root + sep)) return res.writeHead(403).end();
|
|
268
|
+
if ((await stat(file).catch(() => null))?.isDirectory()) file = join(file, 'index.html');
|
|
269
|
+
const body = await readFile(file).catch(() => null);
|
|
270
|
+
if (!body) return res.writeHead(404).end('not found');
|
|
271
|
+
const type = TYPES[extname(file)] ?? 'application/octet-stream';
|
|
272
|
+
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
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
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.
|
|
290
|
+
- Serve what the developer actually opens: the build output folder if the project builds
|
|
291
|
+
one (start or chain its build or watch script when it has one, e.g. with `--watch` or a
|
|
292
|
+
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)`.
|
|
297
|
+
- A page that reloads itself on change (a watch build) is the developer's own; do not
|
|
298
|
+
add a live-reload system for this.
|
|
299
|
+
|
|
204
300
|
## Recipe: in-app agent
|
|
205
301
|
|
|
206
302
|
Server side, wherever the Node server is created:
|