@borgee/agents-host 0.2.2 → 0.2.26

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.
Files changed (76) hide show
  1. package/README.md +184 -21
  2. package/dist/agents-host-supervisor.d.ts +7 -5
  3. package/dist/agents-host-supervisor.js +24 -4
  4. package/dist/agents-host.d.ts +89 -15
  5. package/dist/agents-host.js +2099 -141
  6. package/dist/chat/chat-control-plane.d.ts +13 -2
  7. package/dist/chat/sdk-chat-control-plane.d.ts +14 -3
  8. package/dist/chat/sdk-chat-control-plane.js +54 -2
  9. package/dist/cli-args.d.ts +46 -5
  10. package/dist/cli-args.js +313 -32
  11. package/dist/cli.d.ts +9 -0
  12. package/dist/cli.js +112 -5
  13. package/dist/compatibility-gates.d.ts +35 -0
  14. package/dist/compatibility-gates.js +127 -0
  15. package/dist/config.d.ts +1 -0
  16. package/dist/config.js +23 -5
  17. package/dist/connections-state-store.d.ts +81 -0
  18. package/dist/connections-state-store.js +228 -0
  19. package/dist/context/injection.d.ts +109 -0
  20. package/dist/context/injection.js +350 -0
  21. package/dist/context/prompt.d.ts +4 -1
  22. package/dist/context/prompt.js +170 -1
  23. package/dist/context/turn-preparation.d.ts +9 -0
  24. package/dist/context/turn-preparation.js +106 -0
  25. package/dist/debug.d.ts +44 -0
  26. package/dist/debug.js +135 -0
  27. package/dist/gateway/localhost-gateway.d.ts +52 -0
  28. package/dist/gateway/localhost-gateway.js +857 -0
  29. package/dist/index.js +7 -5
  30. package/dist/local-config.d.ts +4 -1
  31. package/dist/local-config.js +24 -7
  32. package/dist/managed-daemon-log.d.ts +34 -0
  33. package/dist/managed-daemon-log.js +261 -0
  34. package/dist/managed-daemon.d.ts +220 -0
  35. package/dist/managed-daemon.js +1601 -0
  36. package/dist/policy/authorization-audit.d.ts +63 -0
  37. package/dist/policy/authorization-audit.js +94 -0
  38. package/dist/policy/copilot-permission.d.ts +15 -0
  39. package/dist/policy/copilot-permission.js +193 -0
  40. package/dist/policy/gateway-authorization.d.ts +42 -0
  41. package/dist/policy/gateway-authorization.js +162 -0
  42. package/dist/providers/awaiting-user.d.ts +12 -0
  43. package/dist/providers/awaiting-user.js +151 -0
  44. package/dist/providers/claude/adapter.d.ts +3 -1
  45. package/dist/providers/claude/adapter.js +8 -12
  46. package/dist/providers/claude/cli-client.d.ts +12 -5
  47. package/dist/providers/claude/cli-client.js +184 -37
  48. package/dist/providers/claude/session-store.d.ts +1 -0
  49. package/dist/providers/codex/adapter.d.ts +11 -0
  50. package/dist/providers/codex/adapter.js +19 -0
  51. package/dist/providers/codex/cli-client.d.ts +103 -0
  52. package/dist/providers/codex/cli-client.js +1133 -0
  53. package/dist/providers/codex/project-doc.d.ts +3 -0
  54. package/dist/providers/codex/project-doc.js +66 -0
  55. package/dist/providers/codex/session-store.d.ts +38 -0
  56. package/dist/providers/codex/session-store.js +150 -0
  57. package/dist/providers/copilot/adapter.d.ts +3 -1
  58. package/dist/providers/copilot/adapter.js +8 -12
  59. package/dist/providers/copilot/cli-client.d.ts +20 -2
  60. package/dist/providers/copilot/cli-client.js +251 -71
  61. package/dist/providers/copilot/session-store.d.ts +1 -0
  62. package/dist/providers/create-provider.d.ts +11 -2
  63. package/dist/providers/create-provider.js +131 -12
  64. package/dist/run.d.ts +1 -0
  65. package/dist/run.js +5 -2
  66. package/dist/state-paths.d.ts +13 -1
  67. package/dist/state-paths.js +84 -3
  68. package/dist/task-thread-resolution.d.ts +10 -0
  69. package/dist/task-thread-resolution.js +48 -0
  70. package/dist/types.d.ts +174 -1
  71. package/dist/visible-mentions.d.ts +3 -0
  72. package/dist/visible-mentions.js +15 -0
  73. package/package.json +19 -17
  74. package/skills/borgee-agent/SKILL.md +33 -0
  75. package/skills/borgee-agent/borgee-agent.mjs +473 -0
  76. package/skills/borgee-agent/borgee-agent.py +409 -0
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Minimal local runtime host for Borgee agents.
4
4
 
