tide-commander 1.148.0 → 1.150.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 (89) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +6 -3
  3. package/dist/assets/{BossLogsModal-CZMHgMBE.js → BossLogsModal-DvczRUvP.js} +1 -1
  4. package/dist/assets/BossSpawnModal-B2autFKk.js +1 -0
  5. package/dist/assets/{ControlsModal-DJ8Scm16.js → ControlsModal-BaREMQxc.js} +1 -1
  6. package/dist/assets/{DockerLogsModal-Vb4gqdFz.js → DockerLogsModal-DZ0udMCo.js} +1 -1
  7. package/dist/assets/{EmbeddedEditor-D4sHERAj.js → EmbeddedEditor-CEjr0ZSZ.js} +1 -1
  8. package/dist/assets/{GmailOAuthSetup-COIYIbJS.js → GmailOAuthSetup-76BP8J8C.js} +1 -1
  9. package/dist/assets/{GoogleOAuthSetup-DJS59Soi.js → GoogleOAuthSetup-D45GImPI.js} +1 -1
  10. package/dist/assets/{IframeModal-CFysTkn9.js → IframeModal-De63RfJZ.js} +1 -1
  11. package/dist/assets/{IntegrationsPanel-BK8g9ceY.js → IntegrationsPanel-DYrw1Sqk.js} +2 -2
  12. package/dist/assets/{LogViewerModal-DRxR0HYq.js → LogViewerModal-DW-2lpln.js} +1 -1
  13. package/dist/assets/{MonitoringModal-CL7UMOdX.js → MonitoringModal-B0-XXyd3.js} +1 -1
  14. package/dist/assets/{PM2LogsModal-I3aouUlw.js → PM2LogsModal-DOfOhkCY.js} +1 -1
  15. package/dist/assets/{RestoreArchivedAreaModal-PWAg6w6b.js → RestoreArchivedAreaModal-DNGmIJmM.js} +1 -1
  16. package/dist/assets/Scene2DCanvas-BW1E76CQ.js +1 -0
  17. package/dist/assets/SceneManager-DAvc9-Wp.js +104 -0
  18. package/dist/assets/{SkillsPanel-EQ74sIa6.js → SkillsPanel-Br-gLCLA.js} +3 -3
  19. package/dist/assets/{SlackMultiInstanceSetup-CLMUteI0.js → SlackMultiInstanceSetup-DG_bIfDu.js} +1 -1
  20. package/dist/assets/SpawnModal-lWM8OuZW.js +1 -0
  21. package/dist/assets/{StatisticsModal-D6MgA_o0.js → StatisticsModal-LvA0Fcvn.js} +1 -1
  22. package/dist/assets/{SubordinateAssignmentModal-C6n0pMn3.js → SubordinateAssignmentModal-8YxNXcR3.js} +1 -1
  23. package/dist/assets/{TriggerManagerPanel-Umd8iUg1.js → TriggerManagerPanel-DftIuKUG.js} +1 -1
  24. package/dist/assets/{WorkflowEditorPanel-CxjBxs9O.js → WorkflowEditorPanel-oLwyO_C6.js} +1 -1
  25. package/dist/assets/{area-logos-CThPeqIM.js → area-logos-mcpQqUMZ.js} +1 -1
  26. package/dist/assets/grok.ico +0 -0
  27. package/dist/assets/grok.png +0 -0
  28. package/dist/assets/index-Ay7dKyeR.js +1 -0
  29. package/dist/assets/index-BMw7AAAK.js +5 -0
  30. package/dist/assets/{index-Cz-ypmob.js → index-BQpd34Mc.js} +1 -1
  31. package/dist/assets/{index-BUN7MVf5.js → index-C6-68CXL.js} +3 -3
  32. package/dist/assets/index-CIon0DLf.js +2 -0
  33. package/dist/assets/{index-maZSt2YW.js → index-Cwt-E2td.js} +5 -5
  34. package/dist/assets/{index-DelocTaH.js → index-DFVroqA5.js} +1 -1
  35. package/dist/assets/index-DR6_WeF_.js +1 -0
  36. package/dist/assets/{index-h3Cuh2Zn.js → index-O0t07OB_.js} +2 -2
  37. package/dist/assets/main-D5sqeuwB.js +286 -0
  38. package/dist/assets/main-JBkwGXfE.css +1 -0
  39. package/dist/assets/{web-CfvEypdU.js → web-BkrshujV.js} +1 -1
  40. package/dist/assets/{web-CNjTPilF.js → web-DPETNqOf.js} +1 -1
  41. package/dist/assets/{web-bcYaAwP6.js → web-vG1Smf_N.js} +1 -1
  42. package/dist/index.html +2 -2
  43. package/dist/locales/de/config.json +3 -1
  44. package/dist/locales/en/config.json +2 -0
  45. package/dist/locales/en/terminal.json +6 -0
  46. package/dist/locales/en/tools.json +4 -2
  47. package/dist/locales/es/config.json +2 -0
  48. package/dist/locales/fr/config.json +3 -1
  49. package/dist/locales/hi/config.json +3 -1
  50. package/dist/locales/it/config.json +3 -1
  51. package/dist/locales/ja/config.json +3 -1
  52. package/dist/locales/pt/config.json +3 -1
  53. package/dist/locales/ru/config.json +3 -1
  54. package/dist/locales/zh-CN/config.json +3 -1
  55. package/dist/src/packages/server/claude/backend.js +114 -10
  56. package/dist/src/packages/server/claude/runner/process-lifecycle.js +62 -0
  57. package/dist/src/packages/server/claude/runner/stdout-pipeline.js +148 -7
  58. package/dist/src/packages/server/claude/runner/watchdog.js +12 -0
  59. package/dist/src/packages/server/claude/session-loader.js +295 -0
  60. package/dist/src/packages/server/codex/json-event-parser.js +149 -4
  61. package/dist/src/packages/server/data/index.js +1 -0
  62. package/dist/src/packages/server/grok/backend.js +235 -0
  63. package/dist/src/packages/server/grok/index.js +4 -0
  64. package/dist/src/packages/server/grok/json-event-parser.js +153 -0
  65. package/dist/src/packages/server/grok/session-watcher.js +493 -0
  66. package/dist/src/packages/server/opencode/json-event-parser.js +184 -15
  67. package/dist/src/packages/server/routes/agents.js +19 -11
  68. package/dist/src/packages/server/runtime/grok-runtime-provider.js +11 -0
  69. package/dist/src/packages/server/runtime/index.js +1 -0
  70. package/dist/src/packages/server/services/agent-service.js +26 -5
  71. package/dist/src/packages/server/services/grok-usage-service.js +374 -0
  72. package/dist/src/packages/server/services/runtime-command-execution.js +4 -2
  73. package/dist/src/packages/server/services/runtime-events.js +46 -7
  74. package/dist/src/packages/server/services/runtime-service.js +19 -3
  75. package/dist/src/packages/server/utils/tool-formatting.js +40 -12
  76. package/dist/src/packages/server/websocket/handlers/agent-handler.js +70 -17
  77. package/dist/src/packages/server/websocket/listeners/runtime-listeners.js +73 -14
  78. package/dist/src/packages/shared/agent-types.js +10 -0
  79. package/package.json +1 -1
  80. package/dist/assets/BossSpawnModal-C6DxqtKP.js +0 -1
  81. package/dist/assets/Scene2DCanvas-DYPHkU3i.js +0 -1
  82. package/dist/assets/SceneManager-QqKygyaw.js +0 -104
  83. package/dist/assets/SpawnModal-BOeStihN.js +0 -1
  84. package/dist/assets/index-DOzFBkSH.js +0 -1
  85. package/dist/assets/index-DP7kd91h.js +0 -1
  86. package/dist/assets/index-DRyMARFk.js +0 -5
  87. package/dist/assets/index-DuWmOZdY.js +0 -2
  88. package/dist/assets/main-C2zgPci-.js +0 -256
  89. package/dist/assets/main-C3JO2TRI.css +0 -1
