@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 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 <dir>` | Change directory; a different directory starts fresh conversations for this thread |
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":"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"}
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?.(() => this.fileInbox?.disconnect());
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.wsClient.onClose?.(() => this.settingsService.invalidate());
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 result = await this.settingsService.action(message, this.delegationCardsSupported);
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|cd|sandbox)(?:\s|$)/.test(content) || /^\/thread\s+delete(?:\s|$)/.test(content))
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
- if (this.delegation.hasActiveTasks(threadId)) {
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) ? { settingsMenu: result.settingsMenu } : {}),
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();