done-done-axi 0.6.5 → 0.6.7
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 +15 -11
- package/dist/agents.js +27 -13
- package/dist/cli.js +260 -26
- package/dist/config.js +25 -1
- package/dist/judge.js +69 -23
- package/dist/maintain.js +5 -0
- package/docs/examples/statechart-pilot/pane-attach-race.md +1 -1
- package/docs/index.html +8 -6
- package/docs/reference.md +69 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
A command-line check of real screenshots, recordings and output.
|
|
13
13
|
|
|
14
|
-
For developers using coding agents. Tests can pass while the app is still broken.
|
|
14
|
+
For developers using coding agents, alone or in a [Firstmate](#use-with-firstmate-or-another-agent-fleet) fleet. Tests can pass while the app is still broken.
|
|
15
15
|
|
|
16
16
|
<img src="docs/media/demo.png" width="320" alt="Real sample app: Release checklist shows Capture the real app checked and Done. The actual claude-haiku-5-5 judge passes that captured screenshot at sample commit 08d635e46a98.">
|
|
17
17
|
|
|
@@ -20,9 +20,13 @@ For developers using coding agents. Tests can pass while the app is still broken
|
|
|
20
20
|
```sh
|
|
21
21
|
npm install -g done-done-axi
|
|
22
22
|
cd your-app && done-done init
|
|
23
|
-
done-done
|
|
23
|
+
done-done verify --outcome "<what works now>"
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
The last line is your first result: your agent drives the real app, a judge checks each capture, and you get a pass with a receipt, or the judge's reason it did not pass.
|
|
27
|
+
|
|
28
|
+
**With or without Firstmate.** On its own, you or your agent run these three lines. In a [Firstmate](https://github.com/kunchenguid/firstmate) fleet, two files make every worker prove its task, plus an optional merge gate that checks that proof ([how](#use-with-firstmate-or-another-agent-fleet)).
|
|
29
|
+
|
|
26
30
|
[Website](https://umeranjum17.github.io/done-done-axi/) · [Setup](#install-in-3-steps) · [Agent skill](#use-it-from-your-agent) · [Reference](docs/reference.md) · [npm](https://www.npmjs.com/package/done-done-axi)
|
|
27
31
|
|
|
28
32
|
## Install in 3 steps
|
|
@@ -30,16 +34,16 @@ done-done doctor
|
|
|
30
34
|
You need **[Node 22.18+](https://nodejs.org) and git**, plus your own signed-in coding agent or API key for the judge. Early preview; see [what's next](#whats-next).
|
|
31
35
|
|
|
32
36
|
1. **Install.** The first line above puts `done-done` (and the long name `done-done-axi`) on your PATH. No `sudo`? Add `--prefix ~/.local` and put `~/.local/bin` on your `PATH`.
|
|
33
|
-
2. **Set up your repo.** `init`
|
|
34
|
-
3. **
|
|
37
|
+
2. **Set up your repo.** `init` asks you, in a terminal, which coding agent drives your app and which judge checks it. done-done never picks either for you. It then writes a minimal `.done-done.yaml` and a verify skill: how to launch and drive your app. Outside a terminal, pass `--agent <agent> --model <model> --judge <agent> --judge-model <model>` instead.
|
|
38
|
+
3. **Get your first result.** Say what works now, in plain words. `verify` has your agent drive the real product the way a user does and save screenshots or output. A fresh judge checks whether each capture shows your claim. A pass names the capture and writes a receipt for this commit. Anything else stops at a gate with the judge's reason, and `done-done respond` answers it. No judge pass, no receipt.
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
Optional setup check: `done-done doctor --probe` requires a real answer from your chosen agent; it checks setup, not whether your app works.
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
For a signed-in Claude Code setup, pass `--agent claude --model claude-haiku-5-5 --judge claude --judge-model claude-haiku-5-5` to `init`. For Codex, use `--agent codex --model gpt-6.1-sol` with that same judge. Codex readers and probes require a CLI with `exec --ignore-user-config` and `debug models --bundled`: they keep your login, but disable MCP, project instructions and model-provided tools; edit/drive steps keep your normal Codex config. Codex is not a judge route.
|
|
43
|
+
|
|
44
|
+
Claude Code and Codex are proven live. **OpenCode is not yet proven live:** its free tier rejects done-done's tools-off calls with HTTP 403 (`opencode/deepseek-v4.1-flash-free`), so `init`, `doctor --probe` and a judged run are not proven there, and `opencode/muse-spark-1.3-contributor-free` may be absent from the installed catalog. To try OpenCode, choose a model your plan already covers from `opencode models` with `--agent opencode --model <provider/model>`; done-done never needs a new account or API spend.
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
No result? `done-done doctor` changes nothing and names each missing piece, such as a verify skill `init` could not write, with the exact command that fixes it. Commit `.done-done.yaml` and the verify skill so later runs and your teammates use the same recipe. You choose the agents and models; captures go to your chosen judge's provider, on your own plan or key. [Manual CLI](#manual-cli) walks through recording a journey, checking it and saving a receipt.
|
|
43
47
|
|
|
44
48
|
## Why
|
|
45
49
|
|
|
@@ -153,7 +157,7 @@ Another fleet works the same way: add the include text to whatever your workers
|
|
|
153
157
|
|
|
154
158
|
## Learn more
|
|
155
159
|
|
|
156
|
-
- [Vision](VISION.md):
|
|
160
|
+
- [Vision](VISION.md): who done-done is for, the problem, where it is going, what it is not, and the next milestones.
|
|
157
161
|
- [Worked example: a CLI project](docs/example-cli.md): set up, one journey, check and receipt on a command-line tool.
|
|
158
162
|
- [Worked example: create and maintain a verify skill](docs/example-create-maintain.md): init writes the skill, a source change makes it drift, maintain fixes it, then a real browser journey is judged.
|
|
159
163
|
- [Full reference](docs/reference.md): every command and option, the Checks block rules, each file check, and both config files.
|
|
@@ -161,7 +165,7 @@ Another fleet works the same way: add the include text to whatever your workers
|
|
|
161
165
|
|
|
162
166
|
## What's next
|
|
163
167
|
|
|
164
|
-
So far: `init`, `doctor`, `run` (including `--open` and `--close`), `check`, `receipt`, `affected` (the journeys a diff needs), `lint` (a no-model gate on a Checks block), `gate` (a no-model CI check of a committed receipt), `verify` (by journey or by your coding agent, with a gate you answer with `respond`), `maintain`, the capture judge (always on), the `design` visual check, the `look` step, the run tools (`status`, `attach`, `logs`, `rerun`, `abort`, `signoff`, `history`) and the opt-in session hooks for Claude Code, Codex, opencode, Gemini CLI and pi. Coming next:
|
|
168
|
+
So far: `init`, `doctor`, `run` (including `--open` and `--close`), `check`, `receipt`, `affected` (the journeys a diff needs), `lint` (a no-model gate on a Checks block), `gate` (a no-model CI check of a committed receipt), `verify` (by journey or by your coding agent, with a gate you answer with `respond`), `maintain`, the capture judge (always on), the `design` visual check, the `look` step, the run tools (`status`, `attach`, `logs`, `rerun`, `abort`, `signoff`, `history`) and the opt-in session hooks for Claude Code, Codex, opencode, Gemini CLI and pi. Coming next: the [milestones in the vision](VISION.md#next-milestones).
|
|
165
169
|
|
|
166
170
|
## Develop
|
|
167
171
|
|
package/dist/agents.js
CHANGED
|
@@ -255,16 +255,34 @@ const ADAPTERS = {
|
|
|
255
255
|
// answer, and --ephemeral keeps no session. An edit step runs in codex's workspace-write sandbox, which writes only the
|
|
256
256
|
// repo, the run's folders (--add-dir) and $TMPDIR; it may use the network, since the drive launches the app and talks
|
|
257
257
|
// to it, and it keeps the user's config.toml. Without a model, codex runs its own default.
|
|
258
|
-
//
|
|
259
|
-
//
|
|
258
|
+
// Readers keep normal authentication but not user config (MCP), instructions or tools. Feature flags alone
|
|
259
|
+
// are insufficient: the bundled model catalog can force code-mode, collaboration and apply_patch back on.
|
|
260
|
+
// Copy only that public catalog into this call's scratch folder and remove its tool capabilities too.
|
|
260
261
|
codex: {
|
|
261
262
|
streams: true,
|
|
262
|
-
|
|
263
|
+
files: (c) => {
|
|
264
|
+
if (c.tools === 'edit')
|
|
265
|
+
return {};
|
|
266
|
+
const r = spawnSync(c.path, ['debug', 'models', '--bundled'], { encoding: 'utf8', timeout: 10_000, maxBuffer: 16 << 20 });
|
|
267
|
+
if (r.status !== 0)
|
|
268
|
+
throw new Error(`codex tool-less setup: ${r.error?.message || r.stderr || `debug models --bundled exited ${r.status}`}; update Codex CLI`);
|
|
269
|
+
const catalog = JSON.parse(r.stdout);
|
|
270
|
+
if (!Array.isArray(catalog.models) || !catalog.models.length || (c.model && !catalog.models.some((m) => m.slug === c.model)))
|
|
271
|
+
throw new Error(`codex tool-less setup: bundled catalog does not list ${c.model || 'any model'}; choose a model from codex debug models --bundled`);
|
|
272
|
+
for (const m of catalog.models)
|
|
273
|
+
Object.assign(m, { shell_type: 'disabled', apply_patch_tool_type: null, tool_mode: 'direct', multi_agent_version: null, experimental_supported_tools: [], supports_search_tool: false });
|
|
274
|
+
return { 'models.json': JSON.stringify(catalog) };
|
|
275
|
+
},
|
|
263
276
|
// Each sandboxed command runs in its own process namespace, so a server or browser bridge started in the
|
|
264
277
|
// background by one command was gone by the next one, and a drive that launched the app and then browsed it captured nothing.
|
|
265
278
|
editNote: 'Your shell sandbox ends every process a command started, background ones too, when that command ends. So start what a task needs (an app, a server, a browser bridge), use it, save what it produces and stop it within one shell command (a script in $TMPDIR is fine).',
|
|
266
|
-
argv: (c) => ['exec', '--json', '--ephemeral', ...(c.model ? ['-m', c.model] : []),
|
|
267
|
-
'--sandbox', 'workspace-write', '-c', 'sandbox_workspace_write.network_access=true', ...(c.dirs ?? []).flatMap((d) => ['--add-dir', d])]
|
|
279
|
+
argv: (c, dir) => [...(c.tools === 'edit' ? [] : ['--no-daemon']), 'exec', '--json', '--ephemeral', ...(c.model ? ['-m', c.model] : []),
|
|
280
|
+
...(c.tools === 'edit' ? ['--sandbox', 'workspace-write', '-c', 'sandbox_workspace_write.network_access=true', ...(c.dirs ?? []).flatMap((d) => ['--add-dir', d])] : [
|
|
281
|
+
'--ignore-user-config', '--ignore-rules', '--skip-git-repo-check', '--sandbox', 'read-only',
|
|
282
|
+
'-c', 'project_doc_max_bytes=0', '-c', `model_catalog_json=${JSON.stringify(join(dir, 'models.json'))}`,
|
|
283
|
+
'-c', 'web_search="disabled"', '-c', 'tools.update_plan.enabled=false', '-c', 'tools.experimental_request_user_input.enabled=false',
|
|
284
|
+
...['shell_tool', 'multi_agent', 'apps', 'plugins', 'skill_search', 'tool_suggest', 'image_generation', 'view_image', 'sleep_tool', 'goals'].flatMap((f) => ['--disable', f]),
|
|
285
|
+
])],
|
|
268
286
|
answer: (out, c) => {
|
|
269
287
|
let text = '';
|
|
270
288
|
let failed = '';
|
|
@@ -335,11 +353,9 @@ export function knownAgentOf(agent) {
|
|
|
335
353
|
return AGENTS.find((a) => target === a || (target.startsWith(a) && !/[A-Za-z0-9]/.test(target[a.length]))) ?? agent;
|
|
336
354
|
}
|
|
337
355
|
const adapterFor = (agent) => (agent.startsWith('acp:') ? ACP : Object.hasOwn(ADAPTERS, agent) ? ADAPTERS[agent] : undefined);
|
|
338
|
-
// Why an agent cannot run a tool-less call, '' when it can.
|
|
339
|
-
export const editOnlyReason = (agent) => adapterFor(agent)?.editOnly ?? '';
|
|
340
356
|
// Why an agent cannot read a repo tool-less from text plain code gathers, '' when it can: gemini's none mode is a
|
|
341
357
|
// read-only plan mode, not tool-free.
|
|
342
|
-
export const toollessReason = (agent) => (agent === 'gemini' ? 'gemini cannot read tool-less yet, since its none mode is read-only plan mode, not tool-free' :
|
|
358
|
+
export const toollessReason = (agent) => (agent === 'gemini' ? 'gemini cannot read tool-less yet, since its none mode is read-only plan mode, not tool-free' : '');
|
|
343
359
|
// A binary from config: a bare name is looked up on PATH, an absolute path is used when it is an executable file.
|
|
344
360
|
export const findBin = (bin) => (isAbsolute(bin) ? (isExecutable(bin) ? bin : '') : onPath(bin));
|
|
345
361
|
// The binary that starts an agent: agent_path_override.<agent>, else its name on PATH. An acp:<target> agent starts
|
|
@@ -508,16 +524,14 @@ export async function askAgent(c) {
|
|
|
508
524
|
cwd = c.tools === 'none' ? dir : c.cwd;
|
|
509
525
|
if (!adapter)
|
|
510
526
|
throw new Error(`no adapter for ${c.agent} yet`);
|
|
511
|
-
|
|
512
|
-
|
|
527
|
+
const bin = c.path;
|
|
528
|
+
if (!bin)
|
|
529
|
+
throw new Error(c.agent.startsWith('acp:') ? `${c.agent} needs acpx, and acpx is not startable; ${ACPX_INSTALL}` : notStartable(c.agent, c.override));
|
|
513
530
|
if (adapter.readsImages)
|
|
514
531
|
for (const i of c.images ?? [])
|
|
515
532
|
writeFileSync(join(dir, i.name), i.bytes, { mode: 0o600 });
|
|
516
533
|
for (const [name, text] of Object.entries(adapter.files?.(c) ?? {}))
|
|
517
534
|
writeFileSync(join(dir, name), text, { mode: 0o600 });
|
|
518
|
-
const bin = c.path;
|
|
519
|
-
if (!bin)
|
|
520
|
-
throw new Error(c.agent.startsWith('acp:') ? `${c.agent} needs acpx, and acpx is not startable; ${ACPX_INSTALL}` : notStartable(c.agent, c.override));
|
|
521
535
|
let lastError = '';
|
|
522
536
|
for (;;) {
|
|
523
537
|
attempts++;
|