tide-commander 1.165.1 → 1.167.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 (138) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/assets/{BossLogsModal-IqVqHwz-.js → BossLogsModal-CLmSG1H0.js} +1 -1
  3. package/dist/assets/BossSpawnModal-DZlB8KRy.js +1 -0
  4. package/dist/assets/ControlsModal-B1-STBnD.js +1 -0
  5. package/dist/assets/DockerLogsModal-CWnhsG_r.js +2 -0
  6. package/dist/assets/{EmbeddedEditor-BA9mX_Lg.js → EmbeddedEditor-5po-iz0Q.js} +1 -1
  7. package/dist/assets/{GmailOAuthSetup-7nj6aLot.js → GmailOAuthSetup-BB10r44e.js} +1 -1
  8. package/dist/assets/GoogleOAuthSetup-CW_Ib5kq.js +270 -0
  9. package/dist/assets/{IframeModal-DkkCx6nq.js → IframeModal-CPt5x5fr.js} +1 -1
  10. package/dist/assets/IntegrationsPanel-CO-5iHtn.js +2 -0
  11. package/dist/assets/{LogViewerModal-DKYB8dHo.js → LogViewerModal-DicJq6l-.js} +1 -1
  12. package/dist/assets/{MonitoringModal-DOKMIa5U.js → MonitoringModal-B3nwcYZn.js} +1 -1
  13. package/dist/assets/{PM2LogsModal-XlbT9uoY.js → PM2LogsModal-Viw6fBjN.js} +2 -2
  14. package/dist/assets/RestoreArchivedAreaModal-BVH9wxhk.js +1 -0
  15. package/dist/assets/Scene2DCanvas-D6TCimYq.js +1 -0
  16. package/dist/assets/SceneManager-BdJs75zx.js +104 -0
  17. package/dist/assets/{SkillsPanel-BKjpKM1N.js → SkillsPanel-D1WonIBN.js} +1 -1
  18. package/dist/assets/{SlackMultiInstanceSetup-C0k60ioO.js → SlackMultiInstanceSetup-DSTZ5Hry.js} +1 -1
  19. package/dist/assets/SpawnModal-DUpIkQ08.js +1 -0
  20. package/dist/assets/StatisticsModal-BoDgM_8E.js +1 -0
  21. package/dist/assets/SubordinateAssignmentModal-LysAkNGy.js +1 -0
  22. package/dist/assets/{TriggerManagerPanel-RWrID12k.js → TriggerManagerPanel-BHxmBRvy.js} +1 -1
  23. package/dist/assets/{WorkflowEditorPanel-Ccwm4H5t.js → WorkflowEditorPanel-BHayKmMV.js} +1 -1
  24. package/dist/assets/abnfDiagram-VRR7QNED-DBZ5EpAj.js +1 -0
  25. package/dist/assets/arc-UCe2q9lp.js +1 -0
  26. package/dist/assets/architectureDiagram-ZJ3FMSHR-D5zOdUA8.js +36 -0
  27. package/dist/assets/{area-logos-DnrrrkFh.js → area-logos-4nlUPBxf.js} +1 -1
  28. package/dist/assets/blockDiagram-677ZJIJ3-7S-qZlh0.js +132 -0
  29. package/dist/assets/c4Diagram-LMCZKHZV-CgLv5SCO.js +10 -0
  30. package/dist/assets/channel-C59jtig-.js +1 -0
  31. package/dist/assets/chunk-2Q5K7J3B-J08qsAGr.js +1 -0
  32. package/dist/assets/chunk-32BRIVSS-Xy5D5wu7.js +1 -0
  33. package/dist/assets/chunk-5VM5RSS4-DqhmRB6E.js +15 -0
  34. package/dist/assets/chunk-EX3LRPZG-QE89_WgA.js +231 -0
  35. package/dist/assets/chunk-JWPE2WC7-YSc_ua_g.js +1 -0
  36. package/dist/assets/chunk-MOJQB5TN-CcH7NM7I.js +88 -0
  37. package/dist/assets/chunk-RYQCIY6F-CndQTJJ1.js +1 -0
  38. package/dist/assets/chunk-V7JOEXUC-Dauixo5p.js +206 -0
  39. package/dist/assets/chunk-VR4S4FIN-BBU6oFw0.js +1 -0
  40. package/dist/assets/chunk-XXDRQBXY-DXMolb4D.js +1 -0
  41. package/dist/assets/classDiagram-OUVF2IWQ-DHvVmqF9.js +1 -0
  42. package/dist/assets/classDiagram-v2-EOCWNBFH-DHvVmqF9.js +1 -0
  43. package/dist/assets/cose-bilkent-JH36ORCC-Dd9IB924.js +1 -0
  44. package/dist/assets/cynefin-VYW2F7L2-BQxwdSSb.js +178 -0
  45. package/dist/assets/cynefinDiagram-TSTJHNR4-BLnxgd0m.js +62 -0
  46. package/dist/assets/cytoscape.esm-DTSO7Bv0.js +331 -0
  47. package/dist/assets/dagre-VKFMJZFB-BZ7fXVWR.js +4 -0
  48. package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  49. package/dist/assets/diagram-FQU43EPY-BFQ1xjHE.js +3 -0
  50. package/dist/assets/diagram-G47NLZAW-sXsGErM6.js +24 -0
  51. package/dist/assets/diagram-NH7WQ7WH-D6SPifDp.js +24 -0
  52. package/dist/assets/diagram-OA4YK3LP-Mu16f_2g.js +30 -0
  53. package/dist/assets/diagram-WEI45ONY-3BTJg43I.js +41 -0
  54. package/dist/assets/ebnfDiagram-CCIWWBDH-BGl2hs1X.js +1 -0
  55. package/dist/assets/erDiagram-Q63AITRT-D03B1rgc.js +85 -0
  56. package/dist/assets/flowDiagram-23GEKE2U-BCaZJGGE.js +156 -0
  57. package/dist/assets/ganttDiagram-NO4QXBWP-DrTSQR9G.js +292 -0
  58. package/dist/assets/gitGraphDiagram-IHSO6WYX-BvrZLcji.js +106 -0
  59. package/dist/assets/graph-C9eacEi8.js +1 -0
  60. package/dist/assets/index-B7l8Nsf8.js +1 -0
  61. package/dist/assets/index-BK7LL53p.js +1 -0
  62. package/dist/assets/index-CJ6x10Zs.js +2 -0
  63. package/dist/assets/index-D6btqUwj.js +2 -0
  64. package/dist/assets/{index-D-MKKw7S.js → index-DAXUzeVz.js} +6 -6
  65. package/dist/assets/{index-Cjgy2CnG.js → index-DcD9tVKJ.js} +3 -3
  66. package/dist/assets/{index-DZ7i37eV.js → index-Dzup44Dy.js} +6 -6
  67. package/dist/assets/index-JEgWBCoB.js +1 -0
  68. package/dist/assets/index-J_xWyk3Q.js +1 -0
  69. package/dist/assets/infoDiagram-FWYZ7A6U-Bw9k-wkS.js +2 -0
  70. package/dist/assets/init-Gi6I4Gst.js +1 -0
  71. package/dist/assets/ishikawaDiagram-FXEZZL3T-C2oVKtw0.js +70 -0
  72. package/dist/assets/journeyDiagram-5HDEW3XC-pRpwSEa5.js +139 -0
  73. package/dist/assets/kanban-definition-HUTT4EX6-CYq_poR1.js +89 -0
  74. package/dist/assets/katex-C5jXJg4s.js +257 -0
  75. package/dist/assets/layout-DEXfKzaS.js +1 -0
  76. package/dist/assets/linear-DLT2RlFJ.js +1 -0
  77. package/dist/assets/{main-DIf9R6Jx.js → main-06kmV-SQ.js} +125 -125
  78. package/dist/assets/main-BzGnAbiA.css +1 -0
  79. package/dist/assets/map-Czzmt4hB.js +1 -0
  80. package/dist/assets/mermaid.core-DmOBz9SE.js +314 -0
  81. package/dist/assets/mindmap-definition-LN4V7U3C-DzucjpI_.js +96 -0
  82. package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  83. package/dist/assets/pegDiagram-2B236MQR-CIf_bLf4.js +1 -0
  84. package/dist/assets/pieDiagram-ENE6RG2P-Dh9HXeSf.js +39 -0
  85. package/dist/assets/quadrantDiagram-ABIIQ3AL-B5hZRZ5w.js +7 -0
  86. package/dist/assets/railroadDiagram-RFXS5EU6-B1oWAO1u.js +1 -0
  87. package/dist/assets/requirementDiagram-TGXJPOKE-Cg7bjm4O.js +84 -0
  88. package/dist/assets/sankeyDiagram-HTMAVEWB-TLCrcbtk.js +40 -0
  89. package/dist/assets/sequenceDiagram-DBY2YBRQ-BD3b_psw.js +162 -0
  90. package/dist/assets/sizeCapture-X5ZJPWSS-D26nx1uQ.js +1 -0
  91. package/dist/assets/stateDiagram-2N3HPSRC-CIwRQUnK.js +1 -0
  92. package/dist/assets/stateDiagram-v2-6OUMAXLB-C5qcZ4o1.js +1 -0
  93. package/dist/assets/swimlanes-5IMT3BWC-DYbes851.js +2 -0
  94. package/dist/assets/swimlanesDiagram-G3AALYLV-Ke-NRRIa.js +8 -0
  95. package/dist/assets/timeline-definition-FHXFAJF6-Fr9U6JU6.js +120 -0
  96. package/dist/assets/{vendor-three-Chj50gSY.js → vendor-three-3OKhI9bz.js} +1 -1
  97. package/dist/assets/vennDiagram-L72KCM5P-Cns-KLq7.js +34 -0
  98. package/dist/assets/wardleyDiagram-EHGQE667-DHA7rD9Z.js +78 -0
  99. package/dist/assets/{web-DDxnPoTK.js → web-B7c8sthS.js} +1 -1
  100. package/dist/assets/{web-DhZ0XCan.js → web-C05qFIA-.js} +1 -1
  101. package/dist/assets/{web-Dlc8Nyra.js → web-Dja1kfLs.js} +1 -1
  102. package/dist/assets/xychartDiagram-FW5EYKEG-DCnL05Wq.js +7 -0
  103. package/dist/build-info.json +1 -1
  104. package/dist/index.html +3 -3
  105. package/dist/src/packages/server/claude/runner/watchdog.js +27 -0
  106. package/dist/src/packages/server/codex/app-server/codex-app-server-runner.js +34 -4
  107. package/dist/src/packages/server/data/builtin-skills/index.js +2 -0
  108. package/dist/src/packages/server/data/builtin-skills/mermaid-diagrams.js +76 -0
  109. package/dist/src/packages/server/integrations/gmail/gmail-client.js +73 -5
  110. package/dist/src/packages/server/integrations/gmail/gmail-routes.js +9 -4
  111. package/dist/src/packages/server/integrations/google-auth/token-health.js +196 -0
  112. package/dist/src/packages/server/integrations/google-calendar/calendar-client.js +61 -6
  113. package/dist/src/packages/server/integrations/google-calendar/calendar-routes.js +9 -4
  114. package/dist/src/packages/server/integrations/google-drive/drive-client.js +61 -6
  115. package/dist/src/packages/server/integrations/google-drive/drive-routes.js +9 -4
  116. package/dist/src/packages/server/opencode/server/opencode-server-process.js +102 -7
  117. package/dist/src/packages/server/opencode/server/opencode-server-runner.js +13 -0
  118. package/dist/src/packages/server/services/agent-service.js +7 -0
  119. package/dist/src/packages/server/services/runtime-events.js +1 -0
  120. package/package.json +2 -1
  121. package/dist/assets/BossSpawnModal-Dj9ayWfR.js +0 -1
  122. package/dist/assets/ControlsModal-ki85jvDA.js +0 -1
  123. package/dist/assets/DockerLogsModal-CeIuKlvk.js +0 -2
  124. package/dist/assets/GoogleOAuthSetup-Bh-Cy-dE.js +0 -236
  125. package/dist/assets/IntegrationsPanel-DHjpWEFF.js +0 -2
  126. package/dist/assets/RestoreArchivedAreaModal-Du1f8Urv.js +0 -1
  127. package/dist/assets/Scene2DCanvas-BTnpyyK6.js +0 -1
  128. package/dist/assets/SceneManager-owoMSHKT.js +0 -104
  129. package/dist/assets/SpawnModal-Cww_6dcz.js +0 -1
  130. package/dist/assets/StatisticsModal-Dl5loLLI.js +0 -1
  131. package/dist/assets/SubordinateAssignmentModal-DefQL38f.js +0 -1
  132. package/dist/assets/index-B5iakYkB.js +0 -1
  133. package/dist/assets/index-CbJ-R04c.js +0 -2
  134. package/dist/assets/index-CcHBNDP_.js +0 -2
  135. package/dist/assets/index-DG7HgtQn.js +0 -1
  136. package/dist/assets/index-Fcs4x2Vj.js +0 -1
  137. package/dist/assets/index-g0yAcpoy.js +0 -1
  138. package/dist/assets/main-Dnp-3iMX.css +0 -1
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { google } from 'googleapis';
8
8
  import { loadConfig, updateConfig } from './drive-config.js';
