@agentchatham/cli 2.28.0 → 2.34.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/CLAUDE.md CHANGED
@@ -19,10 +19,15 @@ boot paths: up <inv> [agent_id] → bindOrRegister (registration.ts) → bo
19
19
  agentchatham <dir> → ensureIdentity (SDK) → bootAgent
20
20
  cli package: src/cli/index.ts — barrel (parseCliArgs + CliArgs/Command + run* handlers)
21
21
  src/cli/args.ts — arg parsing
22
- src/cli/commands.ts — subcommand handlers (register/list/update/remove/info)
22
+ src/cli/commands.ts — ALL subcommand handlers (register/list/update/remove/info,
23
+ setup-github/github-token/git-credential). One file: a
24
+ handler is `run<Command>`, and nothing else lives here
23
25
  register: src/registration.ts — bindOrRegister: idempotent register-or-bind for `up` (by agent_id)
24
26
  src/identity.ts — findAgentDir: locate an agent dir by its `-<agent_id>` suffix
25
27
  src/bootstrap.ts — runBootstrap stub for `-b` (image scripts; later phase)
28
+ github: src/github/setup.ts — the GitHub integration; see "GitHub integration" below
29
+ host tools: pluginSetup.ts:run() — the ONE child-process runner (git, claude, openclaw).
30
+ Exported for github/setup.ts; do not re-spawn by hand
26
31
  storage: src/agentConfig.ts — per-agent cli.json (read/writeAgentConfig: harness+mode); NO cli dep,
27
32
  so registration.ts reuses it without depending on cli/
28
33
  slash-cmds: src/commands/ — agent in-chat slash-commands (distinct from cli/commands.ts)
@@ -30,6 +35,9 @@ errors: src/errors/ — ErrorClass/TurnError vocabulary + forma
30
35
  abstraction: src/provider.ts — ProviderAgent / ProviderAdapter interfaces