@@ -9,6 +9,7 @@ import { agentService, runtimeService, skillService, customClassService, bossSer
9
9
  import { markInstructionsDirty } from '../../services/instruction-refresh.js';
10
10
  import { createLogger } from '../../utils/index.js';
11
11
  import { ClaudeBackend, parseContextOutput } from '../../claude/backend.js';
12
+ import { getGrokSessionDir, readGrokSignalsUsage } from '../../grok/session-watcher.js';
12
13
  const log = createLogger('AgentHandler');
13
14
  const claudeBackend = new ClaudeBackend();
14
15
  // Test change: Server restart validation - if you see this log, the server restarted successfully
@@ -58,12 +59,14 @@ export async function handleSpawnAgent(ctx, payload) {
58
59
  position: payload.position,
59
60
  initialSkillIds: payload.initialSkillIds,
60
61
  model: payload.model,
62
+ opencodeModel: payload.opencodeModel,
63
+ grokModel: payload.grokModel,
61
64
  customInstructions: payload.customInstructions ? `${payload.customInstructions.length} chars` : undefined,
62
65
  });
63
66
  try {
64
67
  const agent = await agentService.createAgent(payload.name, payload.class, payload.cwd, payload.position, payload.sessionId, payload.useChrome, payload.permissionMode, undefined, // initialSkillIds handled separately below
65
68
  undefined, // isBoss
66
- payload.model, payload.codexModel, payload.customInstructions, payload.provider, payload.codexConfig, payload.effort);
69
+ payload.model, payload.codexModel, payload.customInstructions, payload.provider, payload.codexConfig, payload.effort, payload.opencodeModel, payload.grokModel);
67
70
  log.log('Agent created successfully:', {
68
71
  id: agent.id,
69
72
  name: agent.name,
@@ -119,7 +122,7 @@ async function duplicateAgentConfig(source, name, position) {
119
122
  .map((skill) => skill.id);
120
123
  const agent = await agentService.createAgent(name, source.class, source.cwd, position, undefined, // sessionId - never share the source's; clone=fresh, fork=set below
121
124
  source.useChrome, source.permissionMode, undefined, // initialSkillIds handled separately below
122
- source.isBoss, source.model, source.codexModel, source.customInstructions, source.provider, source.codexConfig, source.effort, source.opencodeModel);
125
+ source.isBoss, source.model, source.codexModel, source.customInstructions, source.provider, source.codexConfig, source.effort, source.opencodeModel, source.grokModel);
123
126
  // Re-apply skills: copied direct assignments + class defaults.
124
127
  const classDefaultSkills = customClassService.getClassDefaultSkillIds(agent.class);
125
128
  const allSkillIds = [...new Set([...directSkillIds, ...classDefaultSkills])];
@@ -135,7 +138,7 @@ function duplicateOffset(source) {
135
138
  // Providers whose conversation history can be forked (resume + native fork flag).
136
139
  // Codex is intentionally excluded for now (no headless fork; would need rollout
137
140
  // duplication) — forking a Codex agent gracefully degrades to a plain clone.
138
- const FORKABLE_PROVIDERS = new Set(['claude', 'opencode']);
141
+ const FORKABLE_PROVIDERS = new Set(['claude', 'opencode', 'grok']);
139
142
  /**
140
143
  * Handle clone_agent message - duplicates an existing agent's configuration
141
144
  * into a brand-new agent (fresh session, no inherited context/memory).
@@ -614,8 +617,11 @@ function buildStatsFromTrackedData(agent) {
614
617
  // Do NOT prefer agent.contextStats here — those can become stale when previous
615
618
  // fallback calls save their (potentially wrong) output back to agent.contextStats
616
619
  // via broadcastContextStats, creating a self-reinforcing feedback loop.
617
- const defaultContextLimit = (agent.provider ?? 'claude') === 'codex' ? 258400
618
- : (agent.provider ?? 'claude') === 'opencode' ? 200000 : 200000;
620
+ const provider = agent.provider ?? 'claude';
621
+ const defaultContextLimit = provider === 'codex' ? 258400
622
+ : provider === 'opencode' ? 200000
623
+ : provider === 'grok' ? 500000
624
+ : 200000;
619
625
  const contextLimit = Math.max(1, Math.round(agent.contextLimit || defaultContextLimit));
620
626
  const rawContextUsed = Math.max(0, Math.round(agent.contextUsed || 0));
621
627
  // Guard: contextUsed can never exceed contextLimit. Values above the limit are
@@ -629,7 +635,7 @@ function buildStatsFromTrackedData(agent) {
629
635
  }
630
636
  const usedPercent = Math.min(100, Math.round((contextUsed / contextLimit) * 100));
631
637
  const freeTokens = Math.max(0, contextLimit - contextUsed);
632
- const model = agent.model || agent.codexModel || agent.opencodeModel || 'unknown';
638
+ const model = agent.model || agent.codexModel || agent.opencodeModel || agent.grokModel || 'unknown';
633
639
  return {
634
640
  model,
635
641
  contextWindow: contextLimit,
@@ -748,12 +754,47 @@ export async function handleRequestContextStats(ctx, payload) {
748
754
  return;
749
755
  }
750
756
  }
757
+ // Grok: streaming-json has no usage events. Read signals.json from the session dir.
758
+ const isGrokProvider = (agent.provider ?? 'claude') === 'grok';
759
+ if (isGrokProvider && agent.sessionId && agent.cwd) {
760
+ try {
761
+ const sessionDir = getGrokSessionDir(agent.cwd, agent.sessionId);
762
+ const usage = readGrokSignalsUsage(sessionDir);
763
+ if (usage) {
764
+ const contextLimit = Math.max(1, usage.contextWindowTokens);
765
+ const contextUsed = Math.max(0, Math.min(usage.contextTokensUsed, contextLimit));
766
+ const usedPercent = Math.min(100, Math.round(usage.contextWindowUsage ?? (contextUsed / contextLimit) * 100));
767
+ const freeTokens = Math.max(0, contextLimit - contextUsed);
768
+ const stats = {
769
+ model: agent.grokModel || agent.model || 'grok',
770
+ contextWindow: contextLimit,
771
+ totalTokens: contextUsed,
772
+ usedPercent,
773
+ categories: {
774
+ systemPrompt: { tokens: 0, percent: 0 },
775
+ systemTools: { tokens: 0, percent: 0 },
776
+ messages: { tokens: contextUsed, percent: Number(((contextUsed / contextLimit) * 100).toFixed(1)) },
777
+ freeSpace: { tokens: freeTokens, percent: Number(((freeTokens / contextLimit) * 100).toFixed(1)) },
778
+ autocompactBuffer: { tokens: 0, percent: 0 },
779
+ },
780
+ lastUpdated: Date.now(),
781
+ };
782
+ log.log(`[contextStats] Grok signals.json for ${agent.name}: ${contextUsed}/${contextLimit}`);
783
+ broadcastContextStats(ctx, payload.agentId, stats, 'from Grok signals.json');
784
+ return;
785
+ }
786
+ log.warn(`[contextStats] Grok signals.json missing/unreadable for ${agent.name} session=${agent.sessionId}`);
787
+ }
788
+ catch (err) {
789
+ log.error(`[contextStats] Grok signals read failed: ${err}`);
790
+ }
791
+ }
751
792
  // Fallback: generate from tracked data
752
793
  const latestAgent = agentService.getAgent(payload.agentId) || agent;
753
794
  const stats = buildStatsFromTrackedData(latestAgent);
754
- const label = latestAgent.provider === 'codex' ? 'estimated from turn usage'
755
- : latestAgent.provider === 'opencode' ? 'estimated from turn usage'
756
- : 'tracked from token usage';
795
+ const label = latestAgent.provider === 'codex' || latestAgent.provider === 'opencode' || latestAgent.provider === 'grok'
796
+ ? 'estimated from turn usage'
797
+ : 'tracked from token usage';
757
798
  broadcastContextStats(ctx, payload.agentId, stats, label);
758
799
  }
759
800
  /**
@@ -813,10 +854,14 @@ export async function handleUpdateAgentProperties(ctx, payload) {
813
854
  const normalizedUpdatedOpencodeModel = updates.opencodeModel !== undefined
814
855
  ? agentService.sanitizeOpencodeModel(updates.opencodeModel)
815
856
  : undefined;
857
+ const normalizedUpdatedGrokModel = updates.grokModel !== undefined
858
+ ? agentService.sanitizeGrokModel(updates.grokModel)
859
+ : undefined;
816
860
  // Track if model changed (requires hot restart to apply new model while preserving context)
817
861
  const modelChanged = updates.model !== undefined && normalizedUpdatedModel !== agent.model;
818
862
  const codexModelChanged = updates.codexModel !== undefined && normalizedUpdatedCodexModel !== agent.codexModel;
819
863
  const opencodeModelChanged = updates.opencodeModel !== undefined && normalizedUpdatedOpencodeModel !== agent.opencodeModel;
864
+ const grokModelChanged = updates.grokModel !== undefined && normalizedUpdatedGrokModel !== agent.grokModel;
820
865
  const providerChanged = updates.provider !== undefined && updates.provider !== agent.provider;
821
866
  const classChanged = updates.class !== undefined && updates.class !== agent.class;
822
867
  const codexConfigChanged = updates.codexConfig !== undefined
@@ -878,6 +923,9 @@ export async function handleUpdateAgentProperties(ctx, payload) {
878
923
  if (updates.opencodeModel !== undefined) {
879
924
  agentUpdates.opencodeModel = normalizedUpdatedOpencodeModel;
880
925
  }
926
+ if (updates.grokModel !== undefined) {
927
+ agentUpdates.grokModel = normalizedUpdatedGrokModel;
928
+ }
881
929
  if (updates.effort !== undefined) {
882
930
  agentUpdates.effort = updates.effort;
883
931
  }
@@ -920,7 +968,8 @@ export async function handleUpdateAgentProperties(ctx, payload) {
920
968
  }
921
969
  // If model changed, do a hot restart: stop process, resume with new model
922
970
  // This preserves context by using --resume with the existing sessionId
923
- if ((modelChanged || codexModelChanged || opencodeModelChanged || providerChanged || codexConfigChanged || classChanged) && sessionId) {
971
+ const modelLikeChanged = modelChanged || codexModelChanged || opencodeModelChanged || grokModelChanged || providerChanged || codexConfigChanged || classChanged;
972
+ if (modelLikeChanged && sessionId) {
924
973
  const reason = providerChanged
925
974
  ? `runtime changed to ${updates.provider}`
926
975
  : classChanged
@@ -931,7 +980,9 @@ export async function handleUpdateAgentProperties(ctx, payload) {
931
980
  ? `Codex model changed to ${updates.codexModel}`
932
981
  : opencodeModelChanged
933
982
  ? `OpenCode model changed to ${updates.opencodeModel}`
934
- : `model changed to ${updates.model}`;
983
+ : grokModelChanged
984
+ ? `Grok model changed to ${updates.grokModel}`
985
+ : `model changed to ${updates.model}`;
935
986
  log.log(`Agent ${agent.name}: ${reason}, hot restarting with --resume to preserve context`);
936
987
  try {
937
988
  await runtimeService.stopAgent(agentId);
@@ -946,7 +997,7 @@ export async function handleUpdateAgentProperties(ctx, payload) {
946
997
  log.error(`Failed to hot restart agent ${agent.name} after runtime config change:`, err);
947
998
  }
948
999
  }
949
- else if ((modelChanged || codexModelChanged || opencodeModelChanged || providerChanged || codexConfigChanged || classChanged) && !sessionId) {
1000
+ else if (modelLikeChanged && !sessionId) {
950
1001
  const reason = providerChanged
951
1002
  ? `runtime changed to ${updates.provider}`
952
1003
  : classChanged
@@ -957,12 +1008,14 @@ export async function handleUpdateAgentProperties(ctx, payload) {
957
1008
  ? `Codex model changed to ${updates.codexModel}`
958
1009
  : opencodeModelChanged
959
1010
  ? `OpenCode model changed to ${updates.opencodeModel}`
960
- : `model changed to ${updates.model}`;
1011
+ : grokModelChanged
1012
+ ? `Grok model changed to ${updates.grokModel}`
1013
+ : `model changed to ${updates.model}`;
961
1014
  log.log(`Agent ${agent.name}: ${reason}, will apply on next session start`);
962
1015
  }
963
1016
  // If Chrome flag changed, do a hot restart to add/remove --chrome flag
964
1017
  // Only restart if model didn't already trigger a restart
965
- if (useChromeChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !providerChanged && !codexConfigChanged && sessionId) {
1018
+ if (useChromeChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !grokModelChanged && !providerChanged && !codexConfigChanged && sessionId) {
966
1019
  const chromeStatus = updates.useChrome ? 'enabled' : 'disabled';
967
1020
  log.log(`Agent ${agent.name}: Chrome ${chromeStatus}, hot restarting with --resume to apply change`);
968
1021
  try {
@@ -982,13 +1035,13 @@ export async function handleUpdateAgentProperties(ctx, payload) {
982
1035
  log.error(`Failed to hot restart agent ${agent.name} after Chrome change:`, err);
983
1036
  }
984
1037
  }
985
- else if (useChromeChanged && !providerChanged && !codexConfigChanged && !codexModelChanged && !opencodeModelChanged && !sessionId) {
1038
+ else if (useChromeChanged && !providerChanged && !codexConfigChanged && !codexModelChanged && !opencodeModelChanged && !grokModelChanged && !sessionId) {
986
1039
  // No existing session, chrome flag will apply on next start
987
1040
  const chromeStatus = updates.useChrome ? 'enabled' : 'disabled';
988
1041
  log.log(`Agent ${agent.name}: Chrome ${chromeStatus}, will apply on next session start`);
989
1042
  }
990
1043
  // If effort changed, hot restart to apply new --effort flag
991
- if (effortChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !providerChanged && !codexConfigChanged && !classChanged && !useChromeChanged && sessionId) {
1044
+ if (effortChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !grokModelChanged && !providerChanged && !codexConfigChanged && !classChanged && !useChromeChanged && sessionId) {
992
1045
  const effortLabel = updates.effort || 'default';
993
1046
  log.log(`Agent ${agent.name}: effort changed to ${effortLabel}, hot restarting with --resume to apply change`);
994
1047
  try {
@@ -1052,7 +1105,7 @@ export async function handleUpdateAgentProperties(ctx, payload) {
1052
1105
  }
1053
1106
  // If skills changed and we didn't already hot restart for model/chrome/cwd change, do it now
1054
1107
  // Skills are injected into the system prompt, so we need to restart to apply them
1055
- if (skillsChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !providerChanged && !codexConfigChanged && !classChanged && !useChromeChanged && !cwdChanged && sessionId) {
1108
+ if (skillsChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !grokModelChanged && !providerChanged && !codexConfigChanged && !classChanged && !useChromeChanged && !cwdChanged && sessionId) {
1056
1109
  log.log(`Agent ${agent.name}: Skills changed, hot restarting with --resume to apply new system prompt`);
1057
1110
  try {
1058
1111
  // Stop the current Claude process
@@ -70,12 +70,10 @@ export function setupRuntimeListeners(ctx) {
70
70
  }
71
71
  // Mirror an agent's tracked tasks (id order) into latestTodos for display.
72
72
  function pushTaskTodos(agentId, tasks) {
73
- if (tasks.size === 0)
74
- return;
75
73
  const items = [...tasks.entries()]
76
74
  .sort((a, b) => Number(a[0]) - Number(b[0]))
77
- .map(([id, t]) => ({ content: t.subject || `Task #${id}`, status: t.status }));
78
- agentService.updateAgent(agentId, { latestTodos: items }, false);
75
+ .map(([id, t]) => ({ id, content: t.subject || `Task #${id}`, status: t.status }));
76
+ agentService.updateAgent(agentId, { latestTodos: items.length > 0 ? items : undefined }, false);
79
77
  }
80
78
  function armSubagentJsonlWatcher(agentId, toolUseId, options) {
81
79
  const parentAgent = agentService.getAgent(agentId);
@@ -142,8 +140,9 @@ export function setupRuntimeListeners(ctx) {
142
140
  const details = formatToolActivity(event.toolName, event.toolInput);
143
141
  ctx.sendActivity(agentId, details);
144
142
  if (event.toolName === 'TodoWrite' && !event.parentToolUseId) {
145
- const todos = parseTodoWriteInput(event.toolInput);
146
- if (todos) {
143
+ const existing = agentService.getAgent(agentId)?.latestTodos || [];
144
+ const todos = parseTodoWriteInput(event.toolInput, existing);
145
+ if (todos && todos.length > 0) {
147
146
  agentService.updateAgent(agentId, { latestTodos: todos }, false);
148
147
  }
149
148
  }
@@ -155,9 +154,14 @@ export function setupRuntimeListeners(ctx) {
155
154
  const id = typeof rawId === 'string' || typeof rawId === 'number' ? String(rawId) : undefined;
156
155
  if (id) {
157
156
  const tasks = taskStateFor(agentId);
158
- const existing = tasks.get(id) ?? { status: 'pending' };
159
- existing.status = normalizeTaskStatus(ti?.status);
160
- tasks.set(id, existing);
157
+ if (ti?.status === 'deleted') {
158
+ tasks.delete(id);
159
+ }
160
+ else {
161
+ const existing = tasks.get(id) ?? { status: 'pending' };
162
+ existing.status = normalizeTaskStatus(ti?.status);
163
+ tasks.set(id, existing);
164
+ }
161
165
  pushTaskTodos(agentId, tasks);
162
166
  }
163
167
  }
@@ -652,29 +656,84 @@ function findGitRoot(startDir) {
652
656
  return null;
653
657
  }
654
658
  }
655
- function parseTodoWriteInput(toolInput) {
659
+ function parseTodoWriteInput(toolInput, existing = []) {
656
660
  if (!toolInput || typeof toolInput !== 'object')
657
661
  return null;
658
662
  const rawTodos = toolInput.todos;
659
663
  if (!Array.isArray(rawTodos))
660
664
  return null;
661
665
  const validStatuses = ['pending', 'in_progress', 'completed'];
662
- const todos = [];
666
+ const merge = toolInput.merge === true;
667
+ const existingById = new Map();
668
+ for (const t of existing) {
669
+ if (t.id)
670
+ existingById.set(t.id, t);
671
+ }
672
+ const pickContent = (item, id) => {
673
+ if (typeof item.content === 'string' && item.content)
674
+ return item.content;
675
+ if (typeof item.subject === 'string' && item.subject)
676
+ return item.subject;
677
+ if (typeof item.text === 'string' && item.text)
678
+ return item.text;
679
+ if (typeof item.description === 'string' && item.description)
680
+ return item.description;
681
+ if (id && existingById.has(id))
682
+ return existingById.get(id).content;
683
+ return id ? `Task ${id}` : '';
684
+ };
685
+ const incoming = [];
663
686
  for (const raw of rawTodos) {
664
687
  if (!raw || typeof raw !== 'object')
665
688
  continue;
666
689
  const item = raw;
667
- const content = typeof item.content === 'string' ? item.content : '';
690
+ const id = typeof item.id === 'string' || typeof item.id === 'number'
691
+ ? String(item.id)
692
+ : undefined;
693
+ const content = pickContent(item, id);
668
694
  const status = typeof item.status === 'string' ? item.status : 'pending';
669
695
  if (!content || !validStatuses.includes(status))
670
696
  continue;
671
697
  const todo = { content, status };
698
+ if (id)
699
+ todo.id = id;
672
700
  if (typeof item.activeForm === 'string' && item.activeForm.length > 0) {
673
701
  todo.activeForm = item.activeForm;
674
702
  }
675
- todos.push(todo);
703
+ incoming.push(todo);
704
+ }
705
+ if (incoming.length === 0) {
706
+ // Status-only empty parse should not wipe the banner.
707
+ return null;
708
+ }
709
+ if (!merge) {
710
+ return incoming;
711
+ }
712
+ // merge:true — overlay onto existing list by id (Grok partial updates).
713
+ const next = existing.map((t) => ({ ...t }));
714
+ const indexById = new Map();
715
+ next.forEach((t, i) => {
716
+ if (t.id)
717
+ indexById.set(t.id, i);
718
+ });
719
+ for (const t of incoming) {
720
+ if (t.id && indexById.has(t.id)) {
721
+ const idx = indexById.get(t.id);
722
+ next[idx] = {
723
+ ...next[idx],
724
+ status: t.status,
725
+ content: t.content || next[idx].content,
726
+ activeForm: t.activeForm ?? next[idx].activeForm,
727
+ id: t.id,
728
+ };
729
+ }
730
+ else {
731
+ if (t.id)
732
+ indexById.set(t.id, next.length);
733
+ next.push(t);
734
+ }
676
735
  }
677
- return todos;
736
+ return next;
678
737
  }
679
738
  function readHeadFileIfSmall(gitRoot, relativePath) {
680
739
  const gitPath = relativePath.split(path.sep).join(path.posix.sep);
@@ -16,6 +16,16 @@ 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 GROK_MODELS = {
20
+ 'grok-4.5': {
21
+ label: 'Grok 4.5',
22
+ description: 'Default Grok Build model',
23
+ icon: '⚡',
24
+ // Authoritative window from live Grok Build signals.json (contextWindowTokens).
25
+ contextWindow: 500000,
26
+ },
27
+ };
28
+ export const DEFAULT_GROK_MODEL = 'grok-4.5';
19
29
  export const CODEX_REASONING_EFFORTS = {
20
30
  none: { label: 'None', description: 'No reasoning', icon: '⚪' },
21
31
  minimal: { label: 'Minimal', description: 'Least reasoning, fastest', icon: '💨' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tide-commander",
3
- "version": "1.148.0",
3
+ "version": "1.150.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 Be,aA as Oe,b3 as Re,b2 as Te,r as t,_ as re,S as W,be as O,k as Fe,s as v,b6 as G,A as de,bf as C,j as s,a9 as y,b7 as Pe,b9 as ze,I as R,ba as K,aQ as A,aO as T,bc as H,$ as Ue}from"./main-C2zgPci-.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";function ue(d){const w=C.filter(E=>!d.has(`Boss ${E}`));return w.length===0?`Boss ${C[Math.floor(Math.random()*C.length)]}-${Date.now()%1e3}`:`Boss ${w[Math.floor(Math.random()*w.length)]}`}function Ke({isOpen:d,onClose:w,onSpawnStart:E,onSpawnEnd:F,spawnPosition:me,spawnAreaId:N}){const{t:n}=Be(["terminal","common"]),J=Oe(),c=Re(),$=Te(),[u,p]=t.useState(""),[L,P]=t.useState(()=>re(W.LAST_CWD)),[r,I]=t.useState("boss"),[X,Q]=t.useState(!1),[pe,_]=t.useState(!1),[V,he]=t.useState(!0),[Y,we]=t.useState("bypass"),[m,z]=t.useState("claude"),[f,g]=t.useState({fullAuto:!0,sandbox:"workspace-write",approvalMode:"on-request",search:!1}),[Z,xe]=t.useState("claude-opus-4-8[1m]"),[ee,fe]=t.useState("gpt-5.6-luna"),[k,D]=t.useState(new Set),[se,U]=t.useState(new Set),[h,be]=t.useState(""),[S,je]=t.useState(""),[ae,Ne]=t.useState(""),B=t.useRef(null),q=t.useRef(!1),ne=t.useRef(!1),b=t.useMemo(()=>$.filter(e=>e.enabled),[$]),le=t.useMemo(()=>{if(!S.trim())return b;const e=S.toLowerCase();return b.filter(a=>a.name.toLowerCase().includes(e)||a.description.toLowerCase().includes(e)||a.slug.toLowerCase().includes(e))},[b,S]),ge=t.useMemo(()=>{var a;const e=c.find(l=>l.id===r);return(a=e==null?void 0:e.defaultSkillIds)!=null&&a.length?$.filter(l=>e.defaultSkillIds.includes(l.id)):[]},[c,r,$]),Se=["full-notifications","streaming-exec","task-label","report-task-to-boss","agent-tracking","agent-memory","send-message-to-agent"];t.useEffect(()=>{if(d&&!ne.current){if(b.length>0){const l=b.filter(i=>Se.includes(i.slug)).map(i=>i.id);l.length>0&&U(new Set(l))}if(re(W.DEFAULT_AGENT_CLASS)==="random"){const i=[...Object.keys(O).filter(j=>j!=="boss"),...c.map(j=>j.id)];i.length>0&&I(i[Math.floor(Math.random()*i.length)])}}ne.current=d},[d,b,c]);const ve=t.useCallback(e=>{U(a=>{const l=new Set(a);return l.has(e)?l.delete(e):l.add(e),l})},[]),o=t.useMemo(()=>c.find(e=>e.id===r),[c,r]),Ce=t.useMemo(()=>{if(o!=null&&o.model)return o.model},[o]),ke=t.useMemo(()=>{if(o!=null&&o.customModelPath)return Fe(`/api/custom-models/${o.id}`)},[o]),Me=o==null?void 0:o.modelScale,ye=t.useMemo(()=>o?"scout":r==="boss"?"architect":r,[r,o]);t.useEffect(()=>{if(!d||!N)return;const e=v.getState().areas.get(N);if(e!=null&&e.directories&&e.directories.length>0){P(e.directories[0]);return}const a=Array.from(v.getState().agents.values()).filter(x=>{var M;return((M=v.getAreaForAgent(x.id))==null?void 0:M.id)===N&&x.cwd});if(a.length===0)return;const l=new Map;for(const x of a)l.set(x.cwd,(l.get(x.cwd)||0)+1);let i="",j=0;for(const[x,M]of l)M>j&&(i=x,j=M);i&&P(i)},[d,N]);const te=t.useMemo(()=>Array.from(J.values()).filter(e=>!e.isBoss&&e.class!=="boss"&&!e.bossId),[J]),ie=t.useMemo(()=>{if(!h.trim())return c;const e=h.toLowerCase();return c.filter(a=>a.name.toLowerCase().includes(e)||a.description.toLowerCase().includes(e)||a.id.toLowerCase().includes(e))},[c,h]),ce=t.useMemo(()=>{if(!h.trim())return G;const e=h.toLowerCase();return G.filter(a=>{const l=de[a.id];return l?a.name.toLowerCase().includes(e)||a.id.toLowerCase().includes(e)||l.description.toLowerCase().includes(e):!1})},[h]),oe=t.useMemo(()=>{if(!h.trim())return!0;const e=h.toLowerCase(),a=O.boss;return"boss".includes(e)||a.description.toLowerCase().includes(e)},[h]);t.useEffect(()=>{if(d&&!q.current){q.current=!0;const e=new Set(Array.from(v.getState().agents.values()).map(l=>l.name)),a=c.find(l=>l.id===r);if(a){const l=C.filter(i=>!e.has(`${a.name} ${i}`));if(l.length===0){const i=C[Math.floor(Math.random()*C.length)];p(`${a.name} ${i}-${Date.now()%1e3}`)}else p(`${a.name} ${l[Math.floor(Math.random()*l.length)]}`)}else p(ue(e));D(new Set),B.current&&(B.current.focus(),B.current.select())}else d||(q.current=!1)},[d]),t.useEffect(()=>{if(!d)return;const e=c.find(a=>a.id===r);if(e)if(u.startsWith("Boss ")){const a=u.substring(5);p(`${e.name} ${a}`)}else{const a=c.find(l=>u.startsWith(l.name+" "));if(a){const l=u.substring(a.name.length+1);p(`${e.name} ${l}`)}else p(`${e.name} ${u}`)}else{const a=c.find(l=>u.startsWith(l.name+" "));if(a){const l=u.substring(a.name.length+1);p(`Boss ${l}`)}else u.startsWith("Boss ")||p(`Boss ${u}`)}},[r]);const Ae=()=>{if(_(!1),!L.trim()){_(!0);return}if(!u.trim()){const l=new Set(Array.from(v.getState().agents.values()).map(i=>i.name));p(ue(l));return}Ue(W.LAST_CWD,L),E(),window.__spawnModalAreaContext=N?{areaId:N}:null;const e=ae.trim()||void 0,a=Array.from(se);v.spawnBossAgent(u.trim(),r,L.trim(),me||void 0,Array.from(k),m==="claude"?V:!1,Y,m,m==="codex"?f:void 0,m==="codex"?ee:void 0,m==="claude"?Z:void 0,e,a),p(""),D(new Set),U(new Set),F(),w()},Ee=()=>{Q(!1),p(""),D(new Set),F(),w()},$e=()=>{Q(!1),_(!0),F()};t.useEffect(()=>(window.__bossSpawnModalSuccess=Ee,window.__bossSpawnModalError=$e,()=>{delete window.__bossSpawnModalSuccess,delete window.__bossSpawnModalError}),[u]);const Le=e=>{e.target===e.currentTarget&&w()},Ie=e=>{e.key==="Escape"&&w()},_e=e=>{const a=new Set(k);a.has(e)?a.delete(e):a.add(e),D(a)};if(!d)return null;const De=O.boss;return s.jsx("div",{className:`modal-overlay ${d?"visible":""}`,onClick:Le,onKeyDown:Ie,children:s.jsxs("div",{className:"modal boss-spawn-modal",children:[s.jsxs("div",{className:"modal-header",children:[s.jsx(y,{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(Pe,{agentClass:ye,modelFile:Ce,customModelUrl:ke,modelScale:Me,width:100,height:120})}),s.jsxs("div",{className:"spawn-class-section",children:[s.jsx("div",{className:"spawn-class-label",children:n("terminal:spawn.bossClass")}),c.length+G.length+1>6&&s.jsx("input",{type:"text",className:"spawn-input class-search-input",placeholder:n("terminal:spawn.filterClasses"),value:h,onChange:e=>be(e.target.value)}),s.jsxs("div",{className:"class-selector-inline",children:[ie.map(e=>s.jsxs("button",{className:`class-chip ${r===e.id?"selected":""}`,onClick:()=>I(e.id),title:e.description,children:[s.jsx(y,{classId:e.id,size:18,className:"class-chip-icon"}),s.jsx("span",{className:"class-chip-name",children:e.name})]},e.id)),oe&&s.jsxs("button",{className:`class-chip ${r==="boss"?"selected":""}`,onClick:()=>I("boss"),title:De.description,children:[s.jsx(y,{classId:"boss",size:18,className:"class-chip-icon"}),s.jsx("span",{className:"class-chip-name",children:n("terminal:spawn.bossClassName")})]}),ce.map(e=>{const a=de[e.id];return a?s.jsxs("button",{className:`class-chip ${r===e.id?"selected":""}`,onClick:()=>I(e.id),title:a.description,children:[s.jsx(y,{classId:e.id,size:18,className:"class-chip-icon"}),s.jsx("span",{className:"class-chip-name",children:e.name})]},e.id):null}),h&&ie.length===0&&!oe&&ce.length===0&&s.jsx("div",{className:"class-search-empty",children:n("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:n("common:labels.name")}),s.jsx("input",{ref:B,type:"text",className:"spawn-input",placeholder:n("terminal:spawn.bossNamePlaceholder"),value:u,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(ze,{value:L,onChange:e=>{P(e),_(!1)},placeholder:n("terminal:spawn.workingDirPlaceholder"),className:"spawn-input",hasError:pe,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 ${m==="claude"?"selected":""}`,onClick:()=>z("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 ${m==="codex"?"selected":""}`,onClick:()=>z("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 ${m==="opencode"?"selected":""}`,onClick:()=>z("opencode"),title:"Use OpenCode CLI (multi-provider)",children:[s.jsx("span",{children:s.jsx(R,{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(K).map(e=>s.jsxs("button",{className:`spawn-select-btn ${Y===e?"selected":""}`,onClick:()=>we(e),title:K[e].description,children:[s.jsx("span",{children:s.jsx(R,{name:e==="bypass"?"bolt":"lock",size:14})}),s.jsx("span",{children:K[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")}),m==="claude"?s.jsx("div",{className:"spawn-select-row spawn-select-row--wrap",children:Object.keys(A).filter(e=>!A[e].deprecated).map(e=>s.jsxs("button",{className:`spawn-select-btn ${Z===e?"selected":""}`,onClick:()=>xe(e),title:A[e].description,children:[s.jsx("span",{children:A[e].icon}),s.jsx("span",{children:A[e].label})]},e))}):m==="codex"?s.jsx("div",{className:"spawn-select-row spawn-select-row--codex-models",children:Object.keys(T).map(e=>s.jsxs("button",{className:`spawn-select-btn ${ee===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))}):m==="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:V,onChange:e=>he(e.target.checked),disabled:m!=="claude"}),s.jsx("span",{children:n("terminal:spawn.chromeBrowser")})]})})]})]}),m==="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:f.fullAuto!==!1,onChange:e=>g(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:!!f.search,onChange:e=>g(a=>({...a,search:e.target.checked}))}),s.jsx("span",{children:n("terminal:spawn.codex.enableSearch")})]}),f.fullAuto===!1&&s.jsxs(s.Fragment,{children:[s.jsxs("select",{className:"spawn-input",value:f.sandbox||"workspace-write",onChange:e=>g(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:f.approvalMode||"on-request",onChange:e=>g(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:f.profile||"",onChange:e=>g(a=>({...a,profile:e.target.value||void 0}))}),s.jsxs("select",{className:"spawn-input",value:f.reasoningEffort||"",onChange:e=>g(a=>({...a,reasoningEffort:e.target.value||void 0})),children:[s.jsx("option",{value:"",children:n("terminal:spawn.codex.reasoningEffortDefault")}),Object.keys(H).map(e=>s.jsxs("option",{value:e,children:[H[e].icon," ",n("terminal:spawn.codex.reasoningEffort"),": ",H[e].label]},e))]})]})]})}),b.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"),")"]})]}),b.length>6&&s.jsx("input",{type:"text",className:"spawn-input skill-search-input",placeholder:n("terminal:spawn.filterSkills"),value:S,onChange:e=>je(e.target.value)}),s.jsxs("div",{className:"spawn-skills-inline",children:[le.map(e=>{const a=se.has(e.id);return ge.some(i=>i.id===e.id)?null:s.jsxs("button",{className:`spawn-skill-chip ${a?"selected":""}`,onClick:()=>ve(e.id),title:e.description,children:[a&&s.jsx("span",{className:"spawn-skill-check",children:s.jsx(R,{name:"check",size:12})}),s.jsx("span",{children:e.name}),e.builtin&&s.jsx("span",{className:"spawn-skill-builtin",children:"TC"})]},e.id)}),S&&le.length===0&&s.jsx("div",{className:"skill-search-empty",children:n("terminal:spawn.noSkillsMatch",{query:S})})]})]}),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:ae,onChange:e=>Ne(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:te.length===0?s.jsx("div",{className:"subordinates-empty",children:n("terminal:spawn.noAvailableAgents")}):te.map(e=>{const a=k.has(e.id),l=O[e.class],i=c.find(x=>x.id===e.class),j=l||i||{color:"#888888"};return s.jsxs("button",{className:`subordinate-chip ${a?"selected":""}`,onClick:()=>_e(e.id),children:[a&&s.jsx("span",{className:"subordinate-check",children:s.jsx(R,{name:"check",size:12})}),s.jsx("span",{className:"subordinate-chip-icon",style:{color:j.color},children:s.jsx(y,{classId:e.class,size:16})}),s.jsx("span",{className:"subordinate-chip-name",children:e.name})]},e.id)})}),k.size>0&&s.jsxs("div",{className:"subordinates-count",children:[k.size," ",n("common:labels.selected").toLowerCase()]})]})]})]}),s.jsxs("div",{className:"modal-footer",children:[s.jsx("button",{className:"btn btn-secondary",onClick:w,children:n("common:buttons.cancel")}),s.jsx("button",{className:"btn btn-boss",onClick:Ae,disabled:X,children:n(X?"common:buttons.deploying":"common:buttons2.deployBoss")})]})]})})}export{Ke as BossSpawnModal};