@divergeai/cli 0.1.2
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 +168 -0
- package/dist/diverge.mjs +9342 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# diverge
|
|
2
|
+
|
|
3
|
+
The Divergent platform CLI: sign in, point coding agents at the platform's
|
|
4
|
+
model gateway, and call platform tools as yourself.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install -g @divergeai/cli
|
|
8
|
+
diverge login # opens the browser; choose your organization
|
|
9
|
+
diverge agents setup claude # Claude Code on the gateway
|
|
10
|
+
diverge agents run dsh -- --profile web --port 3131 --no-open
|
|
11
|
+
diverge tools list --organization-id <id>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Node 22 or later. Linux and macOS are supported; Windows is best-effort.
|
|
15
|
+
|
|
16
|
+
## Sign in
|
|
17
|
+
|
|
18
|
+
`diverge login` runs the browser sign-in (authorization code with PKCE on a
|
|
19
|
+
loopback listener). A login serves exactly one organization: without
|
|
20
|
+
`--organization-id` the platform asks you to choose. The login is cached in
|
|
21
|
+
`~/.diverge/token.json` (mode 0600), refreshes itself, and `diverge logout`
|
|
22
|
+
revokes it on the platform before forgetting it.
|
|
23
|
+
|
|
24
|
+
- `diverge status` shows the deployment, the organization, the scopes, and a
|
|
25
|
+
`Tool execution:` line naming who a tool call would run as: you, or a
|
|
26
|
+
delegated `DIVERGENT_USER_ID` through service credentials. Read it before
|
|
27
|
+
granting anything.
|
|
28
|
+
- The CLI names the account it acts as — `Signed in as:` on `login` and
|
|
29
|
+
`status`, `Acting as:` before every `tools` request — because a token
|
|
30
|
+
names only a user id and the wrong account is invisible without the email:
|
|
31
|
+
use the operator account for operator work, and the break-glass account
|
|
32
|
+
only knowingly.
|
|
33
|
+
- A login is for one account. `diverge login --as <email>` tells the platform
|
|
34
|
+
which one; it signs that account in instead of reusing whatever session the
|
|
35
|
+
browser holds and issues nothing to any other. Without `--as` the account
|
|
36
|
+
of the last login is kept, so switching accounts is always explicit.
|
|
37
|
+
- A login also remembers its scopes: without `--scopes` the next login asks
|
|
38
|
+
for the same ones, so a routine re-login never narrows what the CLI may do.
|
|
39
|
+
A token carries only what was asked at sign-in; the Forge scopes
|
|
40
|
+
(`forge:read forge:write`) are what the Forge lanes need.
|
|
41
|
+
- `diverge token` prints a fresh access token and nothing else. It is the
|
|
42
|
+
credential helper Claude Code and Codex call, so an agent never holds a
|
|
43
|
+
long-lived key.
|
|
44
|
+
- `diverge login --api-url <url>` targets another deployment and remembers it;
|
|
45
|
+
`DIVERGENT_API_URL` overrides per shell.
|
|
46
|
+
|
|
47
|
+
## Coding agents
|
|
48
|
+
|
|
49
|
+
`diverge agents setup <agent>` writes the configuration one agent needs to use
|
|
50
|
+
the gateway, keeping everything else in the file:
|
|
51
|
+
|
|
52
|
+
| agent | what is written |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| `claude` | `~/.claude/settings.json` (or `./.claude/settings.local.json` with `--scope project`): the gateway base URL and `diverge token` as the key helper; `--project-id` adds the project header, `--model-discovery` lets Claude Code list the gateway's models |
|
|
55
|
+
| `opencode` | `~/.config/opencode/opencode.json`: a `divergent-<surface>` provider reading `DIVERGENT_TOKEN` |
|
|
56
|
+
| `codex` | `~/.codex/config.toml`: a `divergent` provider block with `diverge token` as its auth command; `--print` shows it instead |
|
|
57
|
+
| `dsh` | `$DSH_HOME/divergent-<surface>.yml`: a patch overlay with the models the gateway serves, dsh's DeepSeek adapter, telemetry upload and search turned off, and the platform's web search served over `diverge tools bridge` (row `mcp-divergent`) |
|
|
58
|
+
|
|
59
|
+
`diverge agents run dsh` launches DeepSeek Harness on the overlay and keeps
|
|
60
|
+
its token fresh in dsh's own credentials file until it exits. With nothing
|
|
61
|
+
else it starts dsh's web UI and prints the URL; `diverge agents run dsh --
|
|
62
|
+
"<task>"` answers one task headless and exits; anything after `--` goes to
|
|
63
|
+
dsh as given.
|
|
64
|
+
|
|
65
|
+
`diverge agents status` shows the organization, the scopes, and the models
|
|
66
|
+
each surface serves. `diverge agents rotate` keeps a token file fresh
|
|
67
|
+
(default `~/.divergent/token`, every 600 seconds; `--once` writes and exits)
|
|
68
|
+
for a client that reads a file or an environment substitution rather than
|
|
69
|
+
running a helper.
|
|
70
|
+
|
|
71
|
+
### Web search
|
|
72
|
+
|
|
73
|
+
Claude Code and Codex search through their model vendor's own server tool,
|
|
74
|
+
which the gateway forwards unchanged when the organization's upstream is
|
|
75
|
+
Anthropic or OpenAI. Every other model, dsh included, searches through the
|
|
76
|
+
platform's `search_online` tool: one key on the platform, metered and audited
|
|
77
|
+
per organization. The dsh overlay wires it in as `mcp__divergent__search_online`
|
|
78
|
+
(dsh's DeepSeek-backed `web_search` needs a vendor key and is off; `web_fetch`
|
|
79
|
+
stays). In dsh's web profile the shipped agent presets still list `web_search`,
|
|
80
|
+
where a patch cannot reach; it fails loudly and the model uses the bridge's
|
|
81
|
+
tool listed beside it. To give Claude Code or Codex the same tool for a
|
|
82
|
+
non-native upstream, register the bridge once:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
claude mcp add --scope user divergent -- diverge tools bridge --tools search_online
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```toml
|
|
89
|
+
# ~/.codex/config.toml
|
|
90
|
+
[mcp_servers.divergent]
|
|
91
|
+
command = "diverge"
|
|
92
|
+
args = ["tools", "bridge", "--tools", "search_online"]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Platform tools
|
|
96
|
+
|
|
97
|
+
Every command takes the scope it acts in: `--organization-id` (or
|
|
98
|
+
`DIVERGENT_ORG_ID`, else the organization the login was issued to) and, for a
|
|
99
|
+
resource inside a project, `--project-id` (or `DIVERGENT_PROJECT_ID`).
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
diverge tools list --filter rbac # find candidates
|
|
103
|
+
diverge tools describe rbac_assign_role # one schema, on demand
|
|
104
|
+
diverge tools call rbac_list_roles --args-json '{}'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
A write that needs a human is not refused: it is persisted as a pending
|
|
108
|
+
invocation, decided in the platform's approval inbox, and read back here by
|
|
109
|
+
id. Branch on the exit code, never on text:
|
|
110
|
+
|
|
111
|
+
| code | meaning |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| 0 | executed, or approved and executed |
|
|
114
|
+
| 3 | pending: hand over the link, read it back later with `diverge tools invocation <id>` (add `--wait` to stay attached) |
|
|
115
|
+
| 4 | rejected, with the operator's reason |
|
|
116
|
+
| 5 | expired: raise a fresh call, the old id is final |
|
|
117
|
+
| 1 | failure, including approved-but-failed |
|
|
118
|
+
|
|
119
|
+
The CLI raises and reads; it never decides. `diverge tools bridge` serves the
|
|
120
|
+
same catalog as a stdio MCP server for clients without a shell, with
|
|
121
|
+
`divergent_invocation_status` for the read-back. `--tools <name,name>` publishes
|
|
122
|
+
and accepts only those tools: the whole catalog is tens of thousands of tokens
|
|
123
|
+
on every request, so a harness gets the tools it was given and nothing else.
|
|
124
|
+
|
|
125
|
+
## Tenant plugins
|
|
126
|
+
|
|
127
|
+
A tenant plugin is a plugin whose code runs in your organization's own
|
|
128
|
+
runtime and never inside the platform: the platform knows it through a
|
|
129
|
+
manifest (`@divergent/plugin-contract`), enables it per organization, and
|
|
130
|
+
reaches it through your bridge binding. See
|
|
131
|
+
[RFC: Tenant Plugins](../../docs/rfcs/rfc-tenant-plugins.md).
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
diverge plugins validate manifest.json # dry run: every problem the platform would refuse, at once
|
|
135
|
+
diverge plugins publish manifest.json # forge_plugins:create in the login's organization
|
|
136
|
+
diverge plugins list
|
|
137
|
+
diverge plugins retire <pluginId> # the descriptor and its tools go; installations stay
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Tools are pinned to the manifest: a change is a new version published again.
|
|
141
|
+
After publishing, enable the plugin with `forge_set_plugin_state` (or the
|
|
142
|
+
Forge Routing page) and bind the runtime with a bridge binding whose
|
|
143
|
+
`runtimeType` equals the manifest's `runtime.type`; declare `networkPolicy`
|
|
144
|
+
on the binding when the endpoint is a tailnet or LAN address.
|
|
145
|
+
|
|
146
|
+
## Updating
|
|
147
|
+
|
|
148
|
+
`diverge update` installs the latest release with the npm that installed it.
|
|
149
|
+
|
|
150
|
+
## Environment
|
|
151
|
+
|
|
152
|
+
| variable | effect |
|
|
153
|
+
| --- | --- |
|
|
154
|
+
| `DIVERGENT_API_URL` | the deployment for this shell |
|
|
155
|
+
| `DIVERGE_HOME` | state directory, default `~/.diverge` |
|
|
156
|
+
| `DIVERGENT_ORG_ID`, `DIVERGENT_PROJECT_ID` | tool scope when the flags are omitted; without either, the login's organization |
|
|
157
|
+
| `DIVERGENT_CLIENT_ID`, `DIVERGENT_CLIENT_SECRET`, `DIVERGENT_USER_ID` | unattended tool execution with service credentials, delegated to that person |
|
|
158
|
+
| `DSH_HOME` | where dsh keeps its files, default `~/.dsh` |
|
|
159
|
+
|
|
160
|
+
## Security
|
|
161
|
+
|
|
162
|
+
Public OAuth client with PKCE; a sign-in carries the scopes your roles back
|
|
163
|
+
at the organization and omits the rest (`diverge login` says which); access tokens live one hour; refresh tokens
|
|
164
|
+
rotate and a replay revokes the session; the cache is written with mode 0600
|
|
165
|
+
from its first byte; `logout` revokes on the platform; every request carries
|
|
166
|
+
`User-Agent: diverge/<version>`, which the platform records as the calling
|
|
167
|
+
client. The package carries no secret. Released from GitHub Actions by npm
|
|
168
|
+
trusted publishing, so no publish token exists.
|