@borgee/agents-host 0.2.29 → 0.2.31
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 +18 -27
- package/dist/agents-host.d.ts +1 -1
- package/dist/agents-host.js +45 -18
- package/dist/cli-args.d.ts +1 -1
- package/dist/cli-args.js +2 -2
- package/dist/compatibility-gates.js +4 -1
- package/dist/config.d.ts +8 -0
- package/dist/config.js +51 -13
- package/dist/gateway/localhost-gateway.js +5 -1
- package/dist/local-config.js +20 -1
- package/dist/managed-daemon.js +20 -6
- package/dist/providers/claude/cli-client.d.ts +55 -16
- package/dist/providers/claude/cli-client.js +811 -345
- package/dist/providers/create-provider.js +8 -13
- package/dist/types.d.ts +1 -0
- package/package.json +3 -2
- package/skills/borgee-agent/borgee-agent.mjs +2 -1
- package/skills/borgee-agent/borgee-agent.py +3 -1
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ Codex now ships on the same default hosted-provider surface as Claude and Copilo
|
|
|
84
84
|
|
|
85
85
|
The current shipped internal compatibility surface resolves gates in this order:
|
|
86
86
|
|
|
87
|
-
1. start from the shipped defaults: `
|
|
87
|
+
1. start from the shipped defaults: `copilot-provider-v2`, `codex-provider`, `managed-runtime-convergence`, and `policy-audit-enforcement`
|
|
88
88
|
2. add any explicit entries from `AGENTS_HOST_INTERNAL_COMPATIBILITY_GATES`
|
|
89
89
|
3. subtract any explicit entries from `AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES`
|
|
90
90
|
|
|
@@ -98,7 +98,7 @@ Legacy managed roots created before `managed-runtime-settings.json` existed need
|
|
|
98
98
|
Rollback and hardening controls stay explicit:
|
|
99
99
|
|
|
100
100
|
- `AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES=<comma-list>` disables shipped gates for rollback
|
|
101
|
-
- `AGENTS_HOST_INTERNAL_PROVIDER_IMPLEMENTATIONS=
|
|
101
|
+
- `AGENTS_HOST_INTERNAL_PROVIDER_IMPLEMENTATIONS=copilot:v1` forces Copilot back to the v1 adapter while its v2 gate stays enabled; stale `claude:v1|v2` entries are tolerated as no-ops for compatibility
|
|
102
102
|
- `AGENTS_HOST_INTERNAL_POLICY_MODE=enforce` hardens the shipped `policy-audit-enforcement` gate beyond its default `audit-only` mode
|
|
103
103
|
|
|
104
104
|
Or with the CLI:
|
|
@@ -234,7 +234,7 @@ Notes:
|
|
|
234
234
|
| `AGENTS_HOST_DEBUG` | `--debug` | no | off | Extra host/provider lifecycle logs. Set `AGENTS_HOST_DEBUG=1` to enable without the CLI flag. |
|
|
235
235
|
| `BORGEE_AGENT_NAME` | `--name` | no | `Assistant` | Display name used in prompts |
|
|
236
236
|
| `RUNTIME_PROVIDER` | `--provider` | no | `claude` | `claude`, `copilot`, or `codex` |
|
|
237
|
-
| `CLAUDE_COMMAND` / `CLAUDE_ARGS` | `--claude-command` / `--claude-args` | no | `claude` /
|
|
237
|
+
| `CLAUDE_COMMAND` / `CLAUDE_ARGS` | `--claude-command` / `--claude-args` | no | `claude-agent-acp` / empty | Local Claude ACP adapter command + args. The shipped bundled `claude-agent-acp` path requires empty `CLAUDE_ARGS`; non-empty args are only valid when `CLAUDE_COMMAND` points at a custom ACP adapter command. Legacy `claude --print --permission-mode bypassPermissions` is tolerated as a compatibility alias. |
|
|
238
238
|
| `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. |
|
|
239
239
|
| `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`. |
|
|
240
240
|
| `COPILOT_SESSION_TTL_MINUTES` | `--copilot-session-ttl-minutes` | no | `2880` | Idle TTL for per-channel Copilot ACP sessions |
|
|
@@ -317,8 +317,8 @@ The spec shape is:
|
|
|
317
317
|
"host": {
|
|
318
318
|
"borgeeBaseUrl": "https://borgee.example.com",
|
|
319
319
|
"defaults": {
|
|
320
|
-
"claudeCommand": "claude",
|
|
321
|
-
"claudeArgs": [
|
|
320
|
+
"claudeCommand": "claude-agent-acp",
|
|
321
|
+
"claudeArgs": [],
|
|
322
322
|
"codexCommand": "codex-acp",
|
|
323
323
|
"codexArgs": [],
|
|
324
324
|
"copilotCommand": "copilot",
|
|
@@ -384,11 +384,8 @@ paths are also allowed.
|
|
|
384
384
|
borgeeBaseUrl: https://borgee.example.com
|
|
385
385
|
agentsDir: ./agents
|
|
386
386
|
defaults:
|
|
387
|
-
claudeCommand: claude
|
|
388
|
-
claudeArgs:
|
|
389
|
-
- --print
|
|
390
|
-
- --permission-mode
|
|
391
|
-
- bypassPermissions
|
|
387
|
+
claudeCommand: claude-agent-acp
|
|
388
|
+
claudeArgs: []
|
|
392
389
|
codexCommand: codex-acp
|
|
393
390
|
codexArgs: []
|
|
394
391
|
copilotCommand: copilot
|
|
@@ -424,12 +421,6 @@ name: Support Bot
|
|
|
424
421
|
apiKey: bgr_support_xxxxxxxx
|
|
425
422
|
provider: claude
|
|
426
423
|
enabled: true
|
|
427
|
-
claudeArgs:
|
|
428
|
-
- --print
|
|
429
|
-
- --permission-mode
|
|
430
|
-
- bypassPermissions
|
|
431
|
-
- --model
|
|
432
|
-
- sonnet
|
|
433
424
|
```
|
|
434
425
|
|
|
435
426
|
Agent config fields:
|
|
@@ -439,6 +430,7 @@ Agent config fields:
|
|
|
439
430
|
- `apiKey` (**required**)
|
|
440
431
|
- `provider` (**required**): `claude`, `copilot`, or `codex` (roll back Codex only with `AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES=codex-provider`)
|
|
441
432
|
- `enabled` (optional, default `true`)
|
|
433
|
+
- `claudeCommand` / `claudeArgs` (optional): leave unset to use the shipped bundled `claude-agent-acp` path. On that bundled path `claudeArgs` must stay empty. Non-empty `claudeArgs` are only supported when `claudeCommand` points at a custom ACP adapter command.
|
|
442
434
|
- optional overrides for `claudeCommand`, `claudeArgs`, `codexCommand`,
|
|
443
435
|
`codexArgs`, `copilotCommand`, `copilotArgs`, and
|
|
444
436
|
`copilotSessionTtlMinutes`
|
|
@@ -478,10 +470,16 @@ successfully applied snapshot running.
|
|
|
478
470
|
Each Borgee channel is mapped 1:1 to a provider-native session while it stays
|
|
479
471
|
active:
|
|
480
472
|
|
|
481
|
-
- **Claude**:
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
473
|
+
- **Claude**: one persistent `@agentclientprotocol/claude-agent-acp` subprocess
|
|
474
|
+
is shared by a single `AgentsHost`, with one ACP session per Borgee channel.
|
|
475
|
+
Same-channel turns are serialized; different channels keep isolated ACP
|
|
476
|
+
sessions. Ordinary threads keep the shared runtime workspace cwd, while
|
|
477
|
+
eligible `task_assignment` threads switch the real ACP session cwd to that
|
|
478
|
+
same hidden local task-scoped workspace. The host persists the
|
|
479
|
+
channel→ACP-session map in its state root, restores same-host continuity with
|
|
480
|
+
ACP `session/resume` when available, retries stale restores with a fresh
|
|
481
|
+
session immediately, and injects the per-channel local context paths through
|
|
482
|
+
Claude ACP `_meta.systemPrompt.append`.
|
|
485
483
|
- **Codex**: one persistent `@agentclientprotocol/codex-acp` subprocess is
|
|
486
484
|
shared by a single `AgentsHost`, with one ACP session per Borgee channel. When
|
|
487
485
|
the current turn has a materialized channel context payload, Codex refreshes a
|
|
@@ -504,13 +502,6 @@ active:
|
|
|
504
502
|
state root and restores same-host continuity with ACP `session/resume` when
|
|
505
503
|
available, otherwise `session/load` plus local replay cleanup on runtimes
|
|
506
504
|
that advertise only load support.
|
|
507
|
-
- **Claude**: Claude still keeps one provider-native session mapping per Borgee
|
|
508
|
-
channel, but unlike the ACP-backed adapters it spawns a fresh CLI process for
|
|
509
|
-
each turn. Ordinary threads inherit the host runtime cwd; eligible
|
|
510
|
-
`task_assignment` threads run the CLI process with the hidden local
|
|
511
|
-
task-scoped workspace as the process cwd, again without implying that the
|
|
512
|
-
target repository is already checked out there.
|
|
513
|
-
|
|
514
505
|
There is no separate transcript/history store on our side. Claude, Codex, and
|
|
515
506
|
Copilot only persist the native session ids they should try to resume later;
|
|
516
507
|
cross-host continuity still does not exist in this runtime.
|
package/dist/agents-host.d.ts
CHANGED
|
@@ -128,7 +128,7 @@ export declare class AgentsHost {
|
|
|
128
128
|
private resolveVisibleTurnBody;
|
|
129
129
|
private shouldRelayProtocolReply;
|
|
130
130
|
private normalizeMessage;
|
|
131
|
-
private
|
|
131
|
+
private resolveTaskAssignmentDelivery;
|
|
132
132
|
private ensureSelfAgentId;
|
|
133
133
|
private classifyAuthor;
|
|
134
134
|
private refreshParticipantDirectory;
|
package/dist/agents-host.js
CHANGED
|
@@ -527,6 +527,11 @@ export class AgentsHost {
|
|
|
527
527
|
if (!normalized) {
|
|
528
528
|
return;
|
|
529
529
|
}
|
|
530
|
+
const effective = await this.resolveTaskAssignmentDelivery(msg, normalized);
|
|
531
|
+
if (!effective) {
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
msg = effective;
|
|
530
535
|
let taskThreadContext = { state: 'inactive' };
|
|
531
536
|
let attentionSnapshot;
|
|
532
537
|
if (this.attentionFollowSemanticsEnabled
|
|
@@ -542,9 +547,6 @@ export class AgentsHost {
|
|
|
542
547
|
}
|
|
543
548
|
}
|
|
544
549
|
}
|
|
545
|
-
if (msg.message_type === 'task_assignment') {
|
|
546
|
-
await this.markAssignedTaskInProgress(msg.channel_id, normalized.content);
|
|
547
|
-
}
|
|
548
550
|
await this.runUngatedTurn(msg, normalized.authorId, normalized.content, taskThreadContext, attentionSnapshot);
|
|
549
551
|
}
|
|
550
552
|
async handleCollaborationMessage(msg) {
|
|
@@ -552,9 +554,11 @@ export class AgentsHost {
|
|
|
552
554
|
if (!normalized) {
|
|
553
555
|
return;
|
|
554
556
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
+
const effective = await this.resolveTaskAssignmentDelivery(msg, normalized);
|
|
558
|
+
if (!effective) {
|
|
559
|
+
return;
|
|
557
560
|
}
|
|
561
|
+
msg = effective;
|
|
558
562
|
const channelState = this.ensureCollaborationChannelState(msg.channel_id);
|
|
559
563
|
await this.ensureProtocolStateLoaded(msg.channel_id, channelState);
|
|
560
564
|
await this.ensureAttentionSnapshotLoaded(msg.channel_id, channelState);
|
|
@@ -2640,28 +2644,51 @@ export class AgentsHost {
|
|
|
2640
2644
|
content,
|
|
2641
2645
|
};
|
|
2642
2646
|
}
|
|
2643
|
-
|
|
2647
|
+
// Only a task assigned to this agent drives a task-assignment turn: it keeps the message a
|
|
2648
|
+
// task_assignment (and best-effort flips an open task to in_progress). An unassigned or
|
|
2649
|
+
// other-assigned task_assignment degrades to an ordinary message, and this agent's own echo of
|
|
2650
|
+
// it drops, so the creator never auto-starts work it was not assigned.
|
|
2651
|
+
async resolveTaskAssignmentDelivery(msg, normalized) {
|
|
2652
|
+
if (msg.message_type !== 'task_assignment') {
|
|
2653
|
+
return msg;
|
|
2654
|
+
}
|
|
2655
|
+
const selfAgentId = await this.ensureSelfAgentId();
|
|
2656
|
+
let task;
|
|
2644
2657
|
try {
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
preferredTaskId: extractTaskIdFromTaskAssignmentContent(content),
|
|
2658
|
+
task = await waitForTaskForThread(this.borgee, msg.channel_id, {
|
|
2659
|
+
preferredTaskId: extractTaskIdFromTaskAssignmentContent(normalized.content),
|
|
2648
2660
|
attempts: 10,
|
|
2649
2661
|
delayMs: 250,
|
|
2650
2662
|
});
|
|
2651
|
-
if (!task || task.status !== 'open' || task.assigneeId !== selfAgentId) {
|
|
2652
|
-
return;
|
|
2653
|
-
}
|
|
2654
|
-
await this.borgee.updateTask({
|
|
2655
|
-
taskId: task.id,
|
|
2656
|
-
status: 'in_progress',
|
|
2657
|
-
});
|
|
2658
2663
|
}
|
|
2659
2664
|
catch (error) {
|
|
2660
|
-
this.logger.debugError('
|
|
2661
|
-
channelId:
|
|
2665
|
+
this.logger.debugError('task-assignment resolution failed', {
|
|
2666
|
+
channelId: msg.channel_id,
|
|
2662
2667
|
error,
|
|
2663
2668
|
});
|
|
2669
|
+
task = null;
|
|
2670
|
+
}
|
|
2671
|
+
if (task && task.assigneeId === selfAgentId) {
|
|
2672
|
+
if (task.status === 'open') {
|
|
2673
|
+
try {
|
|
2674
|
+
await this.borgee.updateTask({
|
|
2675
|
+
taskId: task.id,
|
|
2676
|
+
status: 'in_progress',
|
|
2677
|
+
});
|
|
2678
|
+
}
|
|
2679
|
+
catch (error) {
|
|
2680
|
+
this.logger.debugError('best-effort task auto-start failed', {
|
|
2681
|
+
channelId: msg.channel_id,
|
|
2682
|
+
error,
|
|
2683
|
+
});
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
return msg;
|
|
2687
|
+
}
|
|
2688
|
+
if (normalized.authorId === selfAgentId) {
|
|
2689
|
+
return null;
|
|
2664
2690
|
}
|
|
2691
|
+
return { ...msg, message_type: 'default' };
|
|
2665
2692
|
}
|
|
2666
2693
|
async ensureSelfAgentId() {
|
|
2667
2694
|
if (this.selfAgentId) {
|
package/dist/cli-args.d.ts
CHANGED
|
@@ -83,4 +83,4 @@ export declare function parseLogArgs(argv: string[]): ParsedLogArgs;
|
|
|
83
83
|
export declare function parseDescribeManagedArgs(argv: string[]): ParsedDescribeManagedArgs;
|
|
84
84
|
export declare function parseCleanupManagedArgs(argv: string[]): ParsedCleanupManagedArgs;
|
|
85
85
|
export declare function parseApplyManagedArgs(argv: string[]): ParsedApplyManagedArgs;
|
|
86
|
-
export declare const USAGE = "Usage:\n agents-host start <serverUrl> <apiKey> [options]\n agents-host start-managed <serverUrl>\n agents-host start-managed <serverUrl> <apiKey> [agent-options]\n agents-host describe-managed <serverUrl>\n agents-host cleanup-managed <serverUrl> [--purge]\n agents-host apply-managed <serverUrl> --stdin\n agents-host apply-managed <serverUrl> --spec-json <json>\n agents-host log <serverUrl> [--lines <n>] [--follow]\n agents-host log <serverUrl> --path\n agents-host start --config <path-to-host-config> [--debug]\n agents-host validate --config <path-to-host-config>\n agents-host describe --config <path-to-host-config>\n agents-host print-layout --root <dir>\n agents-host generate-config --root <dir> --stdin\n agents-host generate-config --root <dir> --spec-json <json>\n\nForeground start options:\n --debug Enable host/provider debug logs (or set AGENTS_HOST_DEBUG=1)\n\nSingle-agent agent options:\n --name <name> Display name (default: Assistant)\n --provider <claude|codex|copilot>\n Runtime provider (default: claude)\n --claude-command <cmd> Local Claude
|
|
86
|
+
export declare const USAGE = "Usage:\n agents-host start <serverUrl> <apiKey> [options]\n agents-host start-managed <serverUrl>\n agents-host start-managed <serverUrl> <apiKey> [agent-options]\n agents-host describe-managed <serverUrl>\n agents-host cleanup-managed <serverUrl> [--purge]\n agents-host apply-managed <serverUrl> --stdin\n agents-host apply-managed <serverUrl> --spec-json <json>\n agents-host log <serverUrl> [--lines <n>] [--follow]\n agents-host log <serverUrl> --path\n agents-host start --config <path-to-host-config> [--debug]\n agents-host validate --config <path-to-host-config>\n agents-host describe --config <path-to-host-config>\n agents-host print-layout --root <dir>\n agents-host generate-config --root <dir> --stdin\n agents-host generate-config --root <dir> --spec-json <json>\n\nForeground start options:\n --debug Enable host/provider debug logs (or set AGENTS_HOST_DEBUG=1)\n\nSingle-agent agent options:\n --name <name> Display name (default: Assistant)\n --provider <claude|codex|copilot>\n Runtime provider (default: claude)\n --claude-command <cmd> Local Claude ACP adapter command (default: claude-agent-acp)\n --claude-args <args> Local Claude ACP adapter args (empty on the shipped bundled path)\n --codex-command <cmd> Local Codex ACP adapter command (default: codex-acp)\n --codex-args <args> Local Codex ACP adapter args\n --copilot-command <cmd> Local Copilot CLI command (default: copilot)\n --copilot-args <args> Ignored by the Copilot ACP prototype\n --copilot-session-ttl-minutes <minutes>\n Idle session TTL for Copilot ACP sessions (default: 2880)\n\nCommand summary:\n start <serverUrl> <apiKey> Start one foreground hosted agent (legacy-compatible behavior)\n start --config <path> Start agents + supervisor + watchers from a host config file\n start-managed <serverUrl> Restart or resume an existing per-serverUrl managed daemon\n start-managed <serverUrl> <apiKey>\n Upsert one agent into the per-serverUrl local daemon and exit after reconcile\n describe-managed <serverUrl> Print managed-runtime spec JSON for machine callers\n cleanup-managed <serverUrl> Stop one managed-runtime daemon locally; --purge also removes its runtime root\n apply-managed <serverUrl> Apply one managed-runtime full-set spec for machine callers\n log <serverUrl> Print the managed daemon log tail for one server runtime\n validate --config <path> Validate local-config files without starting agents or watchers\n describe --config <path> Print the current managed full-set spec as JSON\n print-layout --root <dir> Print the canonical default local-config layout as JSON\n generate-config --root <dir> --stdin Materialize canonical local-config files from stdin\n generate-config --root <dir> --spec-json <json>\n Compatibility input; JSON is exposed in process arguments\n\nExamples:\n agents-host start https://borgee.example.com bgr_xxxxxxxx --provider copilot --debug\n agents-host start-managed https://borgee.example.com\n agents-host start-managed https://borgee.example.com bgr_xxxxxxxx --provider copilot\n agents-host describe-managed https://borgee.example.com\n agents-host cleanup-managed https://borgee.example.com --purge\n printf '%s' '{\"host\":{\"borgeeBaseUrl\":\"https://borgee.example.com\"},\"agents\":[{\"key\":\"cp1\",\"name\":\"Copilot\",\"apiKey\":\"bgr_xxx\",\"provider\":\"copilot\"}]}' | agents-host apply-managed https://borgee.example.com --stdin\n agents-host log https://borgee.example.com --lines 200 --follow\n agents-host log https://borgee.example.com --path\n agents-host start --config ./agents-host.yaml --debug\n agents-host validate --config ./agents-host.yaml\n agents-host describe --config ./agents-host.yaml\n agents-host print-layout --root ./runtime-root\n printf '%s' '{\"host\":{\"borgeeBaseUrl\":\"https://borgee.example.com\"},\"agents\":[{\"key\":\"cp1\",\"name\":\"Copilot\",\"apiKey\":\"bgr_xxx\",\"provider\":\"copilot\"}]}' | agents-host generate-config --root ./runtime-root --stdin\n";
|
package/dist/cli-args.js
CHANGED
|
@@ -494,8 +494,8 @@ Single-agent agent options:
|
|
|
494
494
|
--name <name> Display name (default: Assistant)
|
|
495
495
|
--provider <claude|codex|copilot>
|
|
496
496
|
Runtime provider (default: claude)
|
|
497
|
-
--claude-command <cmd> Local Claude
|
|
498
|
-
--claude-args <args> Local Claude
|
|
497
|
+
--claude-command <cmd> Local Claude ACP adapter command (default: claude-agent-acp)
|
|
498
|
+
--claude-args <args> Local Claude ACP adapter args (empty on the shipped bundled path)
|
|
499
499
|
--codex-command <cmd> Local Codex ACP adapter command (default: codex-acp)
|
|
500
500
|
--codex-args <args> Local Codex ACP adapter args
|
|
501
501
|
--copilot-command <cmd> Local Copilot CLI command (default: copilot)
|
|
@@ -21,7 +21,6 @@ export const INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV = 'AGENTS_HOST_INTERNAL_PROVI
|
|
|
21
21
|
export const MANAGED_RUNTIME_SETTINGS_SCHEMA_VERSION = 1;
|
|
22
22
|
const VALID_PROVIDER_IMPLEMENTATION_ENTRIES = '"claude:v1", "claude:v2", "copilot:v1", or "copilot:v2"';
|
|
23
23
|
export const DEFAULT_INTERNAL_COMPATIBILITY_GATES = Object.freeze([
|
|
24
|
-
CLAUDE_PROVIDER_V2_COMPATIBILITY_GATE,
|
|
25
24
|
COLLABORATION_CAPABILITIES_DIAGNOSTICS_COMPATIBILITY_GATE,
|
|
26
25
|
COLLABORATION_OUTCOME_MODEL_COMPATIBILITY_GATE,
|
|
27
26
|
CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE,
|
|
@@ -118,11 +117,15 @@ export function resolveManagedRuntimeProviderImplementationOverrides(env = proce
|
|
|
118
117
|
const enabledGates = new Set(compatibilityGates);
|
|
119
118
|
return normalizeInternalProviderImplementationOverrides(env[INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV]).filter((assignment) => {
|
|
120
119
|
const [provider] = assignment.split(':');
|
|
120
|
+
if (provider === 'claude') {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
121
123
|
return enabledGates.has(PROVIDER_IMPLEMENTATION_COMPATIBILITY_GATES[provider]);
|
|
122
124
|
});
|
|
123
125
|
}
|
|
124
126
|
export function resolveManagedRuntimeCompatibilityGates(env = process.env) {
|
|
125
127
|
const compatibilityGates = new Set(resolveInternalCompatibilityGates(env));
|
|
128
|
+
compatibilityGates.delete(CLAUDE_PROVIDER_V2_COMPATIBILITY_GATE);
|
|
126
129
|
const explicitlyEnabledGates = parseCompatibilityGates(env[COMPATIBILITY_GATES_ENV]);
|
|
127
130
|
if (compatibilityGates.has(MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE)) {
|
|
128
131
|
compatibilityGates.add(CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE);
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { AgentsHostConfig, ProviderCommandConfig, ProviderKind } from './types.js';
|
|
2
2
|
export declare const MAX_COPILOT_SESSION_TTL_MINUTES: number;
|
|
3
3
|
export declare const DEFAULT_COPILOT_SESSION_TTL_MINUTES: number;
|
|
4
|
+
export declare const DEFAULT_CLAUDE_COMMAND = "claude-agent-acp";
|
|
5
|
+
export declare const LEGACY_CLAUDE_COMMAND = "claude";
|
|
6
|
+
export declare const LEGACY_CLAUDE_ONE_SHOT_ARGS: readonly ["--print", "--permission-mode", "bypassPermissions"];
|
|
4
7
|
export declare const DEFAULT_PROVIDER_COMMAND_CONFIG: ProviderCommandConfig;
|
|
5
8
|
export declare function requireNonEmptyString(value: unknown, message: string): string;
|
|
6
9
|
export declare function optionalNonEmptyString(value: unknown, fieldName: string, sourceLabel: string): string | undefined;
|
|
@@ -9,5 +12,10 @@ export declare function optionalStringArray(value: unknown, fieldName: string, s
|
|
|
9
12
|
export declare function parseCopilotSessionTtlMinutesValue(value: unknown, sourceLabel: string): number;
|
|
10
13
|
export declare function resolveProvider(rawValue: string, sourceLabel: string): ProviderKind;
|
|
11
14
|
export declare function assertProviderCompatibility(provider: ProviderKind, sourceLabel: string, env?: NodeJS.ProcessEnv): void;
|
|
15
|
+
export declare function isLegacyClaudeCompatibilityAlias(command: string, args: string[]): boolean;
|
|
16
|
+
export declare function isLegacyClaudeBinaryCommand(command: string): boolean;
|
|
17
|
+
export declare function hasLegacyClaudeOneShotArgs(args: string[]): boolean;
|
|
18
|
+
export declare function assertClaudeCommandCompatibility(command: string, args: string[], sourceLabel: string): void;
|
|
19
|
+
export declare function assertProviderCommandCompatibility(provider: ProviderKind, config: Pick<ProviderCommandConfig, 'claudeCommand' | 'claudeArgs'>, sourceLabel: string): void;
|
|
12
20
|
export declare function resolveProviderCommandConfig(overrides?: Partial<ProviderCommandConfig>): ProviderCommandConfig;
|
|
13
21
|
export declare function loadConfigFromEnv(env?: NodeJS.ProcessEnv): AgentsHostConfig;
|
package/dist/config.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
1
2
|
import { resolveSingleAgentStateRoot } from './state-paths.js';
|
|
2
3
|
import { CODEX_PROVIDER_COMPATIBILITY_GATE, resolveInternalCompatibilityGates, } from './compatibility-gates.js';
|
|
3
4
|
const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
4
5
|
export const MAX_COPILOT_SESSION_TTL_MINUTES = MAX_TIMER_DELAY_MS / 60_000;
|
|
5
6
|
export const DEFAULT_COPILOT_SESSION_TTL_MINUTES = 2 * 24 * 60;
|
|
7
|
+
export const DEFAULT_CLAUDE_COMMAND = 'claude-agent-acp';
|
|
8
|
+
export const LEGACY_CLAUDE_COMMAND = 'claude';
|
|
9
|
+
export const LEGACY_CLAUDE_ONE_SHOT_ARGS = ['--print', '--permission-mode', 'bypassPermissions'];
|
|
6
10
|
export const DEFAULT_PROVIDER_COMMAND_CONFIG = {
|
|
7
|
-
claudeCommand:
|
|
8
|
-
claudeArgs: [
|
|
11
|
+
claudeCommand: DEFAULT_CLAUDE_COMMAND,
|
|
12
|
+
claudeArgs: [],
|
|
9
13
|
codexCommand: 'codex-acp',
|
|
10
14
|
codexArgs: [],
|
|
11
15
|
copilotCommand: 'copilot',
|
|
@@ -74,6 +78,38 @@ export function assertProviderCompatibility(provider, sourceLabel, env = process
|
|
|
74
78
|
throw new Error(`${sourceLabel}: provider "codex" requires the shipped ${CODEX_PROVIDER_COMPATIBILITY_GATE} path to remain enabled`);
|
|
75
79
|
}
|
|
76
80
|
}
|
|
81
|
+
export function isLegacyClaudeCompatibilityAlias(command, args) {
|
|
82
|
+
if (command !== LEGACY_CLAUDE_COMMAND || args.length !== LEGACY_CLAUDE_ONE_SHOT_ARGS.length) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return args.every((arg, index) => arg === LEGACY_CLAUDE_ONE_SHOT_ARGS[index]);
|
|
86
|
+
}
|
|
87
|
+
export function isLegacyClaudeBinaryCommand(command) {
|
|
88
|
+
return basename(command) === LEGACY_CLAUDE_COMMAND;
|
|
89
|
+
}
|
|
90
|
+
export function hasLegacyClaudeOneShotArgs(args) {
|
|
91
|
+
return (args.length === LEGACY_CLAUDE_ONE_SHOT_ARGS.length
|
|
92
|
+
&& args.every((arg, index) => arg === LEGACY_CLAUDE_ONE_SHOT_ARGS[index]));
|
|
93
|
+
}
|
|
94
|
+
export function assertClaudeCommandCompatibility(command, args, sourceLabel) {
|
|
95
|
+
if (command === DEFAULT_CLAUDE_COMMAND) {
|
|
96
|
+
if (args.length > 0) {
|
|
97
|
+
throw new Error(`Invalid Claude config in ${sourceLabel}: the shipped ${DEFAULT_CLAUDE_COMMAND} path does not accept CLAUDE_ARGS/claudeArgs. Leave them empty or point claudeCommand/CLAUDE_COMMAND at a custom ACP adapter command instead.`);
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (isLegacyClaudeBinaryCommand(command)) {
|
|
102
|
+
if (isLegacyClaudeCompatibilityAlias(command, args)) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
throw new Error(`Invalid Claude config in ${sourceLabel}: raw "${LEGACY_CLAUDE_COMMAND}" commands no longer speak ACP directly. Use the shipped ${DEFAULT_CLAUDE_COMMAND} default, keep only the exact legacy compatibility alias "${LEGACY_CLAUDE_COMMAND} ${LEGACY_CLAUDE_ONE_SHOT_ARGS.join(' ')}", or point claudeCommand/CLAUDE_COMMAND at a real ACP adapter command.`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export function assertProviderCommandCompatibility(provider, config, sourceLabel) {
|
|
109
|
+
if (provider === 'claude') {
|
|
110
|
+
assertClaudeCommandCompatibility(config.claudeCommand, config.claudeArgs, sourceLabel);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
77
113
|
export function resolveProviderCommandConfig(overrides = {}) {
|
|
78
114
|
return {
|
|
79
115
|
claudeCommand: overrides.claudeCommand ?? DEFAULT_PROVIDER_COMMAND_CONFIG.claudeCommand,
|
|
@@ -89,20 +125,22 @@ export function loadConfigFromEnv(env = process.env) {
|
|
|
89
125
|
const provider = resolveProvider(envOr('RUNTIME_PROVIDER', 'claude', env), 'Unsupported RUNTIME_PROVIDER');
|
|
90
126
|
assertProviderCompatibility(provider, 'Unsupported RUNTIME_PROVIDER', env);
|
|
91
127
|
const agentApiKey = requireEnv('BORGEE_AGENT_API_KEY', env);
|
|
128
|
+
const providerConfig = resolveProviderCommandConfig({
|
|
129
|
+
claudeCommand: envOr('CLAUDE_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.claudeCommand, env),
|
|
130
|
+
claudeArgs: parseArgs(envOr('CLAUDE_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.claudeArgs.join(' '), env)),
|
|
131
|
+
codexCommand: envOr('CODEX_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.codexCommand, env),
|
|
132
|
+
codexArgs: parseArgs(envOr('CODEX_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.codexArgs.join(' '), env)),
|
|
133
|
+
copilotCommand: envOr('COPILOT_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.copilotCommand, env),
|
|
134
|
+
copilotArgs: parseArgs(envOr('COPILOT_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.copilotArgs.join(' '), env)),
|
|
135
|
+
copilotSessionTtlMinutes: env.COPILOT_SESSION_TTL_MINUTES && env.COPILOT_SESSION_TTL_MINUTES.trim().length > 0
|
|
136
|
+
? parseCopilotSessionTtlMinutesValue(env.COPILOT_SESSION_TTL_MINUTES, 'environment variable COPILOT_SESSION_TTL_MINUTES')
|
|
137
|
+
: DEFAULT_PROVIDER_COMMAND_CONFIG.copilotSessionTtlMinutes,
|
|
138
|
+
});
|
|
139
|
+
assertProviderCommandCompatibility(provider, providerConfig, 'environment variables');
|
|
92
140
|
return {
|
|
93
141
|
borgeeBaseUrl: requireEnv('BORGEE_BASE_URL', env),
|
|
94
142
|
stateRootDir: resolveSingleAgentStateRoot(env, undefined, agentApiKey),
|
|
95
|
-
...
|
|
96
|
-
claudeCommand: envOr('CLAUDE_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.claudeCommand, env),
|
|
97
|
-
claudeArgs: parseArgs(envOr('CLAUDE_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.claudeArgs.join(' '), env)),
|
|
98
|
-
codexCommand: envOr('CODEX_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.codexCommand, env),
|
|
99
|
-
codexArgs: parseArgs(envOr('CODEX_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.codexArgs.join(' '), env)),
|
|
100
|
-
copilotCommand: envOr('COPILOT_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.copilotCommand, env),
|
|
101
|
-
copilotArgs: parseArgs(envOr('COPILOT_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.copilotArgs.join(' '), env)),
|
|
102
|
-
copilotSessionTtlMinutes: env.COPILOT_SESSION_TTL_MINUTES && env.COPILOT_SESSION_TTL_MINUTES.trim().length > 0
|
|
103
|
-
? parseCopilotSessionTtlMinutesValue(env.COPILOT_SESSION_TTL_MINUTES, 'environment variable COPILOT_SESSION_TTL_MINUTES')
|
|
104
|
-
: DEFAULT_PROVIDER_COMMAND_CONFIG.copilotSessionTtlMinutes,
|
|
105
|
-
}),
|
|
143
|
+
...providerConfig,
|
|
106
144
|
agent: {
|
|
107
145
|
agentApiKey,
|
|
108
146
|
agentName: envOr('BORGEE_AGENT_NAME', 'Assistant', env),
|
|
@@ -778,8 +778,12 @@ function parseUpdateTaskInput(taskId, body) {
|
|
|
778
778
|
status: readOptionalString(body.status),
|
|
779
779
|
assigneeId: readOptionalString(body.assigneeId) ?? readOptionalString(body.assignee_id),
|
|
780
780
|
title: readOptionalString(body.title),
|
|
781
|
+
description: readOptionalString(body.description),
|
|
781
782
|
};
|
|
782
|
-
if (input.status === undefined &&
|
|
783
|
+
if (input.status === undefined &&
|
|
784
|
+
input.assigneeId === undefined &&
|
|
785
|
+
input.title === undefined &&
|
|
786
|
+
input.description === undefined) {
|
|
783
787
|
throw new GatewayHttpError(400, { error: 'no_updates' }, 'bad-request');
|
|
784
788
|
}
|
|
785
789
|
return input;
|
package/dist/local-config.js
CHANGED
|
@@ -2,7 +2,7 @@ import { promises as fs } from 'node:fs';
|
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { dirname, extname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
4
4
|
import { parseDocument, stringify } from 'yaml';
|
|
5
|
-
import { assertProviderCompatibility, optionalNonEmptyString, optionalStringArray, parseCopilotSessionTtlMinutesValue, requireNonEmptyString, resolveProvider, resolveProviderCommandConfig, } from './config.js';
|
|
5
|
+
import { assertProviderCompatibility, assertProviderCommandCompatibility, optionalNonEmptyString, optionalStringArray, parseCopilotSessionTtlMinutesValue, requireNonEmptyString, resolveProvider, resolveProviderCommandConfig, } from './config.js';
|
|
6
6
|
import { resolveLocalConfigAgentStateRoot } from './state-paths.js';
|
|
7
7
|
const SUPPORTED_CONFIG_EXTENSIONS = new Set(['.json', '.yaml', '.yml']);
|
|
8
8
|
export const DEFAULT_LOCAL_HOST_CONFIG_FILENAME = 'agents-host.yaml';
|
|
@@ -186,6 +186,8 @@ export function parseGenerateConfigSpec(value, sourceLabel, env = process.env) {
|
|
|
186
186
|
throw new Error(`Invalid generate-config agents[${index}] in ${sourceLabel}: expected an object`);
|
|
187
187
|
}
|
|
188
188
|
const agent = parseAgentConfigFile(`generate-config agents[${index}] in ${sourceLabel}`, entry, env);
|
|
189
|
+
const providerConfig = resolveAgentProviderCommandConfig(host.defaults, agent);
|
|
190
|
+
assertProviderCommandCompatibility(agent.provider, providerConfig, `generate-config agents[${index}] in ${sourceLabel}`);
|
|
189
191
|
const existingIndex = seenKeys.get(agent.key);
|
|
190
192
|
if (existingIndex !== undefined) {
|
|
191
193
|
throw new Error(`Duplicate generate-config agent key "${agent.key}" in ${sourceLabel} at indexes ${existingIndex} and ${index}`);
|
|
@@ -598,6 +600,7 @@ function buildManagedAgentSnapshot(host, stateRootBaseDir, sourcePath, agent) {
|
|
|
598
600
|
...host.defaults,
|
|
599
601
|
...parseProviderCommandOverrides(agent, `agent config ${sourcePath}`),
|
|
600
602
|
});
|
|
603
|
+
assertProviderCommandCompatibility(agent.provider, providerConfig, `agent config ${sourcePath}`);
|
|
601
604
|
const config = {
|
|
602
605
|
borgeeBaseUrl: host.borgeeBaseUrl,
|
|
603
606
|
stateRootDir: resolveLocalConfigAgentStateRoot(stateRootBaseDir, agent.key),
|
|
@@ -614,6 +617,20 @@ function buildManagedAgentSnapshot(host, stateRootBaseDir, sourcePath, agent) {
|
|
|
614
617
|
config,
|
|
615
618
|
};
|
|
616
619
|
}
|
|
620
|
+
function resolveAgentProviderCommandConfig(hostDefaults, agent) {
|
|
621
|
+
return resolveProviderCommandConfig({
|
|
622
|
+
...hostDefaults,
|
|
623
|
+
...(agent.claudeCommand !== undefined ? { claudeCommand: agent.claudeCommand } : {}),
|
|
624
|
+
...(agent.claudeArgs !== undefined ? { claudeArgs: agent.claudeArgs } : {}),
|
|
625
|
+
...(agent.codexCommand !== undefined ? { codexCommand: agent.codexCommand } : {}),
|
|
626
|
+
...(agent.codexArgs !== undefined ? { codexArgs: agent.codexArgs } : {}),
|
|
627
|
+
...(agent.copilotCommand !== undefined ? { copilotCommand: agent.copilotCommand } : {}),
|
|
628
|
+
...(agent.copilotArgs !== undefined ? { copilotArgs: agent.copilotArgs } : {}),
|
|
629
|
+
...(agent.copilotSessionTtlMinutes !== undefined
|
|
630
|
+
? { copilotSessionTtlMinutes: agent.copilotSessionTtlMinutes }
|
|
631
|
+
: {}),
|
|
632
|
+
});
|
|
633
|
+
}
|
|
617
634
|
export async function loadLocalConfigSnapshot(hostConfigPath, deps = {}) {
|
|
618
635
|
const fileSystem = deps.fileSystem ?? nodeFileSystem;
|
|
619
636
|
const absoluteHostConfigPath = resolve(hostConfigPath);
|
|
@@ -698,6 +715,8 @@ export async function loadLocalConfigGenerateSpec(hostConfigPath, deps = {}) {
|
|
|
698
715
|
}
|
|
699
716
|
const agentRecord = await loadParsedDocument(fileSystem, agentFilePath, 'agent config');
|
|
700
717
|
const agentConfig = parseAgentConfigFile(agentFilePath, agentRecord, deps.env);
|
|
718
|
+
const providerConfig = resolveAgentProviderCommandConfig(hostConfig.defaults, agentConfig);
|
|
719
|
+
assertProviderCommandCompatibility(agentConfig.provider, providerConfig, `agent config ${agentFilePath}`);
|
|
701
720
|
const existingPath = seenKeys.get(agentConfig.key);
|
|
702
721
|
if (existingPath) {
|
|
703
722
|
throw new Error(`Duplicate agent key "${agentConfig.key}" in ${existingPath} and ${agentFilePath}`);
|
package/dist/managed-daemon.js
CHANGED
|
@@ -5,8 +5,8 @@ import { createConnection, createServer } from 'node:net';
|
|
|
5
5
|
import { dirname, join, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { AgentsHostSupervisor } from './agents-host-supervisor.js';
|
|
8
|
-
import { COMPATIBILITY_GATES_ENV, createManagedRuntimeSettingsFingerprint, INTERNAL_DISABLED_COMPATIBILITY_GATES_ENV, INTERNAL_POLICY_MODE_ENV, INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV, MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE, MANAGED_RUNTIME_SETTINGS_SCHEMA_VERSION, resolveDisabledDefaultCompatibilityGates, resolveManagedRuntimeSettingsSnapshot, normalizeInternalProviderImplementationOverrides, } from './compatibility-gates.js';
|
|
9
|
-
import { loadConfigFromEnv } from './config.js';
|
|
8
|
+
import { CLAUDE_PROVIDER_V2_COMPATIBILITY_GATE, COMPATIBILITY_GATES_ENV, createManagedRuntimeSettingsFingerprint, INTERNAL_DISABLED_COMPATIBILITY_GATES_ENV, INTERNAL_POLICY_MODE_ENV, INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV, MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE, MANAGED_RUNTIME_SETTINGS_SCHEMA_VERSION, resolveDisabledDefaultCompatibilityGates, resolveManagedRuntimeSettingsSnapshot, normalizeInternalProviderImplementationOverrides, } from './compatibility-gates.js';
|
|
9
|
+
import { DEFAULT_PROVIDER_COMMAND_CONFIG, hasLegacyClaudeOneShotArgs, loadConfigFromEnv, } from './config.js';
|
|
10
10
|
import { loadLocalConfigGenerateSpec, materializeLocalConfig, parseGenerateConfigSpec, resolveLocalConfigLayout, } from './local-config.js';
|
|
11
11
|
import { normalizeManagedRuntimeKey, resolveManagedBootstrapLockPath, resolveManagedDaemonLogPath, resolveManagedDaemonSocketPath, resolveManagedRuntimeRoot, resolveManagedRuntimeSettingsPath, } from './state-paths.js';
|
|
12
12
|
const MANAGED_ROOT_MODE = 0o700;
|
|
@@ -149,8 +149,9 @@ function resolveDesiredManagedRuntimeSettings(env = process.env) {
|
|
|
149
149
|
function normalizeManagedRuntimeSettingsSnapshot(snapshot) {
|
|
150
150
|
const compatibilityGates = [...new Set(snapshot.compatibilityGates.map((gate) => gate.trim()))]
|
|
151
151
|
.filter((gate) => gate.length > 0)
|
|
152
|
+
.filter((gate) => gate !== CLAUDE_PROVIDER_V2_COMPATIBILITY_GATE)
|
|
152
153
|
.sort((left, right) => left.localeCompare(right));
|
|
153
|
-
const providerImplementationOverrides = normalizeInternalProviderImplementationOverrides(snapshot.providerImplementationOverrides.join(','));
|
|
154
|
+
const providerImplementationOverrides = normalizeInternalProviderImplementationOverrides(snapshot.providerImplementationOverrides.join(',')).filter((assignment) => !assignment.startsWith('claude:'));
|
|
154
155
|
return {
|
|
155
156
|
schemaVersion: MANAGED_RUNTIME_SETTINGS_SCHEMA_VERSION,
|
|
156
157
|
compatibilityGates,
|
|
@@ -341,9 +342,18 @@ export function buildManagedLocalAgentConfig(options) {
|
|
|
341
342
|
},
|
|
342
343
|
};
|
|
343
344
|
}
|
|
344
|
-
function mergeManagedLocalAgentConfig(existingAgent, generatedAgent, envOverrides) {
|
|
345
|
+
function mergeManagedLocalAgentConfig(hostDefaults, existingAgent, generatedAgent, envOverrides) {
|
|
345
346
|
const overrides = envOverrides ?? {};
|
|
346
347
|
const hasOverride = (key) => Object.prototype.hasOwnProperty.call(overrides, key);
|
|
348
|
+
const effectiveExistingClaudeCommand = existingAgent.claudeCommand ?? hostDefaults?.claudeCommand;
|
|
349
|
+
const effectiveExistingClaudeArgs = existingAgent.claudeArgs ?? hostDefaults?.claudeArgs ?? [];
|
|
350
|
+
const hasLegacyClaudeDefaults = effectiveExistingClaudeCommand === 'claude' && hasLegacyClaudeOneShotArgs(effectiveExistingClaudeArgs);
|
|
351
|
+
const shouldRefreshLegacyClaudeDefaults = hasLegacyClaudeDefaults
|
|
352
|
+
&& generatedAgent.claudeCommand === DEFAULT_PROVIDER_COMMAND_CONFIG.claudeCommand
|
|
353
|
+
&& JSON.stringify(generatedAgent.claudeArgs ?? []) === JSON.stringify(DEFAULT_PROVIDER_COMMAND_CONFIG.claudeArgs);
|
|
354
|
+
const shouldResetLegacyClaudeArgsForCommandOverride = hasLegacyClaudeDefaults
|
|
355
|
+
&& hasOverride('CLAUDE_COMMAND')
|
|
356
|
+
&& !hasOverride('CLAUDE_ARGS');
|
|
347
357
|
return {
|
|
348
358
|
...cloneLocalAgentConfig(existingAgent),
|
|
349
359
|
key: generatedAgent.key,
|
|
@@ -351,8 +361,12 @@ function mergeManagedLocalAgentConfig(existingAgent, generatedAgent, envOverride
|
|
|
351
361
|
enabled: true,
|
|
352
362
|
name: hasOverride('BORGEE_AGENT_NAME') ? generatedAgent.name : existingAgent.name,
|
|
353
363
|
provider: hasOverride('RUNTIME_PROVIDER') ? generatedAgent.provider : existingAgent.provider,
|
|
354
|
-
claudeCommand: hasOverride('CLAUDE_COMMAND')
|
|
364
|
+
claudeCommand: hasOverride('CLAUDE_COMMAND') || shouldRefreshLegacyClaudeDefaults
|
|
365
|
+
? generatedAgent.claudeCommand
|
|
366
|
+
: existingAgent.claudeCommand,
|
|
355
367
|
claudeArgs: hasOverride('CLAUDE_ARGS')
|
|
368
|
+
|| shouldRefreshLegacyClaudeDefaults
|
|
369
|
+
|| shouldResetLegacyClaudeArgsForCommandOverride
|
|
356
370
|
? [...(generatedAgent.claudeArgs ?? [])]
|
|
357
371
|
: [...(existingAgent.claudeArgs ?? [])],
|
|
358
372
|
codexCommand: hasOverride('CODEX_COMMAND') ? generatedAgent.codexCommand : existingAgent.codexCommand,
|
|
@@ -1005,7 +1019,7 @@ export async function bootstrapManagedDaemonStart(options, deps = {}) {
|
|
|
1005
1019
|
return existingAgent
|
|
1006
1020
|
? {
|
|
1007
1021
|
...generatedManagedAgent,
|
|
1008
|
-
agent: mergeManagedLocalAgentConfig(existingAgent, generatedManagedAgent.agent, explicitManagedAgentOverrides),
|
|
1022
|
+
agent: mergeManagedLocalAgentConfig(currentManagedSpec?.host.defaults, existingAgent, generatedManagedAgent.agent, explicitManagedAgentOverrides),
|
|
1009
1023
|
}
|
|
1010
1024
|
: generatedManagedAgent;
|
|
1011
1025
|
})();
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import spawn from 'cross-spawn';
|
|
2
|
+
import { PROTOCOL_VERSION, client, methods, ndJsonStream } from '@agentclientprotocol/sdk';
|
|
2
3
|
import { type DebugLogger } from '../../debug.js';
|
|
3
4
|
import type { PreparedProviderTurnInput, ProviderGenerateOptions } from '../../types.js';
|
|
4
5
|
import type { ClaudeChannelSessionStore } from './session-store.js';
|
|
5
|
-
interface
|
|
6
|
+
interface ClaudeAcpRuntime {
|
|
6
7
|
spawn: typeof spawn;
|
|
8
|
+
client: typeof client;
|
|
9
|
+
ndJsonStream: typeof ndJsonStream;
|
|
10
|
+
methods: typeof methods;
|
|
11
|
+
protocolVersion: typeof PROTOCOL_VERSION;
|
|
7
12
|
cwd: string;
|
|
13
|
+
shutdownGracePeriodMs: number;
|
|
14
|
+
shutdownForceKillWaitMs: number;
|
|
8
15
|
}
|
|
9
16
|
/**
|
|
10
|
-
*
|
|
11
|
-
* native provider-session continuity.
|
|
17
|
+
* Persistent ACP-backed client for the Claude ACP adapter.
|
|
12
18
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
19
|
+
* The public caller surface intentionally stays stable: callers still create a
|
|
20
|
+
* `ClaudeCliClient`, then call `generateReply()` and `dispose()`. Internally,
|
|
21
|
+
* the shipped runtime now runs one Claude ACP adapter process and reuses one
|
|
22
|
+
* ACP session per routed Borgee channel.
|
|
17
23
|
*/
|
|
18
24
|
export declare class ClaudeCliClient {
|
|
19
25
|
private readonly command;
|
|
@@ -24,28 +30,61 @@ export declare class ClaudeCliClient {
|
|
|
24
30
|
private readonly runtime;
|
|
25
31
|
private readonly channels;
|
|
26
32
|
private readonly persistedSessions;
|
|
33
|
+
private readonly closingSessions;
|
|
34
|
+
private readonly pendingSessionStarts;
|
|
35
|
+
private readonly pendingSessionCloses;
|
|
36
|
+
private readonly pendingSessionStoreOperations;
|
|
37
|
+
private readonly fatalPromise;
|
|
38
|
+
private rejectFatalPromise;
|
|
39
|
+
private child?;
|
|
40
|
+
private connection?;
|
|
41
|
+
private startPromise?;
|
|
42
|
+
private shutdownPromise?;
|
|
43
|
+
private childExitPromise?;
|
|
44
|
+
private resolveChildExit?;
|
|
45
|
+
private fatalError;
|
|
46
|
+
private disposing;
|
|
47
|
+
private backendClosed;
|
|
27
48
|
private loadedSessionStoreAgentId;
|
|
28
|
-
private stopped;
|
|
29
49
|
private sessionStoreLoadPromise;
|
|
30
50
|
private sessionStoreWriteQueue;
|
|
31
|
-
|
|
51
|
+
private sessionCapabilities;
|
|
52
|
+
private childStderr;
|
|
53
|
+
constructor(command: string, args?: string[], runtimeOverrides?: Partial<ClaudeAcpRuntime>, sessionStore?: ClaudeChannelSessionStore | undefined, resolveSessionStoreAgentId?: () => string | undefined, logger?: DebugLogger);
|
|
32
54
|
generateReply(turn: PreparedProviderTurnInput, options?: ProviderGenerateOptions): Promise<string>;
|
|
33
55
|
generateReply(channelId: string, prompt: string, options?: ProviderGenerateOptions): Promise<string>;
|
|
34
56
|
dispose(): Promise<void>;
|
|
57
|
+
private ensureStarted;
|
|
58
|
+
private startBackend;
|
|
35
59
|
private getOrCreateChannelState;
|
|
36
60
|
private processChannelQueue;
|
|
61
|
+
private getOrCreateSession;
|
|
62
|
+
private startFreshSession;
|
|
63
|
+
private restoreOrCreateSession;
|
|
64
|
+
private restoreSession;
|
|
65
|
+
private clearBufferedSessionReplay;
|
|
66
|
+
private resolveSessionCwd;
|
|
67
|
+
private recycleSessionIfScopeChanged;
|
|
37
68
|
private runTurn;
|
|
38
|
-
private
|
|
69
|
+
private raceWithFatal;
|
|
70
|
+
private failAll;
|
|
71
|
+
private handlePermissionRequest;
|
|
72
|
+
private invalidateSession;
|
|
73
|
+
private closeSession;
|
|
74
|
+
private rejectQueuedTurnsAfterSessionTaint;
|
|
75
|
+
private findChannelIdBySessionId;
|
|
39
76
|
private currentSessionStoreAgentId;
|
|
40
77
|
private ensureSessionStoreLoaded;
|
|
41
|
-
private
|
|
78
|
+
private readPersistedSessionId;
|
|
42
79
|
private persistSession;
|
|
43
80
|
private persistSessionBestEffort;
|
|
44
|
-
private
|
|
45
|
-
private
|
|
46
|
-
private resetSessionIfCwdChanged;
|
|
47
|
-
private resetPersistedSessionBestEffort;
|
|
81
|
+
private clearPersistedSession;
|
|
82
|
+
private clearPersistedSessionBestEffort;
|
|
48
83
|
private enqueueSessionStoreWrite;
|
|
49
|
-
private
|
|
84
|
+
private trackSessionStoreOperation;
|
|
85
|
+
private shutdownBackend;
|
|
86
|
+
private waitForPendingSessionStarts;
|
|
87
|
+
private waitForPendingSessionCloses;
|
|
88
|
+
private waitForChildExit;
|
|
50
89
|
}
|
|
51
90
|
export {};
|