@yu_robotics/remote-cli 1.6.149 → 1.6.152

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.
Files changed (91) hide show
  1. package/README.md +13 -3
  2. package/dist/client/MessageHandler.d.ts +14 -7
  3. package/dist/client/MessageHandler.d.ts.map +1 -1
  4. package/dist/client/MessageHandler.js +225 -96
  5. package/dist/client/MessageHandler.js.map +1 -1
  6. package/dist/client/WebSocketClient.d.ts.map +1 -1
  7. package/dist/client/WebSocketClient.js +2 -1
  8. package/dist/client/WebSocketClient.js.map +1 -1
  9. package/dist/delegation/GitCheckpoint.d.ts.map +1 -1
  10. package/dist/delegation/GitCheckpoint.js +39 -22
  11. package/dist/delegation/GitCheckpoint.js.map +1 -1
  12. package/dist/executor/AcpExecutor.d.ts +6 -1
  13. package/dist/executor/AcpExecutor.d.ts.map +1 -1
  14. package/dist/executor/AcpExecutor.js +96 -7
  15. package/dist/executor/AcpExecutor.js.map +1 -1
  16. package/dist/executor/AgyExecutor.d.ts +9 -1
  17. package/dist/executor/AgyExecutor.d.ts.map +1 -1
  18. package/dist/executor/AgyExecutor.js +66 -0
  19. package/dist/executor/AgyExecutor.js.map +1 -1
  20. package/dist/executor/ClaudePersistentExecutor.d.ts +33 -6
  21. package/dist/executor/ClaudePersistentExecutor.d.ts.map +1 -1
  22. package/dist/executor/ClaudePersistentExecutor.js +308 -38
  23. package/dist/executor/ClaudePersistentExecutor.js.map +1 -1
  24. package/dist/executor/CodexAppServerExecutor.d.ts +2 -1
  25. package/dist/executor/CodexAppServerExecutor.d.ts.map +1 -1
  26. package/dist/executor/CodexAppServerExecutor.js +39 -4
  27. package/dist/executor/CodexAppServerExecutor.js.map +1 -1
  28. package/dist/executor/DshExecutor.js +2 -2
  29. package/dist/executor/DshExecutor.js.map +1 -1
  30. package/dist/executor/IExecutor.d.ts +20 -0
  31. package/dist/executor/IExecutor.d.ts.map +1 -1
  32. package/dist/executor/PiExecutor.d.ts +2 -1
  33. package/dist/executor/PiExecutor.d.ts.map +1 -1
  34. package/dist/executor/PiExecutor.js +70 -53
  35. package/dist/executor/PiExecutor.js.map +1 -1
  36. package/dist/executor/acp/AcpClient.d.ts.map +1 -1
  37. package/dist/executor/acp/AcpClient.js +23 -3
  38. package/dist/executor/acp/AcpClient.js.map +1 -1
  39. package/dist/executor/acp/AcpTypes.d.ts +8 -1
  40. package/dist/executor/acp/AcpTypes.d.ts.map +1 -1
  41. package/dist/executor/claude/ClaudeSettings.d.ts +28 -0
  42. package/dist/executor/claude/ClaudeSettings.d.ts.map +1 -0
  43. package/dist/executor/claude/ClaudeSettings.js +121 -0
  44. package/dist/executor/claude/ClaudeSettings.js.map +1 -0
  45. package/dist/executor/index.d.ts +1 -1
  46. package/dist/executor/index.d.ts.map +1 -1
  47. package/dist/executor/index.js +3 -3
  48. package/dist/executor/index.js.map +1 -1
  49. package/dist/maintenance/BankedResetReminders.d.ts +24 -0
  50. package/dist/maintenance/BankedResetReminders.d.ts.map +1 -0
  51. package/dist/maintenance/BankedResetReminders.js +79 -0
  52. package/dist/maintenance/BankedResetReminders.js.map +1 -0
  53. package/dist/maintenance/CodexQuota.d.ts +12 -0
  54. package/dist/maintenance/CodexQuota.d.ts.map +1 -0
  55. package/dist/maintenance/CodexQuota.js +21 -0
  56. package/dist/maintenance/CodexQuota.js.map +1 -0
  57. package/dist/maintenance/CodexStatusProbe.d.ts +2 -2
  58. package/dist/maintenance/CodexStatusProbe.d.ts.map +1 -1
  59. package/dist/maintenance/CodexStatusProbe.js +2 -2
  60. package/dist/maintenance/CodexStatusProbe.js.map +1 -1
  61. package/dist/maintenance/MaintenanceClient.d.ts.map +1 -1
  62. package/dist/maintenance/MaintenanceClient.js +1 -1
  63. package/dist/maintenance/MaintenanceClient.js.map +1 -1
  64. package/dist/maintenance/SubscriptionInspection.d.ts +6 -4
  65. package/dist/maintenance/SubscriptionInspection.d.ts.map +1 -1
  66. package/dist/maintenance/SubscriptionInspection.js +28 -3
  67. package/dist/maintenance/SubscriptionInspection.js.map +1 -1
  68. package/dist/maintenance/release-notes.json +1 -1
  69. package/dist/settings/SettingsAdmission.d.ts +12 -0
  70. package/dist/settings/SettingsAdmission.d.ts.map +1 -0
  71. package/dist/settings/SettingsAdmission.js +55 -0
  72. package/dist/settings/SettingsAdmission.js.map +1 -0
  73. package/dist/settings/SettingsCatalog.d.ts +23 -0
  74. package/dist/settings/SettingsCatalog.d.ts.map +1 -0
  75. package/dist/settings/SettingsCatalog.js +137 -0
  76. package/dist/settings/SettingsCatalog.js.map +1 -0
  77. package/dist/settings/SettingsService.d.ts +48 -0
  78. package/dist/settings/SettingsService.d.ts.map +1 -0
  79. package/dist/settings/SettingsService.js +218 -0
  80. package/dist/settings/SettingsService.js.map +1 -0
  81. package/dist/thread/ThreadExecutorPool.js +1 -1
  82. package/dist/thread/ThreadExecutorPool.js.map +1 -1
  83. package/dist/thread/types.d.ts +1 -1
  84. package/dist/thread/types.d.ts.map +1 -1
  85. package/dist/types/Settings.d.ts +64 -0
  86. package/dist/types/Settings.d.ts.map +1 -0
  87. package/dist/types/Settings.js +3 -0
  88. package/dist/types/Settings.js.map +1 -0
  89. package/dist/types/index.d.ts +2 -0
  90. package/dist/types/index.d.ts.map +1 -1
  91. package/package.json +1 -1
