@ours.network/fleet 0.10.0-nightly.2 → 0.10.0-nightly.3
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 +17 -20
- package/dist/cli.js +7 -2
- package/dist/docs.d.ts +7 -0
- package/dist/docs.js +177 -0
- package/dist/doctor.js +15 -0
- package/dist/harness/acp-agent.d.ts +11 -0
- package/dist/harness/acp-agent.js +27 -0
- package/dist/harness/claude-code.js +2 -1
- package/dist/harness/codex.js +2 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ The state dir contract:
|
|
|
75
75
|
|---|---|---|
|
|
76
76
|
| Node ≥ 20 | runs `ours-fleet` itself | nodejs.org, `apt`, or `brew` |
|
|
77
77
|
| tmux | roles using `session: tmux` (the default) | `apt install tmux` / `brew install tmux` |
|
|
78
|
-
|
|
|
78
|
+
| Node ≥ 22 | Claude roles using `session: acp` | required by the maintained Claude ACP adapter |
|
|
79
79
|
| a harness CLI, logged in | the agent itself | e.g. Claude Code (`claude`) or Codex CLI (`codex`) |
|
|
80
80
|
| `ours-mcp` daemon | identity + agent-to-agent messaging | `npm i -g @ours.network/mcp && ours-mcp start` |
|
|
81
81
|
|
|
@@ -91,6 +91,12 @@ ours-fleet init # units/dirs/linger for this user
|
|
|
91
91
|
ours-fleet doctor # verifies everything above, with actionable messages
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
The maintained Codex and Claude ACP adapters install as optional dependencies of
|
|
95
|
+
`ours-fleet` and are resolved internally; users do not install adapter commands
|
|
96
|
+
or add them to `PATH`. An explicit `session_options.acp.command` remains
|
|
97
|
+
available for custom adapters. On Node 20–21, tmux and Codex ACP remain
|
|
98
|
+
available, while maintained Claude ACP requires upgrading to Node 22.
|
|
99
|
+
|
|
94
100
|
Each OS user manages their own fleet — to host roles under a sandboxed account,
|
|
95
101
|
become that account and repeat.
|
|
96
102
|
|
|
@@ -123,21 +129,11 @@ ours-fleet spawn Coder --harness codex --model gpt-5.4 \
|
|
|
123
129
|
Permanent spawns are written to `~/fleet.d/<Name>.yaml` — your hand-written
|
|
124
130
|
`~/fleet.yaml` is **never** machine-edited. `ours-fleet rm <Name>` unspawns.
|
|
125
131
|
|
|
126
|
-
From inside Claude Code
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
From inside Codex, install the native fleet plugin:
|
|
132
|
-
|
|
133
|
-
```sh
|
|
134
|
-
npm i -g @ours.network/fleet-codex
|
|
135
|
-
ours-fleet-codex-install
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
Start a new Codex session and say **"spawn an ours agent …"**. The bundled skill
|
|
139
|
-
walks through lifetime, model, sandbox, approval policy, profile, launcher, and
|
|
140
|
-
mail-monitor consent, then verifies the real tmux session and offers oversight.
|
|
132
|
+
From inside Claude Code, Codex, or Hermes with the core `ours` plugin installed,
|
|
133
|
+
say **"spawn an ours agent …"**. The core skill checks for `ours-fleet`, installs
|
|
134
|
+
and initializes it when absent, then consults `ours-fleet docs` for the exact
|
|
135
|
+
version-matched workflow. The older fleet-specific harness packages remain
|
|
136
|
+
published for compatibility but are no longer required or installed by default.
|
|
141
137
|
|
|
142
138
|
## Oversight ("keep an eye")
|
|
143
139
|
|
|
@@ -165,6 +161,7 @@ roles:
|
|
|
165
161
|
## Command reference
|
|
166
162
|
|
|
167
163
|
```
|
|
164
|
+
ours-fleet docs | man AI-friendly complete reference
|
|
168
165
|
ours-fleet up|down|restart|force-restart [-c FILE] [Name...]
|
|
169
166
|
ours-fleet config [-c FILE] validate + print merged plan
|
|
170
167
|
ours-fleet ls | attach | peek | logs [-f] | status <Name>
|
|
@@ -301,11 +298,11 @@ console later; no terminal UI is part of the monitor or session backend.
|
|
|
301
298
|
|
|
302
299
|
## Codex roles
|
|
303
300
|
|
|
304
|
-
Install Codex, the native ours plugin, and the fleet
|
|
301
|
+
Install Codex, the native ours plugin, and the fleet CLI once on the fleet host:
|
|
305
302
|
|
|
306
303
|
```sh
|
|
307
|
-
npm i -g @ours.network/fleet
|
|
308
|
-
ours-fleet
|
|
304
|
+
npm i -g @ours.network/fleet
|
|
305
|
+
ours-fleet init
|
|
309
306
|
ours-fleet doctor --harness codex
|
|
310
307
|
```
|
|
311
308
|
|
|
@@ -407,7 +404,7 @@ cleanly as long as each role has its own `cwd` (the common case); two roles
|
|
|
407
404
|
sharing an identical `cwd` could have their resumes cross — give them distinct
|
|
408
405
|
working directories if that matters. MCP and monitor wiring is provided by
|
|
409
406
|
[`@ours.network/codex`](https://github.com/adapt-toolkit/ours-mcp/tree/main/packages/codex);
|
|
410
|
-
the
|
|
407
|
+
the core ours skill discovers fleet behavior through `ours-fleet docs`.
|
|
411
408
|
`ours-fleet doctor --harness codex` verifies the CLI, ours plugin, and enhanced launcher/fallback.
|
|
412
409
|
|
|
413
410
|
## Learn more
|
package/dist/cli.js
CHANGED
|
@@ -14,6 +14,7 @@ import { up, down, restartRoles, rmRole } from './ops.js';
|
|
|
14
14
|
import { runOnce, runTemp } from './runner.js';
|
|
15
15
|
import { spawnPermanent, spawnTemp } from './spawn.js';
|
|
16
16
|
import { doctor } from './doctor.js';
|
|
17
|
+
import { AI_DOCS } from './docs.js';
|
|
17
18
|
import { controlRequest, controlSocketPath, followControl, } from './session/control.js';
|
|
18
19
|
import './harness/claude-code.js'; // registers the claude-code adapter
|
|
19
20
|
import './harness/codex.js'; // registers the codex adapter
|
|
@@ -39,10 +40,14 @@ const passthrough = (cmd, args) => new Promise(resolve => {
|
|
|
39
40
|
});
|
|
40
41
|
const program = new Command()
|
|
41
42
|
.name('ours-fleet')
|
|
42
|
-
.description('Fleet of persistent, identity-bound AI agents — harness
|
|
43
|
+
.description('Fleet of persistent, identity-bound AI agents — selectable harness and tmux/ACP sessions.')
|
|
43
44
|
.version(VERSION);
|
|
44
45
|
const cOpt = (cmd) => cmd.option('-c, --configuration <file>', 'config file (default: ~/fleet.yaml + ~/fleet.d/)');
|
|
45
46
|
const collect = (value, previous) => [...previous, value];
|
|
47
|
+
program.command('docs')
|
|
48
|
+
.alias('man')
|
|
49
|
+
.description('print the complete AI-friendly command and configuration reference')
|
|
50
|
+
.action(() => { process.stdout.write(AI_DOCS); });
|
|
46
51
|
function acpStateDir(name) {
|
|
47
52
|
const permanent = agentDir(name);
|
|
48
53
|
if (existsSync(controlSocketPath(permanent)))
|
|
@@ -306,7 +311,7 @@ cOpt(program.command('rm <name>').description('stop + delete state dir (+ its fl
|
|
|
306
311
|
}
|
|
307
312
|
});
|
|
308
313
|
cOpt(program.command('spawn <name>').description('spawn a new agent (permanent by default)'))
|
|
309
|
-
.option('--temp', 'temporary:
|
|
314
|
+
.option('--temp', 'temporary: detached supervisor, auto-cleaned, gone on reboot')
|
|
310
315
|
.option('--harness <id>', 'harness adapter (default: defaults.harness)')
|
|
311
316
|
.option('--session <backend>', 'session backend: tmux|acp (default: defaults.session or tmux)')
|
|
312
317
|
.option('--mission <text>', 'one-line mission')
|
package/dist/docs.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable, AI-friendly CLI and configuration reference.
|
|
3
|
+
*
|
|
4
|
+
* Keep this concise enough to place directly in an agent context. Unlike
|
|
5
|
+
* Commander's per-command help, this describes how the pieces compose.
|
|
6
|
+
*/
|
|
7
|
+
export declare const AI_DOCS = "# ours-fleet reference\n\nours-fleet runs persistent or temporary, identity-bound AI roles. A role selects\na harness independently from its session backend:\n\n- harness: `claude-code` or `codex`\n- session: `tmux` (default) or `acp`\n- lifetime: permanent (supervised, restartable) or `spawn --temp`\n\n## Discover and validate\n\n```sh\nours-fleet docs # this complete reference (`man` is an alias)\nours-fleet help <command> # exact flags for one command\nours-fleet config [-c FILE] # validate and print the merged plan; no changes\nours-fleet doctor [-c FILE] [--harness codex|claude-code]\n```\n\nDefault configuration is `~/fleet.yaml` plus sorted `~/fleet.d/*.yaml` role\ndrop-ins. An explicit `-c FILE` replaces `~/fleet.yaml`; fleet.d still adds\nroles. Validate with `config` and `doctor` before starting or restarting.\n\n## Lifecycle and console commands\n\n```sh\nours-fleet init\nours-fleet up|down [Name...]\nours-fleet restart [Name...] # preserve/resume harness context\nours-fleet force-restart [Name...] # fresh context; briefing is reloaded\nours-fleet ls\nours-fleet status|peek|attach|logs Name\nours-fleet logs -f Name\nours-fleet send Name \"prompt\"\nours-fleet send Name --key Enter # tmux only\nours-fleet rm Name\n```\n\n`peek`, `attach`, and text `send` work with tmux and ACP. ACP attachment\nalso accepts `/permit <permission-id> <option-id>`, `/interrupt`, and\n`/detach`. Raw `--key` input is tmux-only.\n\n## Spawn\n\n```sh\nours-fleet spawn [--temp] Name \\\n --harness codex|claude-code --session tmux|acp \\\n --mission \"one line\" --cwd /absolute/path --identity Identity \\\n --coordinator Coordinator --model MODEL \\\n --approval ask|allow|deny \\\n --filesystem read-only|workspace|unrestricted \\\n --unattended deny|wait \\\n --bio-file /path/bio.md --persona-file /path/persona.md\n```\n\nPermanent spawn writes `~/fleet.d/Name.yaml` and starts a supervised role.\n`--temp` writes ephemeral state, starts a detached supervisor, and removes the\nrole after exit/reboot. Both lifetimes support `--session acp`.\n\nCodex-specific spawn flags: `--sandbox`, `--permission-mode`, `--launcher`,\n`--profile`, `--search`, repeatable `--codex-config key=value`, repeatable\n`--add-dir`, and `--monitor`. Run `ours-fleet help spawn` for exact values.\n\n## fleet.yaml\n\n```yaml\nvars:\n work_root: /home/me/work\nstart_stagger_ms: 0\ndefaults:\n harness: codex\n session: acp\n model: gpt-model-id\n permissions:\n approval: ask\n filesystem: workspace\n unattended: deny\n monitor:\n enabled: true\nroles:\n Coordinator:\n harness: codex\n session: acp\n identity: Coordinator\n cwd: ${work_root}/project\n mission: Coordinate work and delegate implementation.\n model: gpt-model-id\n permissions:\n approval: ask\n filesystem: workspace\n unattended: deny\n session_options: # advanced overrides; normally omit\n # acp:\n # command: [/custom/codex-acp, --flag]\n tmux:\n boot_grace_ms: 10000\n monitor:\n enabled: true\n wake_sources: [message_received, file_received, local_contact_request, pending_message]\n batch_ms: 2000\n inject: notification\n turn_fail_threshold: 3\n harness_options:\n launcher: auto\n sandbox: workspace-write\n approval: on-request\n search: false\n profile: fleet\n add_dirs: [/data/shared]\n config:\n model_reasoning_effort: high\n bio: Public role card and when peers should engage it.\n persona: Local operating contract, boundaries, and escalation policy.\n briefing_file: /absolute/custom-briefing.md\n coordinator: AnotherCoordinator\n env:\n KEY: value\n oversee:\n - { role: Worker, interval: 5m }\n```\n\nRole values override defaults. `${name}` substitutes entries from `vars`.\nOther role fields include `max_tokens`, `autocompact_pct`, and `isolation`.\nUse README.md for the complete isolation policy and resource-cap schema.\n\n## Permissions\n\nPrefer the harness-neutral `permissions` block:\n\n- `approval: ask|allow|deny`: whether actions may request or receive approval\n- `filesystem: read-only|workspace|unrestricted`: filesystem intent\n- `unattended: deny|wait`: what ACP does when no console can answer a request\n\nThe backend translates this common intent. Harness-native settings in\n`harness_options` take precedence where supplied. Do not choose\n`allow`/`unrestricted`, Codex `never`/`danger-full-access`, or Claude\n`bypassPermissions` without explicit authorization.\n\nClaude `harness_options`: `permission_mode` (default, acceptEdits, plan,\ndontAsk, bypassPermissions), `plugins`, `mem_palace`, and\n`mem_palace_midsession_autosave`.\n\nCodex `harness_options`: `launcher` (auto, ours-codex, codex), `sandbox`\n(read-only, workspace-write, danger-full-access), `approval` or\n`permission_mode` (untrusted, on-request, never), `profile`, `search`,\n`config`, `add_dirs`, and `monitor`.\n\n## ACP adapters\n\nThe maintained `@agentclientprotocol/codex-acp` and\n`@agentclientprotocol/claude-agent-acp` runtimes are bundled automatically as\noptional ours-fleet dependencies. The supervisor resolves their executable\nentrypoints internally, so default ACP roles do not depend on global PATH.\nThe maintained Claude adapter requires Node 22; tmux and Codex ACP continue to\nwork on the ours-fleet core minimum of Node 20.\n\nOverride an adapter only when necessary with `session_options.acp.command`\n(string or argv list). If optional dependencies were deliberately omitted,\nours-fleet falls back to a compatible globally installed `codex-acp` or\n`claude-agent-acp`. `ours-fleet doctor -c FILE` verifies the resolved adapter.\n\n## Reliable mail wake\n\nThe supervisor monitor is enabled by default. It consumes body-free daemon\nevents and advances its durable cursor only after delivery is accepted. ACP uses\na structured `session/prompt`; tmux uses verified console injection. Message\nbodies are released only when the role calls the ours `get_messages` tool.\n\nSet `monitor.enabled: false` only to retain legacy in-session monitoring.\nInspect `ours-fleet status Name`, `peek Name`, role logs, and\n`~/.ours-fleet/agents/Name/.monitor-status` when diagnosing delivery.\n";
|
package/dist/docs.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable, AI-friendly CLI and configuration reference.
|
|
3
|
+
*
|
|
4
|
+
* Keep this concise enough to place directly in an agent context. Unlike
|
|
5
|
+
* Commander's per-command help, this describes how the pieces compose.
|
|
6
|
+
*/
|
|
7
|
+
export const AI_DOCS = `# ours-fleet reference
|
|
8
|
+
|
|
9
|
+
ours-fleet runs persistent or temporary, identity-bound AI roles. A role selects
|
|
10
|
+
a harness independently from its session backend:
|
|
11
|
+
|
|
12
|
+
- harness: \`claude-code\` or \`codex\`
|
|
13
|
+
- session: \`tmux\` (default) or \`acp\`
|
|
14
|
+
- lifetime: permanent (supervised, restartable) or \`spawn --temp\`
|
|
15
|
+
|
|
16
|
+
## Discover and validate
|
|
17
|
+
|
|
18
|
+
\`\`\`sh
|
|
19
|
+
ours-fleet docs # this complete reference (\`man\` is an alias)
|
|
20
|
+
ours-fleet help <command> # exact flags for one command
|
|
21
|
+
ours-fleet config [-c FILE] # validate and print the merged plan; no changes
|
|
22
|
+
ours-fleet doctor [-c FILE] [--harness codex|claude-code]
|
|
23
|
+
\`\`\`
|
|
24
|
+
|
|
25
|
+
Default configuration is \`~/fleet.yaml\` plus sorted \`~/fleet.d/*.yaml\` role
|
|
26
|
+
drop-ins. An explicit \`-c FILE\` replaces \`~/fleet.yaml\`; fleet.d still adds
|
|
27
|
+
roles. Validate with \`config\` and \`doctor\` before starting or restarting.
|
|
28
|
+
|
|
29
|
+
## Lifecycle and console commands
|
|
30
|
+
|
|
31
|
+
\`\`\`sh
|
|
32
|
+
ours-fleet init
|
|
33
|
+
ours-fleet up|down [Name...]
|
|
34
|
+
ours-fleet restart [Name...] # preserve/resume harness context
|
|
35
|
+
ours-fleet force-restart [Name...] # fresh context; briefing is reloaded
|
|
36
|
+
ours-fleet ls
|
|
37
|
+
ours-fleet status|peek|attach|logs Name
|
|
38
|
+
ours-fleet logs -f Name
|
|
39
|
+
ours-fleet send Name "prompt"
|
|
40
|
+
ours-fleet send Name --key Enter # tmux only
|
|
41
|
+
ours-fleet rm Name
|
|
42
|
+
\`\`\`
|
|
43
|
+
|
|
44
|
+
\`peek\`, \`attach\`, and text \`send\` work with tmux and ACP. ACP attachment
|
|
45
|
+
also accepts \`/permit <permission-id> <option-id>\`, \`/interrupt\`, and
|
|
46
|
+
\`/detach\`. Raw \`--key\` input is tmux-only.
|
|
47
|
+
|
|
48
|
+
## Spawn
|
|
49
|
+
|
|
50
|
+
\`\`\`sh
|
|
51
|
+
ours-fleet spawn [--temp] Name \\
|
|
52
|
+
--harness codex|claude-code --session tmux|acp \\
|
|
53
|
+
--mission "one line" --cwd /absolute/path --identity Identity \\
|
|
54
|
+
--coordinator Coordinator --model MODEL \\
|
|
55
|
+
--approval ask|allow|deny \\
|
|
56
|
+
--filesystem read-only|workspace|unrestricted \\
|
|
57
|
+
--unattended deny|wait \\
|
|
58
|
+
--bio-file /path/bio.md --persona-file /path/persona.md
|
|
59
|
+
\`\`\`
|
|
60
|
+
|
|
61
|
+
Permanent spawn writes \`~/fleet.d/Name.yaml\` and starts a supervised role.
|
|
62
|
+
\`--temp\` writes ephemeral state, starts a detached supervisor, and removes the
|
|
63
|
+
role after exit/reboot. Both lifetimes support \`--session acp\`.
|
|
64
|
+
|
|
65
|
+
Codex-specific spawn flags: \`--sandbox\`, \`--permission-mode\`, \`--launcher\`,
|
|
66
|
+
\`--profile\`, \`--search\`, repeatable \`--codex-config key=value\`, repeatable
|
|
67
|
+
\`--add-dir\`, and \`--monitor\`. Run \`ours-fleet help spawn\` for exact values.
|
|
68
|
+
|
|
69
|
+
## fleet.yaml
|
|
70
|
+
|
|
71
|
+
\`\`\`yaml
|
|
72
|
+
vars:
|
|
73
|
+
work_root: /home/me/work
|
|
74
|
+
start_stagger_ms: 0
|
|
75
|
+
defaults:
|
|
76
|
+
harness: codex
|
|
77
|
+
session: acp
|
|
78
|
+
model: gpt-model-id
|
|
79
|
+
permissions:
|
|
80
|
+
approval: ask
|
|
81
|
+
filesystem: workspace
|
|
82
|
+
unattended: deny
|
|
83
|
+
monitor:
|
|
84
|
+
enabled: true
|
|
85
|
+
roles:
|
|
86
|
+
Coordinator:
|
|
87
|
+
harness: codex
|
|
88
|
+
session: acp
|
|
89
|
+
identity: Coordinator
|
|
90
|
+
cwd: \${work_root}/project
|
|
91
|
+
mission: Coordinate work and delegate implementation.
|
|
92
|
+
model: gpt-model-id
|
|
93
|
+
permissions:
|
|
94
|
+
approval: ask
|
|
95
|
+
filesystem: workspace
|
|
96
|
+
unattended: deny
|
|
97
|
+
session_options: # advanced overrides; normally omit
|
|
98
|
+
# acp:
|
|
99
|
+
# command: [/custom/codex-acp, --flag]
|
|
100
|
+
tmux:
|
|
101
|
+
boot_grace_ms: 10000
|
|
102
|
+
monitor:
|
|
103
|
+
enabled: true
|
|
104
|
+
wake_sources: [message_received, file_received, local_contact_request, pending_message]
|
|
105
|
+
batch_ms: 2000
|
|
106
|
+
inject: notification
|
|
107
|
+
turn_fail_threshold: 3
|
|
108
|
+
harness_options:
|
|
109
|
+
launcher: auto
|
|
110
|
+
sandbox: workspace-write
|
|
111
|
+
approval: on-request
|
|
112
|
+
search: false
|
|
113
|
+
profile: fleet
|
|
114
|
+
add_dirs: [/data/shared]
|
|
115
|
+
config:
|
|
116
|
+
model_reasoning_effort: high
|
|
117
|
+
bio: Public role card and when peers should engage it.
|
|
118
|
+
persona: Local operating contract, boundaries, and escalation policy.
|
|
119
|
+
briefing_file: /absolute/custom-briefing.md
|
|
120
|
+
coordinator: AnotherCoordinator
|
|
121
|
+
env:
|
|
122
|
+
KEY: value
|
|
123
|
+
oversee:
|
|
124
|
+
- { role: Worker, interval: 5m }
|
|
125
|
+
\`\`\`
|
|
126
|
+
|
|
127
|
+
Role values override defaults. \`\${name}\` substitutes entries from \`vars\`.
|
|
128
|
+
Other role fields include \`max_tokens\`, \`autocompact_pct\`, and \`isolation\`.
|
|
129
|
+
Use README.md for the complete isolation policy and resource-cap schema.
|
|
130
|
+
|
|
131
|
+
## Permissions
|
|
132
|
+
|
|
133
|
+
Prefer the harness-neutral \`permissions\` block:
|
|
134
|
+
|
|
135
|
+
- \`approval: ask|allow|deny\`: whether actions may request or receive approval
|
|
136
|
+
- \`filesystem: read-only|workspace|unrestricted\`: filesystem intent
|
|
137
|
+
- \`unattended: deny|wait\`: what ACP does when no console can answer a request
|
|
138
|
+
|
|
139
|
+
The backend translates this common intent. Harness-native settings in
|
|
140
|
+
\`harness_options\` take precedence where supplied. Do not choose
|
|
141
|
+
\`allow\`/\`unrestricted\`, Codex \`never\`/\`danger-full-access\`, or Claude
|
|
142
|
+
\`bypassPermissions\` without explicit authorization.
|
|
143
|
+
|
|
144
|
+
Claude \`harness_options\`: \`permission_mode\` (default, acceptEdits, plan,
|
|
145
|
+
dontAsk, bypassPermissions), \`plugins\`, \`mem_palace\`, and
|
|
146
|
+
\`mem_palace_midsession_autosave\`.
|
|
147
|
+
|
|
148
|
+
Codex \`harness_options\`: \`launcher\` (auto, ours-codex, codex), \`sandbox\`
|
|
149
|
+
(read-only, workspace-write, danger-full-access), \`approval\` or
|
|
150
|
+
\`permission_mode\` (untrusted, on-request, never), \`profile\`, \`search\`,
|
|
151
|
+
\`config\`, \`add_dirs\`, and \`monitor\`.
|
|
152
|
+
|
|
153
|
+
## ACP adapters
|
|
154
|
+
|
|
155
|
+
The maintained \`@agentclientprotocol/codex-acp\` and
|
|
156
|
+
\`@agentclientprotocol/claude-agent-acp\` runtimes are bundled automatically as
|
|
157
|
+
optional ours-fleet dependencies. The supervisor resolves their executable
|
|
158
|
+
entrypoints internally, so default ACP roles do not depend on global PATH.
|
|
159
|
+
The maintained Claude adapter requires Node 22; tmux and Codex ACP continue to
|
|
160
|
+
work on the ours-fleet core minimum of Node 20.
|
|
161
|
+
|
|
162
|
+
Override an adapter only when necessary with \`session_options.acp.command\`
|
|
163
|
+
(string or argv list). If optional dependencies were deliberately omitted,
|
|
164
|
+
ours-fleet falls back to a compatible globally installed \`codex-acp\` or
|
|
165
|
+
\`claude-agent-acp\`. \`ours-fleet doctor -c FILE\` verifies the resolved adapter.
|
|
166
|
+
|
|
167
|
+
## Reliable mail wake
|
|
168
|
+
|
|
169
|
+
The supervisor monitor is enabled by default. It consumes body-free daemon
|
|
170
|
+
events and advances its durable cursor only after delivery is accepted. ACP uses
|
|
171
|
+
a structured \`session/prompt\`; tmux uses verified console injection. Message
|
|
172
|
+
bodies are released only when the role calls the ours \`get_messages\` tool.
|
|
173
|
+
|
|
174
|
+
Set \`monitor.enabled: false\` only to retain legacy in-session monitoring.
|
|
175
|
+
Inspect \`ours-fleet status Name\`, \`peek Name\`, role logs, and
|
|
176
|
+
\`~/.ours-fleet/agents/Name/.monitor-status\` when diagnosing delivery.
|
|
177
|
+
`;
|
package/dist/doctor.js
CHANGED
|
@@ -3,6 +3,7 @@ import { readFileSync } from 'node:fs';
|
|
|
3
3
|
import { realExec } from './exec.js';
|
|
4
4
|
import { loadConfig } from './config.js';
|
|
5
5
|
import { getAdapter } from './harness/registry.js';
|
|
6
|
+
import { resolveBundledAcpAgent } from './harness/acp-agent.js';
|
|
6
7
|
import { agentDir, home, deriveXdgRuntimeDir } from './paths.js';
|
|
7
8
|
import { resolveIsolation } from './isolation/policy.js';
|
|
8
9
|
import { makeBubblewrapBackend } from './isolation/bubblewrap.js';
|
|
@@ -173,6 +174,13 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
|
|
|
173
174
|
}
|
|
174
175
|
for (const role of roles.filter(role => role.session === 'acp')) {
|
|
175
176
|
const configured = role.session_options?.acp?.command;
|
|
177
|
+
const bundled = configured == null
|
|
178
|
+
? role.harness === 'codex'
|
|
179
|
+
? resolveBundledAcpAgent('@agentclientprotocol/codex-acp', 'codex-acp', 'codex-acp')
|
|
180
|
+
: role.harness === 'claude-code'
|
|
181
|
+
? resolveBundledAcpAgent('@agentclientprotocol/claude-agent-acp', 'claude-agent-acp', 'claude-agent-acp')
|
|
182
|
+
: undefined
|
|
183
|
+
: undefined;
|
|
176
184
|
const command = Array.isArray(configured)
|
|
177
185
|
? configured[0]
|
|
178
186
|
: typeof configured === 'string'
|
|
@@ -189,6 +197,13 @@ export async function doctor(opts = {}, exec = realExec, platform = process.plat
|
|
|
189
197
|
});
|
|
190
198
|
continue;
|
|
191
199
|
}
|
|
200
|
+
if (bundled?.bundled) {
|
|
201
|
+
checks.push({
|
|
202
|
+
name: `acp: ${role.name}`, ok: true,
|
|
203
|
+
detail: `${command} bundled with ours-fleet`,
|
|
204
|
+
});
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
192
207
|
const result = await exec('sh', ['-c', 'command -v "$1" >/dev/null 2>&1', 'sh', command]);
|
|
193
208
|
checks.push({
|
|
194
209
|
name: `acp: ${role.name}`,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve an ACP agent shipped as an ours-fleet dependency. Running the JS
|
|
3
|
+
* entrypoint through this process's Node avoids depending on npm exposing a
|
|
4
|
+
* transitive dependency's bin on the user's global PATH.
|
|
5
|
+
*/
|
|
6
|
+
export interface AcpAgentResolution {
|
|
7
|
+
argv: string[];
|
|
8
|
+
bundled: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function resolveBundledAcpAgent(packageName: string, binName: string, fallbackCommand: string): AcpAgentResolution;
|
|
11
|
+
export declare function bundledAcpAgent(packageName: string, binName: string, fallbackCommand: string): string[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
export function resolveBundledAcpAgent(packageName, binName, fallbackCommand) {
|
|
6
|
+
try {
|
|
7
|
+
const manifestPath = require.resolve(`${packageName}/package.json`);
|
|
8
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
9
|
+
const relative = typeof manifest.bin === 'string'
|
|
10
|
+
? manifest.bin
|
|
11
|
+
: manifest.bin?.[binName];
|
|
12
|
+
if (!relative)
|
|
13
|
+
return { argv: [fallbackCommand], bundled: false };
|
|
14
|
+
const entrypoint = resolve(dirname(manifestPath), relative);
|
|
15
|
+
if (!existsSync(entrypoint))
|
|
16
|
+
return { argv: [fallbackCommand], bundled: false };
|
|
17
|
+
return { argv: [process.execPath, entrypoint], bundled: true };
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Supports development installs that intentionally omit optional
|
|
21
|
+
// dependencies and existing hosts with a globally installed adapter.
|
|
22
|
+
return { argv: [fallbackCommand], bundled: false };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function bundledAcpAgent(packageName, binName, fallbackCommand) {
|
|
26
|
+
return resolveBundledAcpAgent(packageName, binName, fallbackCommand).argv;
|
|
27
|
+
}
|
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { home } from '../paths.js';
|
|
4
4
|
import { realExec } from '../exec.js';
|
|
5
5
|
import { registerAdapter } from './registry.js';
|
|
6
|
+
import { bundledAcpAgent } from './acp-agent.js';
|
|
6
7
|
const OPTION_KEYS = ['plugins', 'mem_palace', 'mem_palace_midsession_autosave', 'permission_mode'];
|
|
7
8
|
/** Claude Code's accepted --permission-mode values. */
|
|
8
9
|
const PERMISSION_MODES = ['default', 'acceptEdits', 'plan', 'dontAsk', 'bypassPermissions'];
|
|
@@ -119,7 +120,7 @@ export function makeClaudeCodeAdapter(exec = realExec) {
|
|
|
119
120
|
? [...configured]
|
|
120
121
|
: typeof configured === 'string'
|
|
121
122
|
? ['sh', '-c', configured]
|
|
122
|
-
:
|
|
123
|
+
: bundledAcpAgent('@agentclientprotocol/claude-agent-acp', 'claude-agent-acp', 'claude-agent-acp');
|
|
123
124
|
return { argv, env: prep.env };
|
|
124
125
|
},
|
|
125
126
|
translatePermissions(permissions) {
|
package/dist/harness/codex.js
CHANGED
|
@@ -2,6 +2,7 @@ import { join } from 'node:path';
|
|
|
2
2
|
import { agentDir } from '../paths.js';
|
|
3
3
|
import { realExec } from '../exec.js';
|
|
4
4
|
import { registerAdapter } from './registry.js';
|
|
5
|
+
import { bundledAcpAgent } from './acp-agent.js';
|
|
5
6
|
const OPTION_KEYS = [
|
|
6
7
|
'launcher', 'sandbox', 'approval', 'permission_mode', 'search', 'profile', 'config', 'add_dirs',
|
|
7
8
|
'monitor',
|
|
@@ -193,7 +194,7 @@ export function makeCodexAdapter(exec = realExec) {
|
|
|
193
194
|
? [...configured]
|
|
194
195
|
: typeof configured === 'string'
|
|
195
196
|
? ['sh', '-c', configured]
|
|
196
|
-
:
|
|
197
|
+
: bundledAcpAgent('@agentclientprotocol/codex-acp', 'codex-acp', 'codex-acp');
|
|
197
198
|
return { argv, env: prep.env };
|
|
198
199
|
},
|
|
199
200
|
translatePermissions(permissions) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "0.10.0-nightly.
|
|
3
|
+
"version": "0.10.0-nightly.3",
|
|
4
4
|
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, tmux or ACP sessions, supervision, and ours.network messaging.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|
|
@@ -30,6 +30,10 @@
|
|
|
30
30
|
"commander": "^12.1.0",
|
|
31
31
|
"yaml": "^2.5.0"
|
|
32
32
|
},
|
|
33
|
+
"optionalDependencies": {
|
|
34
|
+
"@agentclientprotocol/claude-agent-acp": "^0.63.0",
|
|
35
|
+
"@agentclientprotocol/codex-acp": "^1.1.7"
|
|
36
|
+
},
|
|
33
37
|
"devDependencies": {
|
|
34
38
|
"@types/node": "^20.14.0",
|
|
35
39
|
"typescript": "^5.5.0",
|