bottega-kit 0.0.0-stage → 0.1.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,83 @@
1
+ # Changelog
2
+
3
+ All notable changes to bottega-kit. Dates are when the version was cut.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.0] — 2026-10-23
8
+
9
+ The first release. A planner, an implementer, a reviewer and an optional judge
10
+ run on Claude Code and Codex in a git worktree, with a receipt for every
11
+ dispatch.
12
+
13
+ **Tasks and configuration.** `bottega init` writes a starter configuration for
14
+ the harnesses it finds on PATH, and `bottega doctor` checks python3, git, gh,
15
+ the configuration, each role's harness and the environment variables profiles
16
+ reference. A `${NAME}` a profile references is read from your environment or
17
+ from `~/.config/bottega-kit/secrets.env`, one `NAME=value` line each, parsed
18
+ and never executed, refused while anyone but you can read it. `bottega new`
19
+ creates a task: a directory outside the repository
20
+ with `task.md` holding your request verbatim, a worktree beside the repository
21
+ and a `bottega/<task-id>` branch. `show`, `list` and `rm` manage tasks.
22
+ `bottega signal` is the command agents run to report `ready`, `needs-work` or
23
+ `blocked`.
24
+
25
+ **Planning and approval.** `bottega plan` runs the planner once; its final
26
+ message becomes the plan, or questions you answer inside `task.md` before the
27
+ next `plan`. `bottega approve` checks the plan, gives each to-do item a stable
28
+ `[T<n>]` id, and freezes the plan's hash, the roles and the round cap. The
29
+ `claude` and `codex` drivers keep every flag in one table. A proxied Claude
30
+ profile runs without your Anthropic credentials. Prompts can be overridden
31
+ per user.
32
+
33
+ **The loop.** `bottega run` alternates the implementer and the reviewer up to
34
+ the cap, then asks the judge if one is bound. It ends done (exit 0) or stopped
35
+ (exit 3) with a reason, and never retries. The reviewer's findings and the
36
+ judge's verdict replace their sections of `task.md`. A planner, reviewer or
37
+ judge that changes tracked code stops the task, and so does a harness that
38
+ reports another model. `bottega resume` continues a stopped task with a fresh
39
+ cap.
40
+
41
+ **Verified live.** On 2026-10-17 and 2026-10-19 seven tasks ran on two
42
+ throwaway repositories with Claude Code 2.1.302 and 2.1.303 and Codex CLI
43
+ 0.163.0, each harness in every role, and `bottega pr` opened a pull request
44
+ on GitHub (`docs/compatibility.md`). The runs found two bugs. A Codex reviewer
45
+ could not find the task by id, because Codex does not pass the orchestrator's
46
+ environment to the agent's shell: `bottega signal` now also accepts the
47
+ absolute task directory, and every prompt names it. A plan with a fenced
48
+ block inside a longer fence lost five lines in the merge: a fence now closes
49
+ only with the same character and at least the same length, as in CommonMark.
50
+ The runs also changed the prompts: the implementer and the reviewer are told
51
+ to give a test suite a long timeout, and that a shell tool handing control
52
+ back while the command runs means wait, not failed. On 2026-10-20 the
53
+ README's proxied profile ran as reviewer: Claude Code 2.1.304 on Z.AI's
54
+ endpoint reported the requested `glm-5.3-flash`, with the key read from
55
+ `secrets.env`.
56
+
57
+ **Pull requests and packaging.** `bottega pr` commits what is left in the
58
+ worktree, pushes the branch to `origin` and opens the pull request with `gh`.
59
+ It works on a done or a stopped task, and a stopped task's pull request says
60
+ why it stopped. An existing pull request is reported, not duplicated.
61
+ `npx bottega-kit` installs the release that matches the npm package. The
62
+ README and `docs/` describe the process, the configuration and the harness
63
+ flags.
64
+
65
+ ### Known limits
66
+
67
+ - Verified live on one machine, on three days, with Claude Code 2.1.302 to
68
+ 2.1.304 and Codex CLI 0.163.0, each in every role, and `bottega pr` on a
69
+ private github.com repository (`docs/compatibility.md`). The Claude Bash
70
+ deny rules were seen to deny every forbidden command; a 150 s test suite
71
+ passed under a Claude reviewer and, after a prompt change, under a Codex
72
+ reviewer that had first given up on it; the Claude `Write` tool created
73
+ files under `acceptEdits`; a proxied profile on Z.AI ran once, as
74
+ reviewer, and Claude Code priced it at its own default rate. A GitHub
75
+ Enterprise host was not exercised; Codex reports no model, so its identity
76
+ stays `requested-only`.
77
+ - Two harnesses: `claude` and `codex`.
78
+ - A text-patch harness for chat-completion endpoints, and Kimi, Grok and
79
+ Gemini drivers, are planned for later (`docs/later.md`).
80
+
81
+ ## [0.0.0] — 2026-10-17
82
+
83
+ - Repository created. Nothing released.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Matteo Scurati
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,44 @@
1
+ bottega-kit
2
+ Copyright (c) 2026 Matteo Scurati
3
+ Licensed under the MIT License (see LICENSE).
4
+
5
+ This project adapts material from vdaubry/bottega
6
+ (https://github.com/vdaubry/bottega), used under the MIT License.
7
+ bottega-kit takes bottega's process (spec-first planning, a human gate on the
8
+ plan, an implementer and a reviewer alternating over one task document). It
9
+ does not take bottega's platform (web server, database, user interface).
10
+
11
+ Files adapted from vdaubry/bottega (HEAD 7e5137f, 2026-10-05):
12
+
13
+ reference/server/constants/templates/plan-template.md -> templates/task.md
14
+ reference/server/constants/prompts/planification.md -> prompts/planner.md
15
+ reference/server/constants/prompts/implementation.md -> prompts/implementer.md
16
+ reference/server/constants/prompts/review.md -> prompts/reviewer.md
17
+
18
+ prompts/judge.md is original to bottega-kit.
19
+
20
+ The vdaubry/bottega licence follows.
21
+
22
+ --------------------------------------------------------------------------------
23
+
24
+ MIT License
25
+
26
+ Copyright (c) 2026 VDA
27
+
28
+ Permission is hereby granted, free of charge, to any person obtaining a copy
29
+ of this software and associated documentation files (the "Software"), to deal
30
+ in the Software without restriction, including without limitation the rights
31
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
+ copies of the Software, and to permit persons to whom the Software is
33
+ furnished to do so, subject to the following conditions:
34
+
35
+ The above copyright notice and this permission notice shall be included in all
36
+ copies or substantial portions of the Software.
37
+
38
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
44
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,217 @@
1
- # Temporary Holding Version
1
+ # bottega-kit
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ bottega-kit runs a planner, an implementer, a reviewer and an optional judge on the
4
+ coding agents you already have — Claude Code and Codex today — one role each, in a
5
+ git worktree, with a receipt for every step. You need git, gh, python3 and at least
6
+ one of those CLIs. This is not vdaubry/bottega: the process is
7
+ [theirs](https://github.com/vdaubry/bottega); the local, file-based, multi-vendor
8
+ loop is this project.
9
+
10
+ A task is one plan, which you approve, and then rounds of implementer and
11
+ reviewer until the reviewer is satisfied or the round cap is reached:
12
+
13
+ ```
14
+ bottega new task directory, worktree and branch; task.md holds your request
15
+ bottega plan one planner dispatch; may end with questions; repeat until there is a plan
16
+ bottega approve ids for the to-do items; plan hash, roles and cap recorded
17
+ bottega run implementer and reviewer, round after round, up to the cap; then the judge
18
+ bottega pr commit if needed, push to origin, open the pull request
19
+ bottega resume after a stop, with a fresh cap
20
+ ```
21
+
22
+ A round is one implementer pass and one reviewer pass; the cap is 3 unless
23
+ you change it. Each role runs under a profile from your configuration: a
24
+ harness, which is the CLI that runs the role (`claude` or `codex`), a model
25
+ and an effort. One profile may serve several roles.
26
+
27
+ ## Current release: 0.1.0
28
+
29
+ The first release: `init`, `doctor`, `new`, `plan`, `approve`, `run`, `resume`,
30
+ `pr` and the task commands, on the `claude` and `codex` harnesses. The loop
31
+ was verified live on 2026-10-17, 2026-10-19 and 2026-10-20 with Claude Code
32
+ 2.1.302 to 2.1.304 and Codex CLI 0.163.0, each in every role, a reviewer on
33
+ Z.AI's endpoint through Claude Code, and `bottega pr` opening a pull request
34
+ on GitHub. See [docs/compatibility.md](docs/compatibility.md).
35
+
36
+ ## What you need
37
+
38
+ - git
39
+ - gh, logged in, for `bottega pr`
40
+ - python3 3.9 or newer
41
+ - at least one of `claude` (Claude Code) and `codex` (Codex CLI), logged in
42
+ - node 18 or newer, only for `npx bottega-kit`
43
+
44
+ ## Install
45
+
46
+ ```sh
47
+ npx bottega-kit
48
+ ```
49
+
50
+ This clones the release that matches the npm package, runs its `./install.sh`,
51
+ then `./doctor.sh`, and deletes the clone. `doctor` fails on a new machine
52
+ until you run `bottega init`. Or from a clone:
53
+
54
+ ```sh
55
+ git clone https://github.com/reasance/bottega-kit
56
+ cd bottega-kit
57
+ ./install.sh
58
+ ```
59
+
60
+ Both copy the command to `~/.local/share/bottega-kit` and link
61
+ `~/.local/bin/bottega`. `./uninstall.sh`, from a clone, removes them and keeps
62
+ your tasks and configuration.
63
+
64
+ ## Example: Fable plans and judges, Opus implements and reviews
65
+
66
+ `~/.config/bottega-kit/config.json`, which `bottega init` writes when it finds
67
+ `claude`:
68
+
69
+ ```json
70
+ {
71
+ "schema_version": 1,
72
+ "profiles": {
73
+ "fable": {"harness": "claude", "model": "claude-fable-5-1", "effort": "max"},
74
+ "opus-builder": {"harness": "claude", "model": "claude-opus-5-5", "effort": "high"},
75
+ "opus-reviewer": {"harness": "claude", "model": "claude-opus-5-5", "effort": "high"}
76
+ },
77
+ "roles": {"planner": "fable", "implementer": "opus-builder",
78
+ "reviewer": "opus-reviewer", "judge": "fable"},
79
+ "rounds": 3
80
+ }
81
+ ```
82
+
83
+ The whole sequence, from a repository with an `origin` on GitHub:
84
+
85
+ ```sh
86
+ bottega init
87
+ bottega doctor
88
+ cd your-repo
89
+ echo '{"test_cmd": "make test"}' > bottega.json # optional: the test command the agents run
90
+ bottega new --title "Add a dry-run flag" --request "Add --dry-run to the export command."
91
+ bottega plan 20261017-0930-add-a-dry-run-flag # a unique prefix or suffix is enough
92
+ # read task.md; answer any questions in it and run plan again
93
+ bottega approve dry-run-flag
94
+ bottega run dry-run-flag
95
+ bottega pr dry-run-flag
96
+ ```
97
+
98
+ `plan` and `run` print one line per dispatch on stdout, and `plan` adds the
99
+ planner's questions when it has any; everything else goes to stderr:
100
+
101
+ ```
102
+ 001 planner fable claude-fable-5-1 → planned (2m41s)
103
+ 002 implementer opus-builder claude-opus-5-5 → done (6m02s)
104
+ 003 reviewer opus-reviewer claude-opus-5-5 → needs-work (2m14s)
105
+ 004 implementer opus-builder claude-opus-5-5 → done (3m40s)
106
+ 005 reviewer opus-reviewer claude-opus-5-5 → ready (1m55s)
107
+ 006 judge fable claude-fable-5-1 → ready (48s)
108
+ ```
109
+
110
+ `pr` prints the pull request's URL, or `pr exists: <url>`.
111
+
112
+ ## Example: three vendors, no judge
113
+
114
+ The planner on Claude Code, the implementer on Codex, the reviewer on Claude
115
+ Code pointed at Z.AI's Anthropic-compatible endpoint:
116
+
117
+ ```json
118
+ {
119
+ "schema_version": 1,
120
+ "profiles": {
121
+ "fable": {"harness": "claude", "model": "claude-fable-5-1", "effort": "max"},
122
+ "sol-builder": {"harness": "codex", "model": "gpt-5.6-sol", "effort": "high"},
123
+ "glm-reviewer": {"harness": "claude", "model": "glm-5.3-flash", "effort": "max",
124
+ "env": {"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
125
+ "ANTHROPIC_AUTH_TOKEN": "${ZAI_API_KEY}",
126
+ "ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.3-flash"},
127
+ "aliases": ["opus"]}
128
+ },
129
+ "roles": {"planner": "fable", "implementer": "sol-builder",
130
+ "reviewer": "glm-reviewer"},
131
+ "rounds": 3
132
+ }
133
+ ```
134
+
135
+ `${ZAI_API_KEY}` is read when the reviewer runs, from your environment or
136
+ from `~/.config/bottega-kit/secrets.env` (one `NAME=value` line each, mode
137
+ 600, parsed and never executed); `doctor` and `approve` refuse while it is set
138
+ in neither. Because `ANTHROPIC_BASE_URL` is set, the reviewer runs with a fresh
139
+ Claude configuration directory and without your Anthropic credentials.
140
+ `aliases` lists other names the endpoint may report for the model; any other
141
+ name stops the run as `identity-mismatch` (on 2026-10-20 Z.AI reported
142
+ `glm-5.3-flash`, the requested name, so the alias went unused). To change one
143
+ role for one task only, pass `--role implementer=sol-builder` to `bottega new`.
144
+
145
+ ## The roles
146
+
147
+ | role | what it does | what it may change | its product |
148
+ |---|---|---|---|
149
+ | planner | reads the repository and the request, writes the plan or asks questions | nothing | its final message becomes the plan in `task.md` |
150
+ | implementer | works through the unchecked to-do items, adds tests, ticks items | the worktree and the boxes in `task.md`; never commits or pushes | a summary, kept in the receipt |
151
+ | reviewer | checks every ticked item, runs the tests and the manual QA scenarios | nothing it keeps: a changed tracked file stops the task | `## Review Findings` and a signal: `ready`, `needs-work` or `blocked` |
152
+ | judge | optional; reads the plan and the diff, says whether to merge | nothing | `## Verdict` and a signal: `ready` or `needs-work` |
153
+
154
+ Agents report back by running `bottega signal`. bottega-kit decides what
155
+ happens next from that signal and the files on disk, never from the agent's
156
+ prose. [docs/process.md](docs/process.md) has the loop step by step.
157
+
158
+ ## Exit codes
159
+
160
+ | code | meaning |
161
+ |---|---|
162
+ | 0 | done |
163
+ | 2 | refused: wrong phase, plan changed since approval, invalid configuration, a binding that no longer works, task locked |
164
+ | 3 | stopped: `blocked`, `cap-reached`, `judge-needs-work`, `dispatch-failed`, `timeout`, `identity-mismatch`, `role-modified-worktree`, `interrupted` |
165
+ | 64 | bad invocation |
166
+
167
+ A stopped task continues with `bottega resume <task> [--rounds N]`.
168
+
169
+ ## Where things live
170
+
171
+ - Configuration: `~/.config/bottega-kit/config.json`, and prompt overrides in
172
+ `~/.config/bottega-kit/prompts/`.
173
+ - Tasks: `~/.local/share/bottega-kit/tasks/<project>/<task-id>/`, holding
174
+ `task.md`, `state.json` and one receipt directory per dispatch under `runs/`.
175
+ They live outside the repository, so they outlive the worktree.
176
+ - The worktree: `<repo>-worktrees/<task-id>/`, beside the repository, on the
177
+ branch `bottega/<task-id>`. `bottega rm` removes it and the branch.
178
+ - A repository may hold `bottega.json` with `test_cmd` and `base`.
179
+
180
+ [docs/configuration.md](docs/configuration.md) covers every setting.
181
+
182
+ ## What bottega-kit never does
183
+
184
+ - Retry a failed dispatch, fall back to another model, or substitute a profile.
185
+ - Bring a model of its own. Every dispatch runs a profile you bound, and the
186
+ harness must report the model you asked for.
187
+ - Put a secret in its configuration, its prompts, a task or a receipt.
188
+ Profiles name environment variables; the key file you keep at mode 600 may
189
+ hold their values; receipts record names, never values.
190
+ - Merge, or push anywhere but `origin`.
191
+ - Let the planner, the reviewer or the judge change your code: their runs are
192
+ checked against the worktree before and after.
193
+
194
+ ## Not vdaubry/bottega
195
+
196
+ [vdaubry/bottega](https://github.com/vdaubry/bottega) is a web platform with a
197
+ server, a database and a UI. bottega-kit took its process: the spec-first task
198
+ document, the planner, implementer and reviewer prompts, the plan template,
199
+ the "agents signal with a command" rule, the review cap with no unreviewed fix
200
+ pass, and one worktree per task. It did not take the platform. The judge
201
+ role, the profiles across vendors and the receipts are this project's. See
202
+ `NOTICE` for the files adapted.
203
+
204
+ ## Documentation
205
+
206
+ - [docs/process.md](docs/process.md): the loop, rounds, resume, signals,
207
+ receipts, rails.
208
+ - [docs/configuration.md](docs/configuration.md): profiles, roles,
209
+ `bottega.json`, prompt overrides, environment variables.
210
+ - [docs/compatibility.md](docs/compatibility.md): what each harness is run
211
+ with, and what has been verified.
212
+ - [docs/later.md](docs/later.md): what is not built yet.
213
+
214
+ ## Licence
215
+
216
+ MIT. The process and parts of the prompts and the template come from
217
+ [vdaubry/bottega](https://github.com/vdaubry/bottega), also MIT; see `NOTICE`.
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env node
2
+ // bottega-kit npm installer: a thin wrapper over the repository's ./install.sh.
3
+ //
4
+ // `npx bottega-kit` clones https://github.com/reasance/bottega-kit at the
5
+ // tag that matches this package's own version (bottega-kit--v<version>), runs
6
+ // ./install.sh from the clone, then ./doctor.sh, then deletes the clone.
7
+ // install.sh copies what it installs into BOTTEGA_DATA_HOME and records the
8
+ // repository and ref (never the temporary path) in installed-version.json, so
9
+ // nothing installed points at the deleted clone.
10
+ //
11
+ // Usage:
12
+ // npx bottega-kit [--ref <tag-or-branch>] [--repo <git-url>] [--skip-doctor]
13
+ //
14
+ // Environment: BOTTEGA_DATA_HOME and BOTTEGA_BIN_HOME, as for ./install.sh.
15
+ // The wrapper never writes a configuration and never handles credentials.
16
+
17
+ import { spawnSync } from "node:child_process";
18
+ import { mkdtempSync, readFileSync, rmSync, statSync } from "node:fs";
19
+ import { tmpdir } from "node:os";
20
+ import { join } from "node:path";
21
+ import process from "node:process";
22
+
23
+ const DEFAULT_REPO = "https://github.com/reasance/bottega-kit";
24
+ const TAG_PREFIX = "bottega-kit--v";
25
+ const USAGE =
26
+ "usage: npx bottega-kit [--ref <tag-or-branch>] [--repo <git-url>] [--skip-doctor]";
27
+ const REQUIRED = [
28
+ "install.sh",
29
+ "doctor.sh",
30
+ "bin/bottega",
31
+ "bin/lib/bottega/version.py",
32
+ ];
33
+
34
+ class WrapperError extends Error {
35
+ constructor(message, code = 1) {
36
+ super(message);
37
+ this.code = code;
38
+ }
39
+ }
40
+
41
+ function packageVersion() {
42
+ const text = readFileSync(new URL("../package.json", import.meta.url), "utf8");
43
+ return JSON.parse(text).version;
44
+ }
45
+
46
+ function parseArgs(argv) {
47
+ const options = { ref: null, repo: null, skipDoctor: false, help: false };
48
+ for (let i = 0; i < argv.length; i += 1) {
49
+ const arg = argv[i];
50
+ const [name, inline] = arg.startsWith("--") && arg.includes("=")
51
+ ? [arg.slice(0, arg.indexOf("=")), arg.slice(arg.indexOf("=") + 1)]
52
+ : [arg, null];
53
+ switch (name) {
54
+ case "--ref":
55
+ case "--repo": {
56
+ const value = inline ?? argv[i + 1];
57
+ if (inline === null) i += 1;
58
+ if (!value || value.startsWith("--")) {
59
+ throw new WrapperError(`${name} needs a value\n${USAGE}`, 64);
60
+ }
61
+ options[name.slice(2)] = value;
62
+ break;
63
+ }
64
+ case "--skip-doctor":
65
+ options.skipDoctor = true;
66
+ break;
67
+ case "-h":
68
+ case "--help":
69
+ options.help = true;
70
+ break;
71
+ default:
72
+ // install.sh takes no arguments, so nothing is forwarded to it.
73
+ throw new WrapperError(`unknown argument: ${arg}\n${USAGE}`, 64);
74
+ }
75
+ }
76
+ return options;
77
+ }
78
+
79
+ function run(command, args, options = {}) {
80
+ const result = spawnSync(command, args, { stdio: "inherit", ...options });
81
+ if (result.error) {
82
+ throw new WrapperError(`could not run ${command}: ${result.error.message}`);
83
+ }
84
+ return result;
85
+ }
86
+
87
+ function requireGit() {
88
+ const probe = spawnSync("git", ["--version"], { stdio: "ignore" });
89
+ if (probe.error || probe.status !== 0) {
90
+ throw new WrapperError("git is required", 69);
91
+ }
92
+ }
93
+
94
+ function clone(repo, ref, dir) {
95
+ const result = run(
96
+ "git",
97
+ ["clone", "--quiet", "--depth", "1", "--branch", ref, repo, dir],
98
+ { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" },
99
+ );
100
+ if (result.status !== 0) {
101
+ const detail = (result.stderr || "").trim();
102
+ throw new WrapperError(
103
+ `could not clone ${repo} at ${ref}${detail ? `:\n${detail}` : ""}`,
104
+ );
105
+ }
106
+ }
107
+
108
+ function checkCheckout(dir, expectedVersion, ref) {
109
+ for (const file of REQUIRED) {
110
+ let ok = false;
111
+ try {
112
+ ok = statSync(join(dir, file)).isFile();
113
+ } catch {
114
+ ok = false;
115
+ }
116
+ if (!ok) {
117
+ throw new WrapperError(`${ref} has no ${file}; it is not a bottega-kit release`);
118
+ }
119
+ }
120
+ const text = readFileSync(join(dir, "bin/lib/bottega/version.py"), "utf8");
121
+ const found = /^__version__ = "([^"]+)"$/m.exec(text)?.[1];
122
+ if (expectedVersion && found !== expectedVersion) {
123
+ throw new WrapperError(
124
+ `${ref} holds bottega-kit ${found ?? "(no version)"}, not ${expectedVersion}`,
125
+ );
126
+ }
127
+ }
128
+
129
+ function main() {
130
+ const options = parseArgs(process.argv.slice(2));
131
+ if (options.help) {
132
+ console.log(USAGE);
133
+ return 0;
134
+ }
135
+ requireGit();
136
+ const version = packageVersion();
137
+ const repo = options.repo ?? DEFAULT_REPO;
138
+ const ref = options.ref ?? `${TAG_PREFIX}${version}`;
139
+ const parent = mkdtempSync(join(tmpdir(), "bottega-kit-"));
140
+ const checkout = join(parent, "bottega-kit");
141
+ try {
142
+ console.log(`bottega-kit: installing ${ref} from ${repo}`);
143
+ clone(repo, ref, checkout);
144
+ // Only the default tag must match this package; --ref is the user's choice.
145
+ checkCheckout(checkout, options.ref ? null : version, ref);
146
+ const env = {
147
+ ...process.env,
148
+ BOTTEGA_INSTALL_SOURCE: repo,
149
+ BOTTEGA_INSTALL_REF: ref,
150
+ };
151
+ const install = run("./install.sh", [], { cwd: checkout, env });
152
+ if (install.status !== 0) {
153
+ throw new WrapperError(
154
+ `install.sh exited with ${install.status}`,
155
+ install.status ?? 1,
156
+ );
157
+ }
158
+ if (options.skipDoctor) {
159
+ return 0;
160
+ }
161
+ const doctor = run("./doctor.sh", [], { cwd: checkout, env });
162
+ if (doctor.status !== 0) {
163
+ console.error(
164
+ `bottega-kit: installed, but doctor reported problems (exit ${doctor.status}). ` +
165
+ "A new install has no configuration yet: run bottega init, then bottega doctor.",
166
+ );
167
+ return doctor.status ?? 1;
168
+ }
169
+ return 0;
170
+ } finally {
171
+ rmSync(parent, { recursive: true, force: true });
172
+ }
173
+ }
174
+
175
+ let code;
176
+ try {
177
+ code = main();
178
+ } catch (error) {
179
+ if (!(error instanceof WrapperError)) throw error;
180
+ console.error(`bottega-kit: ${error.message}`);
181
+ code = error.code;
182
+ }
183
+ process.exit(code);
package/package.json CHANGED
@@ -1,6 +1,39 @@
1
1
  {
2
2
  "name": "bottega-kit",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "A planner, an implementer, a reviewer and an optional judge on the coding agents you already have, in a git worktree, with a receipt for every step.",
5
+ "keywords": [
6
+ "claude-code",
7
+ "codex",
8
+ "coding-agents",
9
+ "git-worktree",
10
+ "developer-tools"
11
+ ],
12
+ "author": {
13
+ "name": "Matteo Scurati",
14
+ "url": "https://github.com/matteoscurati"
15
+ },
16
+ "homepage": "https://github.com/reasance/bottega-kit#readme",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/reasance/bottega-kit.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/reasance/bottega-kit/issues"
23
+ },
24
+ "license": "MIT",
25
+ "type": "module",
26
+ "bin": {
27
+ "bottega-kit": "./bin/npm-installer.mjs"
28
+ },
29
+ "files": [
30
+ "bin/npm-installer.mjs",
31
+ "README.md",
32
+ "LICENSE",
33
+ "NOTICE",
34
+ "CHANGELOG.md"
35
+ ],
36
+ "engines": {
37
+ "node": ">=18"
38
+ }
39
+ }