@@ -10,6 +10,7 @@ const Activity_1 = require("./Activity");
10
10
  const ClaudeSandbox_1 = require("./claude/ClaudeSandbox");
11
11
  const ClaudeFilePolicy_1 = require("./claude/ClaudeFilePolicy");
12
12
  const ExecutionMetadata_1 = require("./ExecutionMetadata");
13
+ const ClaudeSettings_1 = require("./claude/ClaudeSettings");
13
14
  const fs_1 = __importDefault(require("fs"));
14
15
  const path_1 = __importDefault(require("path"));
15
16
  const os_1 = __importDefault(require("os"));
@@ -38,7 +39,13 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
38
39
  threadId;
39
40
  /** Model to pass via --model on process start. Updated by setModel() for future restarts. */
40
41
  model;
42
+ effort;
41
43
  reportedModel;
44
+ // Native control catalog cache & control request state
45
+ cachedModelCatalog = null;
46
+ cachedRawEntries = null;
47
+ catalogInitPromise;
48
+ pendingControlRequests = new Map();
42
49
  // Persistent process
43
50
  claudeProcess = null;
44
51
  isStarting = false;
@@ -97,12 +104,13 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
97
104
  static FILE_POLICY_SCRIPT = path_1.default.join(__dirname, 'claude', 'filePolicyHook.js');