5
- - **Single-agent mode** keeps the existing one-process / one-agent flow.
5
+ - **Standalone env mode** keeps the existing one-process / one-agent flow.
6
6
  - **Local-config mode** adds first-step multi-agent local hosting from a host
7
7
  config file plus one config file per agent, with hot reload.
8
8
 
@@ -15,14 +15,15 @@ Borgee channel message
15
15
  → /ws/plugin (BPP)
16
16
  → @borgee/plugin-sdk
17
17
  → AgentsHost.handleMessage
18
- → local claude / copilot CLI subprocess
18
+ → local claude / codex-acp / copilot runtime
19
19
  → BPP reply
20
20
  → Borgee channel
21
21
  ```
22
22
 
23
23
  **In scope:**
24
24
 
25
- - single-agent env / CLI startup
25
+ - standalone env startup
26
+ - foreground CLI startup for one hosted agent
26
27
  - local-config multi-agent startup
27
28
  - one isolated `AgentsHost` per effective agent key
28
29
  - per-channel conversation memory via each provider's native session mechanism
@@ -48,14 +49,22 @@ For the published CLI entry point:
48
49
 
49
50
  ```bash
50
51
  agents-host start <serverUrl> <apiKey> [options]
51
- agents-host start --config <path-to-host-config>
52
+ agents-host start-managed <serverUrl>
53
+ agents-host start-managed <serverUrl> <apiKey> [agent-options]
54
+ agents-host describe-managed <serverUrl>
55
+ agents-host apply-managed <serverUrl> --stdin
56
+ agents-host apply-managed <serverUrl> --spec-json <json>
57
+ agents-host log <serverUrl> [--lines <n>] [--follow]
58
+ agents-host log <serverUrl> --path
59
+ agents-host start --config <path-to-host-config> [--debug]
52
60
  agents-host validate --config <path-to-host-config>
61
+ agents-host describe --config <path-to-host-config>
53
62
  agents-host print-layout --root <dir>
54
63
  agents-host generate-config --root <dir> --stdin
55
64
  agents-host generate-config --root <dir> --spec-json <json>
56
65
  ```
57
66
 
58
- ## Single-agent mode
67
+ ## Standalone env mode
59
68
 
60
69
  Use the existing env-var flow when you want exactly one hosted agent per
61
70
  process.
@@ -68,21 +77,142 @@ RUNTIME_PROVIDER=claude \
68
77
  pnpm --filter @borgee/agents-host dev
69
78
  ```
70
79
 
80
+ Codex remains opt-in. Select `RUNTIME_PROVIDER=codex` only when `AGENTS_HOST_INTERNAL_COMPATIBILITY_GATES` includes `codex-provider`.
81
+
71
82
  Or with the CLI:
72
83
 