31
36
  adapters: src/providers/*/ — one per provider, implements ProviderAdapter
32
37
  <name>/errors.ts classifies that harness's failures
38
+ opencode/ drives `opencode serve` via @opencode-ai/sdk; the
39
+ model is `<provider>/<model>` and the provider key comes
40
+ from env (OPENROUTER_API_KEY), never from this repo
33
41
  src/providers/shared/ — prose + errno tables the classifiers fall back on
34
42
  loop: src/dispatcher.ts — buffer, retry, watermarks; private to /cli
35
43
  format: src/prompts.ts — formatters; input is ParsedNotification not raw events
@@ -47,6 +55,43 @@ infra: src/lifecycle.ts — shutdown choreography
47
55
  - WS loop: `monitorProvider` owns connect/reconnect. Never call `connectClient` directly.
48
56
  - Identity CRUD: `registerIdentity`, `loadIdentity` from SDK.
49
57
 
58
+ ## GitHub integration
59
+
60
+ Agents never hold a long-lived GitHub credential. Every git operation mints a
61
+ fresh, usually single-repo, ~1h installation token from the backend, which holds
62
+ the org's GitHub App installation (agent_chatham `docs/plans/integrations.md`
63
+ §3.2). Nothing is written to disk, ever.
64
+
65
+ **The mint is the SDK's**, per §7 of that plan. Do not re-implement it here, and
66
+ do not reach for `fetch` in this repo. The SDK exposes two doors and this repo
67
+ uses the unusual one:
68
+
69
+ - `githubTokenFromIdentity(dirName, {repositories})` — what these commands call.
70
+ REST, authenticating from `identity.json`, because the credential helper is a
71
+ fresh process per git operation with no live socket — and must not touch the
72
+ wrapping key / OS keyring for the same reason.
73
+ - `githubToken(client, …)` — the socket path, and what the SDK's `github_token`
74
+ MCP tool calls. That is how a *harness* gets a token for `gh`; the CLI has no
75
+ client in these code paths.
76
+
77
+ What remains here is genuinely CLI and lives in two places: `src/github/setup.ts`
78
+ (the `git config` writes and the managed-boot hook), and `cli/commands.ts` — the
79
+ three handlers plus git's credential protocol, private to the one handler that
80
+ speaks it.
81
+
82
+ Rules:
83
+
84
+ - **The helper's stdout is the wire.** Anything printed there is parsed by git as
85
+ credential data, so failures log to stderr and exit 1 — never stdout.
86
+ - **Silence is a valid answer.** A non-github.com host gets no output at all, so
87
+ git falls through to the user's own helpers. `store`/`erase` are no-ops.
88
+ - **Scope is opt-in.** `setup-github` writes repo-local config by default; only
89
+ a managed VM, which is the agent's own host, gets `--global`.
90
+ - **Boot does not reconfigure.** `maybeSetupGithub` asks git whether the helper
91
+ is already set and returns if it is: `up` runs on every VM start, and the git
92
+ config it writes is host state, not per-run state. Reconfiguring is explicit
93
+ (`agentchatham setup-github --global`).
94
+
50
95
  ## Adding a new provider
51
96
 
52
97
  1. Add name to the `Harness` union in `src/provider.ts` (and `VALID_HARNESSES`)
@@ -61,8 +106,10 @@ infra: src/lifecycle.ts — shutdown choreography
61
106
  ## Error classification
62
107
 
63
108
  Each harness classifies its own errors in `src/providers/<name>/errors.ts`, because
64
- the four share no error types: Claude has typed stream events, Cursor typed error
65
- subclasses, Codex and Gemini carry their cause as prose inside stream events.
109
+ the harnesses share no error types: Claude has typed stream events, Cursor typed error
110
+ subclasses, Codex and Gemini carry their cause as prose inside stream events, and
111
+ OpenCode reports a tagged union on the assistant message whose `APIError` carries the
112
+ upstream HTTP status.
66
113
 
67
114
  `src/errors/` holds what is common and nothing else:
68
115
 
package/README.md CHANGED
@@ -53,13 +53,40 @@ The process runs in the foreground, streaming logs to stdout/stderr. `Ctrl-C` (o
53
53
  | `agentchatham update <dirName> <key>:<value>…` | Update agent config (e.g. `harness:claude`, `mode:cli`). |
54
54
  | `agentchatham rm <dirName>` | Remove an agent. |
55
55
  | `agentchatham ls` | List all registered agents. |
56
+ | `agentchatham setup-github [<dirName>] [--global]` | Wire git to the org's GitHub integration (see below). Defaults to the current repo. |
57
+ | `agentchatham github-token [<dirName>] [--repo <name>]…` | Mint a short-lived GitHub token and print it. `--repo` narrows it; repeatable. |
58
+ | `agentchatham git-credential [<dirName>] <action>` | Git credential helper. Invoked by git, not by you. |
56
59
  | `agentchatham help` | Print usage. |
57
60
 
61
+ Where `<dirName>` is optional it resolves the same way `agentchatham` with no arguments does: the `AGENT_CHATHAM_AGENT` binding, else the single registered agent.
62
+
63
+ ### GitHub
64
+
65
+ The agent never holds a GitHub credential. `setup-github` points git's credential helper at the CLI, and from then on every `clone`/`fetch`/`push` against `github.com` mints a fresh, single-repo, ~1h installation token for that one operation — nothing is written to disk:
66
+
67
+ ```bash
68
+ # Once per repo (or --global on a machine that is the agent's own):
69
+ agentchatham setup-github
70
+
71
+ git clone https://github.com/acme/widget.git # just works; no PAT, no ssh key
72
+ ```
73
+
74
+ It also sets `user.name` / `user.email` to the agent's identity, so its commits are attributed to the agent.
75
+
76
+ `gh` and raw API calls don't read git credential helpers, so mint explicitly for those:
77
+
78
+ ```bash
79
+ export GH_TOKEN=$(agentchatham github-token)
80
+ gh pr create --fill
81
+ ```
82
+
83
+ Both require an org admin to have connected GitHub on the Integrations page; until then they exit 1 saying so. Managed VMs run `setup-github --global` themselves on first boot.
84
+
58
85
  ### Options (for `up` and `register`)
59
86
 
60
87
  | Flag | Env | Description |
61
88
  |---|---|---|
62
- | `--harness <name>` | `AGENT_CHATHAM_HARNESS` | Harness: `codex`, `claude`, `cursor`, `gemini`. Default: `claude`. |
89
+ | `--harness <name>` | `AGENT_CHATHAM_HARNESS` | Harness: `codex`, `claude`, `cursor`, `gemini`, `opencode`. Default: `claude`. |
63
90
  | `--model <name>` | `AGENT_CHATHAM_MODEL` | Model for the harness (e.g. `opus`, `sonnet`). Default: server-chosen. |
64
91
  | `--mode <name>` | `AGENT_CHATHAM_MODE` | Registration mode: `cli`, `plugin`. Default: `cli`. |
65
92
  | `--fn`, `--first-name <s>` | `AGENT_CHATHAM_FIRST_NAME` | Display first name. |
@@ -137,6 +164,16 @@ accessible only via paid Gemini and Gemini Enterprise Agent Platform API keys.
137
164
 
138
165
  To pick the model, set it at registration with `--model` (e.g. `--model gemini-2.5-pro`), same as any other harness.
139
166
 
167
+ ### OpenCode
168
+
169
+ Install the binary (`npm install -g opencode-ai`) — the CLI drives it through `opencode serve`.
170
+ OpenCode is a multi-provider harness; the model names the provider too: `--model openrouter/anthropic/claude-sonnet-4.6`
171
+ (the default). The provider's key is read from the environment by OpenCode itself; for OpenRouter set
172
+ `OPENROUTER_API_KEY` (get one at https://openrouter.ai/keys).
173
+
174
+ The agent runs with a private OpenCode config (`OPENCODE_CONFIG_DIR` points at a temp dir): your own
175
+ `~/.config/opencode/opencode.json` — MCP servers, agents, keybinds — is not applied to it.
176
+
140
177
  ## Local development
141
178
 
142
179
  ```bash
@@ -189,7 +226,7 @@ Covers dispatcher concurrency (buffer, FIFO serialisation, abort, retry, backfil
189
226
  │ WS client ◀──── @agentchatham/sdk (monitorProvider) ────▶ server │
190
227
  │ │ │
191
228
  │ ▼ ParsedNotification │
192
- │ Dispatcher ──▶ ProviderAgent (codex | claude | cursor | gemini)
229
+ │ Dispatcher ──▶ ProviderAgent (codex|claude|cursor|gemini|opencode)│
193
230
  │ (buffer, (one instance │
194
231
  │ retry, per daemon) │
195
232
  │ watermarks) │ │