@yu_robotics/remote-cli 1.6.75 → 1.6.85
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 +32 -1
- package/dist/client/MessageHandler.d.ts +2 -0
- package/dist/client/MessageHandler.d.ts.map +1 -1
- package/dist/client/MessageHandler.js +136 -26
- package/dist/client/MessageHandler.js.map +1 -1
- package/dist/delegation/BackendRegistry.d.ts +22 -0
- package/dist/delegation/BackendRegistry.d.ts.map +1 -0
- package/dist/delegation/BackendRegistry.js +44 -0
- package/dist/delegation/BackendRegistry.js.map +1 -0
- package/dist/delegation/DelegationBridge.d.ts +14 -0
- package/dist/delegation/DelegationBridge.d.ts.map +1 -0
- package/dist/delegation/DelegationBridge.js +130 -0
- package/dist/delegation/DelegationBridge.js.map +1 -0
- package/dist/delegation/DelegationManager.d.ts +56 -0
- package/dist/delegation/DelegationManager.d.ts.map +1 -0
- package/dist/delegation/DelegationManager.js +346 -0
- package/dist/delegation/DelegationManager.js.map +1 -0
- package/dist/delegation/DelegationStore.d.ts +27 -0
- package/dist/delegation/DelegationStore.d.ts.map +1 -0
- package/dist/delegation/DelegationStore.js +114 -0
- package/dist/delegation/DelegationStore.js.map +1 -0
- package/dist/delegation/WorkerPolicy.d.ts +6 -0
- package/dist/delegation/WorkerPolicy.d.ts.map +1 -0
- package/dist/delegation/WorkerPolicy.js +35 -0
- package/dist/delegation/WorkerPolicy.js.map +1 -0
- package/dist/delegation/contract.d.ts +82 -0
- package/dist/delegation/contract.d.ts.map +1 -0
- package/dist/delegation/contract.js +68 -0
- package/dist/delegation/contract.js.map +1 -0
- package/dist/delegation/mcpServer.d.ts +2 -0
- package/dist/delegation/mcpServer.d.ts.map +1 -0
- package/dist/delegation/mcpServer.js +87 -0
- package/dist/delegation/mcpServer.js.map +1 -0
- package/dist/delegation/piExtension.d.ts +15 -0
- package/dist/delegation/piExtension.d.ts.map +1 -0
- package/dist/delegation/piExtension.js +42 -0
- package/dist/delegation/piExtension.js.map +1 -0
- package/dist/executor/AcpExecutor.d.ts +11 -0
- package/dist/executor/AcpExecutor.d.ts.map +1 -1
- package/dist/executor/AcpExecutor.js +77 -7
- package/dist/executor/AcpExecutor.js.map +1 -1
- package/dist/executor/AgyExecutor.d.ts +10 -0
- package/dist/executor/AgyExecutor.d.ts.map +1 -1
- package/dist/executor/AgyExecutor.js +82 -8
- package/dist/executor/AgyExecutor.js.map +1 -1
- package/dist/executor/ClaudePersistentExecutor.d.ts +5 -1
- package/dist/executor/ClaudePersistentExecutor.d.ts.map +1 -1
- package/dist/executor/ClaudePersistentExecutor.js +65 -38
- package/dist/executor/ClaudePersistentExecutor.js.map +1 -1
- package/dist/executor/CodexAppServerExecutor.d.ts +6 -0
- package/dist/executor/CodexAppServerExecutor.d.ts.map +1 -1
- package/dist/executor/CodexAppServerExecutor.js +26 -1
- package/dist/executor/CodexAppServerExecutor.js.map +1 -1
- package/dist/executor/CodexSandbox.d.ts +1 -1
- package/dist/executor/CodexSandbox.d.ts.map +1 -1
- package/dist/executor/CodexSandbox.js +5 -1
- package/dist/executor/CodexSandbox.js.map +1 -1
- package/dist/executor/IExecutor.d.ts +5 -0
- package/dist/executor/IExecutor.d.ts.map +1 -1
- package/dist/executor/KimiExecutor.d.ts +1 -0
- package/dist/executor/KimiExecutor.d.ts.map +1 -1
- package/dist/executor/KimiExecutor.js +1 -0
- package/dist/executor/KimiExecutor.js.map +1 -1
- package/dist/executor/OpenCodeExecutor.d.ts +1 -0
- package/dist/executor/OpenCodeExecutor.d.ts.map +1 -1
- package/dist/executor/OpenCodeExecutor.js +1 -0
- package/dist/executor/OpenCodeExecutor.js.map +1 -1
- package/dist/executor/PiExecutor.d.ts +7 -0
- package/dist/executor/PiExecutor.d.ts.map +1 -1
- package/dist/executor/PiExecutor.js +61 -12
- package/dist/executor/PiExecutor.js.map +1 -1
- package/dist/executor/ZCodeExecutor.d.ts +1 -0
- package/dist/executor/ZCodeExecutor.d.ts.map +1 -1
- package/dist/executor/ZCodeExecutor.js +1 -0
- package/dist/executor/ZCodeExecutor.js.map +1 -1
- package/dist/executor/acp/AcpClient.d.ts +11 -6
- package/dist/executor/acp/AcpClient.d.ts.map +1 -1
- package/dist/executor/acp/AcpClient.js +23 -7
- package/dist/executor/acp/AcpClient.js.map +1 -1
- package/dist/executor/acp/AcpTypes.d.ts +10 -0
- package/dist/executor/acp/AcpTypes.d.ts.map +1 -1
- package/dist/executor/agy/AgyDelegationConfig.d.ts +3 -0
- package/dist/executor/agy/AgyDelegationConfig.d.ts.map +1 -0
- package/dist/executor/agy/AgyDelegationConfig.js +105 -0
- package/dist/executor/agy/AgyDelegationConfig.js.map +1 -0
- package/dist/executor/index.d.ts +4 -1
- package/dist/executor/index.d.ts.map +1 -1
- package/dist/executor/index.js +10 -4
- package/dist/executor/index.js.map +1 -1
- package/dist/executor/pi/PiClient.d.ts +2 -0
- package/dist/executor/pi/PiClient.d.ts.map +1 -1
- package/dist/executor/pi/PiClient.js +43 -5
- package/dist/executor/pi/PiClient.js.map +1 -1
- package/dist/executor/pi/PiTypes.d.ts +3 -0
- package/dist/executor/pi/PiTypes.d.ts.map +1 -1
- package/dist/executor/pi/PiTypes.js +6 -0
- package/dist/executor/pi/PiTypes.js.map +1 -1
- package/dist/executor/zcode/ZCodeClient.d.ts +7 -3
- package/dist/executor/zcode/ZCodeClient.d.ts.map +1 -1
- package/dist/executor/zcode/ZCodeClient.js +13 -2
- package/dist/executor/zcode/ZCodeClient.js.map +1 -1
- package/dist/thread/ThreadExecutorPool.d.ts +7 -0
- package/dist/thread/ThreadExecutorPool.d.ts.map +1 -1
- package/dist/thread/ThreadExecutorPool.js +1 -0
- package/dist/thread/ThreadExecutorPool.js.map +1 -1
- package/dist/thread/ThreadManager.d.ts +1 -1
- package/dist/thread/ThreadManager.d.ts.map +1 -1
- package/dist/thread/ThreadManager.js.map +1 -1
- package/dist/thread/types.d.ts +4 -0
- package/dist/thread/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,11 @@ The client is normally installed and run directly on the developer's machine rat
|
|
|
26
26
|
|
|
27
27
|
## Installation
|
|
28
28
|
|
|
29
|
+
Sending local image files requires a Router with image forwarding support and
|
|
30
|
+
the bot application's `im:resource` permission. Router 1.6.85 and newer render
|
|
31
|
+
local and URL-based Markdown image references as captions; the uploaded image
|
|
32
|
+
is rendered separately using its Feishu image key. Code examples are preserved.
|
|
33
|
+
|
|
29
34
|
```bash
|
|
30
35
|
npm install -g @yu_robotics/remote-cli
|
|
31
36
|
```
|
|
@@ -91,7 +96,7 @@ Linux users upgrading from version 1.6.23 or earlier should run `remote-cli serv
|
|
|
91
96
|
| Command | Description |
|
|
92
97
|
|---------|-------------|
|
|
93
98
|
| `/help` | Show help information |
|
|
94
|
-
| `/status` | Show backend, model, effort, queue, and thread status |
|
|
99
|
+
| `/status` | Show backend, model, effort, delegation, queue, and thread status |
|
|
95
100
|
| `/context` | Show current session context and queue diagnostics |
|
|
96
101
|
| `/skills` | List available skills for the active backend |
|
|
97
102
|
| `/abort` | Abort executing task in current thread |
|
|
@@ -104,6 +109,7 @@ Linux users upgrading from version 1.6.23 or earlier should run `remote-cli serv
|
|
|
104
109
|
| `/effort [auto|level]` | Show or set Codex/AGY/OpenCode/Kimi/ZCode/Pi reasoning effort |
|
|
105
110
|
| `/sandbox [on/off/read-only/default]` | Configure the current Codex or Claude Code thread sandbox, directory grants, and networking |
|
|
106
111
|
| `/backend` | List backends and show the current thread's effective backend |
|
|
112
|
+
| `/delegation [on|off]` | Inspect or enable delegation between installed agent backends in this thread |
|
|
107
113
|
| `/backend <index>` | Switch all threads and clear per-thread backend overrides |
|
|
108
114
|
| `/backend <index> @` | Switch only the current thread |
|
|
109
115
|
| `/backend default @` | Clear the current thread override and follow the global backend |
|
|
@@ -113,6 +119,31 @@ Linux users upgrading from version 1.6.23 or earlier should run `remote-cli serv
|
|
|
113
119
|
|
|
114
120
|
### Threads & Machines
|
|
115
121
|
|
|
122
|
+
Use `/delegation on` in an existing thread to let its selected backend assign
|
|
123
|
+
bounded tasks to other installed, authenticated backends. Claude Code, Codex,
|
|
124
|
+
Pi, AGY, OpenCode, Kimi Code, and ZCode can coordinate or work, including sessions of
|
|
125
|
+
the same backend. Workers return results to the original conversation and use
|
|
126
|
+
its working directory; they do not create extra thread buttons. `/delegation`
|
|
127
|
+
shows discovery and restrictions; `/delegation off` disables the feature. The
|
|
128
|
+
setting is off by default and persists per thread. Start with one trial thread;
|
|
129
|
+
never-enabled threads skip managed tools, prompt changes, and delegation
|
|
130
|
+
configuration. Turning it off cleans only backends used for delegation, including
|
|
131
|
+
when resumed after a CLI restart or a backend switch, while preserving their
|
|
132
|
+
conversations.
|
|
133
|
+
|
|
134
|
+
`/status` shows `Delegation: on/off (current thread)` for the thread receiving
|
|
135
|
+
the command. Reading this setting does not initialize delegation or start workers.
|
|
136
|
+
|
|
137
|
+
Child progress, approvals, and questions use the existing reply flow. `/abort`
|
|
138
|
+
stops managed children as well as the parent. Sandboxed coordinators can delegate
|
|
139
|
+
only to the same backend; enforced read-only workers require Claude Code or Codex. There is one
|
|
140
|
+
active child per parent and at most three per CLI process, with overlapping
|
|
141
|
+
workspaces serialized and bounded time/output. Workspace reservations apply to
|
|
142
|
+
delegation-enabled work; opted-out threads keep ordinary workspace access, so
|
|
143
|
+
use separate workspaces for independent writers. See
|
|
144
|
+
[Cross-backend Delegation](../../README.md#cross-backend-delegation) for limits,
|
|
145
|
+
recovery, context transfer, and permission behavior.
|
|
146
|
+
|
|
116
147
|
| Command | Description |
|
|
117
148
|
|---------|-------------|
|
|
118
149
|
| `/thread list/new/delete` | Manage session threads |
|
|
@@ -38,6 +38,8 @@ export declare class MessageHandler {
|
|
|
38
38
|
private automaticUpdateInProgress;
|
|
39
39
|
private approvalCardsSupported;
|
|
40
40
|
private readonly pendingApprovalCards;
|
|
41
|
+
private readonly delegation;
|
|
42
|
+
private readonly delegationBridges;
|
|
41
43
|
constructor(wsClient: WebSocketClient, threadPool: ThreadExecutorPool, threadManager: ThreadManager, directoryGuard: DirectoryGuard, config: ConfigManager);
|
|
42
44
|
/**
|
|
43
45
|
* Handle message (supports new IncomingMessage format)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageHandler.d.ts","sourceRoot":"","sources":["../../src/client/MessageHandler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAwI,MAAM,UAAU,CAAC;AACjL,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAKxD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"MessageHandler.d.ts","sourceRoot":"","sources":["../../src/client/MessageHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,11 +7,15 @@ const LocalImageDetector_1 = require("../utils/LocalImageDetector");
|
|
|
7
7
|
const MachineCommands_1 = require("../machines/MachineCommands");
|
|
8
8
|
const child_process_1 = require("child_process");
|
|
9
9
|
const promises_1 = require("fs/promises");
|
|
10
|
+
const fs_1 = require("fs");
|
|
10
11
|
const os_1 = require("os");
|
|
11
12
|
const path_1 = require("path");
|
|
12
13
|
const config_1 = require("../types/config");
|
|
13
14
|
const uuid_1 = require("uuid");
|
|
14
15
|
const ZCodeCommand_1 = require("../executor/zcode/ZCodeCommand");
|
|
16
|
+
const DelegationManager_1 = require("../delegation/DelegationManager");
|
|
17
|
+
const DelegationBridge_1 = require("../delegation/DelegationBridge");
|
|
18
|
+
const contract_1 = require("../delegation/contract");
|
|
15
19
|
const EFFORT_BACKENDS = new Set(['codex', 'agy', 'opencode', 'kimi', 'zcode', 'pi']);
|
|
16
20
|
const NATIVE_MODEL_LIST_BACKENDS = new Set(['codex', 'opencode', 'kimi', 'zcode', 'pi']);
|
|
17
21
|
const SLASH_SESSION_BACKENDS = new Set(['opencode', 'kimi', 'zcode', 'pi']);
|
|
@@ -89,12 +93,15 @@ class MessageHandler {
|
|
|
89
93
|
automaticUpdateInProgress = false;
|
|
90
94
|
approvalCardsSupported = false;
|
|
91
95
|
pendingApprovalCards = new Map();
|
|
96
|
+
delegation;
|
|
97
|
+
delegationBridges = new Map();
|
|
92
98
|
constructor(wsClient, threadPool, threadManager, directoryGuard, config) {
|
|
93
99
|
this.wsClient = wsClient;
|
|
94
100
|
this.threadPool = threadPool;
|
|
95
101
|
this.threadManager = threadManager;
|
|
96
102
|
this.directoryGuard = directoryGuard;
|
|
97
103
|
this.config = config;
|
|
104
|
+
this.delegation = new DelegationManager_1.DelegationManager(directoryGuard);
|
|
98
105
|
this.notificationAdapter = new hooks_1.FeishuNotificationAdapter(wsClient);
|
|
99
106
|
this.notificationAdapter.setThreadNameResolver((threadId) => this.threadManager.getThread(threadId)?.name);
|
|
100
107
|
this.notificationAdapter.register();
|
|
@@ -242,9 +249,10 @@ class MessageHandler {
|
|
|
242
249
|
await this.handleBackendCommand(messageId, resolvedThreadId, content.trim());
|
|
243
250
|
return;
|
|
244
251
|
}
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
252
|
+
// Child input belongs to the child executor, even though the parent owns the thread.
|
|
253
|
+
const inputExecutor = this.delegation.waitingExecutor(resolvedThreadId) ?? executor;
|
|
254
|
+
if ('isWaitingInput' in inputExecutor && typeof inputExecutor.isWaitingInput === 'function') {
|
|
255
|
+
const ex = inputExecutor;
|
|
248
256
|
if (ex.isWaitingInput()) {
|
|
249
257
|
const input = content?.trim();
|
|
250
258
|
if (input) {
|
|
@@ -308,6 +316,7 @@ class MessageHandler {
|
|
|
308
316
|
return;
|
|
309
317
|
}
|
|
310
318
|
const queueSensitiveCommand = /^\/(?:clear|new|compact|cd|model|effort|sandbox)(?:\s|$)/.test(content?.trim() ?? '')
|
|
319
|
+
|| /^\/delegation\s+(?:on|off)(?:\s|$)/.test(content?.trim() ?? '')
|
|
311
320
|
|| /^\/thread\s+delete(?:\s|$)/.test(content?.trim() ?? '');
|
|
312
321
|
if (queueSensitiveCommand && this.hasThreadQueueState(resolvedThreadId)) {
|
|
313
322
|
this.sendResponse(messageId, resolvedThreadId, {
|
|
@@ -384,6 +393,8 @@ class MessageHandler {
|
|
|
384
393
|
const activeOperation = this.activeThreadOperations.get(threadId);
|
|
385
394
|
let aborted = false;
|
|
386
395
|
const operation = (async () => {
|
|
396
|
+
if (this.threadManager.getThread(threadId)?.delegation)
|
|
397
|
+
await this.delegation.cancelThread(threadId);
|
|
387
398
|
aborted = await executor.abort();
|
|
388
399
|
if (activeOperation)
|
|
389
400
|
await activeOperation.done;
|
|
@@ -453,6 +464,51 @@ class MessageHandler {
|
|
|
453
464
|
*/
|
|
454
465
|
async handleBuiltInCommand(messageId, threadId, content, executor) {
|
|
455
466
|
const trimmed = content.trim();
|
|
467
|
+
if (trimmed === '/delegation' || trimmed.startsWith('/delegation ')) {
|
|
468
|
+
const argument = trimmed.slice('/delegation'.length).trim();
|
|
469
|
+
if (argument && argument !== 'on' && argument !== 'off') {
|
|
470
|
+
this.sendResponse(messageId, threadId, { success: false, error: 'Usage: /delegation [on|off]' });
|
|
471
|
+
return true;
|
|
472
|
+
}
|
|
473
|
+
if (argument === 'on' && !executor.configureDelegation) {
|
|
474
|
+
this.sendResponse(messageId, threadId, { success: false, error: 'This executor does not support delegation tool registration.' });
|
|
475
|
+
return true;
|
|
476
|
+
}
|
|
477
|
+
if (argument) {
|
|
478
|
+
if (argument === 'off') {
|
|
479
|
+
const thread = this.threadManager.getThread(threadId);
|
|
480
|
+
const backend = this.threadPool.getBackendKey(threadId);
|
|
481
|
+
if (thread.delegationBackends?.includes(backend) || (thread.delegation && !thread.delegationBackends)) {
|
|
482
|
+
await executor.configureDelegation?.(undefined);
|
|
483
|
+
// Preserve cleanup ownership across process recreation and backend switches.
|
|
484
|
+
if (!thread.delegationBackends)
|
|
485
|
+
await this.threadManager.updateThread(threadId, { delegationBackends: [backend] });
|
|
486
|
+
}
|
|
487
|
+
await this.delegationBridges.get(threadId)?.close();
|
|
488
|
+
this.delegationBridges.delete(threadId);
|
|
489
|
+
}
|
|
490
|
+
await this.threadManager.updateThread(threadId, { delegation: argument === 'on' });
|
|
491
|
+
}
|
|
492
|
+
const config = this.config.get('executor') ?? { type: 'auto' };
|
|
493
|
+
const backends = await this.delegation.registry.list(config);
|
|
494
|
+
this.sendResponse(messageId, threadId, { success: true, output: [
|
|
495
|
+
`Delegation: ${this.threadManager.getThread(threadId)?.delegation ? 'on' : 'off'}`,
|
|
496
|
+
`Coordinator: ${executor.configureDelegation ? backendDisplayName(this.threadPool.getBackendKey(threadId)) : 'unsupported for this backend'}`,
|
|
497
|
+
...(this.threadPool.getBackendKey(threadId) === 'zcode'
|
|
498
|
+
? ['ZCode delegation temporarily replaces user-configured MCP servers. Native tools and plugins remain available; /delegation off restores the normal MCP configuration.'] : []),
|
|
499
|
+
...backends.map(item => `${item.backend}: ${item.installed ? item.version : item.reason}`),
|
|
500
|
+
'Authentication and quota are checked when a task runs. Sandboxed coordinators can delegate only to the same backend. Enforced read-only workers are available only for Claude Code and Codex.',
|
|
501
|
+
'Usage: /delegation on|off. Applies to this thread; workers use independent sessions.',
|
|
502
|
+
].join('\n') });
|
|
503
|
+
return true;
|
|
504
|
+
}
|
|
505
|
+
if (trimmed.startsWith('/')) {
|
|
506
|
+
const thread = this.threadManager.getThread(threadId);
|
|
507
|
+
if (!thread?.delegation && thread?.delegationBackends?.includes(this.threadPool.getBackendKey(threadId))) {
|
|
508
|
+
// Native slash commands can resume a session before the next ordinary turn.
|
|
509
|
+
await executor.configureDelegation?.(undefined);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
456
512
|
if (trimmed === '/sandbox' || trimmed.startsWith('/sandbox ')) {
|
|
457
513
|
if (!('getSandboxStatus' in executor) || !('configureSandbox' in executor)) {
|
|
458
514
|
this.sendResponse(messageId, threadId, { success: false, error: '/sandbox is currently supported by the Codex and Claude Code backends.' });
|
|
@@ -497,6 +553,7 @@ class MessageHandler {
|
|
|
497
553
|
output: `📊 Status:
|
|
498
554
|
- Thread: ${thread?.name ?? threadId}
|
|
499
555
|
- Backend: ${backend}
|
|
556
|
+
- Delegation: ${thread?.delegation ? 'on' : 'off'} (current thread)
|
|
500
557
|
- Model: ${model ?? 'backend default'}
|
|
501
558
|
- Reasoning effort: ${effort}
|
|
502
559
|
- Working Directory: ${cwd}
|
|
@@ -567,6 +624,7 @@ Use /compact to reduce conversation context or /clear to start a fresh context.`
|
|
|
567
624
|
- /model [name] - Show models for the active backend, or set this thread's model
|
|
568
625
|
- /effort [auto|level] - Show or set effort for Codex/AGY/OpenCode/Kimi/ZCode/Pi (Claude Code is unsupported)
|
|
569
626
|
- /sandbox [on|off|read-only|default|allow <directory>|remove <directory>|network on|off] - Configure this thread's sandbox (Codex, Claude Code)
|
|
627
|
+
- /delegation [on|off] - Delegate tasks between installed agent backends in this thread
|
|
570
628
|
- /backend - List backends and show the current thread's effective backend
|
|
571
629
|
- /backend <index> - Switch all threads and clear per-thread backend overrides
|
|
572
630
|
- /backend <index> @ - Switch only the current thread
|
|
@@ -1143,6 +1201,12 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1143
1201
|
return;
|
|
1144
1202
|
}
|
|
1145
1203
|
try {
|
|
1204
|
+
if (target.delegation || target.delegationBackends?.length) {
|
|
1205
|
+
await this.delegation.cancelThread(target.id);
|
|
1206
|
+
await this.delegationBridges.get(target.id)?.close();
|
|
1207
|
+
this.delegationBridges.delete(target.id);
|
|
1208
|
+
await this.delegation.store.deleteThread(target.id);
|
|
1209
|
+
}
|
|
1146
1210
|
await this.threadPool.destroyThread(target.id);
|
|
1147
1211
|
await this.threadManager.deleteThread(target.id);
|
|
1148
1212
|
this.sendResponse(messageId, callerThreadId, {
|
|
@@ -1407,7 +1471,7 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1407
1471
|
* its own --print invocation").
|
|
1408
1472
|
*/
|
|
1409
1473
|
static AGY_PASSTHROUGH_COMMANDS = new Set([
|
|
1410
|
-
'/help', '/model', '/skills', '/usage', '/config', '/changelog',
|
|
1474
|
+
'/help', '/model', '/skills', '/usage', '/quota', '/config', '/changelog',
|
|
1411
1475
|
'/agents', '/permissions', '/hooks', '/credits',
|
|
1412
1476
|
]);
|
|
1413
1477
|
async listLocalSkills(cwd, backend) {
|
|
@@ -1482,7 +1546,7 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1482
1546
|
if (backend === 'codex') {
|
|
1483
1547
|
this.sendResponse(messageId, threadId, {
|
|
1484
1548
|
success: false,
|
|
1485
|
-
error: `❌ "${command}" is not exposed as a Codex backend command.\n\nBuilt-in commands (/clear, /compact, /model, /effort, /cd, /thread, /backend, /abort, /status, /help) work on the supported backends.`,
|
|
1549
|
+
error: `❌ "${command}" is not exposed as a Codex backend command.\n\nBuilt-in commands (/clear, /compact, /model, /effort, /cd, /thread, /backend, /delegation, /abort, /status, /help) work on the supported backends.`,
|
|
1486
1550
|
});
|
|
1487
1551
|
return;
|
|
1488
1552
|
}
|
|
@@ -1561,7 +1625,12 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1561
1625
|
* Execute AI command on a specific executor
|
|
1562
1626
|
*/
|
|
1563
1627
|
async executeCommand(messageId, threadId, content, executor, attachments, fromQueue = false) {
|
|
1564
|
-
|
|
1628
|
+
let delegationScope;
|
|
1629
|
+
let delegationBridge;
|
|
1630
|
+
const complete = async (success, error) => {
|
|
1631
|
+
delegationBridge?.activate(undefined);
|
|
1632
|
+
if (delegationScope)
|
|
1633
|
+
await delegationScope.close();
|
|
1565
1634
|
const responseError = fromQueue && !success
|
|
1566
1635
|
? this.pauseQueueAfterFailure(threadId, error || 'Queued command failed') : error;
|
|
1567
1636
|
this.sendResponse(messageId, threadId, { success, error: responseError, threads: this.threadPool.getSummaries() });
|
|
@@ -1571,6 +1640,47 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1571
1640
|
};
|
|
1572
1641
|
try {
|
|
1573
1642
|
const openId = this.getMessageOpenId(messageId);
|
|
1643
|
+
const thread = this.threadManager.getThread(threadId);
|
|
1644
|
+
if (thread?.delegation && executor.configureDelegation) {
|
|
1645
|
+
if (this.delegation.blocksWorkspace(executor.getCurrentWorkingDirectory(), threadId)) {
|
|
1646
|
+
throw new Error('A delegated worker holds this workspace. Wait for it to finish; if worker cleanup failed, stop the worker and restart the CLI.');
|
|
1647
|
+
}
|
|
1648
|
+
const backend = this.threadPool.getBackendKey(threadId);
|
|
1649
|
+
if (!thread.delegationBackends?.includes(backend)) {
|
|
1650
|
+
await this.threadManager.updateThread(threadId, { delegationBackends: [...(thread.delegationBackends ?? []), backend] });
|
|
1651
|
+
}
|
|
1652
|
+
delegationScope = this.delegation.begin({ thread, messageId,
|
|
1653
|
+
backend: this.threadPool.getBackendKey(threadId),
|
|
1654
|
+
config: this.config.get('executor') ?? { type: 'auto' },
|
|
1655
|
+
cwd: executor.getCurrentWorkingDirectory(),
|
|
1656
|
+
onToolUse: tool => this.sendToolUse(messageId, threadId, tool),
|
|
1657
|
+
onToolResult: result => this.sendToolResult(messageId, threadId, result),
|
|
1658
|
+
onNotice: text => this.sendStreamChunk(messageId, threadId, text),
|
|
1659
|
+
onApproval: (request, child) => this.forwardApproval(request, child, messageId, threadId, true),
|
|
1660
|
+
onApprovalResolved: (id, status) => this.resolveApprovalCard(id, status),
|
|
1661
|
+
isWorkspaceBusy: cwd => this.threadManager.listThreads().some(other => {
|
|
1662
|
+
if (other.id === threadId || !this.threadPool.isThreadBusy(other.id))
|
|
1663
|
+
return false;
|
|
1664
|
+
try {
|
|
1665
|
+
return (0, DelegationManager_1.workspacesOverlap)((0, fs_1.realpathSync)(this.threadPool.getExecutor(other.id).getCurrentWorkingDirectory()), cwd);
|
|
1666
|
+
}
|
|
1667
|
+
catch {
|
|
1668
|
+
return true;
|
|
1669
|
+
}
|
|
1670
|
+
}), });
|
|
1671
|
+
delegationBridge = this.delegationBridges.get(threadId) ?? new DelegationBridge_1.DelegationBridge();
|
|
1672
|
+
this.delegationBridges.set(threadId, delegationBridge);
|
|
1673
|
+
const connection = await delegationBridge.start();
|
|
1674
|
+
delegationBridge.activate(delegationScope.invoke);
|
|
1675
|
+
await executor.configureDelegation(connection);
|
|
1676
|
+
if (delegationScope.isClosed() || this.isDestroyed || this.abortOperations.has(threadId)) {
|
|
1677
|
+
throw new Error('Delegation was cancelled before the coordinator started');
|
|
1678
|
+
}
|
|
1679
|
+
content = `${contract_1.DELEGATION_INSTRUCTIONS}\n\nUser request:\n${content}`;
|
|
1680
|
+
}
|
|
1681
|
+
else if (thread?.delegationBackends?.includes(this.threadPool.getBackendKey(threadId)) && executor.configureDelegation) {
|
|
1682
|
+
await executor.configureDelegation(undefined);
|
|
1683
|
+
}
|
|
1574
1684
|
const onTaskNotification = (notification) => {
|
|
1575
1685
|
if (this.isDestroyed || !this.threadManager.getThread(threadId))
|
|
1576
1686
|
return;
|
|
@@ -1578,6 +1688,7 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1578
1688
|
};
|
|
1579
1689
|
const emittedLocalImages = new Set();
|
|
1580
1690
|
const pendingLocalImageEmissions = new Set();
|
|
1691
|
+
const delegationControlTools = new Set();
|
|
1581
1692
|
let streamedOutput = '';
|
|
1582
1693
|
const emitLocalImages = async (text) => {
|
|
1583
1694
|
const thread = this.threadManager.getThread(threadId);
|
|
@@ -1607,8 +1718,16 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1607
1718
|
streamedOutput += chunk;
|
|
1608
1719
|
this.sendStreamChunk(messageId, threadId, chunk);
|
|
1609
1720
|
},
|
|
1610
|
-
onToolUse: (toolUse) =>
|
|
1721
|
+
onToolUse: (toolUse) => {
|
|
1722
|
+
if (delegationScope && /remote_cli_(list_backends|delegate|result|cancel)$/.test(toolUse.name)) {
|
|
1723
|
+
delegationControlTools.add(toolUse.id);
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
this.sendToolUse(messageId, threadId, toolUse);
|
|
1727
|
+
},
|
|
1611
1728
|
onToolResult: (toolResult) => {
|
|
1729
|
+
if (delegationControlTools.delete(toolResult.tool_use_id))
|
|
1730
|
+
return;
|
|
1612
1731
|
this.sendToolResult(messageId, threadId, toolResult);
|
|
1613
1732
|
queueLocalImages(toolResult.content);
|
|
1614
1733
|
},
|
|
@@ -1634,22 +1753,8 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1634
1753
|
return complete(false, `❌ Auto-compact failed: ${compactResult.error}\n\nUse /compact to try again, or /clear to start fresh.`);
|
|
1635
1754
|
}
|
|
1636
1755
|
this.sendStreamChunk(messageId, threadId, '✅ Compaction done. Retrying your request...\n');
|
|
1637
|
-
const
|
|
1638
|
-
|
|
1639
|
-
onStream: (chunk) => {
|
|
1640
|
-
streamedOutput += chunk;
|
|
1641
|
-
this.sendStreamChunk(messageId, threadId, chunk);
|
|
1642
|
-
},
|
|
1643
|
-
onToolUse: (toolUse) => this.sendToolUse(messageId, threadId, toolUse),
|
|
1644
|
-
onToolResult: (toolResult) => {
|
|
1645
|
-
this.sendToolResult(messageId, threadId, toolResult);
|
|
1646
|
-
queueLocalImages(toolResult.content);
|
|
1647
|
-
},
|
|
1648
|
-
onRedactedThinking: () => this.sendRedactedThinking(messageId, threadId),
|
|
1649
|
-
onPlanMode: (planContent) => this.sendPlanMode(messageId, threadId, planContent),
|
|
1650
|
-
onImage: (image) => this.sendImage(messageId, threadId, image),
|
|
1651
|
-
attachments,
|
|
1652
|
-
});
|
|
1756
|
+
const { onApprovalRequest, onApprovalResolved, ...ordinaryRetryOptions } = executeOptions;
|
|
1757
|
+
const retryResult = await executor.execute(content, delegationScope ? executeOptions : ordinaryRetryOptions);
|
|
1653
1758
|
await Promise.all(pendingLocalImageEmissions);
|
|
1654
1759
|
await emitLocalImages(`${streamedOutput}\n${retryResult.output ?? ''}`);
|
|
1655
1760
|
return complete(retryResult.success, retryResult.error);
|
|
@@ -1694,14 +1799,14 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1694
1799
|
backend: this.threadPool.getBackendKey(threadId),
|
|
1695
1800
|
cwd: this.threadPool.getExecutor(threadId).getCurrentWorkingDirectory(), preview: content });
|
|
1696
1801
|
}
|
|
1697
|
-
forwardApproval(approval, executor, taskMessageId, threadId) {
|
|
1802
|
+
forwardApproval(approval, executor, taskMessageId, threadId, delegated = false) {
|
|
1698
1803
|
const openId = this.getMessageOpenId(taskMessageId);
|
|
1699
1804
|
if (!openId)
|
|
1700
1805
|
return false;
|
|
1701
1806
|
const request = { type: 'approval_request', messageId: approval.requestId,
|
|
1702
1807
|
taskMessageId, openId, threadId, threadName: this.threadManager.getThread(threadId)?.name ?? threadId,
|
|
1703
1808
|
cwd: executor.getCurrentWorkingDirectory(), approval, timestamp: Date.now() };
|
|
1704
|
-
this.pendingApprovalCards.set(approval.requestId, { request, executor });
|
|
1809
|
+
this.pendingApprovalCards.set(approval.requestId, { request, executor, delegated });
|
|
1705
1810
|
if (this.approvalCardsSupported)
|
|
1706
1811
|
this.sendApprovalMessage(request);
|
|
1707
1812
|
return this.approvalCardsSupported;
|
|
@@ -1738,7 +1843,9 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1738
1843
|
}
|
|
1739
1844
|
let accepted = false;
|
|
1740
1845
|
try {
|
|
1741
|
-
|
|
1846
|
+
if (!pending.delegated || message.action !== 'remember' || pending.request.approval.canRemember) {
|
|
1847
|
+
accepted = pending.executor.respondToApproval?.(message.messageId, message.action) === true;
|
|
1848
|
+
}
|
|
1742
1849
|
}
|
|
1743
1850
|
catch { /* Report failure without approving another request. */ }
|
|
1744
1851
|
if (accepted) {
|
|
@@ -2025,6 +2132,9 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
2025
2132
|
this.isDestroyed = true;
|
|
2026
2133
|
this.notificationAdapter.unregister();
|
|
2027
2134
|
try {
|
|
2135
|
+
await this.delegation.destroy();
|
|
2136
|
+
await Promise.all([...this.delegationBridges.values()].map(bridge => bridge.close()));
|
|
2137
|
+
this.delegationBridges.clear();
|
|
2028
2138
|
await this.threadPool.destroyAll({ deleteData: false });
|
|
2029
2139
|
this.pendingApprovalCards.clear();
|
|
2030
2140
|
}
|