73
84
  ```bash
74
- agents-host start https://your-borgee-server bgr_xxxxxxxx --provider copilot
85
+ agents-host start https://your-borgee-server bgr_xxxxxxxx --provider copilot --debug
86
+ ```
87
+
88
+ ## Managed daemon bootstrap mode
89
+
90
+ `agents-host start-managed` has two forms:
91
+
92
+ - `agents-host start-managed <serverUrl> <apiKey> [agent-options]` bootstraps or
93
+ reuses the per-server managed daemon, then upserts the requested agent
94
+ - `agents-host start-managed <serverUrl>` restarts or resumes an already-managed
95
+ runtime for that server without re-supplying the agent API key or options
96
+
97
+ Unlike foreground `start`, both forms exit after the managed daemon is ready,
98
+ and the full form additionally waits for the requested agent reconcile.
99
+
100
+ It:
101
+
102
+ 1. resolves a managed runtime root under `~/.borgee/agents-host/managed/`
103
+ specific to that normalized `serverUrl`
104
+ 2. reuses the daemon already serving that runtime root when it is alive
105
+ 3. otherwise starts one local supervisor daemon for that managed root and waits
106
+ for it to become ready
107
+ 4. for the full `<serverUrl> <apiKey> ...` form only, upserts the requested
108
+ agent and waits for that reconcile before reporting success
109
+
110
+ The short resume form does **not** auto-seed a new managed runtime. It fails
111
+ clearly unless that serverUrl already has a persisted managed config with at
112
+ least one persisted agent entry from an earlier full
113
+ `start-managed <serverUrl> <apiKey> ...` bootstrap. Those persisted agents may
114
+ all currently be disabled; the managed runtime is still considered bootstrapped
115
+ and resumable in that case.
116
+
117
+ Each managed runtime root keeps:
118
+
119
+ - `agents-host.yaml` and `agents/` as the stable generated local-config entrypoints
120
+ - `daemon.log` as the detached managed daemon stdout/stderr log file
121
+ - `.state/` as the per-agent runtime state base
122
+ - `ctl.sock` as the local control socket
123
+
124
+ Detached `start-managed` daemon launches append both stdout and stderr to
125
+ `<managed-root>/daemon.log`. This change does not add rotation or truncation;
126
+ the daemon keeps appending to the same private log file until tooling or the
127
+ operator moves or clears it.
128
+
129
+ This MVP does not migrate legacy `~/.borgee/agents-host/single-agent` state
130
+ into the managed runtime root.
131
+
132
+ Agent identities generated through `start-managed` are internal and stable for
133
+ the same API key within one server runtime root; repeated starts with the same
134
+ API key replace that generated agent entry instead of appending duplicates.
135
+
136
+ Example:
137
+
138
+ ```bash
139
+ agents-host start-managed https://your-borgee-server bgr_xxxxxxxx --provider copilot
140
+ agents-host start-managed https://your-borgee-server
141
+ ```
142
+
143
+ ### Machine-oriented managed-runtime commands
144
+
145
+ `describe-managed` and `apply-managed` are JSON-only commands for machine callers.
146
+ They operate on the same per-server managed runtime root as `start-managed`, but
147
+ they expose full-set managed-runtime state instead of the legacy single-agent
148
+ upsert flow.
149
+
150
+ ```bash
151
+ agents-host describe-managed https://your-borgee-server
152
+ printf '%s' '{"host":{"borgeeBaseUrl":"https://your-borgee-server"},"agents":[{"key":"cp1","name":"Copilot","apiKey":"bgr_xxx","provider":"copilot"}]}' \
153
+ | agents-host apply-managed https://your-borgee-server --stdin
154
+ ```
155
+
156
+ - `describe-managed` prints one JSON object to stdout only:
157
+ - `{ "ok": true, "present": false }`
158
+ - `{ "ok": true, "present": true, "spec": { ... } }`
159
+ - `{ "ok": false, "error": { "code": "...", "message": "..." } }`
160
+ - `apply-managed` accepts one full-set managed spec, validates that its
161
+ `host.borgeeBaseUrl` matches the requested runtime binding, rejects empty
162
+ full-set specs, then prints one JSON object to stdout only
163
+ - expected managed failures are reported as structured JSON on stdout and exit 0
164
+ - malformed CLI usage still follows the normal usage stderr + non-zero exit path
165
+ - `--stdin` is preferred because `--spec-json` exposes the JSON in process
166
+ arguments
167
+
168
+ ### Managed daemon logs
169
+
170
+ Resolve or stream the managed daemon log for one server runtime directly from the
171
+ managed runtime root helpers:
172
+
173
+ ```bash
174
+ agents-host log https://your-borgee-server
175
+ agents-host log https://your-borgee-server --lines 0 --follow
176
+ agents-host log https://your-borgee-server --path
75
177
  ```
76
178
 