9
+ import { getTokenHealth, needsReauth, notifyTokenRotated, onTokenRotated, probeTokenHealth, reportGoogleApiError, reportGoogleApiSuccess, startTokenHealthMonitor, } from '../google-auth/token-health.js';
9
10
  import { Readable } from 'stream';
10
11
  // ─── State ───
11
12
  let ctx = null;
@@ -22,6 +23,30 @@ const SCOPES = [
22
23
  ];
23
24
  const REDIRECT_PATH = '/api/drive/auth/callback';
24
25
  let oauth2Client = null;
26
+ /**
27
+ * Build an OAuth2 client whose every outbound call updates shared token health.
28
+ *
29
+ * Every Drive and Docs call made with `auth: oauth2Client` funnels through this one
30
+ * `request()` method, so wrapping it here means a revoked token is detected the moment
31
+ * an agent actually touches Drive — no waiting for the next background probe — without
32
+ * instrumenting each of the ~15 API call sites.
33
+ */
34
+ function createOAuthClient(clientId, clientSecret, redirectUri) {
35
+ const client = new google.auth.OAuth2(clientId, clientSecret, redirectUri);
36
+ const originalRequest = client.request.bind(client);
37
+ client.request = (async (opts) => {
38
+ try {
39
+ const result = await originalRequest(opts);
40
+ reportGoogleApiSuccess();
41
+ return result;
42
+ }
43
+ catch (err) {
44
+ reportGoogleApiError(err);
45
+ throw err;
46
+ }
47
+ });
48
+ return client;
49
+ }
25
50
  function getRedirectUri() {
26
51
  if (!ctx)
27
52
  throw new Error('Google Drive not initialized');
@@ -44,10 +69,16 @@ export async function init(integrationCtx) {
44
69
  ctx.log.info('Google Drive missing OAuth credentials, skipping init');
45
70
  return;
46
71
  }
47
- oauth2Client = new google.auth.OAuth2(clientId, clientSecret, getRedirectUri());
72
+ oauth2Client = createOAuthClient(clientId, clientSecret, getRedirectUri());
48
73
  oauth2Client.setCredentials({ refresh_token: refreshToken });
49
74
  driveApi = google.drive({ version: 'v3', auth: oauth2Client });
50
75
  docsApi = google.docs({ version: 'v1', auth: oauth2Client });
76
+ // Constructing the client above proves nothing — it just wraps the token string.
77
+ // Probe Google (and keep probing) so an expired token is reflected in getStatus().
78
+ startTokenHealthMonitor(ctx);
79
+ // Re-read the shared refresh token if the user re-consents via Gmail or Calendar,
80
+ // otherwise this client keeps using the token it was seeded with here.
81
+ onTokenRotated('google-drive', () => init(integrationCtx));
51
82
  ctx.log.info('Google Drive initialized');
52
83
  }
