tide-commander 1.69.0 → 1.71.0

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 (50) hide show
  1. package/dist/assets/{BossLogsModal-CMDdkhTL.js → BossLogsModal-DoW-oomk.js} +1 -1
  2. package/dist/assets/BossSpawnModal-Boc6sIfS.js +1 -0
  3. package/dist/assets/{ControlsModal-BtJJYkcM.js → ControlsModal-C6o3uZcq.js} +1 -1
  4. package/dist/assets/{DockerLogsModal-Lw19ZQVz.js → DockerLogsModal-D0Qo_MwC.js} +1 -1
  5. package/dist/assets/{EmbeddedEditor-UwKqvTkJ.js → EmbeddedEditor-CekqD_9x.js} +1 -1
  6. package/dist/assets/{GmailOAuthSetup-BOlxzJ7D.js → GmailOAuthSetup-9-5bh2P-.js} +1 -1
  7. package/dist/assets/{GoogleOAuthSetup-DYvaSFQp.js → GoogleOAuthSetup-3dJ_OKsM.js} +1 -1
  8. package/dist/assets/{IframeModal-DRJROx67.js → IframeModal-DbXb7CwV.js} +1 -1
  9. package/dist/assets/{IntegrationsPanel-Bp1O-I5s.js → IntegrationsPanel-Bbu-YttD.js} +2 -2
  10. package/dist/assets/{LogViewerModal-BIlhbii5.js → LogViewerModal-Bz-phlyW.js} +1 -1
  11. package/dist/assets/{MonitoringModal-CuDrTaVn.js → MonitoringModal-DPufvsx3.js} +1 -1
  12. package/dist/assets/{PM2LogsModal-C1VLY7hc.js → PM2LogsModal-BRJEoIGZ.js} +1 -1
  13. package/dist/assets/{RestoreArchivedAreaModal-ObvIYj2V.js → RestoreArchivedAreaModal-DcsT_-25.js} +1 -1
  14. package/dist/assets/{Scene2DCanvas-BM_GFevb.js → Scene2DCanvas-DNsc8p5F.js} +1 -1
  15. package/dist/assets/{SceneManager-FeZQ9HI1.js → SceneManager-DPvh-m5A.js} +1 -1
  16. package/dist/assets/{SkillsPanel-CtFwVaQj.js → SkillsPanel-B_xQv-7n.js} +2 -2
  17. package/dist/assets/SpawnModal-B9jRwDuS.js +1 -0
  18. package/dist/assets/{SubordinateAssignmentModal-aDkxc3YR.js → SubordinateAssignmentModal-nNA0eQY3.js} +1 -1
  19. package/dist/assets/TriggerManagerPanel-CRYqCuDW.js +3 -0
  20. package/dist/assets/{WorkflowEditorPanel-D_8Bnuzv.js → WorkflowEditorPanel-DMj6QkhB.js} +1 -1
  21. package/dist/assets/{index-Br8WLiXq.js → index-B0Bgs8A9.js} +1 -1
  22. package/dist/assets/{index-BIkn0arf.js → index-BKI7mhTU.js} +3 -3
  23. package/dist/assets/{index-9Bftos7u.js → index-BSDP6H43.js} +6 -6
  24. package/dist/assets/index-BXuHHEGh.css +1 -0
  25. package/dist/assets/{index-K0KrIo24.js → index-BwN_ChZo.js} +3 -3
  26. package/dist/assets/index-CAYhCfSA.js +2 -0
  27. package/dist/assets/{index-BYR78OCI.js → index-CIDXn3G0.js} +1 -1
  28. package/dist/assets/{index-CX4tk_vI.js → index-QhVjGjw2.js} +1 -1
  29. package/dist/assets/{index-BMayWtlQ.js → index-VvpWwviS.js} +1 -1
  30. package/dist/assets/{index-YH8hJh62.js → index-fFQ_bGrk.js} +2 -2
  31. package/dist/assets/main-C2_Gs1Uu.css +1 -0
  32. package/dist/assets/{main--_0rf6yB.js → main-DchkmHia.js} +89 -89
  33. package/dist/assets/{web-BuuzpQy3.js → web-BYNdUdPc.js} +1 -1
  34. package/dist/assets/{web-Dn-wQDim.js → web-DPcQ0gLD.js} +1 -1
  35. package/dist/index.html +2 -2
  36. package/dist/locales/en/config.json +6 -1
  37. package/dist/locales/en/terminal.json +4 -1
  38. package/dist/src/packages/server/claude/runner.js +42 -33
  39. package/dist/src/packages/server/codex/backend.js +17 -8
  40. package/dist/src/packages/server/services/cron-service.js +49 -0
  41. package/dist/src/packages/server/services/runtime-command-execution.js +29 -12
  42. package/dist/src/packages/server/services/trigger-service.js +65 -0
  43. package/dist/src/packages/shared/agent-types.js +8 -0
  44. package/package.json +1 -1
  45. package/dist/assets/BossSpawnModal-C7lw2Wzh.js +0 -1
  46. package/dist/assets/SpawnModal-37ChIpU2.js +0 -1
  47. package/dist/assets/TriggerManagerPanel-CQxcjiJu.js +0 -3
  48. package/dist/assets/index-D8fn_Wjl.js +0 -1
  49. package/dist/assets/index-DDfjGtDT.css +0 -1
  50. package/dist/assets/main-BXDdkAuE.css +0 -1
@@ -1 +1 @@
1
- import{b_ as a}from"./main--_0rf6yB.js";import{ImpactStyle as i,NotificationType as r}from"./index-YH8hJh62.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class h extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{h as HapticsWeb};
1
+ import{c1 as a}from"./main-DchkmHia.js";import{ImpactStyle as i,NotificationType as r}from"./index-fFQ_bGrk.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class h extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{h as HapticsWeb};
@@ -1 +1 @@
1
- import{b_ as s}from"./main--_0rf6yB.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class l extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{l as LocalNotificationsWeb};
1
+ import{c1 as s}from"./main-DchkmHia.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class l extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{l as LocalNotificationsWeb};
package/dist/index.html CHANGED
@@ -22,10 +22,10 @@
22
22
  <link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16x16.png" />
23
23
  <link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png" />
24
24
  <title>Tide Commander</title>
25
- <script type="module" crossorigin src="/assets/main--_0rf6yB.js"></script>
25
+ <script type="module" crossorigin src="/assets/main-DchkmHia.js"></script>
26
26
  <link rel="modulepreload" crossorigin href="/assets/vendor-react--Eh9ivFN.js">
27
27
  <link rel="modulepreload" crossorigin href="/assets/vendor-three-Chj50gSY.js">
28
- <link rel="stylesheet" crossorigin href="/assets/main-BXDdkAuE.css">
28
+ <link rel="stylesheet" crossorigin href="/assets/main-C2_Gs1Uu.css">
29
29
  </head>
30
30
  <body>
31
31
  <div id="app"></div>
@@ -68,7 +68,12 @@
68
68
  "hideToken": "Hide token",
69
69
  "codexBinaryPath": "Codex Binary Path",
70
70
  "codexBinaryPathPlaceholder": "Leave empty for auto-detect",
71
- "codexBinaryPathHint": "Path to the native Codex binary. Bypasses the Node.js wrapper for better session persistence."
71
+ "codexBinaryPathHint": "Path to the native Codex binary. Bypasses the Node.js wrapper for better session persistence.",
72
+ "connectScreen": {
73
+ "authTokenLabel": "Auth Token",
74
+ "authTokenPlaceholder": "X-Auth-Token (optional)",
75
+ "authTokenHint": "Optional. Required if your server enforces auth."
76
+ }
72
77
  },
73
78
  "scene": {
74
79
  "characterSize": "Character Size",
@@ -220,7 +220,9 @@
220
220
  "approvalsUntrusted": "Approvals: untrusted",
221
221
  "approvalsOnFailure": "Approvals: on-failure",
222
222
  "approvalsOnRequest": "Approvals: on-request",
223
- "approvalsNever": "Approvals: never"
223
+ "approvalsNever": "Approvals: never",
224
+ "reasoningEffort": "Reasoning Effort",
225
+ "reasoningEffortDefault": "Reasoning Effort: default"
224
226
  }
225
227
  },
