@yu_robotics/remote-cli 1.6.166 → 1.6.170
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 +12 -1
- package/dist/client/MessageHandler.d.ts +5 -0
- package/dist/client/MessageHandler.d.ts.map +1 -1
- package/dist/client/MessageHandler.js +89 -20
- 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/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/package.json +1 -1
package/README.md
CHANGED
|
@@ -176,7 +176,7 @@ Linux users upgrading from version 1.6.23 or earlier should run `remote-cli serv
|
|
|
176
176
|
| `/clear` | Clear context for this thread |
|
|
177
177
|
| `/new` | Alias for `/clear`; start a fresh conversation in this thread |
|
|
178
178
|
| `/compact` | Compress history to save tokens |
|
|
179
|
-
| `/cd
|
|
179
|
+
| `/cd [dir]` | Browse directories as a card, or change directory directly with a path |
|
|
180
180
|
| `/model [name]` | Open native model settings, or set the active backend model with a text argument |
|
|
181
181
|
| `/effort [auto|level]` | Open native effort settings, or set/clear the active backend effort with a text argument |
|
|
182
182
|
| `/sandbox [on/off/read-only/default]` | Configure the current Codex or Claude Code thread sandbox, directory grants, and networking |
|
|
@@ -244,6 +244,15 @@ bound retained delegation results, not backend output buffers. Worker timeouts,
|
|
|
244
244
|
cancellation, and cleanup still apply. This requires a local CLI upgrade and
|
|
245
245
|
works with existing Routers.
|
|
246
246
|
|
|
247
|
+
With CLI and Router 1.6.167 or newer, terminal Worker card excerpts retain up to
|
|
248
|
+
4 KiB of UTF-8 text. Excerpts containing standalone omission markers are shown
|
|
249
|
+
as escaped plain text with a separate explanation rather than interpreting
|
|
250
|
+
contextless Markdown fragments. Intact result Markdown is preserved. Upgrade
|
|
251
|
+
both peers for the larger preview; newer Routers also safely display older
|
|
252
|
+
CLI omission markers. Older or unknown Routers keep the legacy 1000-byte
|
|
253
|
+
head/tail summary, including after reconnect. The 32 KiB result and 64 KiB
|
|
254
|
+
continuation limits stay unchanged.
|
|
255
|
+
|
|
247
256
|
Child progress, approvals, and questions use the existing reply flow. `/abort`
|
|
248
257
|
stops managed children as well as the parent. While delegated results remain
|
|
249
258
|
missing from the active execution, the CLI suppresses coordinator prose/plans/images and displays
|
|
@@ -416,6 +425,8 @@ Backend-specific commands are forwarded only where the active backend supports t
|
|
|
416
425
|
|
|
417
426
|
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.
|
|
418
427
|
|
|
428
|
+
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.
|
|
429
|
+
|
|
419
430
|
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.
|
|
420
431
|
|
|
421
432
|
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":"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"}
|
|
@@ -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,
|
|
@@ -2630,7 +2681,8 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
2630
2681
|
queueConfirmation: result.queueConfirmation,
|
|
2631
2682
|
...(result.executionMetadata ? { executionMetadata: result.executionMetadata } : {}),
|
|
2632
2683
|
...(this.settingsCardsSupported && result.settingsMenu
|
|
2633
|
-
&& (result.settingsMenu.kind !== 'delegation' || this.delegationCardsSupported)
|
|
2684
|
+
&& (result.settingsMenu.kind !== 'delegation' || this.delegationCardsSupported)
|
|
2685
|
+
&& (result.settingsMenu.kind !== 'directory' || this.directoryCardsSupported) ? { settingsMenu: result.settingsMenu } : {}),
|
|
2634
2686
|
cwd,
|
|
2635
2687
|
timestamp: Date.now(),
|
|
2636
2688
|
});
|
|
@@ -2644,6 +2696,22 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
2644
2696
|
executorConfiguration() {
|
|
2645
2697
|
return this.config.get('executor') ?? { type: 'auto' };
|
|
2646
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
|
+
}
|
|
2647
2715
|
settingsState(threadId) {
|
|
2648
2716
|
const thread = this.threadManager.getThread(threadId);
|
|
2649
2717
|
if (!thread)
|
|
@@ -2926,6 +2994,7 @@ You can also use natural language commands to control Claude Code CLI.`,
|
|
|
2926
2994
|
* Destroy handler and all executors
|
|
2927
2995
|
*/
|
|
2928
2996
|
async destroy() {
|
|
2997
|
+
this.directoryBrowser.destroy();
|
|
2929
2998
|
this.settingsService.destroy();
|
|
2930
2999
|
this.isDestroyed = true;
|
|
2931
3000
|
await this.fileInbox?.destroy();
|