53
84
  export async function shutdown() {
@@ -61,16 +92,36 @@ export function getStatus() {
61
92
  const hasCredentials = !!(ctx?.secrets.get('GOOGLE_CLIENT_ID') &&
62
93
  ctx?.secrets.get('GOOGLE_CLIENT_SECRET') &&
63
94
  ctx?.secrets.get('GOOGLE_REFRESH_TOKEN'));
95
+ const health = getTokenHealth();
96
+ const reauth = hasCredentials && needsReauth(health);
97
+ // Having credentials on disk is necessary but not sufficient — a revoked refresh
98
+ // token is still three non-empty strings. Only report connected when Google's last
99
+ // verdict wasn't a rejection. An 'unreachable' probe (offline host) is deliberately
100
+ // NOT treated as a rejection: it would push users into a pointless re-consent flow.
101
+ const wired = config.enabled && hasCredentials && driveApi !== null;
102
+ let error;
103
+ if (!hasCredentials && config.enabled)
104
+ error = 'Missing OAuth credentials';
105
+ else if (reauth)
106
+ error = health.error;
64
107
  return {
65
- authenticated: Boolean(driveApi && hasCredentials),
66
- connected: config.enabled && hasCredentials && driveApi !== null,
67
- lastChecked: Date.now(),
68
- error: !hasCredentials && config.enabled ? 'Missing OAuth credentials' : undefined,
108
+ authenticated: Boolean(driveApi && hasCredentials) && !reauth,
109
+ connected: wired && !reauth,
110
+ lastChecked: health.checkedAt || Date.now(),
111
+ error,
112
+ needsReauth: reauth,
113
+ tokenState: hasCredentials ? health.state : undefined,
69
114
  };
70
115
  }
71
116
  export function isConfigured() {
72
117
  return driveApi !== null;
73
118
  }
119
+ /** Force a live refresh_token exchange against Google and return the updated status. */
120
+ export async function probeToken() {
121
+ if (ctx)
122
+ await probeTokenHealth(ctx, { force: true });
123
+ return getStatus();
124
+ }
74
125
  // ─── OAuth ───
75
126
  export function getAuthUrl() {
76
127
  if (!oauth2Client) {
@@ -79,7 +130,7 @@ export function getAuthUrl() {
79
130
  if (!clientId || !clientSecret || !ctx) {
80
131
  throw new Error('Google Drive OAuth not configured');
81
132
  }
82
- oauth2Client = new google.auth.OAuth2(clientId, clientSecret, getRedirectUri());
133
+ oauth2Client = createOAuthClient(clientId, clientSecret, getRedirectUri());
83
134
  }
84
135
  return oauth2Client.generateAuthUrl({
85
136
  access_type: 'offline',
@@ -99,6 +150,10 @@ export async function handleAuthCallback(code) {
99
150
  docsApi = google.docs({ version: 'v1', auth: oauth2Client });
100
151
  // Auto-enable the integration after successful OAuth
101
152
  updateConfig({ enabled: true });
153
+ // Fresh consent just produced this token. Clears the 'expired' verdict AND re-arms
154
+ // Gmail and Calendar, whose clients still hold the old refresh token — all three
155
+ // share this one secret, so one consent must repair all three.
156
+ await notifyTokenRotated();
102
157
  ctx.log.info('Google Drive OAuth complete. Drive initialized.');
103
158
  }
104
159
  // ─── Files CRUD ───
@@ -283,10 +283,15 @@ router.get('/search', async (req, res) => {
283
283
  }
284
284
  });
285
285
  // ─── Status & Auth ───
286
- // GET /api/drive/status — Get Google Drive auth status
287
- router.get('/status', (_req, res) => {
288
- const status = driveClient.getStatus();
289
- res.json(status);
286
+ // GET /api/drive/status — Get Google Drive auth status.
287
+ // `?probe=1` forces a live refresh_token exchange against Google instead of reusing
288
+ // the cached verdict — the settings UI uses it to verify the token on open, so a
289
+ // revoked token can't keep rendering as "Connected".
290
+ router.get('/status', async (req, res) => {
291
+ if (req.query.probe === '1' || req.query.probe === 'true') {
292
+ await driveClient.probeToken();
293
+ }
294
+ res.json(driveClient.getStatus());
290
295
  });
291
296
  // GET /api/drive/auth/url — Get OAuth authorization URL
292
297
  router.get('/auth/url', (_req, res) => {
@@ -162,17 +162,37 @@ export class OpencodeServerProcess {
162
162
  }
163
163
  // ---- HTTP helpers --------------------------------------------------------
164
164
  async httpJson(method, path, body) {
165
- const res = await fetch(`${this.baseUrl}${path}`, {
166
- method,
167
- headers: body !== undefined ? { 'Content-Type': 'application/json' } : undefined,
168
- body: body !== undefined ? JSON.stringify(body) : undefined,
169
- });
165
+ // Retry ONCE on a transport failure, but ONLY for idempotent GETs. A POST
166
+ // (send message / create session) must NEVER auto-retry: a transport error
167
+ // does NOT prove the request was undelivered. Undici surfaces a stale
168
+ // keep-alive reset AND a `UND_ERR_HEADERS_TIMEOUT` (request delivered, daemon
169
+ // still working the turn) both as `TypeError: fetch failed` — indistinguishable
170
+ // here — so resending a POST can double-post the user's prompt (it did:
171
+ // agents saw the same message twice). GETs carry no such side effect.
172
+ let res;
173
+ try {
174
+ res = await this.doFetch(method, path, body);
175
+ }
176
+ catch (err) {
177
+ if (method !== 'GET' || !isTransportError(err))
178
+ throw err;
179
+ log.warn(`GET ${path} transport error (${describeError(err)}); retrying once on a fresh connection`);
180
+ await sleep(100);
181
+ res = await this.doFetch(method, path, body);
182
+ }
170
183
  if (!res.ok) {
171
184
  throw new Error(`${method} ${path} → ${res.status} ${res.statusText}`);
172
185
  }
173
186
  const text = await res.text();
174
187
  return text ? JSON.parse(text) : null;
175
188
  }
189
+ doFetch(method, path, body) {
190
+ return fetch(`${this.baseUrl}${path}`, {
191
+ method,
192
+ headers: body !== undefined ? { 'Content-Type': 'application/json' } : undefined,
193
+ body: body !== undefined ? JSON.stringify(body) : undefined,
194
+ });
195
+ }
176
196
  /** Create a session (optionally scoped to a working directory). */
177
197
  async createSession(directory) {
178
198
  const body = {};
@@ -184,12 +204,64 @@ export class OpencodeServerProcess {
184
204
  throw new Error('opencode session create returned no id');
185
205
  return id;
186
206
  }
187
- /** Send a prompt to a session. Fire-and-forget: streaming arrives via SSE. */
207
+ /**
208
+ * Send a prompt to a session. opencode holds this POST open for the ENTIRE
209
+ * turn (it doesn't send response headers until the turn finishes) while the
210
+ * output streams over SSE. undici's 300s default headersTimeout would trip
211
+ * `UND_ERR_HEADERS_TIMEOUT` on any turn >5min and falsely error the agent —
212
+ * and that error MUST NOT be retried, because the prompt already landed, so a
213
+ * resend double-posts the user's message. So this one request uses a dedicated
214
+ * Node http request with NO timeout and a fresh (non-pooled) socket: it blocks
215
+ * harmlessly until turn end (SSE drives output + completion), rejects only on a
216
+ * genuine connection failure (surfaced once, never retried), and can't reuse a
217
+ * stale keep-alive socket. Everything else stays on the quick fetch path.
218
+ */
188
219
  sendPrompt(sessionId, text, model) {
189
220
  const body = { parts: [{ type: 'text', text }] };
190
221
  if (model)
191
222
  body.model = model;
192
- return this.httpJson('POST', `/session/${sessionId}/message`, body).then(() => undefined);
223
+ return this.postLongLived(`/session/${sessionId}/message`, body).then(() => undefined);
224
+ }
225
+ /** POST with no read timeout on a fresh socket — for the turn-length message send. */
226
+ postLongLived(path, body) {
227
+ return new Promise((resolve, reject) => {
228
+ if (this.port == null) {
229
+ reject(new Error('opencode server not connected (no port)'));
230
+ return;
231
+ }
232
+ const payload = JSON.stringify(body);
233
+ const req = http.request({
234
+ host: '127.0.0.1',
235
+ port: this.port,
236
+ path,
237
+ method: 'POST',
238
+ agent: false, // fresh socket every send — no keep-alive pool to go stale
239
+ headers: {
240
+ 'Content-Type': 'application/json',
241
+ 'Content-Length': Buffer.byteLength(payload),
242
+ },
243
+ }, (res) => {
244
+ let data = '';
245
+ res.setEncoding('utf8');
246
+ res.on('data', (c) => { data += c; });
247
+ res.on('aborted', () => reject(new Error(`POST ${path} → connection aborted before completion`)));
248
+ res.on('end', () => {
249
+ const status = res.statusCode ?? 0;
250
+ if (status < 200 || status >= 300) {
251
+ reject(new Error(`POST ${path} → ${status} ${res.statusMessage ?? ''}`.trim()));
252
+ return;
253
+ }
254
+ try {
255
+ resolve(data ? JSON.parse(data) : null);
256
+ }
257
+ catch (err) {
258
+ reject(err instanceof Error ? err : new Error(String(err)));
259
+ }
260
+ });
261
+ });
262
+ req.on('error', reject);
263
+ req.end(payload);
264
+ });
193
265
  }
194
266
  async abort(sessionId) {
195
267
  try {
@@ -283,3 +355,26 @@ function findFreePort() {
283
355
  function sleep(ms) {
284
356
  return new Promise((r) => setTimeout(r, ms));
285
357
  }
358
+ /**
359
+ * True for a transport/connection failure (no HTTP response was received), as
360
+ * opposed to a rejected request. `fetch` throws a `TypeError` ("fetch failed")
361
+ * whose `cause` carries the undici socket error (ECONNRESET / UND_ERR_SOCKET /
362
+ * ECONNREFUSED) — the dead-keep-alive-socket case we retry.
363
+ */
364
+ function isTransportError(err) {
365
+ if (!(err instanceof TypeError))
366
+ return false;
367
+ const cause = err.cause;
368
+ const code = cause?.code;
369
+ if (code && ['ECONNRESET', 'ECONNREFUSED', 'UND_ERR_SOCKET', 'EPIPE', 'ETIMEDOUT'].includes(code)) {
370
+ return true;
371
+ }
372
+ // Fall back to the message: undici surfaces the generic "fetch failed" here.
373
+ return /fetch failed/i.test(err.message);
374
+ }
375
+ function describeError(err) {
376
+ const cause = err?.cause;
377
+ const code = cause?.code;
378
+ const msg = err instanceof Error ? err.message : String(err);
379
+ return code ? `${msg} [${code}]` : msg;
380
+ }
@@ -273,6 +273,19 @@ export class OpencodeServerRunner {
273
273
  const msg = err instanceof Error ? err.message : String(err);
274
274
  log.error(`sendPrompt failed for ${agentId.slice(0, 8)}: ${msg}`);
275
275
  this.callbacks.onError(agentId, `OpenCode prompt failed: ${msg}`);
276
+ // Reset the turn state so a failed send does NOT wedge the runner.
277
+ // Without this, turnState stays 'processing' forever — only a
278
+ // `step_complete` SSE event clears it, and that never comes for a turn
279
+ // that never started — so every later message is queued indefinitely and
280
+ // "never arrives" (the user-visible symptom). Guard it: only recover when
281
+ // THIS state is still the agent's current in-flight turn, so we don't
282
+ // double-drain into a concurrent turn (if a step_complete already advanced
283
+ // it) or act on a state a stop()/new turn already replaced. drainQueue
284
+ // re-queues safely when the daemon is unreachable, so this can't spin.
285
+ if (this.agents.get(agentId) === state && state.turnState === 'processing') {
286
+ state.turnState = 'waiting_for_input';
287
+ this.drainQueue(agentId, state);
288
+ }
276
289
  }
277
290
  }
278
291
  drainQueue(agentId, state) {
@@ -491,6 +491,13 @@ export function updateAgent(id, updates, updateActivity = true) {
491
491
  if (enteredIdleState && !('latestTodos' in normalizedUpdates)) {
492
492
  normalizedUpdates.latestTodos = undefined;
493
493
  }
494
+ // Drop the stored error message once the agent recovers from error to any
495
+ // other status (new command → working, recovery init, turn complete → idle),
496
+ // so the status-badge hover doesn't show a stale error after recovery.
497
+ const leftErrorState = agent.status === 'error' && nextStatus !== 'error';
498
+ if (leftErrorState && !('lastError' in normalizedUpdates)) {
499
+ normalizedUpdates.lastError = undefined;
500
+ }
494
501
  // When an agent goes idle (process finished / run complete) clear any *transient*
495
502
  // tracking status so the board doesn't show a phantom 'working'/'thinking' agent.
496
503
  // Only 'working' (longer-running work) and 'thinking' (start-of-turn) are transient;
@@ -627,6 +627,7 @@ export function createRuntimeEventHandlers(deps) {
627
627
  status: 'error',
628
628
  currentTask: undefined,
629
629
  currentTool: undefined,
630
+ lastError: error,
630
631
  });
631
632
  emitError(agentId, error);
632
633
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tide-commander",
3
- "version": "1.165.1",
3
+ "version": "1.167.0",
4
4
  "description": "Visual multi-agent orchestrator and manager for Claude Code with 3D/2D interface",
5
5
  "repository": {
6
6
  "type": "git",
@@ -87,6 +87,7 @@
87
87
  "i18next": "^26.0.3",
88
88
  "i18next-browser-languagedetector": "^8.2.1",
89
89
  "i18next-http-backend": "^3.0.2",
90
+ "mermaid": "^11.16.0",
90
91
  "mssql": "^12.4.0",
91
92
  "multer": "^2.1.1",
92
93
  "mysql2": "^3.16.2",
@@ -1 +0,0 @@
1
- import{u as Be,aC as Re,b6 as Oe,b5 as Te,r as t,_ as re,S as G,bj as O,k as Fe,s as S,ba as W,A as de,bk as C,j as s,a9 as y,bb as Pe,bd as ze,I as T,be as K,aT as A,aR as F,bh as H,$ as Ue}from"./main-DIf9R6Jx.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";function ue(u){const w=C.filter($=>!u.has(`Boss ${$}`));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:u,onClose:w,onSpawnStart:$,onSpawnEnd:P,spawnPosition:me,spawnAreaId:g}){const{t:n}=Be(["terminal","common"]),J=Re(),c=Oe(),E=Te(),[m,p]=t.useState(""),[L,z]=t.useState(()=>re(G.LAST_CWD)),[d,I]=t.useState("boss"),[X,V]=t.useState(!1),[pe,_]=t.useState(!1),[Y,he]=t.useState(!0),[Q,we]=t.useState("bypass"),[o,D]=t.useState("claude"),[f,N]=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,B]=t.useState(new Set),[se,U]=t.useState(new Set),[h,be]=t.useState(""),[v,je]=t.useState(""),[ae,ge]=t.useState(""),R=t.useRef(null),q=t.useRef(!1),ne=t.useRef(!1),b=t.useMemo(()=>E.filter(e=>e.enabled),[E]),le=t.useMemo(()=>{if(!v.trim())return b;const e=v.toLowerCase();return b.filter(a=>a.name.toLowerCase().includes(e)||a.description.toLowerCase().includes(e)||a.slug.toLowerCase().includes(e))},[b,v]),Ne=t.useMemo(()=>{var a;const e=c.find(l=>l.id===d);return(a=e==null?void 0:e.defaultSkillIds)!=null&&a.length?E.filter(l=>e.defaultSkillIds.includes(l.id)):[]},[c,d,E]),ve=["full-notifications","streaming-exec","task-label","report-task-to-boss","agent-tracking","agent-memory","send-message-to-agent"];t.useEffect(()=>{if(u&&!ne.current){if(b.length>0){const l=b.filter(i=>ve.includes(i.slug)).map(i=>i.id);l.length>0&&U(new Set(l))}if(re(G.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=u},[u,b,c]);const Se=t.useCallback(e=>{U(a=>{const l=new Set(a);return l.has(e)?l.delete(e):l.add(e),l})},[]),r=t.useMemo(()=>c.find(e=>e.id===d),[c,d]),Ce=t.useMemo(()=>{if(r!=null&&r.model)return r.model},[r]),ke=t.useMemo(()=>{if(r!=null&&r.customModelPath)return Fe(`/api/custom-models/${r.id}`)},[r]),Me=r==null?void 0:r.modelScale,ye=t.useMemo(()=>r?"scout":d==="boss"?"architect":d,[d,r]);t.useEffect(()=>{if(!u||!g)return;const e=S.getState().areas.get(g);if(e!=null&&e.directories&&e.directories.length>0){z(e.directories[0]);return}const a=Array.from(S.getState().agents.values()).filter(x=>{var M;return((M=S.getAreaForAgent(x.id))==null?void 0:M.id)===g&&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&&z(i)},[u,g]);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 W;const e=h.toLowerCase();return W.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(u&&!q.current){q.current=!0;const e=new Set(Array.from(S.getState().agents.values()).map(l=>l.name)),a=c.find(l=>l.id===d);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));B(new Set),R.current&&(R.current.focus(),R.current.select())}else u||(q.current=!1)},[u]),t.useEffect(()=>{if(!u)return;const e=c.find(a=>a.id===d);if(e)if(m.startsWith("Boss ")){const a=m.substring(5);p(`${e.name} ${a}`)}else{const a=c.find(l=>m.startsWith(l.name+" "));if(a){const l=m.substring(a.name.length+1);p(`${e.name} ${l}`)}else p(`${e.name} ${m}`)}else{const a=c.find(l=>m.startsWith(l.name+" "));if(a){const l=m.substring(a.name.length+1);p(`Boss ${l}`)}else m.startsWith("Boss ")||p(`Boss ${m}`)}},[d]);const Ae=()=>{if(_(!1),!L.trim()){_(!0);return}if(!m.trim()){const l=new Set(Array.from(S.getState().agents.values()).map(i=>i.name));p(ue(l));return}Ue(G.LAST_CWD,L),$(),window.__spawnModalAreaContext=g?{areaId:g}:null;const e=ae.trim()||void 0,a=Array.from(se);S.spawnBossAgent(m.trim(),d,L.trim(),me||void 0,Array.from(k),o==="claude"?Y:!1,Q,o,o==="codex"?f:void 0,o==="codex"?ee:void 0,o==="claude"?Z:void 0,e,a),p(""),B(new Set),U(new Set),P(),w()},$e=()=>{V(!1),p(""),B(new Set),P(),w()},Ee=()=>{V(!1),_(!0),P()};t.useEffect(()=>(window.__bossSpawnModalSuccess=$e,window.__bossSpawnModalError=Ee,()=>{delete window.__bossSpawnModalSuccess,delete window.__bossSpawnModalError}),[m]);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),B(a)};if(!u)return null;const De=O.boss;return s.jsx("div",{className:`modal-overlay ${u?"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+W.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 ${d===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 ${d==="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 ${d===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:R,type:"text",className:"spawn-input",placeholder:n("terminal:spawn.bossNamePlaceholder"),value:m,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=>{z(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 ${o==="claude"?"selected":""}`,onClick:()=>D("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 ${o==="codex"?"selected":""}`,onClick:()=>D("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 ${o==="opencode"?"selected":""}`,onClick:()=>D("opencode"),title:"Use OpenCode CLI (multi-provider)",children:[s.jsx("span",{children:s.jsx(T,{name:"status-pending",size:14,weight:"fill",color:"#4ade80"})}),s.jsx("span",{children:"OpenCode"})]}),s.jsxs("button",{className:`spawn-select-btn spawn-select-btn--grok ${o==="grok"?"selected":""}`,onClick:()=>D("grok"),title:"Use Grok CLI (headless)",children:[s.jsx("img",{src:"/assets/grok.png",alt:"Grok",className:"spawn-provider-icon"}),s.jsx("span",{children:"Grok"})]})]})]}),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 ${Q===e?"selected":""}`,onClick:()=>we(e),title:K[e].description,children:[s.jsx("span",{children:s.jsx(T,{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")}),o==="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))}):o==="codex"?s.jsx("div",{className:"spawn-select-row spawn-select-row--codex-models",children:Object.keys(F).map(e=>s.jsxs("button",{className:`spawn-select-btn ${ee===e?"selected":""}`,onClick:()=>fe(e),title:F[e].description,children:[s.jsx("span",{children:F[e].icon}),s.jsx("span",{children:F[e].label})]},e))}):o==="opencode"?s.jsx("input",{type:"text",className:"spawn-input",defaultValue:"minimax/MiniMax-M1-80k",placeholder:"provider/model (e.g., minimax/MiniMax-M1-80k)"}):o==="grok"?s.jsx("div",{className:"spawn-inline-hint",children:"grok-4.5"}):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:Y,onChange:e=>he(e.target.checked),disabled:o!=="claude"}),s.jsx("span",{children:n("terminal:spawn.chromeBrowser")})]})})]})]}),o==="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=>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:!!f.search,onChange:e=>N(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=>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:f.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:f.profile||"",onChange:e=>N(a=>({...a,profile:e.target.value||void 0}))}),s.jsxs("select",{className:"spawn-input",value:f.reasoningEffort||"",onChange:e=>N(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:v,onChange:e=>je(e.target.value)}),s.jsxs("div",{className:"spawn-skills-inline",children:[le.map(e=>{const a=se.has(e.id);return Ne.some(i=>i.id===e.id)?null:s.jsxs("button",{className:`spawn-skill-chip ${a?"selected":""}`,onClick:()=>Se(e.id),title:e.description,children:[a&&s.jsx("span",{className:"spawn-skill-check",children:s.jsx(T,{name:"check",size:12})}),s.jsx("span",{children:e.name}),e.builtin&&s.jsx("span",{className:"spawn-skill-builtin",children:"TC"})]},e.id)}),v&&le.length===0&&s.jsx("div",{className:"skill-search-empty",children:n("terminal:spawn.noSkillsMatch",{query:v})})]})]}),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=>ge(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(T,{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};
@@ -1 +0,0 @@
1
- import{u as K,cZ as Q,aC as J,c_ as W,c$ as ee,r as u,aq as se,n as te,cO as D,d0 as z,d1 as ae,j as e,d2 as ne,C as re,s as g,d3 as R,d4 as V}from"./main-DIf9R6Jx.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";const G={global:"terminal:controls.contextGlobal",commander:"terminal:controls.contextCommander",toolbox:"terminal:controls.contextToolbox"},le={global:"terminal:controls.contextGlobalDesc",commander:"terminal:controls.contextCommanderDesc",toolbox:"terminal:controls.contextToolboxDesc"},U={camera:["camera-pan","camera-orbit","camera-rotate","camera-zoom","camera-tilt"],interaction:["primary-action","selection-box","context-menu","move-command"]},oe={camera:"terminal:controls.cameraControls",interaction:"terminal:controls.interaction"};function pe({isOpen:s,onClose:r}){const{t:a}=K(["terminal","common"]),l=Q(),o=J(),h=W(),N=ee(),[x,C]=u.useState("keyboard"),[b,v]=u.useState(""),[p,j]=u.useState("all"),[m,f]=u.useState(!1),[c,d]=u.useState(null),[k,w]=u.useState(null),Y=se.useRef(null),{handleMouseDown:Z,handleClick:_}=te(r);if(u.useEffect(()=>{if(!s||m)return;const t=n=>{n.key==="Escape"&&(n.preventDefault(),n.stopPropagation(),r())};return document.addEventListener("keydown",t,!0),()=>document.removeEventListener("keydown",t,!0)},[s,r,m]),u.useEffect(()=>{s||(v(""),f(!1),d(null))},[s]),u.useEffect(()=>{if(!s||!m)return;const t=n=>{if(n.key==="Escape"){n.preventDefault(),n.stopPropagation(),f(!1),d(null);return}if(["Control","Alt","Shift","Meta"].includes(n.key))return;n.preventDefault(),n.stopPropagation();let i=n.key;n.code.startsWith("Key")&&n.code.length===4?i=n.code.charAt(3).toLowerCase():n.code.startsWith("Digit")&&n.code.length===6?i=n.code.charAt(5):n.code==="Space"&&(i="Space"),d({key:i,modifiers:{ctrl:n.ctrlKey,alt:n.altKey,shift:n.shiftKey,meta:n.metaKey}})};return document.addEventListener("keydown",t,!0),()=>document.removeEventListener("keydown",t,!0)},[s,m]),!s)return null;const F=l.filter(t=>{const n=a(`terminal:controls.shortcuts.${t.id}.name`,{defaultValue:t.name}),i=a(`terminal:controls.shortcuts.${t.id}.description`,{defaultValue:t.description});if(m&&c){const A=S=>S===" "||S==="Space"?"Space":S.length===1?S.toLowerCase():S,B=A(t.key),L=A(c.key);if(!(L.length===1&&/^[a-zA-Z]$/.test(B)?`Key${B.toUpperCase()}`==`Key${L.toUpperCase()}`:B===L))return!1;const M=t.modifiers,T=c.modifiers;return(M.ctrl||!1)===(T.ctrl||!1)&&(M.alt||!1)===(T.alt||!1)&&(M.shift||!1)===(T.shift||!1)&&(M.meta||!1)===(T.meta||!1)}if(!b)return!0;const y=b.toLowerCase();return n.toLowerCase().includes(y)||i.toLowerCase().includes(y)||D(t).toLowerCase().includes(y)}),E=Array.from(o.values()).map(t=>t).filter(t=>t.shortcut&&t.shortcut.trim().length>0).filter(t=>{const n=z(t.shortcut).toLowerCase();if(m&&c){const y={key:c.key,code:c.key.length===1&&/^[a-zA-Z]$/.test(c.key)?`Key${c.key.toUpperCase()}`:c.key.length===1&&/^[0-9]$/.test(c.key)?`Digit${c.key}`:c.key==="Space"?"Space":c.key,ctrlKey:!!c.modifiers.ctrl,altKey:!!c.modifiers.alt,shiftKey:!!c.modifiers.shift,metaKey:!!c.modifiers.meta};return ae(y,t.shortcut)}if(!b)return!0;const i=b.toLowerCase();return t.name.toLowerCase().includes(i)||n.toLowerCase().includes(i)}),P=F.reduce((t,n)=>(t[n.context]||(t[n.context]=[]),t[n.context].push(n),t),{}),I=(t,n)=>{g.updateShortcut(t,n)},$=()=>{w(x)},X=()=>{k==="keyboard"?g.resetShortcuts():(k==="mouse"||k==="trackpad")&&g.resetMouseControls()},q=k==="keyboard"?"terminal:controls.confirmResetKeyboard":k==="mouse"?"terminal:controls.confirmResetMouse":"terminal:controls.confirmResetTrackpad",O=["global","commander","toolbox"],H=h.bindings.reduce((t,n)=>(U.camera.includes(n.action)?t.camera.push(n):U.interaction.includes(n.action)&&t.interaction.push(n),t),{camera:[],interaction:[]});return e.jsxs("div",{className:"shortcuts-modal-overlay",onMouseDown:Z,onClick:_,children:[e.jsxs("div",{className:"shortcuts-modal controls-modal",children:[e.jsxs("div",{className:"shortcuts-modal-header",children:[e.jsxs("div",{className:"shortcuts-modal-title",children:[e.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("circle",{cx:"12",cy:"12",r:"3"}),e.jsx("path",{d:"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"})]}),e.jsx("span",{children:a("terminal:controls.title")})]}),e.jsx("button",{className:"shortcuts-modal-close",onClick:r,children:"×"})]}),e.jsxs("div",{className:"controls-main-tabs",children:[e.jsxs("button",{className:`controls-main-tab ${x==="keyboard"?"active":""}`,onClick:()=>C("keyboard"),children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"4",width:"20",height:"16",rx:"2"}),e.jsx("path",{d:"M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M18 12h.01M8 16h8"})]}),a("terminal:controls.keyboard")]}),e.jsxs("button",{className:`controls-main-tab ${x==="mouse"?"active":""}`,onClick:()=>C("mouse"),children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"6",y:"3",width:"12",height:"18",rx:"6"}),e.jsx("line",{x1:"12",y1:"7",x2:"12",y2:"11"})]}),a("terminal:controls.mouse")]}),e.jsxs("button",{className:`controls-main-tab ${x==="trackpad"?"active":""}`,onClick:()=>C("trackpad"),children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"4",width:"20",height:"16",rx:"2"}),e.jsx("circle",{cx:"12",cy:"12",r:"3"})]}),a("terminal:controls.trackpad")]})]}),x==="keyboard"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"shortcuts-modal-toolbar",children:[m?e.jsxs("div",{className:"shortcuts-search find-by-shortcut-active",children:[e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"4",width:"20",height:"16",rx:"2"}),e.jsx("path",{d:"M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M18 12h.01M8 16h8"})]}),c?e.jsxs("span",{className:"find-by-shortcut-display",children:[D({key:c.key,modifiers:c.modifiers}),e.jsx("button",{className:"shortcuts-search-clear",onClick:()=>d(null),children:"×"})]}):e.jsx("span",{className:"find-by-shortcut-prompt",children:a("terminal:controls.pressKeyCombination")})]}):e.jsxs("div",{className:"shortcuts-search",children:[e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("circle",{cx:"11",cy:"11",r:"8"}),e.jsx("path",{d:"M21 21l-4.35-4.35"})]}),e.jsx("input",{ref:Y,type:"text",placeholder:a("terminal:controls.searchShortcuts"),value:b,onChange:t=>v(t.target.value),autoFocus:!0}),b&&e.jsx("button",{className:"shortcuts-search-clear",onClick:()=>v(""),children:"×"})]}),e.jsx("button",{className:`shortcuts-find-by-key-btn ${m?"active":""}`,onClick:()=>{f(!m),d(null),v("")},title:a(m?"terminal:controls.switchToTextSearch":"terminal:controls.findByPressingKeys"),children:e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"4",width:"20",height:"16",rx:"2"}),e.jsx("path",{d:"M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M18 12h.01M8 16h8"})]})}),e.jsx("button",{className:"shortcuts-reset-all-btn",onClick:$,children:a("common:buttons.reset")})]}),e.jsxs("div",{className:"shortcuts-context-tabs",children:[e.jsxs("button",{className:`shortcuts-context-tab ${p==="all"?"active":""}`,onClick:()=>j("all"),children:[a("common:labels.all"),e.jsx("span",{className:"shortcuts-context-tab-count",children:F.length})]}),O.map(t=>{var i;const n=((i=P[t])==null?void 0:i.length)||0;return e.jsxs("button",{className:`shortcuts-context-tab ${p===t?"active":""}`,onClick:()=>j(t),children:[a(G[t]),e.jsx("span",{className:"shortcuts-context-tab-count",children:n})]},t)})]}),e.jsxs("div",{className:"shortcuts-modal-content",children:[O.map(t=>{const n=P[t]||[];return n.length===0||p!=="all"&&p!==t?null:e.jsxs("div",{className:"shortcuts-context-group",children:[p==="all"&&e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:a(G[t])}),e.jsx("span",{className:"shortcuts-context-description",children:a(le[t])})]}),e.jsx("div",{className:"shortcuts-grid",children:n.map(i=>e.jsxs("div",{className:"shortcut-item",children:[e.jsxs("div",{className:"shortcut-item-info",children:[e.jsx("span",{className:"shortcut-item-name",children:a(`terminal:controls.shortcuts.${i.id}.name`,{defaultValue:i.name})}),e.jsx("span",{className:"shortcut-item-description",children:a(`terminal:controls.shortcuts.${i.id}.description`,{defaultValue:i.description})})]}),e.jsx(ne,{shortcut:i,onUpdate:y=>I(i.id,y)})]},i.id))})]},t)}),F.length===0&&E.length===0&&e.jsx("div",{className:"shortcuts-empty",children:m?c?e.jsx("p",{children:a("terminal:controls.noShortcutBoundTo",{keys:D({key:c.key,modifiers:c.modifiers})})}):e.jsx("p",{children:a("terminal:controls.pressKeyCombinationToFind")}):e.jsx("p",{children:a("terminal:controls.noShortcutsFound",{query:b})})}),E.length>0&&(p==="all"||p==="global")&&e.jsxs("div",{className:"shortcuts-context-group",children:[p==="all"&&e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:"Agent Terminal Shortcuts"}),e.jsx("span",{className:"shortcuts-context-description",children:"Per-agent global shortcuts that open the guake terminal"})]}),e.jsx("div",{className:"shortcuts-grid",children:E.map(t=>e.jsxs("div",{className:"shortcut-item",children:[e.jsxs("div",{className:"shortcut-item-info",children:[e.jsx("span",{className:"shortcut-item-name",children:t.name}),e.jsx("span",{className:"shortcut-item-description",children:"Open terminal for this agent"})]}),e.jsx("div",{className:"key-capture-container",children:e.jsx("button",{className:"key-capture-input disabled",disabled:!0,children:e.jsx("span",{className:"key-capture-value",children:z(t.shortcut)})})})]},t.id))})]})]})]}),x==="mouse"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"shortcuts-modal-toolbar",children:[e.jsx("span",{className:"mouse-controls-subtitle",children:a("terminal:controls.cameraAndInteraction")}),e.jsx("button",{className:"shortcuts-reset-all-btn",onClick:$,children:a("common:buttons.reset")})]}),e.jsxs("div",{className:"shortcuts-modal-content mouse-controls-content",children:[e.jsx("div",{className:"mouse-controls-bindings",children:Object.entries(H).map(([t,n])=>e.jsxs("div",{className:"shortcuts-context-group",children:[e.jsx("div",{className:"shortcuts-context-header",children:e.jsx("span",{className:"shortcuts-context-label",children:a(oe[t])})}),e.jsx("div",{className:"shortcuts-grid",children:n.map(i=>e.jsx(ce,{binding:i},i.id))})]},t))}),e.jsxs("div",{className:"shortcuts-context-group",children:[e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:a("terminal:controls.sensitivity")}),e.jsx("span",{className:"shortcuts-context-description",children:a("terminal:controls.adjustCameraSpeed")})]}),e.jsx(ie,{sensitivity:h.sensitivity})]})]})]}),x==="trackpad"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"shortcuts-modal-toolbar",children:[e.jsx("span",{className:"mouse-controls-subtitle",children:a("terminal:controls.trackpadGestureSettings")}),e.jsx("button",{className:"shortcuts-reset-all-btn",onClick:$,children:a("common:buttons.reset")})]}),e.jsx("div",{className:"shortcuts-modal-content trackpad-controls-content",children:e.jsx(de,{config:N})})]}),e.jsx("div",{className:"shortcuts-modal-footer",children:e.jsx("span",{className:"shortcuts-modal-hint",children:a(x==="keyboard"?m?"terminal:controls.hintFindByShortcut":"terminal:controls.hintKeyboard":x==="mouse"?"terminal:controls.hintMouse":"terminal:controls.hintTrackpad")})})]}),e.jsx(re,{isOpen:k!==null,title:a("common:buttons.resetToDefaults"),message:a(q),confirmLabel:a("common:buttons.reset"),cancelLabel:a("common:buttons.cancel"),variant:"danger",onConfirm:X,onClose:()=>w(null)})]})}function ce({binding:s}){const{t:r}=K(["terminal"]),a=W(),[l,o]=u.useState(!1),[h,N]=u.useState(null);u.useEffect(()=>{if(!l)return;const j=d=>{d.preventDefault(),d.stopPropagation();const w={0:"left",1:"middle",2:"right",3:"back",4:"forward"}[d.button];w&&N({button:w,modifiers:{ctrl:d.ctrlKey,alt:d.altKey,shift:d.shiftKey,meta:d.metaKey}})},m=d=>{d.key==="Escape"&&(d.preventDefault(),d.stopPropagation(),o(!1),N(null))},f=()=>{h&&R(a.bindings,h,s.id).length===0&&g.updateMouseBinding(s.id,{button:h.button,modifiers:h.modifiers}),o(!1),N(null)},c=setTimeout(()=>{document.addEventListener("mousedown",j,!0),document.addEventListener("keydown",m,!0),document.addEventListener("click",f,!0)},100);return()=>{clearTimeout(c),document.removeEventListener("mousedown",j,!0),document.removeEventListener("keydown",m,!0),document.removeEventListener("click",f,!0)}},[l,h,s.id,a.bindings]);const x=h?R(a.bindings,h,s.id):[],C=r(`terminal:controls.mouseBindings.${s.id}.name`,{defaultValue:s.name}),b=r(`terminal:controls.mouseBindings.${s.id}.description`,{defaultValue:s.description}),v=j=>r(`terminal:controls.mouseButtons.${j}`,{defaultValue:j}),p=h?V({...s,...h},v):V(s,v);return e.jsxs("div",{className:`shortcut-item ${s.enabled?"":"disabled"}`,children:[e.jsxs("div",{className:"shortcut-item-info",children:[e.jsx("span",{className:"shortcut-item-name",children:C}),e.jsx("span",{className:"shortcut-item-description",children:b})]}),e.jsxs("div",{className:"key-capture-container",children:[e.jsx("button",{className:`key-capture-input ${l?"capturing":""} ${x.length>0?"conflict":""}`,onClick:()=>o(!0),children:l?h?e.jsx("span",{className:"key-capture-value",style:{color:"#f1fa8c"},children:p}):e.jsx("span",{style:{color:"#6272a4",fontStyle:"italic"},children:r("terminal:controls.clickToCapture")}):e.jsx("span",{className:"key-capture-value",children:p})}),x.length>0&&e.jsxs("span",{className:"key-capture-conflict",children:[r("terminal:controls.conflicts"),": ",x.map(j=>r(`terminal:controls.mouseBindings.${j.id}.name`,{defaultValue:j.name})).join(", ")]})]})]})}function ie({sensitivity:s}){const{t:r}=K(["terminal"]),a=u.useCallback((l,o)=>{g.updateCameraSensitivity({[l]:o})},[]);return e.jsxs("div",{className:"sensitivity-inline-settings",children:[e.jsxs("div",{className:"sensitivity-sliders",children:[e.jsxs("div",{className:"sensitivity-slider-row",children:[e.jsx("label",{children:r("terminal:controls.panSpeed")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:s.panSpeed,onChange:l=>a("panSpeed",parseFloat(l.target.value))}),e.jsxs("span",{className:"sensitivity-slider-value",children:[s.panSpeed.toFixed(1),"x"]})]}),e.jsxs("div",{className:"sensitivity-slider-row",children:[e.jsx("label",{children:r("terminal:controls.orbitSpeed")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:s.orbitSpeed,onChange:l=>a("orbitSpeed",parseFloat(l.target.value))}),e.jsxs("span",{className:"sensitivity-slider-value",children:[s.orbitSpeed.toFixed(1),"x"]})]}),e.jsxs("div",{className:"sensitivity-slider-row",children:[e.jsx("label",{children:r("terminal:controls.zoomSpeed")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:s.zoomSpeed,onChange:l=>a("zoomSpeed",parseFloat(l.target.value))}),e.jsxs("span",{className:"sensitivity-slider-value",children:[s.zoomSpeed.toFixed(1),"x"]})]}),e.jsxs("div",{className:"sensitivity-slider-row",children:[e.jsx("label",{children:r("terminal:controls.smoothing")}),e.jsx("input",{type:"range",min:"0",max:"1",step:"0.1",value:s.smoothing,onChange:l=>a("smoothing",parseFloat(l.target.value))}),e.jsx("span",{className:"sensitivity-slider-value",children:s.smoothing.toFixed(1)})]})]}),e.jsxs("div",{className:"sensitivity-checkboxes-inline",children:[e.jsxs("label",{className:"sensitivity-checkbox-inline",children:[e.jsx("input",{type:"checkbox",checked:s.invertPanX,onChange:l=>a("invertPanX",l.target.checked)}),e.jsx("span",{children:r("terminal:controls.invertPanX")})]}),e.jsxs("label",{className:"sensitivity-checkbox-inline",children:[e.jsx("input",{type:"checkbox",checked:s.invertPanY,onChange:l=>a("invertPanY",l.target.checked)}),e.jsx("span",{children:r("terminal:controls.invertPanY")})]}),e.jsxs("label",{className:"sensitivity-checkbox-inline",children:[e.jsx("input",{type:"checkbox",checked:s.invertOrbitX,onChange:l=>a("invertOrbitX",l.target.checked)}),e.jsx("span",{children:r("terminal:controls.invertOrbitX")})]}),e.jsxs("label",{className:"sensitivity-checkbox-inline",children:[e.jsx("input",{type:"checkbox",checked:s.invertOrbitY,onChange:l=>a("invertOrbitY",l.target.checked)}),e.jsx("span",{children:r("terminal:controls.invertOrbitY")})]})]})]})}function de({config:s}){const{t:r}=K(["terminal"]),a=u.useCallback((o,h)=>{g.updateTrackpadConfig({[o]:h})},[]),l=u.useCallback((o,h)=>{g.updateTrackpadConfig({sensitivity:{[o]:h}})},[]);return e.jsxs("div",{className:"trackpad-settings",children:[e.jsxs("div",{className:"shortcuts-context-group",children:[e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:r("terminal:controls.trackpadGestures")}),e.jsx("span",{className:"shortcuts-context-description",children:r("terminal:controls.enableTrackpadSupport")})]}),e.jsx("div",{className:"trackpad-toggle-row",children:e.jsxs("label",{className:"trackpad-toggle",children:[e.jsx("input",{type:"checkbox",checked:s.enabled,onChange:o=>a("enabled",o.target.checked)}),e.jsx("span",{className:"trackpad-toggle-label",children:r("terminal:controls.enableTrackpadGestures")})]})})]}),e.jsxs("div",{className:"shortcuts-context-group",children:[e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:r("terminal:controls.gestureControls")}),e.jsx("span",{className:"shortcuts-context-description",children:r("terminal:controls.enableDisableGestures")})]}),e.jsxs("div",{className:"trackpad-gestures-grid",children:[e.jsxs("label",{className:`trackpad-gesture-item ${s.enabled?"":"disabled"}`,children:[e.jsx("input",{type:"checkbox",checked:s.pinchToZoom,onChange:o=>a("pinchToZoom",o.target.checked),disabled:!s.enabled}),e.jsxs("div",{className:"trackpad-gesture-info",children:[e.jsx("span",{className:"trackpad-gesture-name",children:r("terminal:controls.pinchToZoom")}),e.jsx("span",{className:"trackpad-gesture-desc",children:r("terminal:controls.pinchToZoomDesc")})]})]}),e.jsxs("label",{className:`trackpad-gesture-item ${s.enabled?"":"disabled"}`,children:[e.jsx("input",{type:"checkbox",checked:s.twoFingerPan,onChange:o=>a("twoFingerPan",o.target.checked),disabled:!s.enabled}),e.jsxs("div",{className:"trackpad-gesture-info",children:[e.jsx("span",{className:"trackpad-gesture-name",children:r("terminal:controls.twoFingerPan")}),e.jsx("span",{className:"trackpad-gesture-desc",children:r("terminal:controls.twoFingerPanDesc")})]})]}),e.jsxs("label",{className:`trackpad-gesture-item ${s.enabled?"":"disabled"}`,children:[e.jsx("input",{type:"checkbox",checked:s.shiftTwoFingerOrbit,onChange:o=>a("shiftTwoFingerOrbit",o.target.checked),disabled:!s.enabled}),e.jsxs("div",{className:"trackpad-gesture-info",children:[e.jsx("span",{className:"trackpad-gesture-name",children:r("terminal:controls.shiftTwoFingerOrbit")}),e.jsx("span",{className:"trackpad-gesture-desc",children:r("terminal:controls.shiftTwoFingerOrbitDesc")})]})]})]})]}),e.jsxs("div",{className:"shortcuts-context-group",children:[e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:r("terminal:controls.sensitivity")}),e.jsx("span",{className:"shortcuts-context-description",children:r("terminal:controls.adjustGestureSensitivity")})]}),e.jsxs("div",{className:"trackpad-sensitivity-sliders",children:[e.jsxs("div",{className:`trackpad-slider-row ${!s.enabled||!s.pinchToZoom?"disabled":""}`,children:[e.jsx("label",{children:r("terminal:controls.zoom")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:s.sensitivity.zoom,onChange:o=>l("zoom",parseFloat(o.target.value)),disabled:!s.enabled||!s.pinchToZoom}),e.jsxs("span",{className:"trackpad-slider-value",children:[s.sensitivity.zoom.toFixed(1),"x"]})]}),e.jsxs("div",{className:`trackpad-slider-row ${!s.enabled||!s.twoFingerPan?"disabled":""}`,children:[e.jsx("label",{children:r("terminal:controls.pan")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:s.sensitivity.pan,onChange:o=>l("pan",parseFloat(o.target.value)),disabled:!s.enabled||!s.twoFingerPan}),e.jsxs("span",{className:"trackpad-slider-value",children:[s.sensitivity.pan.toFixed(1),"x"]})]}),e.jsxs("div",{className:`trackpad-slider-row ${!s.enabled||!s.shiftTwoFingerOrbit?"disabled":""}`,children:[e.jsx("label",{children:r("terminal:controls.orbit")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:s.sensitivity.orbit,onChange:o=>l("orbit",parseFloat(o.target.value)),disabled:!s.enabled||!s.shiftTwoFingerOrbit}),e.jsxs("span",{className:"trackpad-slider-value",children:[s.sensitivity.orbit.toFixed(1),"x"]})]})]})]})]})}export{pe as ControlsModal};
@@ -1,2 +0,0 @@
1
- import{u as p,f as u,h as S,r as n,s as o,j as x}from"./main-DIf9R6Jx.js";import{L as k}from"./LogViewerModal-DKYB8dHo.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";function h({building:e,isOpen:t,onClose:i,onMinimize:m}){var a;const{t:c}=p(["terminal"]),g=u(),d=S(),r=g.get(e.id)||"",l=d.has(e.id);n.useEffect(()=>{var s;return t&&((s=e.docker)!=null&&s.enabled)&&o.startLogStreaming(e.id,200),()=>{e.id&&o.stopLogStreaming(e.id)}},[t,e.id,(a=e.docker)==null?void 0:a.enabled]);const L=n.useMemo(()=>r.split(`
2
- `).map((s,f)=>({text:s,lineNumber:f+1})),[r]);return x.jsx(k,{isOpen:t,onClose:i,onMinimize:m,title:`${e.name} - ${c("terminal:logs.dockerLogs")}`,icon:"🐳",lines:L,isStreaming:l,onClear:()=>o.clearStreamingLogs(e.id)})}export{h as DockerLogsModal};