@yu_robotics/remote-cli 1.6.165 → 1.6.169
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 +16 -1
- package/dist/client/MessageHandler.d.ts +5 -0
- package/dist/client/MessageHandler.d.ts.map +1 -1
- package/dist/client/MessageHandler.js +108 -33
- package/dist/client/MessageHandler.js.map +1 -1
- package/dist/client/WebSocketClient.d.ts.map +1 -1
- package/dist/client/WebSocketClient.js +1 -0
- package/dist/client/WebSocketClient.js.map +1 -1
- package/dist/delegation/DelegationManager.d.ts +3 -0
- package/dist/delegation/DelegationManager.d.ts.map +1 -1
- package/dist/delegation/DelegationManager.js +6 -2
- package/dist/delegation/DelegationManager.js.map +1 -1
- package/dist/executor/ClaudePersistentExecutor.d.ts.map +1 -1
- package/dist/executor/ClaudePersistentExecutor.js +18 -8
- package/dist/executor/ClaudePersistentExecutor.js.map +1 -1
- package/dist/maintenance/release-notes.json +1 -1
- package/dist/settings/DirectoryBrowser.d.ts +50 -0
- package/dist/settings/DirectoryBrowser.d.ts.map +1 -0
- package/dist/settings/DirectoryBrowser.js +309 -0
- package/dist/settings/DirectoryBrowser.js.map +1 -0
- package/dist/settings/SettingsService.d.ts +1 -1
- package/dist/settings/SettingsService.d.ts.map +1 -1
- package/dist/settings/SettingsService.js +2 -0
- package/dist/settings/SettingsService.js.map +1 -1
- package/dist/types/Settings.d.ts +12 -2
- package/dist/types/Settings.d.ts.map +1 -1
- package/dist/utils/LocalImageDetector.d.ts +2 -2
- package/dist/utils/LocalImageDetector.d.ts.map +1 -1
- package/dist/utils/LocalImageDetector.js +2 -0
- package/dist/utils/LocalImageDetector.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,8 @@ Router 1.6.117 and newer explicitly label standalone background-task notificatio
|
|
|
20
20
|
|
|
21
21
|
## Public Activity
|
|
22
22
|
|
|
23
|
+
From Router 1.6.169, reply-card thread lists start collapsed. Use **Show threads** to expand the list in the same card, or **Switch to this thread** to select the thread that produced the reply. Opening or hiding the list does not change the input target; a successful switch hides the list and confirms the new target without changing the reply's source label. No separate thread-management card is sent. The recursive element budget is 180 instead of 150, with room reserved for the expanded controls; table and size thresholds are unchanged. This presentation update requires the newer Router, not a new CLI protocol capability.
|
|
24
|
+
|
|
23
25
|
From Router 1.6.158, completion pagination keeps the final body item (or complete worker group) with the completion note, optional model metadata and thread controls when they fit together. This avoids preventable footer-only continuations, including replies without model metadata. Indivisible oversized groups still split according to node, size and table limits; thread-button refreshes preserve the final body. This does not change streaming completion timing or the wire protocol.
|
|
24
26
|
|
|
25
27
|
From CLI 1.6.153, Codex shell calls no longer lose their label when native command actions are absent or unknown. Native reads, searches, and directory listings remain preferred. Other calls use fixed operation labels such as `Run npm command` or `Run Git command` for simple allowlisted programs, and `Run shell command` for compound or unrecognized commands. These are deterministic operation labels, not model-authored purpose summaries: installed Codex 0.160.0 command items have no per-call description field. Arguments, full paths, output, and execution-wide reasoning are never copied into these fallback labels. Late native action metadata can enrich a pending row before its first result; repeated results retain one row. Existing description fields, heading limits, and card-node counts are unchanged; upgrade the CLI, with no new Router capability required.
|
|
@@ -76,6 +78,8 @@ The client is normally installed and run directly on the developer's machine rat
|
|
|
76
78
|
|
|
77
79
|
## Installation
|
|
78
80
|
|
|
81
|
+
Claude tool-result content blocks are normalized to text; embedded media and unknown payloads are not scanned for local files. Local image detection and forwarding are best-effort: failures do not fail the task or terminate the CLI. Web-result excerpts remain excluded from local-file scanning.
|
|
82
|
+
|
|
79
83
|
Sending local image files requires a Router with image forwarding support and
|
|
80
84
|
the bot application's `im:resource` permission. Router 1.6.85 and newer render
|
|
81
85
|
local and URL-based Markdown image references as captions; the uploaded image
|
|
@@ -174,7 +178,7 @@ Linux users upgrading from version 1.6.23 or earlier should run `remote-cli serv
|
|
|
174
178
|
| `/clear` | Clear context for this thread |
|
|
175
179
|
| `/new` | Alias for `/clear`; start a fresh conversation in this thread |
|
|
176
180
|
| `/compact` | Compress history to save tokens |
|
|
177
|
-
| `/cd
|
|
181
|
+
| `/cd [dir]` | Browse directories as a card, or change directory directly with a path |
|
|
178
182
|
| `/model [name]` | Open native model settings, or set the active backend model with a text argument |
|
|
179
183
|
| `/effort [auto|level]` | Open native effort settings, or set/clear the active backend effort with a text argument |
|
|
180
184
|
| `/sandbox [on/off/read-only/default]` | Configure the current Codex or Claude Code thread sandbox, directory grants, and networking |
|
|
@@ -242,6 +246,15 @@ bound retained delegation results, not backend output buffers. Worker timeouts,
|
|
|
242
246
|
cancellation, and cleanup still apply. This requires a local CLI upgrade and
|
|
243
247
|
works with existing Routers.
|
|
244
248
|
|
|
249
|
+
With CLI and Router 1.6.167 or newer, terminal Worker card excerpts retain up to
|
|
250
|
+
4 KiB of UTF-8 text. Excerpts containing standalone omission markers are shown
|
|
251
|
+
as escaped plain text with a separate explanation rather than interpreting
|
|
252
|
+
contextless Markdown fragments. Intact result Markdown is preserved. Upgrade
|
|
253
|
+
both peers for the larger preview; newer Routers also safely display older
|
|
254
|
+
CLI omission markers. Older or unknown Routers keep the legacy 1000-byte
|
|
255
|
+
head/tail summary, including after reconnect. The 32 KiB result and 64 KiB
|
|
256
|
+
continuation limits stay unchanged.
|
|
257
|
+
|
|
245
258
|
Child progress, approvals, and questions use the existing reply flow. `/abort`
|
|
246
259
|
stops managed children as well as the parent. While delegated results remain
|
|
247
260
|
missing from the active execution, the CLI suppresses coordinator prose/plans/images and displays
|
|
@@ -414,6 +427,8 @@ Backend-specific commands are forwarded only where the active backend supports t
|
|
|
414
427
|
|
|
415
428
|
Use one thread per project or task so each thread keeps its own working directory, backend session, model, and queue. Use `/backend <index>` for a global switch, or `/backend <index> @` to override only the current thread. `/backend default @` removes that override.
|
|
416
429
|
|
|
430
|
+
With CLI and Router 1.6.168 or newer, `/cd` opens a directory-only browser with child, Parent, Allowed roots, Refresh, Use this directory, and Cancel controls. Navigation never changes context or runs a backend. Only Apply changes the original thread, following the existing all-backend context reset and delegation-lane invalidation; the same directory remains a no-op. Both card Apply and text `/cd <path>` share exclusive settings admission and reject active, delegated, queued, aborting, or updating work. Older peers retain text behavior. Symbolic-link directories are omitted; Parent stops at the nearest allowed root. Snapshots expire after ten minutes and reject changed policy, cwd, root, directory, or ancestor identity. Scans cap at 4096 entries, 128 directories, or five seconds between filesystem operations, with explicit partial-list guidance; at most 32 roots are offered. Cards fill before budget-driven paging. Application-level canonical and identity checks are not an OS sandbox or protection against all external filesystem races and bind mounts.
|
|
431
|
+
|
|
417
432
|
With CLI 1.6.93 or newer, `/cd` to a different normalized directory clears saved conversation bindings for every backend in that thread, including inactive ones. Returning to the old directory does not restore its previous conversation. Selecting the same directory preserves context; backend switching without a directory change still resumes conversations. Thread identity, model, effort, sandbox grants, delegation settings, and native history files remain intact. Separate plans should use separate threads, even when they share a directory. This change requires a CLI upgrade and works with existing Routers.
|
|
418
433
|
|
|
419
434
|
Thread switch panels show `Reply from:` with the reply's full thread name and workspace. Under `Switch thread`, a check mark (`✓`) and primary button styling identify the destination of new top-level messages when the card is finalized or clicked. Selected buttons remain clickable. Switching updates only the clicked card; other historical cards retain their last displayed selection.
|
|
@@ -38,10 +38,13 @@ export declare class MessageHandler {
|
|
|
38
38
|
private approvalCardsSupported;
|
|
39
39
|
private streamingContextSupported;
|
|
40
40
|
private delegationProgressSupported;
|
|
41
|
+
private routerVersion?;
|
|
41
42
|
private delegationProgressTextSupported;
|
|
42
43
|
private activityProgressSupported;
|
|
43
44
|
private workerContextResetSupported;
|
|
44
45
|
private settingsCardsSupported;
|
|
46
|
+
private directoryCardsSupported;
|
|
47
|
+
private readonly directoryBrowser;
|
|
45
48
|
private delegationCardsSupported;
|
|
46
49
|
private readonly settingsAdmission;
|
|
47
50
|
private readonly settingsCatalogReader;
|
|
@@ -183,6 +186,8 @@ export declare class MessageHandler {
|
|
|
183
186
|
private sendStructuredContent;
|
|
184
187
|
private sendResponse;
|
|
185
188
|
private executorConfiguration;
|
|
189
|
+
/** Shared card/text Apply path. Callers hold exclusive settings admission. */
|
|
190
|
+
private changeWorkingDirectory;
|
|
186
191
|
private settingsState;
|
|
187
192
|
private settingsBusy;
|
|
188
193
|
private settingsFallback;
|
|
@@ -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;AAQpD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAgK,MAAM,UAAU,CAAC;AACzM,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAMxD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"MessageHandler.d.ts","sourceRoot":"","sources":["../../src/client/MessageHandler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAQpD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAgK,MAAM,UAAU,CAAC;AACzM,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAMxD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAwHxD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAsBD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,mBAAmB,CAA4B;IACvD,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,eAAe,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsC;IACnE,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAA+C;IACzF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyC;IACxE,qEAAqE;IACrE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IAC/D,0FAA0F;IAC1F,OAAO,CAAC,QAAQ,CAAC,cAAc,CA2B5B;IACH,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA4C;IACnF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAoC;IACpE,OAAO,CAAC,yBAAyB,CAAS;IAC1C,OAAO,CAAC,sBAAsB,CAAS;IACvC,OAAO,CAAC,yBAAyB,CAAS;IAC1C,OAAO,CAAC,2BAA2B,CAAS;IAC5C,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,+BAA+B,CAAS;IAChD,OAAO,CAAC,yBAAyB,CAAS;IAC1C,OAAO,CAAC,2BAA2B,CAAS;IAC5C,OAAO,CAAC,sBAAsB,CAAS;IACvC,OAAO,CAAC,uBAAuB,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,wBAAwB,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA2B;IAC7D,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAwB;IAC9D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAoG;IACzI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuC;IACzE,OAAO,CAAC,SAAS,CAAC,CAAY;gBAG5B,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,kBAAkB,EAC9B,aAAa,EAAE,aAAa,EAC5B,cAAc,EAAE,cAAc,EAC9B,MAAM,EAAE,aAAa;IAuEjB,gCAAgC,IAAI,OAAO,CAAC,IAAI,CAAC;IAUvD;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAiGtE,uBAAuB,IAAI,OAAO;IAqBlC,kBAAkB,IAAI,IAAI;IAI1B;;OAEG;YACW,oBAAoB;YAoDpB,4BAA4B;IA+S1C;;OAEG;YACW,kBAAkB;IAwDhC;;OAEG;YACW,iBAAiB;IAiB/B,OAAO,CAAC,cAAc;YAOR,wBAAwB;IAsBtC;;;OAGG;YACW,oBAAoB;IAsZlC,OAAO,CAAC,uBAAuB;IAmC/B,OAAO,CAAC,+BAA+B;IAUvC,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,cAAc;YASR,kBAAkB;YA8ElB,sBAAsB;IAmDpC,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,mBAAmB;IAK3B;;;;;;;;;OASG;YACW,eAAe;IAqC7B;;OAEG;YACW,mBAAmB;IA0GjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAS1B;;;OAGG;YACW,oBAAoB;IA6MlC;;OAEG;YACW,qBAAqB;IAiBnC;;OAEG;IACH,OAAO,CAAC,UAAU;IAuBlB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAM9B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAG7C;YAEW,eAAe;IAgC7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;;;;;;;;;;;;OAaG;YACW,mBAAmB;IAgEjC;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IA0E/B;;OAEG;YACW,cAAc;YAkWd,sBAAsB;IAoBpC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,sBAAsB;IAuB9B,iFAAiF;IACjF,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,sBAAsB;IAyB9B,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,qBAAqB;IAmB7B,OAAO,CAAC,YAAY;IAsDpB,OAAO,CAAC,qBAAqB;IAI7B,8EAA8E;YAChE,sBAAsB;IAgBpC,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,gBAAgB;IAYxB,uFAAuF;YACzE,sBAAsB;IAsBpC,mFAAmF;YACrE,eAAe;YA2Cf,mBAAmB;IAuBjC,OAAO,CAAC,YAAY;YAUN,cAAc;YAuBd,oBAAoB;IAgHlC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB/B"}
|
|
@@ -37,6 +37,7 @@ const ActivityProgress_1 = require("../utils/ActivityProgress");
|
|
|
37
37
|
const SettingsAdmission_1 = require("../settings/SettingsAdmission");
|
|
38
38
|
const SettingsCatalog_1 = require("../settings/SettingsCatalog");
|
|
39
39
|
const SettingsService_1 = require("../settings/SettingsService");
|
|
40
|
+
const DirectoryBrowser_1 = require("../settings/DirectoryBrowser");
|
|
40
41
|
const SessionResumeService_1 = require("../session/SessionResumeService");
|
|
41
42
|
const adapters_1 = require("../session/adapters");
|
|
42
43
|
const PiSessionCatalog_1 = require("../session/adapters/PiSessionCatalog");
|
|
@@ -170,10 +171,13 @@ class MessageHandler {
|
|
|
170
171
|
approvalCardsSupported = false;
|
|
171
172
|
streamingContextSupported = false;
|
|
172
173
|
delegationProgressSupported = false;
|
|
174
|
+
routerVersion;
|
|
173
175
|
delegationProgressTextSupported = false;
|
|
174
176
|
activityProgressSupported = false;
|
|
175
177
|
workerContextResetSupported = false;
|
|
176
178
|
settingsCardsSupported = false;
|
|
179
|
+
directoryCardsSupported = false;
|
|
180
|
+
directoryBrowser;
|
|
177
181
|
delegationCardsSupported = false;
|
|
178
182
|
settingsAdmission = new SettingsAdmission_1.SettingsAdmission();
|
|
179
183
|
settingsCatalogReader;
|
|
@@ -188,7 +192,10 @@ class MessageHandler {
|
|
|
188
192
|
this.threadManager = threadManager;
|
|
189
193
|
this.directoryGuard = directoryGuard;
|
|
190
194
|
this.config = config;
|
|
191
|
-
this.wsClient.onClose?.(() =>
|
|
195
|
+
this.wsClient.onClose?.(() => {
|
|
196
|
+
this.routerVersion = undefined;
|
|
197
|
+
this.fileInbox?.disconnect();
|
|
198
|
+
});
|
|
192
199
|
this.delegation = new DelegationManager_1.DelegationManager(directoryGuard);
|
|
193
200
|
this.settingsCatalogReader = new SettingsCatalog_1.SettingsCatalogReader(directoryGuard);
|
|
194
201
|
this.settingsService = new SettingsService_1.SettingsService({
|
|
@@ -228,7 +235,26 @@ class MessageHandler {
|
|
|
228
235
|
delegation: (id, enabled) => this.applyDelegationSetting(id, enabled),
|
|
229
236
|
delegationSupported: id => Boolean(this.threadPool.getExecutor(id).configureDelegation),
|
|
230
237
|
});
|
|
231
|
-
this.
|
|
238
|
+
this.directoryBrowser = new DirectoryBrowser_1.DirectoryBrowser({
|
|
239
|
+
guard: this.directoryGuard,
|
|
240
|
+
state: id => {
|
|
241
|
+
const thread = this.threadManager.getThread(id);
|
|
242
|
+
const state = this.settingsState(id);
|
|
243
|
+
return thread && state ? { threadName: thread.name, cwd: thread.workingDirectory,
|
|
244
|
+
revision: state.revision, backend: state.coordinatorBackend } : undefined;
|
|
245
|
+
},
|
|
246
|
+
busy: (id, except) => this.settingsBusy(id, except),
|
|
247
|
+
exclusive: async (id, body) => {
|
|
248
|
+
try {
|
|
249
|
+
return await this.settingsAdmission.mutation(id, body);
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
void this.startNextQueuedCommand(id);
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
apply: (id, target) => this.changeWorkingDirectory(id, target),
|
|
256
|
+
});
|
|
257
|
+
this.wsClient.onClose?.(() => { this.settingsService.invalidate(); this.directoryCardsSupported = false; this.directoryBrowser.invalidate(); });
|
|
232
258
|
this.notificationAdapter = new hooks_1.FeishuNotificationAdapter(wsClient);
|
|
233
259
|
this.notificationAdapter.setThreadNameResolver((threadId) => this.threadManager.getThread(threadId)?.name);
|
|
234
260
|
this.notificationAdapter.register();
|
|
@@ -267,7 +293,12 @@ class MessageHandler {
|
|
|
267
293
|
return;
|
|
268
294
|
case 'settings_action':
|
|
269
295
|
if (this.settingsCardsSupported) {
|
|
270
|
-
const
|
|
296
|
+
const request = message;
|
|
297
|
+
const directory = typeof request.snapshotId === 'string' && request.snapshotId.startsWith('directory-');
|
|
298
|
+
if (directory && !this.directoryCardsSupported)
|
|
299
|
+
return;
|
|
300
|
+
const result = directory ? await this.directoryBrowser.action(request)
|
|
301
|
+
: await this.settingsService.action(request, this.delegationCardsSupported);
|
|
271
302
|
this.wsClient.send(result);
|
|
272
303
|
}
|
|
273
304
|
return;
|
|
@@ -290,6 +321,7 @@ class MessageHandler {
|
|
|
290
321
|
const data = message.data;
|
|
291
322
|
if (data?.success !== true)
|
|
292
323
|
return;
|
|
324
|
+
this.routerVersion = typeof data.routerVersion === 'string' ? data.routerVersion : undefined;
|
|
293
325
|
if (data.capabilities?.fileTransferV1 === true && !this.fileInbox) {
|
|
294
326
|
try {
|
|
295
327
|
const fileServer = this.config.get('serverUrl');
|
|
@@ -312,6 +344,7 @@ class MessageHandler {
|
|
|
312
344
|
this.delegationProgressSupported = data.capabilities?.delegationProgress === true;
|
|
313
345
|
this.workerContextResetSupported = this.delegationProgressSupported && data.capabilities?.workerContextReset === true;
|
|
314
346
|
this.settingsCardsSupported = data.capabilities?.settingsCards === true;
|
|
347
|
+
this.directoryCardsSupported = this.settingsCardsSupported && data.capabilities?.directoryCards === true;
|
|
315
348
|
this.delegationCardsSupported = this.settingsCardsSupported && data.capabilities?.delegationCards === true;
|
|
316
349
|
this.delegationProgressTextSupported = this.delegationProgressSupported
|
|
317
350
|
&& data.capabilities?.delegationProgressText === true;
|
|
@@ -350,7 +383,8 @@ class MessageHandler {
|
|
|
350
383
|
|| this.pendingQueueConfirmations.size > 0
|
|
351
384
|
|| this.pendingReplaces.size > 0
|
|
352
385
|
|| this.activeThreadOperations.size > 0
|
|
353
|
-
|| this.abortOperations.size > 0
|
|
386
|
+
|| this.abortOperations.size > 0
|
|
387
|
+
|| this.threadManager.listThreads().some(thread => this.settingsAdmission.isBlocked(thread.id))) {
|
|
354
388
|
return false;
|
|
355
389
|
}
|
|
356
390
|
this.automaticUpdateInProgress = true;
|
|
@@ -406,16 +440,18 @@ class MessageHandler {
|
|
|
406
440
|
// Abort and addressed human replies must remain available during native work.
|
|
407
441
|
if (content === '/abort' || /^(?:yes|no)(?:\s|$)/.test(content) || content.startsWith('/input '))
|
|
408
442
|
return await body();
|
|
409
|
-
if (/^\/(?:backend|model|effort)\s+\S/.test(content)) {
|
|
443
|
+
if (/^\/(?:backend|model|effort|cd)\s+\S/.test(content)) {
|
|
410
444
|
const global = /^\/backend\s/.test(content) && !/\s@$/.test(content);
|
|
411
445
|
await this.settingsAdmission.mutation(global ? '*' : threadId, async () => {
|
|
412
446
|
this.settingsService.invalidate(global ? undefined : threadId);
|
|
447
|
+
if (/^\/cd\s/.test(content))
|
|
448
|
+
this.directoryBrowser.invalidate(threadId);
|
|
413
449
|
await body();
|
|
414
450
|
});
|
|
415
451
|
}
|
|
416
452
|
else {
|
|
417
453
|
await this.settingsAdmission.command(threadId, message.messageId, async () => {
|
|
418
|
-
if (/^\/(?:clear|new|
|
|
454
|
+
if (/^\/(?:clear|new|sandbox)(?:\s|$)/.test(content) || /^\/thread\s+delete(?:\s|$)/.test(content))
|
|
419
455
|
this.settingsService.invalidate(threadId);
|
|
420
456
|
await body();
|
|
421
457
|
});
|
|
@@ -450,6 +486,31 @@ class MessageHandler {
|
|
|
450
486
|
return;
|
|
451
487
|
}
|
|
452
488
|
const settingsCommand = content?.trim() ?? '';
|
|
489
|
+
if (this.directoryCardsSupported && openId && settingsCommand === '/cd') {
|
|
490
|
+
try {
|
|
491
|
+
const menu = await this.directoryBrowser.open(resolvedThreadId, openId, messageId);
|
|
492
|
+
this.sendResponse(messageId, resolvedThreadId, { success: true,
|
|
493
|
+
output: 'Directory browser. Navigation does not change the thread; choose Use this directory to apply. Text command: /cd <path>.', settingsMenu: menu }, true);
|
|
494
|
+
}
|
|
495
|
+
catch {
|
|
496
|
+
this.sendResponse(messageId, resolvedThreadId, { success: false,
|
|
497
|
+
error: 'The directory browser could not open. Check allowed directories and permissions, or use /cd <path>.' }, true);
|
|
498
|
+
}
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
// Text Apply also runs before acquiring a model-turn busy flag. Its caller
|
|
502
|
+
// already holds the same exclusive admission writer as directory-card Apply.
|
|
503
|
+
if (/^\/cd\s+\S/.test(settingsCommand)) {
|
|
504
|
+
try {
|
|
505
|
+
const result = await this.changeWorkingDirectory(resolvedThreadId, settingsCommand.slice(3).trim());
|
|
506
|
+
this.sendResponse(messageId, resolvedThreadId, result, true);
|
|
507
|
+
}
|
|
508
|
+
catch (error) {
|
|
509
|
+
this.sendResponse(messageId, resolvedThreadId, { success: false,
|
|
510
|
+
error: error instanceof Error ? error.message : 'Failed to change directory. Check /status before retrying.' }, true);
|
|
511
|
+
}
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
453
514
|
if (this.settingsCardsSupported && openId && (/^\/(?:backend|model|effort)$/.test(settingsCommand)
|
|
454
515
|
|| (this.delegationCardsSupported && settingsCommand === '/delegation'))) {
|
|
455
516
|
const kind = content.trim().slice(1);
|
|
@@ -1051,7 +1112,7 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1051
1112
|
await this.handleBackendCommand(messageId, threadId, trimmed);
|
|
1052
1113
|
return true;
|
|
1053
1114
|
}
|
|
1054
|
-
if (trimmed.startsWith('/cd')) {
|
|
1115
|
+
if (trimmed === '/cd' || trimmed.startsWith('/cd ')) {
|
|
1055
1116
|
const parts = trimmed.split(/\s+/);
|
|
1056
1117
|
if (parts.length < 2) {
|
|
1057
1118
|
this.sendResponse(messageId, threadId, { success: false, error: 'Usage: /cd <directory>' });
|
|
@@ -1059,18 +1120,7 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
1059
1120
|
}
|
|
1060
1121
|
const targetDir = parts.slice(1).join(' ');
|
|
1061
1122
|
try {
|
|
1062
|
-
|
|
1063
|
-
throw new Error('Cannot change working directory while a delegated worker is running. Wait for it to finish or send /abort first.');
|
|
1064
|
-
}
|
|
1065
|
-
const generation = this.threadManager.getThread(threadId)?.delegationWorkspaceGeneration ?? 0;
|
|
1066
|
-
const { cwd: newCwd, changed } = await this.threadPool.setWorkingDirectory(threadId, targetDir);
|
|
1067
|
-
const cleanup = changed
|
|
1068
|
-
? await this.delegation.invalidateWorkspaceGeneration(threadId, generation + 1)
|
|
1069
|
-
: { removed: 0, failed: 0 };
|
|
1070
|
-
this.sendResponse(messageId, threadId, {
|
|
1071
|
-
success: true,
|
|
1072
|
-
output: `✅ Changed working directory to: ${newCwd}${changed ? '\nConversation context cleared for all direct and delegated backends in this thread.' : ''}${cleanup.failed ? `\n⚠️ ${cleanup.failed} delegated worker lane(s) could not be cleaned up. Retry with /delegation reset after checking filesystem permissions.` : ''}`,
|
|
1073
|
-
});
|
|
1123
|
+
this.sendResponse(messageId, threadId, await this.changeWorkingDirectory(threadId, targetDir));
|
|
1074
1124
|
}
|
|
1075
1125
|
catch (error) {
|
|
1076
1126
|
this.sendResponse(messageId, threadId, {
|
|
@@ -2044,6 +2094,7 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
2044
2094
|
onToolUse: tool => this.sendToolUse(messageId, threadId, tool),
|
|
2045
2095
|
onToolResult: result => this.sendToolResult(messageId, threadId, result),
|
|
2046
2096
|
onNotice: text => this.sendStreamChunk(messageId, threadId, text),
|
|
2097
|
+
routerVersion: () => this.routerVersion,
|
|
2047
2098
|
onProgress: this.delegationProgressSupported
|
|
2048
2099
|
? progress => this.sendDelegationProgress(messageId, threadId, progress)
|
|
2049
2100
|
: undefined,
|
|
@@ -2089,19 +2140,25 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
2089
2140
|
const webToolNames = new Set(['websearch', 'webfetch', 'web_search', 'web_fetch', 'search_web', 'read_url_content', 'fetch']);
|
|
2090
2141
|
let streamedOutput = '';
|
|
2091
2142
|
const emitLocalImages = async (text) => {
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2143
|
+
try {
|
|
2144
|
+
const thread = this.threadManager.getThread(threadId);
|
|
2145
|
+
if (typeof text !== 'string' || !text || !thread?.workingDirectory)
|
|
2146
|
+
return;
|
|
2147
|
+
const images = await (0, LocalImageDetector_1.readLocalImages)(text, thread.workingDirectory, (candidate, cwd) => (this.directoryGuard.isSafePath(candidate, cwd)));
|
|
2148
|
+
for (const image of images) {
|
|
2149
|
+
if (emittedLocalImages.has(image.path))
|
|
2150
|
+
continue;
|
|
2151
|
+
emittedLocalImages.add(image.path);
|
|
2152
|
+
this.sendImage(messageId, threadId, {
|
|
2153
|
+
type: 'image',
|
|
2154
|
+
data: image.data,
|
|
2155
|
+
mimeType: image.mimeType,
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
catch {
|
|
2160
|
+
// Image forwarding is optional; never reject a task or log native content on failure.
|
|
2161
|
+
console.warn('Failed to forward local images; continuing task output.');
|
|
2105
2162
|
}
|
|
2106
2163
|
};
|
|
2107
2164
|
const queueLocalImages = (text) => {
|
|
@@ -2624,7 +2681,8 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
2624
2681
|
queueConfirmation: result.queueConfirmation,
|
|
2625
2682
|
...(result.executionMetadata ? { executionMetadata: result.executionMetadata } : {}),
|
|
2626
2683
|
...(this.settingsCardsSupported && result.settingsMenu
|
|
2627
|
-
&& (result.settingsMenu.kind !== 'delegation' || this.delegationCardsSupported)
|
|
2684
|
+
&& (result.settingsMenu.kind !== 'delegation' || this.delegationCardsSupported)
|
|
2685
|
+
&& (result.settingsMenu.kind !== 'directory' || this.directoryCardsSupported) ? { settingsMenu: result.settingsMenu } : {}),
|
|
2628
2686
|
cwd,
|
|
2629
2687
|
timestamp: Date.now(),
|
|
2630
2688
|
});
|
|
@@ -2638,6 +2696,22 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
2638
2696
|
executorConfiguration() {
|
|
2639
2697
|
return this.config.get('executor') ?? { type: 'auto' };
|
|
2640
2698
|
}
|
|
2699
|
+
/** Shared card/text Apply path. Callers hold exclusive settings admission. */
|
|
2700
|
+
async changeWorkingDirectory(threadId, targetDir) {
|
|
2701
|
+
if (this.isDestroyed || this.automaticUpdateInProgress || this.abortOperations.has(threadId)
|
|
2702
|
+
|| this.threadPool.isThreadBusy(threadId) || this.hasThreadQueueState(threadId)) {
|
|
2703
|
+
throw new Error('Cannot change working directory while the thread has active or queued work. Retry when it is idle.');
|
|
2704
|
+
}
|
|
2705
|
+
if (this.delegation.hasActiveTasks(threadId)) {
|
|
2706
|
+
throw new Error('Cannot change working directory while a delegated worker is running. Wait for it to finish or send /abort first.');
|
|
2707
|
+
}
|
|
2708
|
+
this.settingsService.invalidate(threadId);
|
|
2709
|
+
const generation = this.threadManager.getThread(threadId)?.delegationWorkspaceGeneration ?? 0;
|
|
2710
|
+
const { cwd, changed } = await this.threadPool.setWorkingDirectory(threadId, targetDir);
|
|
2711
|
+
const cleanup = changed ? await this.delegation.invalidateWorkspaceGeneration(threadId, generation + 1) : { removed: 0, failed: 0 };
|
|
2712
|
+
this.directoryBrowser.invalidate(threadId);
|
|
2713
|
+
return { success: true, output: `✅ Changed working directory to: ${cwd}${changed ? '\nConversation context cleared for all direct and delegated backends in this thread.' : ''}${cleanup.failed ? `\n⚠️ ${cleanup.failed} delegated worker lane(s) could not be cleaned up. Retry with /delegation reset after checking filesystem permissions.` : ''}` };
|
|
2714
|
+
}
|
|
2641
2715
|
settingsState(threadId) {
|
|
2642
2716
|
const thread = this.threadManager.getThread(threadId);
|
|
2643
2717
|
if (!thread)
|
|
@@ -2920,6 +2994,7 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
2920
2994
|
* Destroy handler and all executors
|
|
2921
2995
|
*/
|
|
2922
2996
|
async destroy() {
|
|
2997
|
+
this.directoryBrowser.destroy();
|
|
2923
2998
|
this.settingsService.destroy();
|
|
2924
2999
|
this.isDestroyed = true;
|
|
2925
3000
|
await this.fileInbox?.destroy();
|