77
- ### Environment variables / equivalent single-agent CLI flags
179
+ - default output prints the last 100 log lines
180
+ - `--follow` keeps polling for appended content and resumes after truncation or
181
+ replacement
182
+ - `--lines <n>` accepts non-negative integers only; `0` suppresses the initial
183
+ tail before follow mode
184
+ - `--path` prints only the resolved log path and does not require the file to
185
+ exist yet
186
+
187
+ ### Debug mode
188
+
189
+ Enable extra host/provider lifecycle logs with either:
190
+
191
+ ```bash
192
+ agents-host start https://your-borgee-server bgr_xxxxxxxx --provider copilot --debug
193
+ AGENTS_HOST_DEBUG=1 agents-host start --config ./agents-host.yaml
194
+ ```
195
+
196
+ Notes:
197
+
198
+ - `--debug` applies to foreground `start <serverUrl> <apiKey>` and `start --config <path>`
199
+ - `AGENTS_HOST_DEBUG=1` is the env fallback for both the CLI and `pnpm --filter @borgee/agents-host dev`
200
+ - `start-managed` intentionally does not accept `--debug` or `AGENTS_HOST_DEBUG=1`, because it may reuse an already-running daemon whose log mode is already fixed
201
+ - host-authored debug logs stay secret-safe: they avoid API keys, raw prompt text, raw replies, and other sensitive tokens
202
+ - Copilot child-process stderr is passed through only in debug mode
203
+ - local-config mode prefixes debug logs with the managed agent key so interleaved output stays readable
204
+
205
+ ### Environment variables / equivalent single-agent agent options
78
206
 
79
207
  | Variable | CLI flag | Required | Default | Description |
80
208
  | ---------------------------------- | -------------------------------------- | -------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------ |
81
209
  | `BORGEE_BASE_URL` | positional `<serverUrl>` | yes | — | Borgee server base URL |
82
210
  | `BORGEE_AGENT_API_KEY` | positional `<apiKey>` | yes | — | Agent API key from the web UI |
211
+ | `AGENTS_HOST_DEBUG` | `--debug` | no | off | Extra host/provider lifecycle logs. Set `AGENTS_HOST_DEBUG=1` to enable without the CLI flag. |
83
212
  | `BORGEE_AGENT_NAME` | `--name` | no | `Assistant` | Display name used in prompts |
84
- | `RUNTIME_PROVIDER` | `--provider` | no | `claude` | `claude` or `copilot` |
213
+ | `RUNTIME_PROVIDER` | `--provider` | no | `claude` | `claude`, `copilot`, or `codex` when `codex-provider` is enabled |
85
214
  | `CLAUDE_COMMAND` / `CLAUDE_ARGS` | `--claude-command` / `--claude-args` | no | `claude` / `--print` | Local Claude CLI command + args |
215
+ | `CODEX_COMMAND` / `CODEX_ARGS` | `--codex-command` / `--codex-args` | no | `codex-acp` / empty | Local Codex ACP adapter command + args. The default launch resolves the bundled `@agentclientprotocol/codex-acp` entrypoint. |
86
216
  | `COPILOT_COMMAND` / `COPILOT_ARGS` | `--copilot-command` / `--copilot-args` | no | `copilot` / parsed but ignored by ACP runtime | Local Copilot CLI command. The persistent Copilot ACP prototype always launches `copilot --acp`. |
87
217
  | `COPILOT_SESSION_TTL_MINUTES` | `--copilot-session-ttl-minutes` | no | `2880` | Idle TTL for per-channel Copilot ACP sessions |
88
218
 
@@ -165,7 +295,9 @@ The spec shape is:
165
295
  "borgeeBaseUrl": "https://borgee.example.com",