98
105
  // Activity tracking for timeout extension (optional, can be disabled)
99
106
  activityTrackingEnabled = false;
100
- constructor(directoryGuard, initialWorkingDirectory, threadId, model, sandbox, claudeCommand, lifecycleHooks = true, delegationWorker = false) {
107
+ constructor(directoryGuard, initialWorkingDirectory, threadId, model, sandbox, claudeCommand, lifecycleHooks = true, delegationWorker = false, effort) {
101
108
  super();
102
109
  this.lifecycleHooks = lifecycleHooks;
103
110
  this.delegationWorker = delegationWorker;
104
111
  this.directoryGuard = directoryGuard;
105
112
  this.model = model;
113
+ this.effort = effort === 'auto' ? undefined : effort;
106
114
  this.sandbox = new ClaudeSandbox_1.ClaudeSandbox(directoryGuard, sandbox, threadId);
107
115
  this.claudeCommand = claudeCommand ?? 'claude';
108
116
  // Use provided working directory or fall back to process.cwd()
@@ -213,8 +221,20 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
213
221
  return this.currentWorkingDirectory;
214
222
  }
215
223
  getExecutionMetadata() {
216
- const data = (0, ExecutionMetadata_1.configuredExecutionMetadata)(this.model);
217
- data.effortSource = 'unknown';
224
+ let effectiveEffort = this.effort;
225
+ if (this.effort && this.cachedRawEntries) {
226
+ const activeModel = this.reportedModel || this.model;
227
+ const entry = activeModel
228
+ ? this.cachedRawEntries.find(e => e.value === activeModel || (e.resolvedModel !== undefined && e.resolvedModel === activeModel))
229
+ : this.cachedRawEntries.find(e => e.value === 'default');
230
+ if (entry && (!entry.supportsEffort || !entry.supportedEffortLevels?.includes(this.effort))) {
231
+ effectiveEffort = undefined;
232
+ }
233
+ }
234
+ const data = (0, ExecutionMetadata_1.configuredExecutionMetadata)(this.model, effectiveEffort);
235
+ if (!effectiveEffort) {
236
+ data.effortSource = 'unknown';
237
+ }
218
238
  if (this.isProcessRunning() && this.reportedModel) {
219
239
  data.model = this.reportedModel;
220
240
  data.modelSource = 'reported';
@@ -259,6 +279,8 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
259
279
  * Start the persistent Claude process
260
280
  */
261
281
  async startProcess() {
282
+ if (this.isDestroyed || (this.isStopping && this.claudeProcess))
283
+ throw new Error('Claude process is unavailable or its exit is unconfirmed');
262
284
  if (this.claudeProcess || this.isStarting) {
263
285
  return;
264
286
  }
@@ -321,6 +343,9 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
321
343
  if (this.model) {
322
344
  args.push('--model', this.model);
323
345
  }
346
+ if (this.effort) {
347
+ args.push('--effort', this.effort);
348
+ }
324
349
  if (this.sessionId) {
325
350
  args.push('--resume', this.sessionId);
326
351
  console.log(`[ClaudePersistent] Resuming session: ${this.sessionId}`);
@@ -410,8 +435,12 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
410
435
  // Use 'close' event (fires after all I/O streams are closed, i.e. after all stdout
411
436
  // data events have been processed) instead of 'exit' for command completion logic.
412
437
  child.on('close', (code, signal) => {
438
+ if (this.claudeProcess !== child)
439
+ return;
413
440
  flushStderr();
414
441
  this.clearApprovals('Claude process exited');
442
+ this.rejectPendingControlRequests('Claude process exited before control response');
443
+ this.clearCatalogCache();
415
444
  this.claudeProcess = null;
416
445
  // Check if this was an intentional stop (abort/reset)
417
446
  const wasIntentionalStop = this.isStopping;
@@ -530,32 +559,33 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
530
559
  this.filePolicyRoots = [];
531
560
  this.filePolicyStarted = false;
532
561
  this.clearApprovals('Claude process stopped');
562
+ this.rejectPendingControlRequests('Claude process stopped before control response');
563
+ this.clearCatalogCache();
533
564
  if (!this.claudeProcess) {
534
565
  return;
535
566
  }
536
567
  console.log('[ClaudePersistent] Stopping process...');
537
568
  this.isStopping = true;
538
- // Send EOF to stdin to gracefully close
539
- this.claudeProcess.stdin?.end();
540
- // Kill after timeout
541
- const killTimeout = setTimeout(() => {
542
- if (this.claudeProcess) {
543
- console.log('[ClaudePersistent] Force killing process...');
544
- this.claudeProcess.kill('SIGTERM');
569
+ const child = this.claudeProcess;
570
+ // A signal is not evidence of exit. Bound the wait and retain the child on
571
+ // failure so the caller cannot silently launch a replacement over it.
572
+ await new Promise((resolve, reject) => {
573
+ const term = setTimeout(() => child.kill('SIGTERM'), 5_000);
574
+ const kill = setTimeout(() => child.kill('SIGKILL'), 8_000);
575
+ const deadline = setTimeout(() => { cleanup(); reject(new Error('Claude process exit could not be confirmed')); }, 9_000);
576
+ const cleanup = () => { clearTimeout(term); clearTimeout(kill); clearTimeout(deadline); child.removeListener('close', closed); };
577
+ const closed = () => { cleanup(); resolve(); };
578
+ child.once('close', closed);
579
+ try {
580
+ child.stdin?.end();
545
581
  }
546
- }, 5000);
547
- // Wait for process to exit
548
- await new Promise(resolve => {
549
- if (!this.claudeProcess) {
550
- resolve();
551
- return;
582
+ catch {
583
+ child.kill('SIGTERM');
552
584
  }
553
- this.claudeProcess.on('close', () => {
554
- clearTimeout(killTimeout);
555
- resolve();
556
- });
557
585
  });
558
- this.claudeProcess = null;
586
+ if (this.claudeProcess === child)
587
+ this.claudeProcess = null;
588
+ this.isStopping = false;
559
589
  console.log('[ClaudePersistent] Process stopped');
560
590
  }
561
591
  // ── Sandbox approval channel ─────────────────────────────────────────────
@@ -885,6 +915,41 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
885
915
  }
886
916
  return text;
887
917
  }
918
+ handleControlMessage(message) {
919
+ if (message.type !== 'control_response' || !message.response) {
920
+ return;
921
+ }
922
+ const { subtype, request_id, response, error } = message.response;
923
+ if (!request_id)
924
+ return;
925
+ const pending = this.pendingControlRequests.get(request_id);
926
+ if (!pending)
927
+ return;
928
+ this.pendingControlRequests.delete(request_id);
929
+ clearTimeout(pending.timer);
930
+ if (subtype === 'success') {
931
+ if (Buffer.byteLength(JSON.stringify(response ?? {}), 'utf8') > 1024 * 1024) {
932
+ pending.reject(new Error('Claude control response exceeds the supported size'));
933
+ return;
934
+ }
935
+ pending.resolve(response ?? {});
936
+ }
937
+ else {
938
+ pending.reject(new Error(error || `Claude control request failed with status: ${subtype}`));
939
+ }
940
+ }
941
+ rejectPendingControlRequests(reason) {
942
+ for (const [id, pending] of this.pendingControlRequests.entries()) {
943
+ clearTimeout(pending.timer);
944
+ pending.reject(new Error(reason));
945
+ }
946
+ this.pendingControlRequests.clear();
947
+ }
948
+ clearCatalogCache() {
949
+ this.cachedModelCatalog = null;
950
+ this.cachedRawEntries = null;
951
+ this.catalogInitPromise = undefined;
952
+ }
888
953
  /**
889
954
  * Handle a line of JSON output from Claude
890
955
  */
@@ -892,6 +957,12 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
892
957
  try {
893
958
  // Parse message first to check type
894
959
  const parsedMessage = JSON.parse(line);
960
+ // Handle native Claude Control response packets (models catalog, etc.).
961
+ // These bypass raw stdout logging to prevent any potential account/credential leakage.
962
+ if (parsedMessage.type === 'control_response' || parsedMessage.type === 'control_request') {
963
+ this.handleControlMessage(parsedMessage);
964
+ return;
965
+ }
895
966
  // Skip logging for stream_event messages to avoid console spam
896
967
  // Token deltas are handled below without logging every fragment.
897
968
  if (parsedMessage.type !== 'stream_event') {
@@ -1625,29 +1696,226 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
1625
1696
  this.stopProcess().catch((err) => console.error('[ClaudePersistent] Failed to stop process on reset:', err));
1626
1697
  }
1627
1698
  /**
1628
- * Send /model slash command to the running Claude process to switch models.
1629
- * Also stores the model so future process restarts start with --model already set,
1630
- * since a live /model change does not survive a process respawn on its own.
1699
+ * Switch the model for future commands.
1700
+ * Restarts the process if running, preserving the session via --resume.
1701
+ * Rejects known incompatible effort rather than silently changing a second preference.
1702
+ * Retains a deliberate text-argument full-model path if not found in catalog.
1631
1703
  */
1632
- setModel(model, onStream) {
1633
- console.log(`[ClaudePersistent] Sending /model ${model} slash command`);
1704
+ async setModel(model, _onStream) {
1705
+ if (this.isDestroyed) {
1706
+ return { success: false, error: 'Executor has been destroyed' };
1707
+ }
1708
+ if (this.isBusy()) {
1709
+ return { success: false, error: 'Cannot change model while Claude is busy' };
1710
+ }
1711
+ if (this.effort && !this.cachedRawEntries) {
1712
+ try {
1713
+ await this.listModels();
1714
+ }
1715
+ catch {
1716
+ return { success: false, error: 'Cannot validate the saved reasoning effort. Reset /effort auto before changing models.' };
1717
+ }
1718
+ }
1719
+ let matchedEntry;
1720
+ if (this.cachedRawEntries) {
1721
+ matchedEntry = this.cachedRawEntries.find(e => e.value === model || (e.resolvedModel !== undefined && e.resolvedModel === model));
1722
+ }
1723
+ if (this.effort && matchedEntry) {
1724
+ if (!matchedEntry.supportsEffort || !matchedEntry.supportedEffortLevels?.includes(this.effort)) {
1725
+ return { success: false, error: 'The saved reasoning effort is incompatible with this model. Reset /effort auto before changing models.' };
1726
+ }
1727
+ }
1728
+ await this.stopProcess();
1634
1729
  this.model = model;
1730
+ this.reportedModel = undefined;
1731
+ return {
1732
+ success: true,
1733
+ output: `Model set to ${this.model}.`,
1734
+ };
1735
+ }
1736
+ async clearModel() {
1737
+ if (this.isDestroyed)
1738
+ return;
1739
+ if (this.isBusy()) {
1740
+ throw new Error('Cannot clear model while Claude is busy');
1741
+ }
1742
+ this.model = undefined;
1743
+ this.reportedModel = undefined;
1744
+ await this.stopProcess();
1745
+ }
1746
+ /**
1747
+ * Query models available to the authenticated Claude backend using native control initialization.
1748
+ * Bounded by 10s timeout, cached per process instance, and rejects without injecting user prompts.
1749
+ */
1750
+ async listModels() {
1751
+ if (this.isDestroyed) {
1752
+ throw new Error('Executor has been destroyed');
1753
+ }
1754
+ if (this.cachedModelCatalog) {
1755
+ return (0, ClaudeSettings_1.parseClaudeModelsCatalog)(this.cachedRawEntries, this.reportedModel || this.model).models;
1756
+ }
1757
+ if (this.catalogInitPromise) {
1758
+ return this.catalogInitPromise;
1759
+ }
1760
+ const pending = this.performControlInitialization().finally(() => {
1761
+ if (this.catalogInitPromise === pending)
1762
+ this.catalogInitPromise = undefined;
1763
+ });
1764
+ this.catalogInitPromise = pending;
1765
+ return pending;
1766
+ }
1767
+ async performControlInitialization() {
1768
+ await this.startProcess();
1769
+ const child = this.claudeProcess;
1770
+ if (!child || !child.stdin || child.killed) {
1771
+ throw new Error('Claude process is not available for control initialization');
1772
+ }
1773
+ const stdin = child.stdin;
1774
+ const requestId = `catalog-${(0, crypto_1.randomUUID)()}`;
1775
+ const requestPacket = {
1776
+ type: 'control_request',
1777
+ request_id: requestId,
1778
+ request: {
1779
+ subtype: 'initialize',
1780
+ },
1781
+ };
1635
1782
  return new Promise((resolve, reject) => {
1636
- this.reportedModel = undefined;
1637
- if (this.isDestroyed) {
1638
- resolve({ success: false, error: 'Executor has been destroyed' });
1639
- return;
1640
- }
1641
- this.commandQueue.push({
1642
- prompt: `/model ${model}`,
1643
- options: { onStream },
1644
- resolve,
1645
- reject,
1646
- isSlashCommand: true,
1783
+ let timer;
1784
+ const cleanup = () => {
1785
+ if (timer)
1786
+ clearTimeout(timer);
1787
+ this.pendingControlRequests.delete(requestId);
1788
+ };
1789
+ timer = setTimeout(() => {
1790
+ cleanup();
1791
+ reject(new Error('Claude control initialization timed out after 10000ms'));
1792
+ }, 10_000);
1793
+ this.pendingControlRequests.set(requestId, {
1794
+ resolve: (response) => {
1795
+ cleanup();
1796
+ if (this.claudeProcess !== child || this.isDestroyed || this.isStopping) {
1797
+ reject(new Error('Claude catalog process is no longer active'));
1798
+ return;
1799
+ }
1800
+ try {
1801
+ const rawResponse = response || {};
1802
+ const { models, rawEntries } = (0, ClaudeSettings_1.parseClaudeModelsCatalog)(rawResponse.models, this.reportedModel || this.model);
1803
+ this.cachedRawEntries = rawEntries;
1804
+ this.cachedModelCatalog = models;
1805
+ resolve(models);
1806
+ }
1807
+ catch (err) {
1808
+ reject(err instanceof Error ? err : new Error(String(err)));
1809
+ }
1810
+ },
1811
+ reject: (err) => {
1812
+ cleanup();
1813
+ reject(err);
1814
+ },
1815
+ timer,
1647
1816
  });
1648
- this.processQueue();
1817
+ try {
1818
+ stdin.write(JSON.stringify(requestPacket) + '\n', (err) => {
1819
+ if (err) {
1820
+ cleanup();
1821
+ reject(new Error(`Failed to write control request to Claude stdin: ${err.message}`));
1822
+ }
1823
+ });
1824
+ }
1825
+ catch (err) {
1826
+ cleanup();
1827
+ reject(err instanceof Error ? err : new Error(String(err)));
1828
+ }
1649
1829
  });
1650
1830
  }
1831
+ /**
1832
+ * Query reasoning effort levels supported for the current model.
1833
+ */
1834
+ async listEfforts() {
1835
+ if (this.isDestroyed) {
1836
+ return {
1837
+ choices: [],
1838
+ current: this.effort,
1839
+ default: undefined,
1840
+ supportsReset: true,
1841
+ unavailableReason: 'Executor has been destroyed',
1842
+ };
1843
+ }
1844
+ try {
1845
+ await this.listModels();
1846
+ }
1847
+ catch (err) {
1848
+ return {
1849
+ choices: [],
1850
+ current: this.effort,
1851
+ default: undefined,
1852
+ supportsReset: true,
1853
+ unavailableReason: err instanceof Error ? err.message : 'Claude model catalog unavailable',
1854
+ };
1855
+ }
1856
+ if (!this.cachedRawEntries) {
1857
+ return {
1858
+ choices: [],
1859
+ current: this.effort,
1860
+ default: undefined,
1861
+ supportsReset: true,
1862
+ unavailableReason: 'Reasoning effort is not supported for Claude Code.',
1863
+ };
1864
+ }
1865
+ const activeModel = this.reportedModel || this.model;
1866
+ return (0, ClaudeSettings_1.resolveClaudeEfforts)(this.cachedRawEntries, activeModel, this.effort);
1867
+ }
1868
+ /**
1869
+ * Set reasoning effort level for future commands.
1870
+ * 'auto' clears the override. Non-auto values validate against native supported levels.
1871
+ * Preserves the session while recycling the idle process and passing --effort to the next spawn.
1872
+ */
1873
+ async setEffort(effort) {
1874
+ if (this.isDestroyed) {
1875
+ return { success: false, error: 'Executor has been destroyed' };
1876
+ }
1877
+ if (this.isBusy()) {
1878
+ return { success: false, error: 'Cannot change reasoning effort while Claude is busy' };
1879
+ }
1880
+ const normalized = effort.trim().toLowerCase();
1881
+ if (normalized === 'auto' || normalized === '') {
1882
+ await this.stopProcess();
1883
+ this.effort = undefined;
1884
+ return {
1885
+ success: true,
1886
+ output: 'Reasoning effort restored to default.',
1887
+ };
1888
+ }
1889
+ let effortInfo;
1890
+ try {
1891
+ effortInfo = await this.listEfforts();
1892
+ }
1893
+ catch (err) {
1894
+ return {
1895
+ success: false,
1896
+ error: err instanceof Error ? err.message : 'Failed to query available reasoning efforts',
1897
+ };
1898
+ }
1899
+ if (effortInfo.unavailableReason || !effortInfo.choices.length) {
1900
+ return {
1901
+ success: false,
1902
+ error: effortInfo.unavailableReason || 'Reasoning effort is not supported for the current model.',
1903
+ };
1904
+ }
1905
+ const match = effortInfo.choices.find(c => c.value.toLowerCase() === normalized);
1906
+ if (!match) {
1907
+ return {
1908
+ success: false,
1909
+ error: `Unsupported reasoning effort: ${effort}. Supported values: auto, ${effortInfo.choices.map(c => c.value).join(', ')}.`,
1910
+ };
1911
+ }
1912
+ await this.stopProcess();
1913
+ this.effort = match.value;
1914
+ return {
1915
+ success: true,
1916
+ output: `Reasoning effort set to ${match.value}.`,
1917
+ };
1918
+ }
1651
1919
  /**
1652
1920
  * Send /compact slash command to the running Claude process to compress conversation history.
1653
1921
  * This asks Claude CLI to summarize the conversation and reduce context size.
@@ -1756,6 +2024,8 @@ class ClaudePersistentExecutor extends events_1.EventEmitter {
1756
2024
  }
1757
2025
  this.commandQueue = [];
1758
2026
  this.clearApprovals('Executor destroyed');
2027
+ this.rejectPendingControlRequests('Executor has been destroyed');
2028
+ this.clearCatalogCache();
1759
2029
  if (this.approvalServer) {
1760
2030
  const server = this.approvalServer;
1761
2031
  this.approvalServer = null;