226
228
  "overview": {
@@ -247,6 +249,7 @@
247
249
  "clickToSwitch": "Click to switch to this agent",
248
250
  "sameAreaOnly": "Same Area",
249
251
  "subagentsCompleted": "{{count}} subagents (all completed)",
252
+ "hasDraft": "Has unsent draft",
250
253
  "statusLabels": {
251
254
  "working": "Working",
252
255
  "idle": "Idle",
@@ -305,26 +305,33 @@ export class ClaudeRunner {
305
305
  log.error(`❌ [SEND_MESSAGE] No active process for agent ${agentId}`);
306
306
  return false;
307
307
  }
308
- // tmux mode: send via tmux send-keys — EXCEPT for backends that close stdin
309
- // after the initial prompt (codex). Those are launched as `cat <file> | codex`
310
- // so codex's stdin is the pipe, NOT the tmux pane. Once cat hits EOF, codex
311
- // gets EOF; tmux send-keys would write to a pane codex isn't reading. We must
312
- // queue those messages and deliver them via respawn-with-session-resume
313
- // triggered by the watchdog_missing_process handler when the session dies.
314
- // Also queue mid-turn messages for all backends — send-keys mid-turn is
315
- // unreliable and can interfere with the current prompt being processed.
308
+ // tmux mode dispatch:
309
+ // - Stdin-closed backends (codex, opencode) MUST queue. They were
310
+ // launched as `cat <file> | codex …` so their stdin is the pipe, not
311
+ // the tmux pane. Once cat hits EOF they receive EOF; tmux send-keys
312
+ // would write to a pane they aren't reading. Delivery happens via
313
+ // respawn-with-session-resume when the session dies (handled by the
314
+ // watchdog_missing_process branch).
315
+ // - Stdin-open backends (claude) are launched as
316
+ // `(cat <file>; cat) | claude --input-format stream-json …` — the
317
+ // trailing `cat` reads from the tmux pane, so send-keys writes are
318
+ // fed to claude's stdin as additional stream-json lines. Claude
319
+ // handles mid-turn `{type:"user",…}` messages natively (queues them
320
+ // internally for post-turn or injects them per its own protocol), so
321
+ // we write immediately regardless of turnState instead of blocking
322
+ // the user until step_complete.
316
323
  if (activeProcess.tmuxSession) {
317
324
  const tmuxTurnState = activeProcess.turnState || 'processing';
318
325
  const tmuxBackendClosesStdin = this.backend.shouldCloseStdinAfterPrompt?.() === true;
319
- if (tmuxTurnState === 'processing' || tmuxBackendClosesStdin) {
326
+ if (tmuxBackendClosesStdin) {
320
327
  const queue = this.messageQueue.get(agentId) ?? [];
321
328
  queue.push(message);
322
329
  this.messageQueue.set(agentId, queue);
323
- log.log(`📋 [QUEUE-TMUX] Agent ${agentId}: queued message (turnState=${tmuxTurnState}, closesStdin=${tmuxBackendClosesStdin}, queue=${queue.length}, ${message.length} chars)`);
330
+ log.log(`📋 [QUEUE-TMUX] Agent ${agentId}: queued message (stdin-closed backend, turnState=${tmuxTurnState}, queue=${queue.length}, ${message.length} chars)`);
324
331
  return true;
325
332
  }
326
333
  const stdinInput = this.backend.formatStdinInput(message);
327
- log.log(`📨 [SEND_MESSAGE] Agent ${agentId} (tmux mode), sending via tmux send-keys (${stdinInput.length} chars)`);
334
+ log.log(`📨 [SEND_MESSAGE] Agent ${agentId} (tmux, turnState=${tmuxTurnState}), sending via tmux send-keys (${stdinInput.length} chars)`);
328
335
  const ok = sendToTmux(agentId, stdinInput);
329
336
  if (ok) {
330
337
  activeProcess.turnState = 'processing';
@@ -334,35 +341,37 @@ export class ClaudeRunner {
334
341
  const turnState = activeProcess.turnState || 'processing';
335
342
  const messageLen = message.length;
336
343
  const backendClosesStdin = this.backend.shouldCloseStdinAfterPrompt?.() === true;
337
- // Queue mid-turn messages BEFORE any stdin-writability check. Writing to the OS
338
- // stdin pipe mid-turn is unreliable on all backends (async callback + possible
339
- // pipe close), and backends like codex/opencode explicitly close stdin after the
340
- // initial prompt so there is nothing to write to at all. For stdin-closed backends
341
- // we queue regardless of turnState — there is a race window between step_complete
342
- // (turnState flips to 'waiting_for_input') and process exit where direct stdin
343
- // write would fail, the fallthrough path SIGINTs the old process, and the
344
- // respawn-with-queue path is skipped (cleanTurnEnd requires a clean exit).
345
- // The queue is the source of truth; drain happens after the current turn ends
346
- // (via stdin for stdin-open backends, or via session-resume respawn for
347
- // stdin-closed ones).
348
- if (turnState === 'processing' || backendClosesStdin) {
344
+ // Stdin-closed backends (codex, opencode) MUST always queue: there is
345
+ // literally no open stdin to write to after the initial prompt.
346
+ // sendCommand's interrupt-and-restart branch handles mid-turn prompts for
347
+ // these by stopping+respawning; this queue catches the narrow
348
+ // step_complete/process_exit race window where respawn is the only
349
+ // delivery path (cleanTurnEnd in runner.ts:248 picks it up).
350
+ if (backendClosesStdin) {
349
351
  const queue = this.messageQueue.get(agentId) ?? [];
350
352
  queue.push(message);
351
353
  this.messageQueue.set(agentId, queue);
352
- log.log(`📋 [QUEUE] Agent ${agentId}: queued message for post-turn delivery (turnState=${turnState}, closesStdin=${backendClosesStdin}, queue=${queue.length}, ${messageLen} chars)`);
354
+ log.log(`📋 [QUEUE] Agent ${agentId}: queued message for respawn delivery (stdin-closed backend, turnState=${turnState}, queue=${queue.length}, ${messageLen} chars)`);
353
355
  return true;
354
356
  }
355
- // Agent is waiting for input: send directly via stdin (immediate processing)
357
+ // Stdin-open backends (claude): write directly regardless of turnState.
358
+ // Claude's --input-format stream-json accepts additional
359
+ // {type:"user",...} JSON lines at any time and interleaves them with the
360
+ // current turn per its own protocol. Blocking on 'waiting_for_input'
361
+ // previously made the user wait for step_complete before Claude even saw
362
+ // the message; now it goes straight to Claude's stdin.
356
363
  const stdin = activeProcess.process.stdin;
357
- if (!stdin) {
358
- log.error(`❌ [SEND_MESSAGE] stdin is null for agent ${agentId}`);
359
- return false;
360
- }
361
- if (!stdin.writable) {
362
- log.error(`❌ [SEND_MESSAGE] stdin is not writable for agent ${agentId} (destroyed: ${stdin.destroyed}, closed: ${stdin.closed})`);
363
- return false;
364
+ if (!stdin || !stdin.writable) {
365
+ // Defensive fallback: if stdin unexpectedly isn't writable (pipe
366
+ // closed, process dying), queue so the respawn path can recover the
367
+ // message instead of dropping it.
368
+ log.warn(`⚠️ [SEND_MESSAGE] Agent ${agentId}: stdin not writable (stdin=${!!stdin}, writable=${stdin?.writable}); queueing for recovery path (turnState=${turnState}, ${messageLen} chars)`);
369
+ const queue = this.messageQueue.get(agentId) ?? [];
370
+ queue.push(message);
371
+ this.messageQueue.set(agentId, queue);
372
+ return true;
364
373
  }
365
- log.log(`📨 [SEND_MESSAGE] Agent ${agentId} is idle (turnState=${turnState}), sending directly via stdin (${messageLen} chars)`);
374
+ log.log(`📨 [SEND_MESSAGE] Agent ${agentId} (turnState=${turnState}), sending directly via stdin (${messageLen} chars)`);
366
375
  return this.writeToStdin(agentId, activeProcess, message);
367
376
  }
368
377
  /**
@@ -85,6 +85,11 @@ export class CodexBackend {
85
85
  if (codexConfig?.profile) {
86
86
  args.push('--profile', codexConfig.profile);
87
87
  }
88
+ if (codexConfig?.reasoningEffort) {
89
+ // Pass as a two-arg pair so the spawned process receives the flag and
90
+ // value as separate argv entries — no shell-level quoting needed.
91
+ args.push('-c', `model_reasoning_effort=${codexConfig.reasoningEffort}`);
92
+ }
88
93
  if (config.workingDir) {
89
94
  args.push('-C', config.workingDir);
90
95
  }
@@ -115,15 +120,18 @@ export class CodexBackend {
115
120
  return null;
116
121
  }
117
122
  getExecutablePath() {
118
- // Priority: 1) CODEX_BINARY env var 2) Settings UI 3) auto-detect
119
- const envBinary = process.env.CODEX_BINARY;
120
- if (envBinary && fs.existsSync(envBinary)) {
121
- return envBinary;
122
- }
123
+ // Priority: 1) Settings UI 2) CODEX_BINARY env var 3) auto-detect
124
+ // The Settings UI value is an explicit user override and must win over
125
+ // the env var default so the user can point Tide Commander at a specific
126
+ // codex install without clearing their shell environment.
123
127
  const settingsBinary = getCodexBinaryPath();
124
128
  if (settingsBinary && fs.existsSync(settingsBinary)) {
125
129
  return settingsBinary;
126
130
  }
131
+ const envBinary = process.env.CODEX_BINARY;
132
+ if (envBinary && fs.existsSync(envBinary)) {
133
+ return envBinary;
134
+ }
127
135
  return this.detectInstallation() || 'codex';
128
136
  }
129
137
  detectInstallation() {
@@ -149,10 +157,11 @@ export class CodexBackend {
149
157
  getExtraEnv() {
150
158
  // When using the native binary directly, we need to add
151
159
  // the vendor path directory to PATH so codex can find bundled tools like rg.
152
- const envBinary = process.env.CODEX_BINARY || getCodexBinaryPath();
153
- if (!envBinary)
160
+ // Match the precedence used by getExecutablePath(): Settings UI wins over env var.
161
+ const binary = getCodexBinaryPath() || process.env.CODEX_BINARY;
162
+ if (!binary)
154
163
  return {};
155
- const codexDir = path.dirname(envBinary); // .../codex/
164
+ const codexDir = path.dirname(binary); // .../codex/
156
165
  const archRoot = path.dirname(codexDir); // .../x86_64-unknown-linux-musl/
157
166
  const pathDir = path.join(archRoot, 'path');
158
167
  if (fs.existsSync(pathDir)) {
@@ -132,6 +132,55 @@ function getDateInTimezone(timezone) {
132
132
  }
133
133
  // ─── Public API ───
134
134
  const CHECK_INTERVAL_MS = 30_000; // Check every 30 seconds
135
+ // Max safe setTimeout delay (2^31-1 ms ≈ 24.8 days). Longer waits are chained.
136
+ const MAX_SETTIMEOUT_MS = 2_147_483_647;
137
+ /**
138
+ * Schedule a callback to fire exactly once at the given absolute datetime.
139
+ * If the time is already in the past, the callback is fired immediately (next tick).
140
+ * Returns a CronJob-compatible handle that can be stopped via `stop(job)`.
141
+ */
142
+ export function scheduleOnce(runAtIso, callback) {
143
+ const id = `once_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
144
+ const runAtMs = new Date(runAtIso).getTime();
145
+ const job = {
146
+ id,
147
+ expression: `@once ${runAtIso}`,
148
+ timezone: 'UTC',
149
+ callback,
150
+ timer: null,
151
+ lastFired: null,
152
+ };
153
+ const fire = (reason) => {
154
+ job.lastFired = Date.now();
155
+ log.log(`One-shot cron ${id} fired (runAt=${runAtIso}, ${reason})`);
156
+ activeJobs.delete(id);
157
+ try {
158
+ callback();
159
+ }
160
+ catch (err) {
161
+ log.error(`One-shot cron ${id} callback error:`, err);
162
+ }
163
+ };
164
+ const armTimer = () => {
165
+ const remaining = runAtMs - Date.now();
166
+ // Always schedule via setTimeout (delay clamped to >= 0) so the callback
167
+ // never runs synchronously within scheduleOnce — callers often update state
168
+ // after this returns, and a sync callback would race that.
169
+ const delay = Math.max(0, Math.min(remaining, MAX_SETTIMEOUT_MS));
170
+ job.timer = setTimeout(() => {
171
+ if (remaining > MAX_SETTIMEOUT_MS) {
172
+ // Chained wait: re-arm for the remaining interval
173
+ armTimer();
174
+ return;
175
+ }
176
+ fire('scheduled');
177
+ }, delay);
178
+ };
179
+ armTimer();
180
+ activeJobs.set(id, job);
181
+ log.log(`Scheduled one-shot cron ${id} for ${runAtIso}`);
182
+ return job;
183
+ }
135
184
  export function schedule(expression, timezone, callback) {
136
185
  const id = `cron_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
137
186
  const job = {
@@ -69,10 +69,29 @@ export function createRuntimeCommandExecution(deps) {
69
69
  }
70
70
  const processRunning = runner.isRunning(agentId);
71
71
  // For backends that close stdin after the initial prompt (codex, opencode),
72
- // a new user prompt arriving mid-turn should INTERRUPT the current work and
73
- // RESTART the session with the new prompt — not wait for the current turn
74
- // to finish and then deliver the queued message via session-resume (which
75
- // is the default queue-based behavior for these backends).
72
+ // a new user prompt arriving while the process is alive should INTERRUPT
73
+ // the current work and RESTART the session with the new prompt — not wait
74
+ // for the current turn to finish and then deliver the queued message via
75
+ // session-resume (which is the default queue-based behavior).
76
+ //
77
+ // Why no turnState gate: stdin is closed, so there's literally no way to
78
+ // deliver a follow-up prompt without respawning. 'waiting_for_input' is
79
+ // also not a reliable "turn is over" signal across these backends —
80
+ // opencode's NDJSON emits `step_finish` per LLM step (see
81
+ // src/packages/server/opencode/json-event-parser.ts:197-207), so during a
82
+ // single conversational turn the runner's turnState oscillates
83
+ // processing → waiting_for_input → processing → … between steps. Gating
84
+ // on 'waiting_for_input' would strand the new prompt on those mid-turn
85
+ // windows: sendMessage would queue it, but the process isn't exiting
86
+ // (it's starting the next step), so the queue-respawn path never fires.
87
+ // Codex happens to emit `step_complete` once per turn (via
88
+ // src/packages/server/codex/json-event-parser.ts:300-301), so the old
89
+ // gate looked fine there — but the correct invariant for ALL stdin-closed
90
+ // backends is: process-alive + new-prompt ⇒ interrupt + respawn.
91
+ //
92
+ // SIGINT on a process already at true turn-end (about to exit cleanly on
93
+ // its own) is harmless — process-lifecycle's stop() just short-circuits
94
+ // the natural exit, and the fresh spawn still resumes the same sessionId.
76
95
  //
77
96
  // Safe for tmux mode: runner.stop() routes through
78
97
  // src/packages/server/claude/runner/process-lifecycle.ts:281-284 which
@@ -86,14 +105,12 @@ export function createRuntimeCommandExecution(deps) {
86
105
  const backendClosesStdin = runner.closesStdinAfterPrompt?.() === true;
87
106
  if (processRunning && backendClosesStdin && !forceNewSession) {
88
107
  const turnState = runner.getTurnState?.(agentId);
89
- if (turnState !== 'waiting_for_input') {
90
- log.log(`[sendCommand] Agent ${agentId} (${agent.provider}): mid-turn prompt (turnState=${turnState ?? 'unknown'}) interrupting current work and restarting session with new prompt`);
91
- emitOutput(agentId, '🛑 [System] Interrupting current work to process new prompt…', false, undefined, 'system-interrupt-restart');
92
- await runner.stop(agentId, true);
93
- agentService.updateAgent(agentId, { taskCount: (agent.taskCount || 0) + 1 });
94
- await executeCommand(agentId, command, systemPrompt, forceNewSession, customAgent);
95
- return;
96
- }
108
+ log.log(`[sendCommand] Agent ${agentId} (${agent.provider}): in-flight prompt (turnState=${turnState ?? 'unknown'}) — interrupting current work and restarting session with new prompt`);
109
+ emitOutput(agentId, '🛑 [System] Interrupting current work to process new prompt…', false, undefined, 'system-interrupt-restart');
110
+ await runner.stop(agentId, true);
111
+ agentService.updateAgent(agentId, { taskCount: (agent.taskCount || 0) + 1 });
112
+ await executeCommand(agentId, command, systemPrompt, forceNewSession, customAgent);
113
+ return;
97
114
  }
98
115
  if (processRunning && !forceNewSession) {
99
116
  if (runner.supportsStdin()) {
@@ -615,9 +615,15 @@ function interpolateTemplate(template, variables) {
615
615
  });
616
616
  }
617
617
  // ─── Cron Management ───
618
+ // Grace window for firing a one-shot whose runAt slipped past while the server was down.
619
+ const ONE_SHOT_MISS_GRACE_MS = 5 * 60 * 1000;
618
620
  function startCronJob(trigger) {
619
621
  // Stop existing job if any
620
622
  stopCronJob(trigger.id);
623
+ if (trigger.config.runOnce) {
624
+ startOneShotJob(trigger);
625
+ return;
626
+ }
621
627
  const job = cronService.schedule(trigger.config.expression, trigger.config.timezone, () => {
622
628
  const variables = {
623
629
  'cron.expression': trigger.config.expression,
@@ -629,6 +635,65 @@ function startCronJob(trigger) {
629
635
  cronJobs.set(trigger.id, job);
630
636
  log.log(`Started cron job for trigger ${trigger.name}: ${trigger.config.expression}`);
631
637
  }
638
+ function startOneShotJob(trigger) {
639
+ const runAt = trigger.config.runAt;
640
+ if (!runAt) {
641
+ log.warn(`One-shot trigger ${trigger.name} has no runAt; skipping schedule`);
642
+ return;
643
+ }
644
+ // Already completed — do not re-arm.
645
+ if (trigger.config.completedAt) {
646
+ log.log(`One-shot trigger ${trigger.name} already completed at ${new Date(trigger.config.completedAt).toISOString()}`);
647
+ return;
648
+ }
649
+ const runAtMs = new Date(runAt).getTime();
650
+ if (Number.isNaN(runAtMs)) {
651
+ log.error(`One-shot trigger ${trigger.name} has invalid runAt: ${runAt}`);
652
+ return;
653
+ }
654
+ const now = Date.now();
655
+ const overdueMs = now - runAtMs;
656
+ if (overdueMs > ONE_SHOT_MISS_GRACE_MS) {
657
+ // Missed by more than the grace window — mark missed and disable.
658
+ log.warn(`One-shot trigger ${trigger.name} missed (overdue by ${Math.round(overdueMs / 1000)}s); marking as missed`);
659
+ const updatedConfig = { ...trigger.config, missedAt: now };
660
+ updateTrigger(trigger.id, {
661
+ enabled: false,
662
+ status: 'error',
663
+ lastError: 'missed: server was down at runAt',
664
+ config: updatedConfig,
665
+ });
666
+ return;
667
+ }
668
+ const job = cronService.scheduleOnce(runAt, () => {
669
+ const variables = {
670
+ 'cron.runAt': runAt,
671
+ 'cron.scheduledAt': new Date().toISOString(),
672
+ ...(trigger.config.payload || {}),
673
+ };
674
+ void handleOneShotFire(trigger.id, variables);
675
+ });
676
+ cronJobs.set(trigger.id, job);
677
+ log.log(`Armed one-shot trigger ${trigger.name} for ${runAt}${overdueMs > 0 ? ' (within grace window, firing immediately)' : ''}`);
678
+ }
679
+ async function handleOneShotFire(triggerId, variables) {
680
+ const trigger = triggers.get(triggerId);
681
+ if (!trigger || trigger.type !== 'cron')
682
+ return;
683
+ const cronTrigger = trigger;
684
+ if (!cronTrigger.config.runOnce)
685
+ return;
686
+ // Mark completed + disabled BEFORE firing. fireTrigger internally calls
687
+ // updateTrigger which would otherwise re-enter startCronJob and re-arm the
688
+ // one-shot. The completedAt guard in startOneShotJob short-circuits that.
689
+ const updatedConfig = { ...cronTrigger.config, completedAt: Date.now() };
690
+ updateTrigger(triggerId, {
691
+ enabled: false,
692
+ config: updatedConfig,
693
+ });
694
+ cronJobs.delete(triggerId);
695
+ await fireTrigger(triggerId, variables);
696
+ }
632
697
  function stopCronJob(triggerId) {
633
698
  const job = cronJobs.get(triggerId);
634
699
  if (job) {
@@ -16,6 +16,14 @@ export const PERMISSION_MODES = {
16
16
  bypass: { label: 'Permissionless', description: 'Skip all permission prompts (less safe, faster)' },
17
17
  interactive: { label: 'Interactive', description: 'Ask for approval before sensitive operations' },
18
18
  };
19
+ export const CODEX_REASONING_EFFORTS = {
20
+ none: { label: 'None', description: 'No reasoning', icon: '⚪' },
21
+ minimal: { label: 'Minimal', description: 'Least reasoning, fastest', icon: '💨' },
22
+ low: { label: 'Low', description: 'Light reasoning', icon: '🏃' },
23
+ medium: { label: 'Medium', description: 'Balanced reasoning', icon: '⚖️' },
24
+ high: { label: 'High', description: 'Deep reasoning', icon: '🔬' },
25
+ xhigh: { label: 'X-High', description: 'Extra-high reasoning, slowest', icon: '🧠' },
26
+ };
19
27
  export const CODEX_MODELS = {
20
28
  'gpt-5.5': {
21
29
  label: 'GPT-5.5',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tide-commander",
3
- "version": "1.69.0",
3
+ "version": "1.71.0",
4
4
  "description": "Visual multi-agent orchestrator and manager for Claude Code with 3D/2D interface",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +0,0 @@
1
- import{u as Ee,a4 as Ie,as as De,ar as _e,r as t,C as Be,S as ae,l as Re,av as z,A as ne,aD as O,s as T,aE as j,j as s,N as S,ax as ze,az as Oe,I as L,aA as P,ac as g,aa as E,E as Te}from"./main--_0rf6yB.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";function le(u){const h=j.filter(C=>!u.has(`Boss ${C}`));return h.length===0?`Boss ${j[Math.floor(Math.random()*j.length)]}-${Date.now()%1e3}`:`Boss ${h[Math.floor(Math.random()*h.length)]}`}function Ue({isOpen:u,onClose:h,onSpawnStart:C,onSpawnEnd:I,spawnPosition:te}){const{t:n}=Ee(["terminal","common"]),q=Ie(),o=De(),k=_e(),[r,p]=t.useState(""),[M,ie]=t.useState(()=>Be(ae.LAST_CWD)),[c,D]=t.useState("boss"),[F,U]=t.useState(!1),[ce,y]=t.useState(!1),[W,oe]=t.useState(!0),[G,re]=t.useState("bypass"),[d,_]=t.useState("claude"),[b,N]=t.useState({fullAuto:!0,sandbox:"workspace-write",approvalMode:"on-request",search:!1}),[K,de]=t.useState("opus[1m]"),[H,pe]=t.useState("gpt-5.3-codex"),[v,A]=t.useState(new Set),[J,B]=t.useState(new Set),[m,me]=t.useState(""),[f,ue]=t.useState(""),[V,he]=t.useState(""),$=t.useRef(null),R=t.useRef(!1),X=t.useRef(!1),w=t.useMemo(()=>k.filter(e=>e.enabled),[k]),Y=t.useMemo(()=>{if(!f.trim())return w;const e=f.toLowerCase();return w.filter(a=>a.name.toLowerCase().includes(e)||a.description.toLowerCase().includes(e)||a.slug.toLowerCase().includes(e))},[w,f]),xe=t.useMemo(()=>{var a;const e=o.find(l=>l.id===c);return(a=e==null?void 0:e.defaultSkillIds)!=null&&a.length?k.filter(l=>e.defaultSkillIds.includes(l.id)):[]},[o,c,k]),we=["full-notifications","streaming-exec","task-label","report-task-to-boss","send-message-to-agent"];t.useEffect(()=>{if(u&&!X.current&&w.length>0){const a=w.filter(l=>we.includes(l.slug)).map(l=>l.id);a.length>0&&B(new Set(a))}X.current=u},[u,w]);const be=t.useCallback(e=>{B(a=>{const l=new Set(a);return l.has(e)?l.delete(e):l.add(e),l})},[]),i=t.useMemo(()=>o.find(e=>e.id===c),[o,c]),fe=t.useMemo(()=>{if(i!=null&&i.model)return i.model},[i]),je=t.useMemo(()=>{if(i!=null&&i.customModelPath)return Re(`/api/custom-models/${i.id}`)},[i]),Ne=i==null?void 0:i.modelScale,ve=t.useMemo(()=>i?"scout":c==="boss"?"architect":c,[c,i]),Q=t.useMemo(()=>Array.from(q.values()).filter(e=>!e.isBoss&&e.class!=="boss"&&!e.bossId),[q]),Z=t.useMemo(()=>{if(!m.trim())return o;const e=m.toLowerCase();return o.filter(a=>a.name.toLowerCase().includes(e)||a.description.toLowerCase().includes(e)||a.id.toLowerCase().includes(e))},[o,m]),ee=t.useMemo(()=>{if(!m.trim())return z;const e=m.toLowerCase();return z.filter(a=>{const l=ne[a.id];return l?a.name.toLowerCase().includes(e)||a.id.toLowerCase().includes(e)||l.description.toLowerCase().includes(e):!1})},[m]),se=t.useMemo(()=>{if(!m.trim())return!0;const e=m.toLowerCase(),a=O.boss;return"boss".includes(e)||a.description.toLowerCase().includes(e)},[m]);t.useEffect(()=>{if(u&&!R.current){R.current=!0;const e=new Set(Array.from(T.getState().agents.values()).map(l=>l.name)),a=o.find(l=>l.id===c);if(a){const l=j.filter(x=>!e.has(`${a.name} ${x}`));if(l.length===0){const x=j[Math.floor(Math.random()*j.length)];p(`${a.name} ${x}-${Date.now()%1e3}`)}else p(`${a.name} ${l[Math.floor(Math.random()*l.length)]}`)}else p(le(e));A(new Set),$.current&&($.current.focus(),$.current.select())}else u||(R.current=!1)},[u]),t.useEffect(()=>{if(!u)return;const e=o.find(a=>a.id===c);if(e)if(r.startsWith("Boss ")){const a=r.substring(5);p(`${e.name} ${a}`)}else{const a=o.find(l=>r.startsWith(l.name+" "));if(a){const l=r.substring(a.name.length+1);p(`${e.name} ${l}`)}else p(`${e.name} ${r}`)}else{const a=o.find(l=>r.startsWith(l.name+" "));if(a){const l=r.substring(a.name.length+1);p(`Boss ${l}`)}else r.startsWith("Boss ")||p(`Boss ${r}`)}},[c]);const Se=()=>{if(y(!1),!M.trim()){y(!0);return}if(!r.trim()){const l=new Set(Array.from(T.getState().agents.values()).map(x=>x.name));p(le(l));return}Te(ae.LAST_CWD,M),C();const e=V.trim()||void 0,a=Array.from(J);T.spawnBossAgent(r.trim(),c,M.trim(),te||void 0,Array.from(v),d==="claude"?W:!1,G,d,d==="codex"?b:void 0,d==="codex"?H:void 0,d==="claude"?K:void 0,e,a),p(""),A(new Set),B(new Set),I(),h()},ge=()=>{U(!1),p(""),A(new Set),I(),h()},Ce=()=>{U(!1),y(!0),I()};t.useEffect(()=>(window.__bossSpawnModalSuccess=ge,window.__bossSpawnModalError=Ce,()=>{delete window.__bossSpawnModalSuccess,delete window.__bossSpawnModalError}),[r]);const ke=e=>{e.target===e.currentTarget&&h()},Me=e=>{e.key==="Escape"&&h()},ye=e=>{const a=new Set(v);a.has(e)?a.delete(e):a.add(e),A(a)};if(!u)return null;const Ae=O.boss;return s.jsx("div",{className:`modal-overlay ${u?"visible":""}`,onClick:ke,onKeyDown:Me,children:s.jsxs("div",{className:"modal boss-spawn-modal",children:[s.jsxs("div",{className:"modal-header",children:[s.jsx(S,{classId:"boss",size:22,className:"boss-header-icon"}),n("terminal:spawn.deployBossTitle")]}),s.jsxs("div",{className:"modal-body spawn-modal-body",children:[s.jsxs("div",{className:"spawn-top-section",children:[s.jsx("div",{className:"spawn-preview-compact",children:s.jsx(ze,{agentClass:ve,modelFile:fe,customModelUrl:je,modelScale:Ne,width:100,height:120})}),s.jsxs("div",{className:"spawn-class-section",children:[s.jsx("div",{className:"spawn-class-label",children:n("terminal:spawn.bossClass")}),o.length+z.length+1>6&&s.jsx("input",{type:"text",className:"spawn-input class-search-input",placeholder:n("terminal:spawn.filterClasses"),value:m,onChange:e=>me(e.target.value)}),s.jsxs("div",{className:"class-selector-inline",children:[Z.map(e=>s.jsxs("button",{className:`class-chip ${c===e.id?"selected":""}`,onClick:()=>D(e.id),title:e.description,children:[s.jsx(S,{classId:e.id,size:18,className:"class-chip-icon"}),s.jsx("span",{className:"class-chip-name",children:e.name})]},e.id)),se&&s.jsxs("button",{className:`class-chip ${c==="boss"?"selected":""}`,onClick:()=>D("boss"),title:Ae.description,children:[s.jsx(S,{classId:"boss",size:18,className:"class-chip-icon"}),s.jsx("span",{className:"class-chip-name",children:n("terminal:spawn.bossClassName")})]}),ee.map(e=>{const a=ne[e.id];return a?s.jsxs("button",{className:`class-chip ${c===e.id?"selected":""}`,onClick:()=>D(e.id),title:a.description,children:[s.jsx(S,{classId:e.id,size:18,className:"class-chip-icon"}),s.jsx("span",{className:"class-chip-name",children:e.name})]},e.id):null}),m&&Z.length===0&&!se&&ee.length===0&&s.jsx("div",{className:"class-search-empty",children:n("terminal:spawn.noClassesMatch",{query:m})})]})]})]}),s.jsxs("div",{className:"spawn-form-section",children:[s.jsxs("div",{className:"spawn-form-row",children:[s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("common:labels.name")}),s.jsx("input",{ref:$,type:"text",className:"spawn-input",placeholder:n("terminal:spawn.bossNamePlaceholder"),value:r,onChange:e=>p(e.target.value)})]}),s.jsxs("div",{className:"spawn-field spawn-field-wide",children:[s.jsx("label",{className:"spawn-label",children:n("terminal:spawn.workingDir")}),s.jsx(Oe,{value:M,onChange:e=>{ie(e),y(!1)},placeholder:n("terminal:spawn.workingDirPlaceholder"),className:"spawn-input",hasError:ce,directoriesOnly:!0})]})]}),s.jsxs("div",{className:"spawn-form-row",children:[s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("common:labels.runtime")}),s.jsxs("div",{className:"spawn-select-row",children:[s.jsxs("button",{className:`spawn-select-btn ${d==="claude"?"selected":""}`,onClick:()=>_("claude"),title:n("terminal:spawn.useClaudeCli"),children:[s.jsx("img",{src:"/assets/claude.ico",alt:"Claude",className:"spawn-provider-icon"}),s.jsx("span",{children:"Claude"})]}),s.jsxs("button",{className:`spawn-select-btn ${d==="codex"?"selected":""}`,onClick:()=>_("codex"),title:n("terminal:spawn.useCodexCli"),children:[s.jsx("img",{src:"/assets/codex.ico",alt:"Codex",className:"spawn-provider-icon"}),s.jsx("span",{children:"Codex"})]}),s.jsxs("button",{className:`spawn-select-btn spawn-select-btn--opencode ${d==="opencode"?"selected":""}`,onClick:()=>_("opencode"),title:"Use OpenCode CLI (multi-provider)",children:[s.jsx("span",{children:s.jsx(L,{name:"status-pending",size:14,weight:"fill",color:"#4ade80"})}),s.jsx("span",{children:"OpenCode"})]})]})]}),s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("common:labels.permissions")}),s.jsx("div",{className:"spawn-select-row",children:Object.keys(P).map(e=>s.jsxs("button",{className:`spawn-select-btn ${G===e?"selected":""}`,onClick:()=>re(e),title:P[e].description,children:[s.jsx("span",{children:s.jsx(L,{name:e==="bypass"?"bolt":"lock",size:14})}),s.jsx("span",{children:P[e].label})]},e))})]})]}),s.jsxs("div",{className:"spawn-form-row",children:[s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("common:labels.model")}),d==="claude"?s.jsx("div",{className:"spawn-select-row",children:Object.keys(g).filter(e=>!g[e].deprecated).map(e=>s.jsxs("button",{className:`spawn-select-btn ${K===e?"selected":""}`,onClick:()=>de(e),title:g[e].description,children:[s.jsx("span",{children:g[e].icon}),s.jsx("span",{children:g[e].label})]},e))}):d==="codex"?s.jsx("div",{className:"spawn-select-row spawn-select-row--codex-models",children:Object.keys(E).map(e=>s.jsxs("button",{className:`spawn-select-btn ${H===e?"selected":""}`,onClick:()=>pe(e),title:E[e].description,children:[s.jsx("span",{children:E[e].icon}),s.jsx("span",{children:E[e].label})]},e))}):d==="opencode"?s.jsx("input",{type:"text",className:"spawn-input",defaultValue:"minimax/MiniMax-M1-80k",placeholder:"provider/model (e.g., minimax/MiniMax-M1-80k)"}):s.jsx("div",{className:"spawn-inline-hint",children:n("terminal:spawn.codex.configuration")})]}),s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("common:labels.browser")}),s.jsx("div",{className:"spawn-form-row spawn-options-row",children:s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:W,onChange:e=>oe(e.target.checked),disabled:d!=="claude"}),s.jsx("span",{children:n("terminal:spawn.chromeBrowser")})]})})]})]}),d==="codex"&&s.jsx("div",{className:"spawn-form-row",children:s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("terminal:spawn.codex.config")}),s.jsxs("div",{className:"spawn-options-row",style:{display:"flex",flexDirection:"column",gap:8},children:[s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:b.fullAuto!==!1,onChange:e=>N(a=>({...a,fullAuto:e.target.checked}))}),s.jsx("span",{children:n("terminal:spawn.codex.useFullAuto")})]}),s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:!!b.search,onChange:e=>N(a=>({...a,search:e.target.checked}))}),s.jsx("span",{children:n("terminal:spawn.codex.enableSearch")})]}),b.fullAuto===!1&&s.jsxs(s.Fragment,{children:[s.jsxs("select",{className:"spawn-input",value:b.sandbox||"workspace-write",onChange:e=>N(a=>({...a,sandbox:e.target.value})),children:[s.jsx("option",{value:"read-only",children:n("terminal:spawn.codex.sandboxReadOnly")}),s.jsx("option",{value:"workspace-write",children:n("terminal:spawn.codex.sandboxWorkspaceWrite")}),s.jsx("option",{value:"danger-full-access",children:n("terminal:spawn.codex.sandboxDangerFullAccess")})]}),s.jsxs("select",{className:"spawn-input",value:b.approvalMode||"on-request",onChange:e=>N(a=>({...a,approvalMode:e.target.value})),children:[s.jsx("option",{value:"untrusted",children:n("terminal:spawn.codex.approvalsUntrusted")}),s.jsx("option",{value:"on-failure",children:n("terminal:spawn.codex.approvalsOnFailure")}),s.jsx("option",{value:"on-request",children:n("terminal:spawn.codex.approvalsOnRequest")}),s.jsx("option",{value:"never",children:n("terminal:spawn.codex.approvalsNever")})]})]}),s.jsx("input",{type:"text",className:"spawn-input",placeholder:n("terminal:spawn.codex.profileOptional"),value:b.profile||"",onChange:e=>N(a=>({...a,profile:e.target.value||void 0}))})]})]})}),w.length>0&&s.jsxs("div",{className:"spawn-skills-section",children:[s.jsxs("label",{className:"spawn-label",children:[n("terminal:spawn.skills")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",n("common:labels.optional"),")"]})]}),w.length>6&&s.jsx("input",{type:"text",className:"spawn-input skill-search-input",placeholder:n("terminal:spawn.filterSkills"),value:f,onChange:e=>ue(e.target.value)}),s.jsxs("div",{className:"spawn-skills-inline",children:[Y.map(e=>{const a=J.has(e.id);return xe.some(x=>x.id===e.id)?null:s.jsxs("button",{className:`spawn-skill-chip ${a?"selected":""}`,onClick:()=>be(e.id),title:e.description,children:[a&&s.jsx("span",{className:"spawn-skill-check",children:s.jsx(L,{name:"check",size:12})}),s.jsx("span",{children:e.name}),e.builtin&&s.jsx("span",{className:"spawn-skill-builtin",children:"TC"})]},e.id)}),f&&Y.length===0&&s.jsx("div",{className:"skill-search-empty",children:n("terminal:spawn.noSkillsMatch",{query:f})})]})]}),s.jsxs("div",{className:"spawn-custom-instructions-section",children:[s.jsxs("label",{className:"spawn-label",children:[n("terminal:spawn.customInstructions")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",n("common:labels.optional"),")"]})]}),s.jsx("textarea",{className:"spawn-input spawn-textarea",placeholder:n("terminal:spawn.customInstructionsBossPlaceholder"),value:V,onChange:e=>he(e.target.value),rows:3})]}),s.jsxs("div",{className:"spawn-subordinates-section",children:[s.jsxs("label",{className:"spawn-label",children:[n("terminal:spawn.initialSubordinates")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",n("common:labels.optional"),")"]})]}),s.jsx("div",{className:"subordinates-selector-compact",children:Q.length===0?s.jsx("div",{className:"subordinates-empty",children:n("terminal:spawn.noAvailableAgents")}):Q.map(e=>{const a=v.has(e.id),l=O[e.class],x=o.find(Le=>Le.id===e.class),$e=l||x||{color:"#888888"};return s.jsxs("button",{className:`subordinate-chip ${a?"selected":""}`,onClick:()=>ye(e.id),children:[a&&s.jsx("span",{className:"subordinate-check",children:s.jsx(L,{name:"check",size:12})}),s.jsx("span",{className:"subordinate-chip-icon",style:{color:$e.color},children:s.jsx(S,{classId:e.class,size:16})}),s.jsx("span",{className:"subordinate-chip-name",children:e.name})]},e.id)})}),v.size>0&&s.jsxs("div",{className:"subordinates-count",children:[v.size," ",n("common:labels.selected").toLowerCase()]})]})]})]}),s.jsxs("div",{className:"modal-footer",children:[s.jsx("button",{className:"btn btn-secondary",onClick:h,children:n("common:buttons.cancel")}),s.jsx("button",{className:"btn btn-boss",onClick:Se,disabled:F,children:n(F?"common:buttons.deploying":"common:buttons2.deployBoss")})]})]})})}export{Ue as BossSpawnModal};
@@ -1 +0,0 @@
1
- import{u as Ve,ar as Ze,as as es,at as ss,au as as,r as t,C as ye,S as ne,av as te,A as Ae,l as le,aw as ns,s as S,h as ts,j as s,ax as ls,N as De,ay as x,az as os,aA as oe,I as ie,ac as T,aa as K,aB as is,ab as ce,aC as cs,E as rs}from"./main--_0rf6yB.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";function Ee(r,g){const b=g.filter(C=>!r.has(C));return b.length===0?`${g[Math.floor(Math.random()*g.length)]}-${Date.now()%1e3}`:b[Math.floor(Math.random()*b.length)]}function us({isOpen:r,onClose:g,onSpawnStart:b,onSpawnEnd:C,spawnPosition:Ie,spawnAreaId:N}){const{t:a}=Ve(["terminal","common"]),P=Ze(),p=es(),re=ss(),H=re.length>0?re:as,[m,v]=t.useState(""),[M,F]=t.useState(()=>ye(ne.LAST_CWD)),[i,k]=t.useState("scout"),[de,E]=t.useState(!1),[Le,z]=t.useState(!1),[pe,J]=t.useState(!1),[me,ue]=t.useState(""),[y,Y]=t.useState([]),[A,R]=t.useState(null),[_e,he]=t.useState(!1),[I,we]=t.useState(""),[h,$e]=t.useState(""),[U,Te]=t.useState(!1),[q,Pe]=t.useState("bypass"),[o,X]=t.useState("claude"),[j,L]=t.useState({fullAuto:!0,sandbox:"workspace-write",approvalMode:"on-request",search:!1}),[xe,Q]=t.useState(new Set),[V,fe]=t.useState("opus[1m]"),[Z,ge]=t.useState("xHigh"),[ee,Fe]=t.useState("gpt-5.3-codex"),[se,ze]=t.useState("minimax/MiniMax-M1-80k"),[je,Re]=t.useState(""),[D,Ue]=t.useState(""),O=t.useRef(null),Ne=t.useRef(!1),_=t.useCallback(()=>{window.__spawnModalAreaContext=null},[]),w=t.useMemo(()=>P.filter(e=>e.enabled),[P]),qe=["full-notifications","streaming-exec","task-label","report-task-to-boss","agent-tracking","send-message-to-agent"];t.useEffect(()=>{if(r&&!Ne.current){if(w.length>0){const l=w.filter(c=>qe.includes(c.slug)).map(c=>c.id);l.length>0&&Q(new Set(l))}const n=ye(ne.DEFAULT_AGENT_CLASS);if(n==="random"){const c=[...Object.keys(cs),...p.map(u=>u.id)];k(c[Math.floor(Math.random()*c.length)])}else k(n||"scout")}Ne.current=r},[r,w,p]);const ve=t.useMemo(()=>{if(!D.trim())return w;const e=D.toLowerCase();return w.filter(n=>n.name.toLowerCase().includes(e)||n.description.toLowerCase().includes(e)||n.slug.toLowerCase().includes(e))},[w,D]),Oe=t.useCallback(e=>{Q(n=>{const l=new Set(n);return l.has(e)?l.delete(e):l.add(e),l})},[]);t.useMemo(()=>w.filter(e=>e.assignedAgentClasses.includes(i)),[w,i]);const We=t.useMemo(()=>{var n;const e=p.find(l=>l.id===i);return(n=e==null?void 0:e.defaultSkillIds)!=null&&n.length?P.filter(l=>e.defaultSkillIds.includes(l.id)):[]},[p,i,P]),Se=t.useMemo(()=>{if(!I.trim())return y;const e=I.toLowerCase();return y.filter(n=>n.sessionId.toLowerCase().includes(e)||n.projectPath.toLowerCase().includes(e)||n.firstMessage&&n.firstMessage.toLowerCase().includes(e))},[y,I]),W=t.useMemo(()=>{if(!h.trim())return p;const e=h.toLowerCase();return p.filter(n=>n.name.toLowerCase().includes(e)||n.description.toLowerCase().includes(e)||n.id.toLowerCase().includes(e))},[p,h]),B=t.useMemo(()=>{if(!h.trim())return te;const e=h.toLowerCase();return te.filter(n=>{const l=Ae[n.id];return n.name.toLowerCase().includes(e)||n.id.toLowerCase().includes(e)||l.description.toLowerCase().includes(e)})},[h]);t.useEffect(()=>{if(!r||!h.trim())return;const e=[...W.map(n=>n.id),...B.map(n=>n.id)];e.length===1&&e[0]!==i&&k(e[0])},[r,h,W,B,i]);const d=t.useMemo(()=>p.find(e=>e.id===i),[p,i]),Be=t.useMemo(()=>{if(d!=null&&d.model)return d.model},[d]),Ge=t.useMemo(()=>{if(d!=null&&d.customModelPath)return le(`/api/custom-models/${d.id}`)},[d]),Ke=d==null?void 0:d.modelScale,He=t.useMemo(()=>d?"scout":i,[i,d]),G=t.useCallback(async e=>{he(!0);try{const n=e?le(`/api/agents/claude-sessions?cwd=${encodeURIComponent(e)}`):le("/api/agents/claude-sessions"),c=await(await ns(n)).json();Y(c.sessions||[])}catch(n){console.error("Failed to fetch sessions:",n),Y([])}finally{he(!1)}},[]);t.useEffect(()=>{r?G(M||void 0):(Y([]),R(null),we(""))},[r,G]),t.useEffect(()=>{if(!r)return;const e=setTimeout(()=>{G(M||void 0),R(null)},300);return()=>clearTimeout(e)},[M,r,G]),t.useEffect(()=>{if(!r||!N)return;const e=S.getState().areas.get(N);if(e!=null&&e.directories&&e.directories.length>0){F(e.directories[0]);return}const n=Array.from(S.getState().agents.values()).filter(f=>{var $;return(($=S.getAreaForAgent(f.id))==null?void 0:$.id)===N&&f.cwd});if(n.length===0)return;const l=new Map;for(const f of n)l.set(f.cwd,(l.get(f.cwd)||0)+1);let c="",u=0;for(const[f,$]of l)$>u&&(c=f,u=$);c&&F(c)},[r,N]),t.useEffect(()=>{if(r){const e=new Set(Array.from(S.getState().agents.values()).map(u=>u.name)),n=Ee(e,H),l=p.find(u=>u.id===i),c=l?`${l.name} ${n}`:n;v(c),O.current&&(O.current.focus(),O.current.select())}},[r,H]),t.useEffect(()=>{if(!r)return;const e=p.find(n=>n.id===i);if(e){const n=p.find(l=>m.startsWith(l.name+" "));if(n){const l=m.substring(n.name.length+1);v(`${e.name} ${l}`)}else v(`${e.name} ${m}`)}else{const n=p.find(l=>m.startsWith(l.name+" "));if(n){const l=m.substring(n.name.length+1);v(l)}}},[i]),t.useEffect(()=>{i==="boss"&&fe("claude-opus-4-7")},[i]);const Je=()=>{var c;console.log("[SpawnModal] handleSpawn called"),z(!1);const e=A&&((c=y.find(u=>u.sessionId===A))==null?void 0:c.projectPath)||M;if(console.log("[SpawnModal] Effective CWD:",e),console.log("[SpawnModal] Agent name:",m),console.log("[SpawnModal] Agent class:",i),console.log("[SpawnModal] Permission mode:",q),console.log("[SpawnModal] Provider:",o),console.log("[SpawnModal] Use Chrome:",U),console.log("[SpawnModal] Session ID:",A||"none"),!e.trim()){console.error("[SpawnModal] Empty CWD, showing error"),z(!0);return}if(!m.trim()){console.log("[SpawnModal] Empty name, regenerating");const u=new Set(Array.from(S.getState().agents.values()).map(f=>f.name));v(Ee(u,H));return}rs(ne.LAST_CWD,e),E(!0),b();const n=Array.from(xe),l=je.trim()||void 0;console.log("[SpawnModal] Calling store.spawnAgent with:",{name:m.trim(),class:i,cwd:e.trim(),sessionId:A||void 0,useChrome:o==="claude"?U:!1,permissionMode:q,provider:o,codexConfig:o==="codex"?j:void 0,codexModel:o==="codex"?ee:void 0,opencodeModel:o==="opencode"?se:void 0,initialSkillIds:n,model:o==="claude"?V:void 0,customInstructions:l?`${l.length} chars`:void 0,spawnAreaId:N||void 0}),window.__spawnModalAreaContext=N?{areaId:N}:null,S.spawnAgent(m.trim(),i,e.trim(),Ie||void 0,A||void 0,o==="claude"?U:!1,q,n,o,o==="codex"?j:void 0,o==="codex"?ee:void 0,o==="claude"?V:void 0,l,o==="claude"?Z:void 0,o==="opencode"?se:void 0)},be=()=>{console.log("[SpawnModal] Agent creation successful"),E(!1),v(""),Q(new Set),_(),C(),g()},Ce=()=>{console.error("[SpawnModal] Agent creation failed"),E(!1),z(!0),_(),C()},Me=e=>{console.log("[SpawnModal] Directory not found:",e),E(!1),ue(e),J(!0),C()},ke=()=>{J(!1),E(!0),b(),S.createDirectoryAndSpawn(me,m.trim(),i)},ae=()=>{J(!1),ue(""),_()};t.useEffect(()=>(window.__spawnModalSuccess=be,window.__spawnModalError=Ce,window.__spawnModalDirNotFound=Me,()=>{_(),delete window.__spawnModalSuccess,delete window.__spawnModalError,delete window.__spawnModalDirNotFound}),[m,i,be,Ce,Me,_]);const{handleMouseDown:Ye,handleClick:Xe}=ts(g),Qe=e=>{e.key==="Escape"&&g()};return!r&&!pe?null:pe?s.jsx("div",{className:"modal-overlay visible",onClick:ae,onKeyDown:e=>{e.key==="Escape"&&ae(),e.key==="Enter"&&ke()},children:s.jsxs("div",{className:"modal confirm-modal",onClick:e=>e.stopPropagation(),children:[s.jsx("div",{className:"modal-header",children:a("terminal:spawn.directoryNotFound")}),s.jsxs("div",{className:"modal-body confirm-modal-body",children:[s.jsx("p",{children:a("terminal:spawn.directoryNotExist")}),s.jsx("code",{className:"confirm-modal-path",children:me}),s.jsx("p",{children:a("terminal:spawn.wouldYouCreate")})]}),s.jsxs("div",{className:"modal-footer",children:[s.jsx("button",{className:"btn btn-secondary",onClick:ae,children:a("common:buttons.cancel")}),s.jsx("button",{className:"btn btn-primary",onClick:ke,autoFocus:!0,children:a("terminal:spawn.createDirectory")})]})]})}):s.jsx("div",{className:`modal-overlay ${r?"visible":""}`,onMouseDown:Ye,onClick:Xe,onKeyDown:Qe,children:s.jsxs("div",{className:"modal spawn-modal",children:[s.jsx("div",{className:"modal-header",children:a("terminal:spawn.deployTitle")}),s.jsxs("div",{className:"modal-body spawn-modal-body",children:[s.jsxs("div",{className:"spawn-top-section",children:[s.jsx("div",{className:"spawn-preview-compact",children:s.jsx(ls,{agentClass:He,modelFile:Be,customModelUrl:Ge,modelScale:Ke,width:100,height:120})}),s.jsxs("div",{className:"spawn-class-section",children:[s.jsx("div",{className:"spawn-class-label",children:a("terminal:spawn.agentClass")}),p.length+te.length>6&&s.jsx("input",{type:"text",className:"spawn-input class-search-input",placeholder:a("terminal:spawn.filterClasses"),value:h,onChange:e=>$e(e.target.value)}),s.jsxs("div",{className:"class-selector-inline",children:[W.map(e=>s.jsxs("button",{className:`class-chip ${i===e.id?"selected":""}`,onClick:()=>k(e.id),title:e.description,children:[s.jsx(De,{classId:e.id,size:18,className:"class-chip-icon"}),s.jsx("span",{className:"class-chip-name",children:e.name})]},e.id)),B.map(e=>{const n=Ae[e.id];return s.jsxs("button",{className:`class-chip ${i===e.id?"selected":""}`,onClick:()=>k(e.id),title:n.description,children:[s.jsx(De,{classId:e.id,size:18,className:"class-chip-icon"}),s.jsx("span",{className:"class-chip-name",children:e.name})]},e.id)}),h&&W.length===0&&B.length===0&&s.jsx("div",{className:"class-search-empty",children:a("terminal:spawn.noClassesMatch",{query:h})})]})]})]}),s.jsxs("div",{className:"spawn-form-section",children:[s.jsxs("div",{className:"spawn-form-row",children:[s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:a("common:labels.name")}),s.jsx("input",{ref:O,type:"text",className:"spawn-input",placeholder:a("terminal:spawn.agentNamePlaceholder"),value:m,onChange:e=>v(e.target.value)})]}),s.jsxs("div",{className:"spawn-field spawn-field-wide",children:[s.jsxs("label",{className:"spawn-label",children:[a("terminal:spawn.workingDir"),s.jsx(x,{text:a("terminal:spawn.helpWorkingDir"),title:a("terminal:spawn.workingDir"),position:"top",size:"sm"})]}),s.jsx(os,{value:M,onChange:e=>{F(e),z(!1)},placeholder:a("terminal:spawn.workingDirPlaceholder"),className:`spawn-input ${Le?"error":""}`,directoriesOnly:!0})]})]}),s.jsxs("div",{className:"spawn-form-row",children:[s.jsxs("div",{className:"spawn-field",children:[s.jsxs("label",{className:"spawn-label",children:[a("terminal:spawn.selectRuntime"),s.jsx(x,{text:a("terminal:spawn.helpRuntime"),title:a("terminal:spawn.runtimeTitle"),position:"top",size:"sm"})]}),s.jsxs("div",{className:"spawn-select-row",children:[s.jsxs("button",{className:`spawn-select-btn ${o==="claude"?"selected":""}`,onClick:()=>X("claude"),title:a("terminal:spawn.useClaudeCli"),children:[s.jsx("img",{src:"/assets/claude.ico",alt:"Claude",className:"spawn-provider-icon"}),s.jsx("span",{children:"Claude"})]}),s.jsxs("button",{className:`spawn-select-btn ${o==="codex"?"selected":""}`,onClick:()=>X("codex"),title:a("terminal:spawn.useCodexCli"),children:[s.jsx("img",{src:"/assets/codex.ico",alt:"Codex",className:"spawn-provider-icon"}),s.jsx("span",{children:"Codex"})]}),s.jsxs("button",{className:`spawn-select-btn spawn-select-btn--opencode ${o==="opencode"?"selected":""}`,onClick:()=>X("opencode"),title:"Use OpenCode CLI (multi-provider)",children:[s.jsx("img",{src:"/assets/opencode.svg",alt:"OpenCode",className:"spawn-provider-icon"}),s.jsx("span",{children:"OpenCode"})]})]})]}),s.jsxs("div",{className:"spawn-field",children:[s.jsxs("label",{className:"spawn-label",children:[a("common:labels.permissions"),s.jsx(x,{text:a("terminal:spawn.helpPermission"),title:a("terminal:spawn.permissionMode"),position:"top",size:"sm"})]}),s.jsx("div",{className:"spawn-select-row",children:Object.keys(oe).map(e=>s.jsxs("button",{className:`spawn-select-btn ${q===e?"selected":""}`,onClick:()=>Pe(e),title:oe[e].description,children:[s.jsx("span",{children:s.jsx(ie,{name:e==="bypass"?"bolt":"lock",size:12})}),s.jsx("span",{children:oe[e].label})]},e))})]})]}),s.jsx("div",{className:"spawn-form-row",children:s.jsxs("div",{className:"spawn-field",children:[s.jsxs("label",{className:"spawn-label",children:[a("common:labels.model"),s.jsx(x,{text:a("terminal:spawn.helpModel"),title:a("terminal:spawn.modelTitle"),position:"top",size:"sm"})]}),o==="claude"?s.jsx("div",{className:"spawn-select-row spawn-select-row--wrap",children:Object.keys(T).filter(e=>!T[e].deprecated).map(e=>s.jsxs("button",{className:`spawn-select-btn ${V===e?"selected":""}`,onClick:()=>fe(e),title:T[e].description,children:[s.jsx("span",{children:T[e].icon}),s.jsx("span",{children:T[e].label})]},e))}):o==="codex"?s.jsx("div",{className:"spawn-select-row spawn-select-row--codex-models",children:Object.keys(K).map(e=>s.jsxs("button",{className:`spawn-select-btn ${ee===e?"selected":""}`,onClick:()=>Fe(e),title:K[e].description,children:[s.jsx("span",{children:K[e].icon}),s.jsx("span",{children:K[e].label})]},e))}):o==="opencode"?s.jsx(is,{value:se,onChange:ze,inputId:"spawn-opencode-model"}):s.jsx("div",{className:"spawn-inline-hint",children:a("terminal:spawn.chooseCodexModel")})]})}),s.jsxs("div",{className:"spawn-form-row",children:[o==="claude"&&s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:"Effort"}),s.jsxs("div",{className:"spawn-select-row spawn-select-row--effort",children:[s.jsx("button",{className:`spawn-select-btn spawn-select-btn--compact ${Z===void 0?"selected":""}`,onClick:()=>ge(void 0),title:"Use default effort level",children:s.jsx("span",{children:"Default"})}),Object.keys(ce).map(e=>s.jsx("button",{className:`spawn-select-btn spawn-select-btn--compact ${Z===e?"selected":""}`,onClick:()=>ge(e),title:ce[e].description,children:s.jsx("span",{children:ce[e].label})},e))]})]}),s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:a("terminal:spawn.browser")}),s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:U,onChange:e=>Te(e.target.checked),disabled:o!=="claude"}),s.jsxs("span",{children:[s.jsx(ie,{name:"globe",size:12})," ",a("terminal:spawn.chromeBrowser")]}),s.jsx(x,{text:a(o==="claude"?"terminal:spawn.helpChrome":"terminal:spawn.helpChromeDisabled"),title:a("terminal:spawn.chromeBrowser"),position:"top",size:"sm"})]})]})]}),o==="codex"&&s.jsxs("div",{className:"codex-config-section",children:[s.jsx("div",{className:"codex-config-title",children:a("terminal:spawn.codex.configuration")}),s.jsxs("div",{className:"codex-config-options",children:[s.jsxs("div",{className:"codex-option-group",children:[s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:j.fullAuto!==!1,onChange:e=>L(n=>({...n,fullAuto:e.target.checked}))}),s.jsx("span",{children:a("terminal:spawn.codex.fullAuto")}),s.jsx(x,{text:a("terminal:spawn.helpFullAuto"),title:a("terminal:spawn.fullAutoTitle"),position:"top",size:"sm"})]}),s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:!!j.search,onChange:e=>L(n=>({...n,search:e.target.checked}))}),s.jsx("span",{children:a("terminal:spawn.codex.search")}),s.jsx(x,{text:a("terminal:spawn.helpSearch"),title:a("terminal:spawn.searchTitle"),position:"top",size:"sm"})]})]}),j.fullAuto===!1&&s.jsxs("div",{className:"codex-option-group",children:[s.jsx("div",{className:"codex-option-header",children:a("terminal:spawn.codex.restrictions")}),s.jsxs("select",{className:"spawn-input codex-select",value:j.sandbox||"workspace-write",onChange:e=>L(n=>({...n,sandbox:e.target.value})),children:[s.jsxs("option",{value:"read-only",children:["📖 ",a("terminal:spawn.codex.sandboxReadOnly")]}),s.jsxs("option",{value:"workspace-write",children:["✏️ ",a("terminal:spawn.codex.sandboxWorkspaceWrite")]}),s.jsxs("option",{value:"danger-full-access",children:["⚡ ",a("terminal:spawn.codex.sandboxDangerFullAccess")]})]}),s.jsxs("select",{className:"spawn-input codex-select",value:j.approvalMode||"on-request",onChange:e=>L(n=>({...n,approvalMode:e.target.value})),children:[s.jsxs("option",{value:"untrusted",children:["🔒 ",a("terminal:spawn.codex.approvalsUntrusted")]}),s.jsxs("option",{value:"on-failure",children:["⚠️ ",a("terminal:spawn.codex.approvalsOnFailure")]}),s.jsxs("option",{value:"on-request",children:["🤔 ",a("terminal:spawn.codex.approvalsOnRequest")]}),s.jsxs("option",{value:"never",children:["✅ ",a("terminal:spawn.codex.approvalsNever")]})]})]}),s.jsxs("div",{className:"codex-option-group",children:[s.jsx("div",{className:"codex-option-header",children:a("terminal:spawn.codex.profile")}),s.jsx("input",{type:"text",className:"spawn-input codex-profile-input",placeholder:a("terminal:spawn.codex.profilePlaceholder"),value:j.profile||"",onChange:e=>L(n=>({...n,profile:e.target.value||void 0}))})]})]})]}),w.length>0&&s.jsxs("div",{className:"spawn-skills-section",children:[s.jsxs("label",{className:"spawn-label",children:[a("terminal:spawn.skills")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",a("common:labels.optional"),")"]}),s.jsx(x,{text:a("terminal:spawn.helpSkills"),title:a("terminal:spawn.skillsTitle"),position:"top",size:"sm"})]}),w.length>6&&s.jsx("input",{type:"text",className:"spawn-input skill-search-input",placeholder:a("terminal:spawn.filterSkills"),value:D,onChange:e=>Ue(e.target.value)}),s.jsxs("div",{className:"spawn-skills-inline",children:[ve.map(e=>{const n=xe.has(e.id);return We.some(c=>c.id===e.id)?null:s.jsxs("button",{className:`spawn-skill-chip ${n?"selected":""}`,onClick:()=>Oe(e.id),title:e.description,children:[n&&s.jsx("span",{className:"spawn-skill-check",children:s.jsx(ie,{name:"check",size:10})}),s.jsx("span",{children:e.name}),e.builtin&&s.jsx("span",{className:"spawn-skill-builtin",children:"TC"})]},e.id)}),D&&ve.length===0&&s.jsx("div",{className:"skill-search-empty",children:a("terminal:spawn.noSkillsMatch",{query:D})})]})]}),s.jsxs("div",{className:"spawn-custom-instructions-section",children:[s.jsxs("label",{className:"spawn-label",children:[a("terminal:spawn.customInstructions")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",a("common:labels.optional"),")"]}),s.jsx(x,{text:a("terminal:spawn.helpCustomInstructions"),title:a("terminal:spawn.customInstructions"),position:"top",size:"sm"})]}),s.jsx("textarea",{className:"spawn-input spawn-textarea",placeholder:a("terminal:spawn.customInstructionsPlaceholder"),value:je,onChange:e=>Re(e.target.value),rows:3})]}),s.jsxs("div",{className:"spawn-sessions-section",children:[s.jsxs("label",{className:"spawn-label",children:[a("terminal:spawn.linkSession")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",a("common:labels.optional"),")"]}),s.jsx(x,{text:a("terminal:spawn.helpLinkSession"),title:a("terminal:spawn.linkSessionTitle"),position:"top",size:"sm"})]}),y.length>0&&s.jsx("input",{type:"text",className:"spawn-input session-search-input",placeholder:a("terminal:spawn.searchSessions"),value:I,onChange:e=>we(e.target.value)}),s.jsx("div",{className:"sessions-list",children:_e?s.jsx("div",{className:"sessions-loading",children:a("terminal:spawn.loadingSessions")}):y.length===0?s.jsx("div",{className:"sessions-empty",children:a("terminal:spawn.noSessions")}):Se.length===0?s.jsx("div",{className:"sessions-empty",children:a("terminal:spawn.noSessionsMatch",{query:I})}):Se.map(e=>{const n=A===e.sessionId,l=Date.now()-new Date(e.lastModified).getTime(),c=l<6e4?a("common:time.justNow"):l<36e5?a("common:time.minutesAgo",{count:Math.floor(l/6e4)}):l<864e5?a("common:time.hoursAgo",{count:Math.floor(l/36e5)}):a("common:time.daysAgo",{count:Math.floor(l/864e5)});return s.jsxs("div",{className:`session-item ${n?"selected":""}`,onClick:()=>{n?R(null):(R(e.sessionId),F(e.projectPath))},children:[s.jsxs("div",{className:"session-item-header",children:[s.jsx("span",{className:"session-item-path",children:e.projectPath}),s.jsx("span",{className:"session-item-age",children:c})]}),s.jsx("div",{className:"session-item-preview",children:e.firstMessage||a("terminal:spawn.messagesCount",{count:e.messageCount})})]},e.sessionId)})})]})]})]}),s.jsxs("div",{className:"modal-footer",children:[s.jsx("button",{className:"btn btn-secondary",onClick:g,children:a("common:buttons.cancel")}),s.jsx("button",{className:"btn btn-primary",onClick:Je,disabled:de,children:a(de?"common:buttons.deploying":"common:buttons2.deploy")})]})]})})}export{us as SpawnModal};