166
296
  "defaults": {
167
297
  "claudeCommand": "claude",
168
- "claudeArgs": ["--print"],
298
+ "claudeArgs": ["--print", "--permission-mode", "bypassPermissions"],
299
+ "codexCommand": "codex-acp",
300
+ "codexArgs": [],
169
301
  "copilotCommand": "copilot",
170
302
  "copilotArgs": ["-s", "--no-color", "--allow-all-tools", "--output-format", "text"],
171
303
  "copilotSessionTtlMinutes": 2880
@@ -232,6 +364,10 @@ defaults:
232
364
  claudeCommand: claude
233
365
  claudeArgs:
234
366
  - --print
367
+ - --permission-mode
368
+ - bypassPermissions
369
+ codexCommand: codex-acp
370
+ codexArgs: []
235
371
  copilotCommand: copilot
236
372
  copilotArgs:
237
373
  - -s
@@ -248,12 +384,14 @@ Host config fields:
248
384
  - `agentsDir` (optional, default `./agents` relative to the host config file)
249
385
  - `defaults.claudeCommand`
250
386
  - `defaults.claudeArgs`
387
+ - `defaults.codexCommand`
388
+ - `defaults.codexArgs`
251
389
  - `defaults.copilotCommand`
252
390
  - `defaults.copilotArgs`
253
391
  - `defaults.copilotSessionTtlMinutes`
254
392
 
255
393
  Absent host defaults fall back to the same code-level defaults used by the
256
- single-agent env / CLI flow.
394
+ standalone env flow, foreground `start`, and `start-managed`.
257
395
 
258
396
  ### Agent config
259
397
 
@@ -265,6 +403,8 @@ provider: claude
265
403
  enabled: true
266
404
  claudeArgs:
267
405
  - --print
406
+ - --permission-mode
407
+ - bypassPermissions
268
408
  - --model
269
409
  - sonnet
270
410
  ```
@@ -274,10 +414,11 @@ Agent config fields:
274
414
  - `key` (**required**): stable identity used for diffing and reload decisions
275
415
  - `name` (**required**)
276
416
  - `apiKey` (**required**)
277
- - `provider` (**required**): `claude` or `copilot`
417
+ - `provider` (**required**): `claude`, `copilot`, or gated `codex`
278
418
  - `enabled` (optional, default `true`)
279
- - optional overrides for `claudeCommand`, `claudeArgs`, `copilotCommand`,
280
- `copilotArgs`, and `copilotSessionTtlMinutes`
419
+ - optional overrides for `claudeCommand`, `claudeArgs`, `codexCommand`,
420
+ `codexArgs`, `copilotCommand`, `copilotArgs`, and
421
+ `copilotSessionTtlMinutes`
281
422
 
282
423
  Array overrides are **replacement**, not concatenation. For example, an agent
283
424
  `claudeArgs` value replaces the host default `claudeArgs` entirely.
@@ -318,16 +459,38 @@ active:
318
459
  after uses `-r/--resume <uuid>`. The host persists the channel→session map in
319
460
  its state root, serializes cross-channel map rewrites, and retries once with a
320
461
  fresh session immediately if Claude reports a stale `--resume` target.
462
+ - **Codex**: one persistent `@agentclientprotocol/codex-acp` subprocess is
463
+ shared by a single `AgentsHost`, with one ACP session per Borgee channel. When
464
+ the current turn has a materialized channel context payload, Codex refreshes a
465
+ same-directory `AGENTS.md` project document inside a provider-visible
466
+ per-channel projection directory and exposes that directory to Codex through
467
+ ACP `additionalDirectories`. Ordinary threads keep the shared runtime
468
+ workspace as the ACP session cwd, while eligible `task_assignment` threads
469
+ switch the real ACP session cwd to a hidden local task workspace under
470
+ `<startup-workspace>/.borgee-task-workspaces/<thread>/<task>/`; that local
471
+ writable workspace is explicitly not a claim that the target repository is
472
+ already checked out there. The host persists the channel→ACP-session map in
473
+ its state root and attempts ACP `session/resume` first when the adapter
474
+ advertises it, otherwise `session/load`.
321
475
  - **Copilot**: one persistent `copilot --acp` subprocess is shared by a single
322
476
  `AgentsHost`, with one ACP session per Borgee channel. Same-channel turns are
323
- serialized; different channels keep isolated ACP sessions. The host persists
324
- the channel→ACP-session map in its state root and restores same-host
325
- continuity with ACP `session/resume` when available, otherwise `session/load`
326
- plus local replay cleanup on runtimes that advertise only load support.
327
-
328
- There is no separate transcript/history store on our side. Claude and Copilot
329
- only persist the native session ids they should try to resume later; cross-host
330
- continuity still does not exist in this runtime.
477
+ serialized; different channels keep isolated ACP sessions. Ordinary threads
478
+ keep the shared runtime workspace cwd, while eligible `task_assignment`
479
+ threads switch the real ACP session cwd to that same hidden local
480
+ task-scoped workspace. The host persists the channel→ACP-session map in its
481
+ state root and restores same-host continuity with ACP `session/resume` when
482
+ available, otherwise `session/load` plus local replay cleanup on runtimes
483
+ that advertise only load support.
484
+ - **Claude**: Claude still keeps one provider-native session mapping per Borgee
485
+ channel, but unlike the ACP-backed adapters it spawns a fresh CLI process for
486
+ each turn. Ordinary threads inherit the host runtime cwd; eligible
487
+ `task_assignment` threads run the CLI process with the hidden local
488
+ task-scoped workspace as the process cwd, again without implying that the
489
+ target repository is already checked out there.
490
+
491
+ There is no separate transcript/history store on our side. Claude, Codex, and
492
+ Copilot only persist the native session ids they should try to resume later;
493
+ cross-host continuity still does not exist in this runtime.
331
494
 
332
495
  ## Testing
333
496
 
@@ -1,3 +1,4 @@
1
+ import type { AgentsHostRuntimeOptions, LoggerLike } from './debug.js';
1
2
  import type { AgentsHostConfig, LocalConfigSnapshot } from './types.js';
2
3
  export interface HostRunner {
3
4
  start(): Promise<void>;
@@ -10,15 +11,12 @@ export interface WatchEventInfo {
10
11
  eventType?: string;
11
12
  filename?: string;
12
13
  }
13
- export interface LoggerLike {
14
- log(...args: unknown[]): void;
15
- error(...args: unknown[]): void;
16
- }
17
14
  export interface AgentsHostSupervisorDeps {
18
- createHost?: (config: AgentsHostConfig) => HostRunner;
15
+ createHost?: (config: AgentsHostConfig, runtimeOptions?: AgentsHostRuntimeOptions) => HostRunner;
19
16
  loadSnapshot?: (configPath: string) => Promise<LocalConfigSnapshot>;
20
17
  watchPath?: (path: string, onEvent: (event?: WatchEventInfo) => void) => WatchHandle;
21
18
  logger?: LoggerLike;
19
+ debug?: boolean;
22
20
  }
23
21
  export declare class AgentsHostSupervisor {
24
22
  private readonly hostConfigPath;
@@ -26,18 +24,22 @@ export declare class AgentsHostSupervisor {
26
24
  private readonly loadSnapshot;
27
25
  private readonly watchPath;
28
26
  private readonly logger;
27
+ private readonly debug;
29
28
  private readonly activeHosts;
30
29
  private readonly watchers;
31
30
  private currentSnapshot;
32
31
  private reloadTimer;
33
32
  private reloadInFlight;
34
33
  private pendingReload;
34
+ private pendingReloadFailOnStartError;
35
35
  private runningReloadPromise;
36
36
  private shuttingDown;
37
37
  private started;
38
38
  constructor(hostConfigPath: string, deps?: AgentsHostSupervisorDeps);
39
39
  start(): Promise<void>;
40
40
  stop(): Promise<void>;
41
+ reloadNow(failOnStartError?: boolean): Promise<void>;
42
+ hasActiveAgent(key: string): boolean;
41
43
  private scheduleReload;
42
44
  private clearReloadTimer;
43
45
  private runReloadLoop;
@@ -12,18 +12,20 @@ export class AgentsHostSupervisor {
12
12
  loadSnapshot;
13
13
  watchPath;
14
14
  logger;
15
+ debug;
15
16
  activeHosts = new Map();
16
17
  watchers = new Map();
17
18
  currentSnapshot = null;
18
19
  reloadTimer = null;
19
20
  reloadInFlight = false;
20
21
  pendingReload = false;
22
+ pendingReloadFailOnStartError = false;
21
23
  runningReloadPromise = null;
22
24
  shuttingDown = false;
23
25
  started = false;
24
26
  constructor(hostConfigPath, deps = {}) {
25
27
  this.hostConfigPath = resolve(hostConfigPath);
26
- this.createHost = deps.createHost ?? ((config) => new AgentsHost(config));
28
+ this.createHost = deps.createHost ?? ((config, runtimeOptions) => new AgentsHost(config, { runtimeOptions }));
27
29
  this.loadSnapshot = deps.loadSnapshot ?? ((configPath) => loadLocalConfigSnapshot(configPath));
28
30
  this.watchPath =
29
31
  deps.watchPath ??
@@ -34,6 +36,7 @@ export class AgentsHostSupervisor {
34
36
  });
35
37
  }));
36
38
  this.logger = deps.logger ?? console;
39
+ this.debug = deps.debug === true;
37
40
  }
38
41
  async start() {
39
42
  if (this.started) {
@@ -81,6 +84,12 @@ export class AgentsHostSupervisor {
81
84
  await this.stopActiveHost(key, activeHost);
82
85
  }
83
86
  }
87
+ async reloadNow(failOnStartError = false) {
88
+ await this.runReloadLoop(failOnStartError);
89
+ }
90
+ hasActiveAgent(key) {
91
+ return this.activeHosts.has(key);
92
+ }
84
93
  scheduleReload() {
85
94
  if (this.shuttingDown) {
86
95
  return;
@@ -88,7 +97,7 @@ export class AgentsHostSupervisor {
88
97
  this.clearReloadTimer();
89
98
  this.reloadTimer = setTimeout(() => {
90
99
  this.reloadTimer = null;
91
- void this.runReloadLoop();
100
+ void this.runReloadLoop().catch(() => undefined);
92
101
  }, RELOAD_DEBOUNCE_MS);
93
102
  }
94
103
  clearReloadTimer() {
@@ -100,18 +109,25 @@ export class AgentsHostSupervisor {
100
109
  async runReloadLoop(failOnStartError = false) {
101
110
  if (this.reloadInFlight) {
102
111
  this.pendingReload = true;
112
+ this.pendingReloadFailOnStartError ||= failOnStartError;
113
+ await this.runningReloadPromise;
103
114
  return;
104
115
  }
105
116
  this.reloadInFlight = true;
117
+ let nextFailOnStartError = failOnStartError;
106
118
  this.runningReloadPromise = (async () => {
107
119
  try {
108
120
  do {
121
+ const currentFailOnStartError = nextFailOnStartError;
109
122
  this.pendingReload = false;
110
- await this.reloadOnce(failOnStartError);
123
+ this.pendingReloadFailOnStartError = false;
124
+ await this.reloadOnce(currentFailOnStartError);
125
+ nextFailOnStartError = this.pendingReloadFailOnStartError;
111
126
  } while (this.pendingReload && !this.shuttingDown);
112
127
  }
113
128
  finally {
114
129
  this.reloadInFlight = false;
130
+ this.pendingReloadFailOnStartError = false;
115
131
  this.runningReloadPromise = null;
116
132
  }
117
133
  })();
@@ -256,7 +272,11 @@ export class AgentsHostSupervisor {
256
272
  if (this.shuttingDown) {
257
273
  return;
258
274
  }
259
- const runner = this.createHost(agent.config);
275
+ const runner = this.createHost(agent.config, {
276
+ debug: this.debug,
277
+ logger: this.logger,
278
+ logPrefix: `[agents-host][agent:${agent.key}]`,
279
+ });
260
280
  try {
261
281
  await runner.start();
262
282
  this.activeHosts.set(agent.key, {
@@ -1,44 +1,118 @@
1
1
  import type { ChatControlPlane } from './chat/chat-control-plane.js';
2
+ import { type AgentsHostRuntimeOptions } from './debug.js';
2
3
  import type { ProviderAdapter } from './providers/provider-adapter.js';
3
4
  import type { AgentsHostConfig } from './types.js';
4
5
  /**
5
6
  * Minimal single-agent agents host: connects one local Claude/Copilot CLI
6
7
  * to exactly one Borgee agent over `@borgee/plugin-sdk` (BPP / `/ws/plugin`).
7
- *
8
- * Conversation memory is handled entirely by each provider's native
9
- * per-channel CLI session (Claude `--resume`, Copilot `--session-id`) — see
10
- * the cli-client.ts file under each provider's folder. This class does not
11
- * keep any message history itself.
12
- *
13
- * Out of scope for this single-agent runner (see README): execution/remote-command
14
- * dispatch, node provisioning, systemd install, and scheduled (periodic)
15
- * prompts. Multi-agent local hosting is handled one level up by the local-config
16
- * supervisor, which creates one isolated `AgentsHost` per effective agent key.
17
- *
18
- * Message gating (mention-only / DM rules) is NOT done here: the server
19
- * enforces per-agent + per-channel `require_mention` at BPP fan-out, so this
20
- * host simply replies to every message it is handed (minus its own).
21
8
  */
22
9
  export declare class AgentsHost {
23
10
  private readonly config;
11
+ private readonly runtime;
24
12
  private readonly provider;
25
13
  private readonly borgee;
14
+ private readonly logger;
15
+ private readonly collaborationEnabled;
26
16
  private readonly activeTurns;
17
+ private readonly awaitingUserByChannel;
27
18
  private readonly progressChannelQueues;
28
19
  private readonly progressDrafts;
20
+ private readonly collaborationDrafts;
21
+ private readonly collaborationChannels;
22
+ private readonly participantDirectoryByUserId;
23
+ private readonly participantKindsByUserId;
24
+ private readonly participantRefreshBackoffByUserId;
25
+ private participantRefreshPromise;
26
+ private participantDirectorySupported;
29
27
  private selfAgentId;
28
+ private selfAgentProfile;
30
29
  private selfAgentIdPromise;
31
30
  private started;
32
31
  private controlPlaneClosed;
33
32
  constructor(config: AgentsHostConfig, deps?: {
34
33
  borgee?: ChatControlPlane;
35
34
  provider?: ProviderAdapter;
35
+ runtimeOptions?: AgentsHostRuntimeOptions;
36
36
  });
37
37
  start(): Promise<void>;
38
38
  stop(): Promise<void>;
39
- private handleMessage;
40
39
  private trackActiveTurn;
40
+ private dispatchMessage;
41
+ private handleLegacyMessage;
42
+ private handleCollaborationMessage;
43
+ private detectProtocolKickoffCandidate;
44
+ private validateProtocolKickoffCandidate;
45
+ private resolveProtocolKickoffRequest;
46
+ private validateProtocolKickoffRounds;
47
+ private protocolRequestFromKickoffDecision;
48
+ private evaluateIssuerProtocolKickoff;
49
+ private waitForProtocolKickoffDecision;
50
+ private ensureProtocolKickoffDecisionRecord;
51
+ private finalizeProtocolKickoffDecision;
52
+ private matchesProtocolKickoffDecisionRecord;
53
+ private resolveProtocolKickoffDecisionPath;
54
+ private resolveSharedProtocolStatusPath;
55
+ private readProtocolKickoffDecisionRecord;
56
+ private writeProtocolKickoffDecisionRecord;
57
+ private handleActiveProtocolAnchorReplay;
58
+ private startProtocolForAnchor;
59
+ private deliverDeferredTurnReply;
60
+ private handleActiveProtocolParticipantMessage;
61
+ private enqueueCollaborationMessage;
62
+ private ensureCollaborationChannelState;
63
+ private ensureCollaborationProcessor;
64
+ private processCollaborationQueue;
65
+ private tryResumeBlockedFromQueue;
66
+ private runCollaborationTurn;
67
+ private runProtocolManagedTurn;
68
+ private buildIncomingContent;
69
+ private otherProtocolParticipant;
70
+ private resolveProtocolStatePath;
71
+ private ensureProtocolStateLoaded;
72
+ private reconcileOwnProtocolStateFromPeers;
73
+ private loadPersistedProtocolStates;
74
+ private resumeOwnedProtocolTurns;
75
+ private buildResumedProtocolMessage;
76
+ private persistProtocolState;
77
+ private persistSharedProtocolStatus;
78
+ private readSharedProtocolStatus;
79
+ private clearProtocolFallback;
80
+ private armProtocolFallback;
81
+ private runProtocolFallback;
82
+ private handleProtocolFallbackFailure;
83
+ private finishProtocolState;
84
+ private cancelProtocolState;
85
+ private confirmProtocolMessage;
86
+ private runUngatedTurn;
87
+ private executeTurn;
88
+ private canAcceptTurnOutput;
89
+ private canAcceptCompletedTurnOutput;
90
+ private canContinueSharedProtocol;
41
91
  private enqueueProgressChannelTurn;
42
92
  private ensureProgressDraft;
93
+ private publishCollaborationDraft;
94
+ private finalizeCollaborationDraft;
95
+ private clearCollaborationDraft;
96
+ private readCollaborationDraft;
97
+ private discardDraft;
98
+ private supersedeActiveTurn;
99
+ private invalidateChannelTurn;
100
+ private rememberRecentTurn;
101
+ private resolveAuthorizedCollaborationTurn;
102
+ private updateAwaitingUserState;
103
+ private resolveVisibleTurnBody;
104
+ private shouldRelayProtocolReply;
105
+ private normalizeMessage;
106
+ private markAssignedTaskInProgress;
43
107
  private ensureSelfAgentId;
108
+ private classifyAuthor;
109
+ private refreshParticipantDirectory;
110
+ private classifyBlockedWakeAuthor;
111
+ private classifyQueuedBlockedWakeCandidate;
112
+ private inferAuthorKind;
113
+ private buildCollaborationGrounding;
114
+ private hydratePromptIdentityCache;
115
+ private resolvePromptIdentity;
116
+ private isUnsupportedSemanticOperation;
117
+ private authorizeCollaborationSend;
44
118
  }