tide-commander 1.87.0 → 1.88.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{BossLogsModal-S3Rke-8g.js → BossLogsModal-BXQh_FI_.js} +1 -1
- package/dist/assets/{BossSpawnModal-BjWGNCnz.js → BossSpawnModal-BevC86-H.js} +1 -1
- package/dist/assets/{ControlsModal-6yfU0XjZ.js → ControlsModal-OTv1pMsh.js} +1 -1
- package/dist/assets/{DockerLogsModal-CYq0hNz6.js → DockerLogsModal-oLpkSRWn.js} +1 -1
- package/dist/assets/{EmbeddedEditor-ZBdqRDqm.js → EmbeddedEditor-Ch6-Ql2A.js} +1 -1
- package/dist/assets/{GmailOAuthSetup-BcV5jAse.js → GmailOAuthSetup-wOwZdO76.js} +1 -1
- package/dist/assets/{GoogleOAuthSetup-DyUW_STE.js → GoogleOAuthSetup-ChVRBoAO.js} +1 -1
- package/dist/assets/{IframeModal-D9A3dUUc.js → IframeModal-BAQxs9VC.js} +1 -1
- package/dist/assets/{IntegrationsPanel-CHaNJBJW.js → IntegrationsPanel-YFcOTDdT.js} +2 -2
- package/dist/assets/{LogViewerModal-BWkbY7wa.js → LogViewerModal-CSAEl5nL.js} +1 -1
- package/dist/assets/{MonitoringModal-AZzokZAZ.js → MonitoringModal-Bgu6BN93.js} +1 -1
- package/dist/assets/{PM2LogsModal-q98eiBfq.js → PM2LogsModal-D0iQKsKn.js} +1 -1
- package/dist/assets/{RestoreArchivedAreaModal-CTxRP2qE.js → RestoreArchivedAreaModal-SDm4CHQ_.js} +1 -1
- package/dist/assets/{Scene2DCanvas-C11dztp1.js → Scene2DCanvas-kZMJfRRF.js} +1 -1
- package/dist/assets/{SceneManager-CsW9MYrD.js → SceneManager-CcMFDU1A.js} +1 -1
- package/dist/assets/{SkillsPanel-BeZr9w6E.js → SkillsPanel-DKT8TwSH.js} +1 -1
- package/dist/assets/{SpawnModal-DY_KM6lX.js → SpawnModal-DKfic48e.js} +1 -1
- package/dist/assets/{SubordinateAssignmentModal-D6RvjGX9.js → SubordinateAssignmentModal-BfSS7J4H.js} +1 -1
- package/dist/assets/{TriggerManagerPanel-BmqjXv9T.js → TriggerManagerPanel-C8zZf9rr.js} +2 -2
- package/dist/assets/{WorkflowEditorPanel-Rd5ZjJmt.js → WorkflowEditorPanel-BsEbQzL1.js} +1 -1
- package/dist/assets/{index-DHHRkTG1.js → index-BW6pasQS.js} +1 -1
- package/dist/assets/{index-DSvJOrb7.js → index-Bm2GprIp.js} +2 -2
- package/dist/assets/{index-BoORE9Q1.js → index-Cn6pTvu9.js} +1 -1
- package/dist/assets/{index-BYVHgVEo.js → index-Cq-zN7dW.js} +1 -1
- package/dist/assets/{index-BtJyOo4p.js → index-CrveGM3a.js} +1 -1
- package/dist/assets/index-DBbK5bs6.js +8 -0
- package/dist/assets/index-DeGYOmjB.js +2 -0
- package/dist/assets/{index-DRGyDtmm.js → index-JfilXCJq.js} +1 -1
- package/dist/assets/{index-BxaEkSIx.js → index-NPF6_aDv.js} +3 -3
- package/dist/assets/{main-kpU9m5LW.css → main-Cm8LaUxX.css} +1 -1
- package/dist/assets/main-CwfJmt2N.js +209 -0
- package/dist/assets/{web-DS0FHmg8.js → web-CN0zYUhV.js} +1 -1
- package/dist/assets/{web-D3zCwsS9.js → web-Dik5OZ1r.js} +1 -1
- package/dist/assets/{web-DEq3Te_H.js → web-JhU3bMzp.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/src/packages/server/data/builtin-skills/explore-database.js +175 -0
- package/dist/src/packages/server/data/builtin-skills/index.js +2 -0
- package/dist/src/packages/server/data/index.js +56 -2
- package/dist/src/packages/server/index.js +2 -1
- package/dist/src/packages/server/integrations/gmail/gmail-trigger-handler.js +9 -1
- package/dist/src/packages/server/integrations/whatsapp/index.js +5 -4
- package/dist/src/packages/server/integrations/whatsapp/whatsapp-client.js +10 -0
- package/dist/src/packages/server/integrations/whatsapp/whatsapp-routes.js +68 -0
- package/dist/src/packages/server/integrations/whatsapp/whatsapp-trigger-handler.js +113 -0
- package/dist/src/packages/server/routes/database.js +221 -0
- package/dist/src/packages/server/routes/files.js +128 -18
- package/dist/src/packages/server/routes/index.js +2 -0
- package/dist/src/packages/server/services/building-service.js +41 -0
- package/dist/src/packages/server/services/database-service.js +61 -9
- package/dist/src/packages/server/services/index.js +1 -0
- package/dist/src/packages/server/services/ssh-tunnel-service.js +255 -0
- package/dist/src/packages/server/websocket/handler.js +2 -1
- package/dist/src/packages/server/websocket/handlers/database-handler.js +35 -0
- package/package.json +3 -1
- package/dist/assets/index-BOr_tbLK.js +0 -2
- package/dist/assets/index-Co7njQ0Q.js +0 -8
- package/dist/assets/main-BrZe9Zbd.js +0 -201
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH Tunnel Service
|
|
3
|
+
*
|
|
4
|
+
* Manages SSH tunnel lifecycles for Database buildings. Each tunnel:
|
|
5
|
+
* 1. Opens an ssh2 Client to the configured jump host.
|
|
6
|
+
* 2. Listens on a local TCP port (auto-assigned or fixed via config.localPort).
|
|
7
|
+
* 3. On each incoming local connection, calls client.forwardOut() to relay
|
|
8
|
+
* traffic to the DB target host:port as seen FROM the SSH server.
|
|
9
|
+
*
|
|
10
|
+
* Tunnels are keyed by connection ID and reused across pool factories.
|
|
11
|
+
* Errors are surfaced as Error rejections; credentials are NEVER logged.
|
|
12
|
+
*/
|
|
13
|
+
import { Client as SSHClient } from 'ssh2';
|
|
14
|
+
import net from 'net';
|
|
15
|
+
import fs from 'fs';
|
|
16
|
+
import { createLogger } from '../utils/index.js';
|
|
17
|
+
const log = createLogger('SSHTunnelService');
|
|
18
|
+
// Active tunnels keyed by connection ID. Stored as Promise so concurrent
|
|
19
|
+
// callers share a single bring-up.
|
|
20
|
+
const tunnels = new Map();
|
|
21
|
+
function buildSSHConnectConfig(cfg) {
|
|
22
|
+
const base = {
|
|
23
|
+
host: cfg.host,
|
|
24
|
+
port: cfg.port || 22,
|
|
25
|
+
username: cfg.username,
|
|
26
|
+
readyTimeout: cfg.readyTimeoutMs ?? 20000,
|
|
27
|
+
keepaliveInterval: cfg.keepaliveIntervalMs ?? 10000,
|
|
28
|
+
};
|
|
29
|
+
if (cfg.authMethod === 'password') {
|
|
30
|
+
if (!cfg.password) {
|
|
31
|
+
throw new Error('SSH password required when authMethod is "password"');
|
|
32
|
+
}
|
|
33
|
+
base.password = cfg.password;
|
|
34
|
+
return base;
|
|
35
|
+
}
|
|
36
|
+
// privateKey auth: prefer inline, fall back to file path
|
|
37
|
+
let key;
|
|
38
|
+
if (cfg.privateKey && cfg.privateKey.trim().length > 0) {
|
|
39
|
+
key = cfg.privateKey;
|
|
40
|
+
}
|
|
41
|
+
else if (cfg.privateKeyPath && cfg.privateKeyPath.trim().length > 0) {
|
|
42
|
+
try {
|
|
43
|
+
key = fs.readFileSync(cfg.privateKeyPath);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
47
|
+
throw new Error(`Failed to read SSH private key file: ${msg}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!key) {
|
|
51
|
+
throw new Error('SSH private key required when authMethod is "privateKey"');
|
|
52
|
+
}
|
|
53
|
+
base.privateKey = key;
|
|
54
|
+
if (cfg.passphrase)
|
|
55
|
+
base.passphrase = cfg.passphrase;
|
|
56
|
+
return base;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Open the SSH client and listen on a local TCP port that forwards each
|
|
60
|
+
* incoming connection to remoteHost:remotePort via the SSH server.
|
|
61
|
+
*/
|
|
62
|
+
function openTunnel(connectionId, cfg, remoteHost, remotePort) {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
let connectConfig;
|
|
65
|
+
try {
|
|
66
|
+
connectConfig = buildSSHConnectConfig(cfg);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
reject(err);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const client = new SSHClient();
|
|
73
|
+
let resolved = false;
|
|
74
|
+
const cleanupOnFailure = (err) => {
|
|
75
|
+
if (resolved)
|
|
76
|
+
return;
|
|
77
|
+
resolved = true;
|
|
78
|
+
try {
|
|
79
|
+
client.end();
|
|
80
|
+
}
|
|
81
|
+
catch { /* ignore */ }
|
|
82
|
+
reject(err);
|
|
83
|
+
};
|
|
84
|
+
client.on('error', (err) => {
|
|
85
|
+
log.error(`SSH error for connection ${connectionId}: ${err.message}`);
|
|
86
|
+
cleanupOnFailure(new Error(`SSH connection failed: ${err.message}`));
|
|
87
|
+
});
|
|
88
|
+
let handleRef;
|
|
89
|
+
client.on('close', () => {
|
|
90
|
+
if (handleRef && !handleRef.closed) {
|
|
91
|
+
handleRef.closed = true;
|
|
92
|
+
log.warn(`SSH client closed unexpectedly for ${connectionId}; tunnel marked dead`);
|
|
93
|
+
try {
|
|
94
|
+
handleRef.server.close();
|
|
95
|
+
}
|
|
96
|
+
catch { /* ignore */ }
|
|
97
|
+
// Remove from registry so next caller rebuilds the tunnel
|
|
98
|
+
if (tunnels.get(connectionId) instanceof Promise) {
|
|
99
|
+
tunnels.delete(connectionId);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
client.on('ready', () => {
|
|
104
|
+
const server = net.createServer((localSocket) => {
|
|
105
|
+
client.forwardOut('127.0.0.1', 0, remoteHost, remotePort, (err, stream) => {
|
|
106
|
+
if (err) {
|
|
107
|
+
log.error(`Forward-out failed for ${connectionId}: ${err.message}`);
|
|
108
|
+
localSocket.destroy(err);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
localSocket.pipe(stream).pipe(localSocket);
|
|
112
|
+
stream.on('error', () => localSocket.destroy());
|
|
113
|
+
localSocket.on('error', () => stream.destroy());
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
server.on('error', (err) => {
|
|
117
|
+
log.error(`Local tunnel server error (${connectionId}): ${err.message}`);
|
|
118
|
+
cleanupOnFailure(err);
|
|
119
|
+
});
|
|
120
|
+
const desiredPort = cfg.localPort && cfg.localPort > 0 ? cfg.localPort : 0;
|
|
121
|
+
server.listen(desiredPort, '127.0.0.1', () => {
|
|
122
|
+
const addr = server.address();
|
|
123
|
+
const localPort = typeof addr === 'object' && addr ? addr.port : desiredPort;
|
|
124
|
+
if (!localPort) {
|
|
125
|
+
cleanupOnFailure(new Error('Failed to determine local tunnel port'));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
resolved = true;
|
|
129
|
+
log.log(`Tunnel up: ${connectionId} 127.0.0.1:${localPort} -> ${cfg.host}:${cfg.port || 22} -> ${remoteHost}:${remotePort}`);
|
|
130
|
+
const handle = {
|
|
131
|
+
connectionId,
|
|
132
|
+
localHost: '127.0.0.1',
|
|
133
|
+
localPort,
|
|
134
|
+
remoteHost,
|
|
135
|
+
remotePort,
|
|
136
|
+
client,
|
|
137
|
+
server,
|
|
138
|
+
closed: false,
|
|
139
|
+
};
|
|
140
|
+
handleRef = handle;
|
|
141
|
+
resolve(handle);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
try {
|
|
145
|
+
client.connect(connectConfig);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
149
|
+
cleanupOnFailure(new Error(`Failed to start SSH connect: ${msg}`));
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get or create a tunnel for the given connection ID. If a tunnel already
|
|
155
|
+
* exists with the same target, it is reused; otherwise the prior one is
|
|
156
|
+
* closed and a new one created.
|
|
157
|
+
*/
|
|
158
|
+
export async function getOrCreateTunnel(connectionId, cfg, remoteHost, remotePort) {
|
|
159
|
+
const existingPromise = tunnels.get(connectionId);
|
|
160
|
+
if (existingPromise) {
|
|
161
|
+
try {
|
|
162
|
+
const existing = await existingPromise;
|
|
163
|
+
if (!existing.closed &&
|
|
164
|
+
existing.remoteHost === remoteHost &&
|
|
165
|
+
existing.remotePort === remotePort) {
|
|
166
|
+
return existing;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// Fall through and recreate
|
|
171
|
+
}
|
|
172
|
+
await closeTunnel(connectionId);
|
|
173
|
+
}
|
|
174
|
+
const created = openTunnel(connectionId, cfg, remoteHost, remotePort);
|
|
175
|
+
tunnels.set(connectionId, created);
|
|
176
|
+
try {
|
|
177
|
+
return await created;
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
tunnels.delete(connectionId);
|
|
181
|
+
throw err;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Run a one-off transient tunnel (no caching). Caller MUST close it.
|
|
186
|
+
* Useful for "Test Connection" flows where we don't want to keep the
|
|
187
|
+
* tunnel alive after the test.
|
|
188
|
+
*/
|
|
189
|
+
export async function openTransientTunnel(cfg, remoteHost, remotePort) {
|
|
190
|
+
const transientId = `transient_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
191
|
+
return openTunnel(transientId, cfg, remoteHost, remotePort);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Close an active tunnel by connection ID.
|
|
195
|
+
*/
|
|
196
|
+
export async function closeTunnel(connectionId) {
|
|
197
|
+
const promise = tunnels.get(connectionId);
|
|
198
|
+
tunnels.delete(connectionId);
|
|
199
|
+
if (!promise)
|
|
200
|
+
return;
|
|
201
|
+
try {
|
|
202
|
+
const handle = await promise;
|
|
203
|
+
await closeTunnelHandle(handle);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Already failed to open; nothing to close.
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Close a tunnel handle (used for transient tunnels and via closeTunnel).
|
|
211
|
+
*/
|
|
212
|
+
export async function closeTunnelHandle(handle) {
|
|
213
|
+
if (handle.closed)
|
|
214
|
+
return;
|
|
215
|
+
handle.closed = true;
|
|
216
|
+
try {
|
|
217
|
+
await new Promise((resolve) => {
|
|
218
|
+
handle.server.close(() => resolve());
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
catch { /* ignore */ }
|
|
222
|
+
try {
|
|
223
|
+
handle.client.end();
|
|
224
|
+
}
|
|
225
|
+
catch { /* ignore */ }
|
|
226
|
+
log.log(`Tunnel closed: ${handle.connectionId}`);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Close every active tunnel. Called during graceful shutdown.
|
|
230
|
+
*/
|
|
231
|
+
export async function closeAllTunnels() {
|
|
232
|
+
const ids = Array.from(tunnels.keys());
|
|
233
|
+
await Promise.all(ids.map((id) => closeTunnel(id)));
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Snapshot of currently open tunnels (for status/debug).
|
|
237
|
+
*/
|
|
238
|
+
export async function listOpenTunnels() {
|
|
239
|
+
const out = [];
|
|
240
|
+
for (const [id, promise] of tunnels.entries()) {
|
|
241
|
+
try {
|
|
242
|
+
const h = await promise;
|
|
243
|
+
if (!h.closed) {
|
|
244
|
+
out.push({
|
|
245
|
+
connectionId: id,
|
|
246
|
+
localPort: h.localPort,
|
|
247
|
+
remoteHost: h.remoteHost,
|
|
248
|
+
remotePort: h.remotePort,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
catch { /* skip failed */ }
|
|
253
|
+
}
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
@@ -17,7 +17,7 @@ import { handleBuildingCommand, handlePM2LogsStart, handlePM2LogsStop, handleDoc
|
|
|
17
17
|
import { handleSendCommand } from './handlers/command-handler.js';
|
|
18
18
|
import { handleCreateSecret, handleUpdateSecret, handleDeleteSecret, } from './handlers/secrets-handler.js';
|
|
19
19
|
import { secretsService } from '../services/secrets-service.js';
|
|
20
|
-
import { handleTestDatabaseConnection, handleListDatabases, handleListTables, handleGetTableSchema, handleExecuteQuery, handleRequestQueryHistory, handleToggleQueryFavorite, handleDeleteQueryHistory, handleClearQueryHistory, } from './handlers/database-handler.js';
|
|
20
|
+
import { handleTestDatabaseConnection, handleTestDatabaseConnectionTransient, handleListDatabases, handleListTables, handleGetTableSchema, handleExecuteQuery, handleRequestQueryHistory, handleToggleQueryFavorite, handleDeleteQueryHistory, handleClearQueryHistory, } from './handlers/database-handler.js';
|
|
21
21
|
import { handlePermissionResponse } from './handlers/permission-handler.js';
|
|
22
22
|
import { handleSendNotification } from './handlers/notification-handler.js';
|
|
23
23
|
import { handleSyncAreas, handleSyncBuildings } from './handlers/sync-handler.js';
|
|
@@ -185,6 +185,7 @@ const messageHandlers = {
|
|
|
185
185
|
boss_building_logs_start: handleBossBuildingLogsStart,
|
|
186
186
|
boss_building_logs_stop: handleBossBuildingLogsStop,
|
|
187
187
|
test_database_connection: handleTestDatabaseConnection,
|
|
188
|
+
test_database_connection_transient: handleTestDatabaseConnectionTransient,
|
|
188
189
|
list_databases: handleListDatabases,
|
|
189
190
|
execute_query: handleExecuteQuery,
|
|
190
191
|
request_query_history: handleRequestQueryHistory,
|
|
@@ -46,6 +46,41 @@ export async function handleTestDatabaseConnection(ctx, payload) {
|
|
|
46
46
|
},
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Handle test_database_connection_transient message — for testing an unsaved
|
|
51
|
+
* connection (e.g. from the Create Database modal "Test Connection" button).
|
|
52
|
+
* The connection object is passed inline; no building lookup is performed.
|
|
53
|
+
* If SSH is enabled, a one-shot tunnel is brought up and torn down per call.
|
|
54
|
+
*/
|
|
55
|
+
export async function handleTestDatabaseConnectionTransient(ctx, payload) {
|
|
56
|
+
const { requestId, connection } = payload;
|
|
57
|
+
if (!connection || !connection.id) {
|
|
58
|
+
ctx.sendToClient({
|
|
59
|
+
type: 'database_connection_result',
|
|
60
|
+
payload: {
|
|
61
|
+
buildingId: '',
|
|
62
|
+
connectionId: '',
|
|
63
|
+
requestId,
|
|
64
|
+
success: false,
|
|
65
|
+
error: 'Invalid connection payload',
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
log.log(`Testing transient connection: ${connection.name} (${connection.engine})${connection.ssh?.enabled ? ' via SSH tunnel' : ''}`);
|
|
71
|
+
const result = await databaseService.testConnection(connection, { transient: true });
|
|
72
|
+
ctx.sendToClient({
|
|
73
|
+
type: 'database_connection_result',
|
|
74
|
+
payload: {
|
|
75
|
+
buildingId: '',
|
|
76
|
+
connectionId: connection.id,
|
|
77
|
+
requestId,
|
|
78
|
+
success: result.success,
|
|
79
|
+
error: result.error,
|
|
80
|
+
serverVersion: result.serverVersion,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
49
84
|
/**
|
|
50
85
|
* Handle list_databases message
|
|
51
86
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tide-commander",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.88.1",
|
|
4
4
|
"description": "Visual multi-agent orchestrator and manager for Claude Code with 3D/2D interface",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -100,6 +100,7 @@
|
|
|
100
100
|
"react-i18next": "^17.0.2",
|
|
101
101
|
"react-markdown": "^10.1.0",
|
|
102
102
|
"remark-gfm": "^4.0.1",
|
|
103
|
+
"ssh2": "^1.17.0",
|
|
103
104
|
"three": "^0.170.0",
|
|
104
105
|
"unzip-stream": "^0.3.4",
|
|
105
106
|
"ws": "^8.18.0"
|
|
@@ -120,6 +121,7 @@
|
|
|
120
121
|
"@types/prismjs": "^1.26.5",
|
|
121
122
|
"@types/react": "^19.2.8",
|
|
122
123
|
"@types/react-dom": "^19.2.3",
|
|
124
|
+
"@types/ssh2": "^1.15.5",
|
|
123
125
|
"@types/three": "^0.170.0",
|
|
124
126
|
"@types/unzip-stream": "^0.3.4",
|
|
125
127
|
"@types/ws": "^8.5.13",
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as a,z as an,B as Et,u as $t,E as sn,j as e,V as ln,G as rn,H as on,J as St,S as y,K as Mt,L as jt,M as Tt,N as ct,O as se,P as cn,s as h,U as Bt,W as Ft,X as dn,v as Pt,w as Lt,I as u,Y as un,m as pn,Z as mn,_ as Wt,$ as Ht,a0 as fn,a1 as hn,a2 as gn,a3 as xn,a4 as bn,a5 as _n,a6 as wn,a7 as vn,a8 as Cn,a9 as jn,aa as Rt,C as Nn,ab as kn,ac as yn,ad as An,ae as In,af as En,ag as Sn,ah as Mn,ai as Tn,aj as Pn,ak as Ln,al as Rn,am as Dn,an as zn,ao as On,ap as $n,aq as Bn}from"./main-BrZe9Zbd.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";function Fn(_){const c=a.useRef(_);c.current=_,a.useEffect(()=>{if(!an())return;let w=null,I=!1;return Et.addListener("backButton",()=>{c.current()==="exit"&&Et.exitApp()}).then(E=>{I?E.remove():w=E}),()=>{I=!0,w&&(w.remove(),w=null)}},[])}const Wn=a.memo(function({className:c=""}){const{t:w}=$t(["common"]),[I,E]=sn(),Y=a.useRef(null),[H,ie]=a.useState(null);a.useLayoutEffect(()=>{const C=Y.current;if(!C)return;const Z=C.querySelector(".view-mode-toggle__btn--active");Z&&ie({left:Z.offsetLeft,width:Z.offsetWidth})},[I]);const M=a.useCallback(C=>{if(C!==I){if(typeof window<"u"&&window.dispatchEvent(new CustomEvent("tide:viewmode-switch-pressed",{detail:{mode:C}})),C==="3d"){requestAnimationFrame(()=>E(C));return}E(C)}},[I,E]);return e.jsxs("div",{className:`view-mode-toggle ${c}`,ref:Y,children:[H&&e.jsx("div",{className:"view-mode-toggle__indicator",style:{left:H.left,width:H.width}}),ln.map(C=>e.jsxs("button",{className:`view-mode-toggle__btn ${I===C?"view-mode-toggle__btn--active":""}`,onClick:()=>M(C),title:w(`common:viewMode.descriptions.${C}`),children:[e.jsxs("span",{className:"view-mode-toggle__icon",children:[C==="2d"&&e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2"}),e.jsx("line",{x1:"3",y1:"12",x2:"21",y2:"12"}),e.jsx("line",{x1:"12",y1:"3",x2:"12",y2:"21"})]}),C==="3d"&&e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("path",{d:"M12 2L2 7l10 5 10-5-10-5z"}),e.jsx("path",{d:"M2 17l10 5 10-5"}),e.jsx("path",{d:"M2 12l10 5 10-5"})]}),C==="flat"&&e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"3",y:"3",width:"8",height:"8",rx:"1"}),e.jsx("rect",{x:"13",y:"3",width:"8",height:"8",rx:"1"}),e.jsx("rect",{x:"3",y:"13",width:"8",height:"8",rx:"1"}),e.jsx("rect",{x:"13",y:"13",width:"8",height:"8",rx:"1"})]}),C==="dashboard"&&e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"3",y:"3",width:"7",height:"9",rx:"1"}),e.jsx("rect",{x:"14",y:"3",width:"7",height:"5",rx:"1"}),e.jsx("rect",{x:"14",y:"12",width:"7",height:"9",rx:"1"}),e.jsx("rect",{x:"3",y:"16",width:"7",height:"5",rx:"1"})]})]}),e.jsx("span",{className:"view-mode-toggle__label",children:w(`common:viewMode.labels.${C}`)})]},C))]})}),dt=3,ut=280,Dt=320,Ct=240,zt=64,Hn=["simple","chat","advanced"],Vn={simple:"Simple",chat:"Chat",advanced:"Advanced"},Gn={simple:"○",chat:"◐",advanced:"◉"},Xn={simple:"Simple view — clean messages only",chat:"Chat view — assistant replies (no tool calls)",advanced:"Advanced view — everything including tools"},Ot="flat-clear-context";function Un(_){const c=_.split("/").filter(Boolean);return c.length===0?_:c.slice(-2).join("/")}function qn(_){if(_.provider==="codex"){const Y=_.codexModel||"gpt-5.3-codex",H=On[Y];return{model:(H==null?void 0:H.label)||Y}}if(_.provider==="opencode")return{model:_.opencodeModel||"opencode"};const c=_.model||"sonnet",w=Bn[c],I=_.effort,E=I?$n[I]:void 0;return{model:(w==null?void 0:w.label)||c,effort:E==null?void 0:E.label}}function Kn(_,c){if(c.type==="rectangle"&&c.width&&c.height){const w=c.width/2,I=c.height/2;return _.x>=c.center.x-w&&_.x<=c.center.x+w&&_.z>=c.center.z-I&&_.z<=c.center.z+I}if(c.type==="circle"&&c.radius){const w=_.x-c.center.x,I=_.z-c.center.z;return w*w+I*I<=c.radius*c.radius}return!1}const Yn=kn.memo(function({agentId:c,terminalViewMode:w,onTerminalViewModeChange:I,inspectorOpen:E,onToggleInspector:Y,onImageClick:H,onFileClick:ie,onBashClick:M,onViewMarkdown:C,onRequestClearSubordinates:Z,onOpenBuilding:Re,keyboard:Ve,canNavigateBack:Ge,canNavigateForward:De,onNavigateBack:le,onNavigateForward:z,agentInfoOpen:ye,onToggleAgentInfo:J}){var Me,ne,nt,F;const g=yn(c),P=Ft(),me=a.useRef(null),Ae=a.useRef(null);a.useEffect(()=>{const i=Ae.current;if(!i)return;const r=o=>{o.button===3?(o.preventDefault(),o.stopPropagation(),le()):o.button===4&&(o.preventDefault(),o.stopPropagation(),z())},d=o=>{(o.button===3||o.button===4)&&o.preventDefault()};return i.addEventListener("mouseup",r),i.addEventListener("mousedown",d),()=>{i.removeEventListener("mouseup",r),i.removeEventListener("mousedown",d)}},[le,z]),a.useEffect(()=>{const i=Ae.current;if(!i)return;let r=0,d=0,o=0;const Ce=250,Te=600,Pe=80,xt=1.5,K=O=>{let T=O instanceof HTMLElement?O:null;for(;T&&T!==i;){const We=window.getComputedStyle(T).overflowX;if((We==="auto"||We==="scroll")&&T.scrollWidth>T.clientWidth)return!0;T=T.parentElement}return!1},Le=O=>{const T=Date.now();if(T<o){O.preventDefault();return}if(Math.abs(O.deltaX)<=Math.abs(O.deltaY)*xt){r=0;return}if(K(O.target)){r=0;return}T-d>Ce&&(r=0),d=T,r+=O.deltaX,r<=-Pe?(r=0,o=T+Te,O.preventDefault(),le()):r>=Pe&&(r=0,o=T+Te,O.preventDefault(),z())};return i.addEventListener("wheel",Le,{passive:!1}),()=>i.removeEventListener("wheel",Le)},[le,z]);const fe=Bt(),ze=a.useMemo(()=>{if(!g)return null;const i=new Set,r=[];for(const d of fe.values())d.archived||d.directories.length===0||d.assignedAgentIds.includes(c)&&(i.add(d.id),r.push(d));for(const d of fe.values())d.archived||d.directories.length===0||i.has(d.id)||Kn({x:g.position.x,z:g.position.z},d)&&(i.add(d.id),r.push(d));return r.length===0?null:r.flatMap(d=>d.directories.filter(o=>o&&o.trim().length>0).map(o=>({areaId:d.id,areaName:d.name,dir:o})))},[g,c,fe]),{branches:Xe,fetchRemote:Ue,fetchingDirs:Oe}=An(ze),Ie=a.useMemo(()=>{var d;const i=h.getAreaForAgent(c);if(!i)return[];const r=[];for(const o of P.values())o.type==="terminal"&&h.isPositionInArea(o.position,i)&&r.push({id:o.id,name:o.name,hasUrl:!!((d=o.terminalStatus)!=null&&d.url)});return r},[c,P]),he=a.useMemo(()=>{var d;const i=h.getAreaForAgent(c);if(!i)return[];const r=[];for(const o of P.values())o.type==="server"&&((d=o.pm2)!=null&&d.enabled)&&h.isPositionInArea(o.position,i)&&r.push({id:o.id,name:o.name});return r},[c,P]),re=a.useMemo(()=>{const i=h.getAreaForAgent(c);if(!i)return[];const r=[];for(const d of P.values())d.type==="database"&&d.database&&h.isPositionInArea(d.position,i)&&r.push({id:d.id,name:d.name});return r},[c,P]),[,oe]=a.useReducer(i=>i+1,0),V=((Me=me.current)==null?void 0:Me.search.searchMode)??!1,pt=a.useCallback(()=>{var i;(i=me.current)==null||i.search.toggleSearch(),oe()},[]),qe=In(),ce=qe.isPending(Ot),[$,U]=a.useState(null),G=$?P.get($):null,{height:q,onResizeStart:Ee}=En(),[B,Q]=a.useState(()=>jt(y.GIT_PANEL_OPEN,!1)),[ge,Ke]=a.useState(()=>jt(y.BUILDINGS_PANEL_OPEN,!1)),[de,xe]=a.useState(!1),mt=a.useCallback(()=>{xe(i=>{const r=!i;return r&&Sn.setEnabled(!0),r})},[]),ft=a.useCallback(()=>xe(!1),[]),be=a.useCallback(()=>{Q(i=>{const r=!i;return se(y.GIT_PANEL_OPEN,r),r})},[]),ht=a.useCallback(()=>{Ke(i=>{const r=!i;return se(y.BUILDINGS_PANEL_OPEN,r),r})},[]),Ye=a.useCallback(()=>{Q(!1),se(y.GIT_PANEL_OPEN,!1)},[]),gt=a.useCallback(()=>{Ke(!1),se(y.BUILDINGS_PANEL_OPEN,!1)},[]),$e=Mn();a.useEffect(()=>{if(!$)return;Ie.some(r=>r.id===$)||U(null)},[$,Ie]);const[_e,ue]=a.useState(!1),Be=a.useRef(null);if(a.useEffect(()=>{if(!_e)return;const i=r=>{Be.current&&!Be.current.contains(r.target)&&ue(!1)};return document.addEventListener("mousedown",i),()=>document.removeEventListener("mousedown",i)},[_e]),!g)return e.jsx("div",{className:"flat-chat flat-chat--empty",children:e.jsxs("div",{className:"flat-chat__placeholder",children:[e.jsx("span",{className:"flat-chat__placeholder-icon",children:"💬"}),e.jsx("span",{className:"flat-chat__placeholder-text",children:"Select an agent to start chatting"})]})});const ee=g.contextStats,Ze=!!ee,Je=ee?ee.totalTokens:g.contextUsed||0,we=ee?ee.contextWindow:g.contextLimit||2e5,x=ee?ee.usedPercent:Math.round(Je/we*100),L=Math.max(0,Math.min(100,x)),X=Math.round(L*10)/10,Se=Math.round((100-L)*10)/10,Fe=L>=80?"#ff4a4a":L>=60?"#ff9e4a":L>=40?"#ffd700":"#4aff9e",Qe=(Je/1e3).toFixed(1),et=(we/1e3).toFixed(1),te=g.cwd,tt=te?Un(te):null,pe=((ne=g.subordinateIds)==null?void 0:ne.length)||0,ve=pe>0;return e.jsxs("div",{ref:Ae,className:`flat-terminal-wrapper ${B||ge||de?"flat-terminal-wrapper--with-side-panel":""}`,children:[e.jsxs("div",{className:"flat-terminal-wrapper__header",children:[e.jsxs("button",{type:"button",className:`flat-terminal-wrapper__header-main ${ye?"flat-terminal-wrapper__header-main--active":""}`,onClick:J,title:ye?"Hide agent info":"Show agent info","aria-pressed":ye,children:[e.jsx(Wt,{agent:g,size:28}),e.jsxs("span",{className:"flat-terminal-wrapper__header-info",children:[e.jsx("span",{className:"flat-terminal-wrapper__header-name",children:g.name}),e.jsx("span",{className:"flat-terminal-wrapper__header-status",style:{color:Ht(g.status)},children:g.status})]}),g.taskLabel&&e.jsxs("span",{className:"flat-terminal-wrapper__header-task",title:g.taskLabel,children:["📋 ",g.taskLabel]}),e.jsxs("span",{className:"flat-terminal-wrapper__header-model",children:[e.jsx("img",{src:g.provider==="codex"?"/assets/codex.png":g.provider==="opencode"?"/assets/opencode.png":"/assets/claude.png",alt:g.provider,className:"flat-terminal-wrapper__header-provider-icon",title:g.provider==="codex"?"Codex Agent":g.provider==="opencode"?"OpenCode Agent":"Claude Agent"}),(()=>{const{model:i,effort:r}=qn(g);return e.jsxs("span",{className:"flat-terminal-wrapper__header-model-chip",title:r?`Model: ${i} · Effort: ${r}`:`Model: ${i}`,children:[e.jsx("span",{className:"flat-terminal-wrapper__header-model-name",children:i}),r&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"flat-terminal-wrapper__header-model-sep","aria-hidden":"true",children:"·"}),e.jsx("span",{className:"flat-terminal-wrapper__header-model-effort",children:r})]})]})})()]})]}),e.jsxs("div",{className:"flat-terminal-wrapper__header-meta",children:[e.jsx("div",{className:"flat-terminal-wrapper__view-mode",role:"group","aria-label":"Message view mode",children:Hn.map(i=>e.jsxs("button",{type:"button",className:`flat-terminal-wrapper__view-mode-btn ${w===i?"flat-terminal-wrapper__view-mode-btn--active":""}`,onClick:()=>I(i),title:Xn[i],"aria-pressed":w===i,children:[e.jsx("span",{className:"flat-terminal-wrapper__view-mode-icon","aria-hidden":"true",children:Gn[i]}),e.jsx("span",{className:"flat-terminal-wrapper__view-mode-label",children:Vn[i]})]},i))}),e.jsxs("div",{className:"flat-terminal-wrapper__actions",role:"group","aria-label":"Terminal actions",children:[e.jsx("button",{type:"button",className:"flat-terminal-wrapper__action-btn",onClick:le,disabled:!Ge,title:"Back to previous agent","aria-label":"Back to previous agent",children:e.jsx(u,{name:"arrow-left",size:14})}),e.jsx("button",{type:"button",className:"flat-terminal-wrapper__action-btn",onClick:z,disabled:!De,title:"Forward to next agent","aria-label":"Forward to next agent",children:e.jsx(u,{name:"arrow-right",size:14})}),e.jsx("button",{type:"button",className:`flat-terminal-wrapper__action-btn ${V?"flat-terminal-wrapper__action-btn--active":""}`,onClick:pt,title:V?"Close search":"Search messages","aria-pressed":V,children:e.jsx(u,{name:V?"cross":"search",size:14})}),e.jsx("button",{type:"button",className:`flat-terminal-wrapper__action-btn flat-terminal-wrapper__action-btn--danger ${ce?"flat-terminal-wrapper__action-btn--confirm":""}`,onClick:()=>qe.handleClick(Ot,()=>{var i;h.clearContext(c),(i=me.current)==null||i.historyLoader.clearHistory()}),title:ce?"Click again to confirm clear context":"Clear context",children:e.jsx(u,{name:ce?"question":"clear",size:14})}),e.jsx("button",{type:"button",className:`flat-terminal-wrapper__action-btn ${B?"flat-terminal-wrapper__action-btn--active":""}`,onClick:be,title:B?"Hide git panel":"Show git changes","aria-pressed":B,children:e.jsx(u,{name:"git-branch",size:14})}),e.jsx("button",{type:"button",className:`flat-terminal-wrapper__action-btn ${ge?"flat-terminal-wrapper__action-btn--active":""}`,onClick:ht,title:ge?"Hide buildings panel":"Show area buildings","aria-pressed":ge,children:e.jsx(u,{name:"buildings",size:14})}),e.jsxs("div",{className:"flat-terminal-wrapper__more",ref:Be,children:[e.jsx("button",{type:"button",className:`flat-terminal-wrapper__action-btn ${_e?"flat-terminal-wrapper__action-btn--active":""}`,onClick:()=>ue(i=>!i),title:"More actions","aria-expanded":_e,children:"⋮"}),_e&&e.jsxs("div",{className:"flat-terminal-wrapper__more-menu",role:"menu",children:[e.jsxs("button",{type:"button",role:"menuitem",className:`flat-terminal-wrapper__more-item ${de?"flat-terminal-wrapper__more-item--active":""}`,onClick:()=>{mt(),ue(!1)},title:de?"Hide Debug Panel":"Show Debug Panel",children:[e.jsx(u,{name:"bug",size:14}),e.jsx("span",{children:de?"Hide Debug Panel":"Show Debug Panel"})]}),e.jsx("div",{className:"flat-terminal-wrapper__more-divider"}),e.jsxs("button",{type:"button",role:"menuitem",className:"flat-terminal-wrapper__more-item",onClick:()=>{h.collapseContext(c),ue(!1)},disabled:g.status!=="idle",title:g.status!=="idle"?"Agent must be idle to collapse context":"Collapse context",children:[e.jsx(u,{name:"package",size:14}),e.jsx("span",{children:"Collapse context"})]}),ve&&e.jsxs("button",{type:"button",role:"menuitem",className:"flat-terminal-wrapper__more-item flat-terminal-wrapper__more-item--danger",onClick:()=>{Z(c,pe),ue(!1)},children:[e.jsx(u,{name:"crown",size:14}),e.jsxs("span",{children:["Clear ",pe," subordinate",pe===1?"":"s"]})]}),e.jsx("div",{className:"flat-terminal-wrapper__more-divider"}),e.jsxs("button",{type:"button",role:"menuitem",className:"flat-terminal-wrapper__more-item flat-terminal-wrapper__more-item--danger",onClick:()=>{h.killAgent(c),ue(!1)},children:[e.jsx(u,{name:"cross",size:14}),e.jsx("span",{children:"Remove agent"})]})]})]})]}),e.jsxs("button",{type:"button",className:`flat-terminal-wrapper__inspector-toggle ${E?"flat-terminal-wrapper__inspector-toggle--active":""}`,onClick:Y,title:E?"Hide inspector panel":"Show inspector panel","aria-label":E?"Hide inspector panel":"Show inspector panel","aria-pressed":E,children:[e.jsx("span",{className:"flat-terminal-wrapper__inspector-icon","aria-hidden":"true",children:e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("rect",{x:"1.5",y:"2.5",width:"13",height:"11",rx:"1.5"}),e.jsx("line",{x1:"10",y1:"2.5",x2:"10",y2:"13.5"})]})}),e.jsx("span",{className:"flat-terminal-wrapper__inspector-label",children:"Inspector"})]}),e.jsx("button",{type:"button",className:"flat-terminal-wrapper__close",onClick:()=>h.deselectAll(),title:"Close chat","aria-label":"Close chat",children:e.jsx(u,{name:"cross",size:14})})]})]}),e.jsx(Tn,{ref:me,agentId:c,agent:g,viewMode:w,isOpen:!0,onImageClick:H,onFileClick:ie,onBashClick:M,onViewMarkdown:C,keyboard:Ve,hasModalOpen:!1}),G&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"guake-bottom-terminal-resize",onMouseDown:Ee,role:"separator","aria-orientation":"horizontal","aria-label":"Resize embedded terminal"}),e.jsxs("div",{className:"flat-bottom-panel",role:"region","aria-label":`Embedded terminal: ${G.name}`,style:{height:q},children:[e.jsxs("div",{className:"flat-bottom-panel__header",children:[e.jsxs("span",{className:"flat-bottom-panel__title",children:[e.jsx(u,{name:"terminal",size:12}),e.jsx("span",{children:G.name}),!((nt=G.terminalStatus)!=null&&nt.url)&&e.jsx("span",{className:"flat-bottom-panel__muted",children:"(starting...)"})]}),e.jsx("button",{type:"button",className:"flat-bottom-panel__close",onClick:()=>U(null),title:"Close embedded terminal","aria-label":"Close embedded terminal",children:e.jsx(u,{name:"cross",size:12})})]}),e.jsx("div",{className:"flat-bottom-panel__body",children:(F=G.terminalStatus)!=null&&F.url?e.jsx(Pn,{terminalUrl:G.terminalStatus.url,visible:!0}):e.jsx("div",{className:"flat-bottom-panel__placeholder",children:"Starting terminal..."})})]})]}),e.jsxs("div",{className:"flat-terminal-wrapper__statusbar",role:"contentinfo",children:[g.isDetached&&e.jsxs("span",{className:"flat-terminal-wrapper__detached",title:"Reattaching session...",children:[e.jsx(u,{name:"refresh",size:12}),e.jsx("span",{children:"Reattaching"})]}),te&&tt&&e.jsxs("span",{className:"flat-terminal-wrapper__cwd",title:`Open in file explorer: ${te}`,"aria-label":`Open ${te} in file explorer`,role:"button",tabIndex:0,onClick:()=>h.openFileExplorer(te),onKeyDown:i=>{(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),h.openFileExplorer(te))},children:[e.jsx("span",{className:"flat-terminal-wrapper__cwd-icon",children:e.jsx(u,{name:"folder",size:12})}),e.jsx("span",{className:"flat-terminal-wrapper__cwd-text",children:tt})]}),ze&&ze.map(({areaId:i,areaName:r,dir:d})=>{const o=Xe.get(d),Ce=Oe.has(d),Te=d.split("/").filter(Boolean).pop()||d;return e.jsxs("span",{className:"flat-terminal-wrapper__area-dir",title:`${r}: ${d}${o?` (${o.branch}${o.ahead?` ↑${o.ahead}`:""}${o.behind?` ↓${o.behind}`:""})`:""}`,onClick:()=>h.openFileExplorerForAreaFolder(i,d),children:[e.jsx(u,{name:"folder-open",size:12}),e.jsx("span",{className:"flat-terminal-wrapper__area-dir-name",children:Te}),o&&e.jsxs(e.Fragment,{children:[e.jsxs("span",{className:"flat-terminal-wrapper__area-dir-branch",children:[e.jsx(u,{name:"git-branch",size:10})," ",o.branch]}),o.ahead>0&&e.jsxs("span",{className:"flat-terminal-wrapper__branch-ahead",title:`${o.ahead} ahead`,children:[e.jsx(u,{name:"arrow-up",size:9}),o.ahead]}),o.behind>0&&e.jsxs("span",{className:"flat-terminal-wrapper__branch-behind",title:`${o.behind} behind`,children:[e.jsx(u,{name:"arrow-down",size:9}),o.behind]}),e.jsx("span",{className:`flat-terminal-wrapper__area-fetch ${Ce?"flat-terminal-wrapper__area-fetch--fetching":""}`,title:"Git fetch",onClick:Pe=>{Pe.stopPropagation(),Ue(d)},children:e.jsx(u,{name:Ce?"hourglass":"download",size:12})})]})]},`${i}:${d}`)}),e.jsxs("span",{className:"flat-terminal-wrapper__context",onClick:()=>h.setContextModalAgentId(c),title:Ze?`Context usage: ${Qe}k / ${et}k tokens (${X}% used). Click to view stats.`:"Click to fetch context stats",children:[e.jsx("span",{className:"flat-terminal-wrapper__context-icon",children:e.jsx(u,{name:"dashboard",size:12})}),e.jsx("span",{className:"flat-terminal-wrapper__context-label",children:"Ctx:"}),e.jsx("span",{className:"flat-terminal-wrapper__context-bar",children:e.jsx("span",{className:"flat-terminal-wrapper__context-bar-fill",style:{width:`${L}%`,backgroundColor:Fe}})}),e.jsxs("span",{className:"flat-terminal-wrapper__context-tokens",style:{color:Fe},children:[Qe,"k/",et,"k"]}),e.jsxs("span",{className:"flat-terminal-wrapper__context-free",children:["(",Se,"% free)"]}),!Ze&&e.jsx("span",{className:"flat-terminal-wrapper__context-warning",title:"No context stats yet",children:e.jsx(u,{name:"warn",size:12})})]}),e.jsx("div",{className:"flat-terminal-wrapper__statusbar-spacer","aria-hidden":"true"}),Ie.length>0&&e.jsx("span",{className:"flat-terminal-wrapper__buildings",role:"group","aria-label":"Area terminals",children:Ie.map(i=>{const r=$===i.id;return e.jsx("button",{type:"button",className:`flat-terminal-wrapper__building-btn ${r?"flat-terminal-wrapper__building-btn--active":""} ${i.hasUrl?"":"flat-terminal-wrapper__building-btn--offline"}`,title:`${r?"Hide":"Show"} terminal: ${i.name}${i.hasUrl?"":" (starting...)"}`,onClick:()=>{if(r){U(null);return}i.hasUrl||h.sendBuildingCommand(i.id,"start"),U(i.id)},children:e.jsx(u,{name:"terminal",size:14})},i.id)})}),he.length>0&&e.jsx("span",{className:"flat-terminal-wrapper__buildings",role:"group","aria-label":"Area PM2 logs",children:he.map(i=>e.jsx("button",{type:"button",className:"flat-terminal-wrapper__building-btn",title:`Open logs: ${i.name}`,onClick:()=>Re(i.id),children:e.jsx(u,{name:"scroll",size:14})},i.id))}),re.length>0&&e.jsx("span",{className:"flat-terminal-wrapper__buildings",role:"group","aria-label":"Area databases",children:re.map(i=>e.jsx("button",{type:"button",className:"flat-terminal-wrapper__building-btn",title:`Open database: ${i.name}`,onClick:()=>Re(i.id),children:e.jsx(u,{name:"hard-drives",size:14})},i.id))}),e.jsx("div",{className:"flat-terminal-wrapper__theme",children:e.jsx(Ln,{})})]}),B&&e.jsx(Rn,{agentId:c,agents:$e,onClose:Ye,branchInfoMap:Xe,fetchRemote:Ue,fetchingDirs:Oe}),ge&&e.jsx(Dn,{agentId:c,onClose:gt}),de&&e.jsx(zn,{agentId:c,onClose:ft})]})});function ea({onAgentClick:_,onBuildingClick:c,onBuildingDoubleClick:w,onBuildingPopup:I,onOpenSpawnModal:E,onOpenBossSpawnModal:Y,onOpenAreaModal:H}){const{t:ie}=$t(["common"]),M=rn(),C=on(),[Z,Re]=a.useState(null),[Ve,Ge]=a.useState(null),[De,le]=a.useState(null),[z,ye]=a.useState(null),[J,g]=a.useState(null),[P,me]=a.useState(null),[Ae,fe]=a.useState(!1),ze=a.useCallback(()=>{fe(t=>!t)},[]),Xe=a.useCallback(()=>{fe(!1)},[]),[Ue,Oe]=a.useState(()=>{const t=St(y.VIEW_MODE);return t==="simple"||t==="chat"||t==="advanced"?t:"simple"}),Ie=a.useCallback(t=>{Oe(t),Mt(y.VIEW_MODE,t)},[]);a.useEffect(()=>{const t=n=>{if(n.key!==y.VIEW_MODE)return;const s=n.newValue;(s==="simple"||s==="chat"||s==="advanced")&&Oe(s)};return window.addEventListener("storage",t),()=>window.removeEventListener("storage",t)},[]);const[he,re]=a.useState(()=>jt(y.FLAT_INSPECTOR_OPEN,!1)),[oe,V]=a.useState(!1),pt=a.useCallback(()=>V(t=>!t),[]),qe=a.useCallback(()=>V(!1),[]);a.useEffect(()=>{window.dispatchEvent(new CustomEvent("tide-flat-agents-drawer-state",{detail:{open:oe}}))},[oe]),a.useEffect(()=>{window.dispatchEvent(new CustomEvent("tide-flat-inspector-state",{detail:{open:he}}))},[he]),a.useEffect(()=>{const t=()=>V(b=>!b),n=()=>{re(b=>{const l=!b;return se(y.FLAT_INSPECTOR_OPEN,l),l})},s=()=>{V(!1),re(!1),se(y.FLAT_INSPECTOR_OPEN,!1)},p=()=>V(!1),m=()=>{re(!1),se(y.FLAT_INSPECTOR_OPEN,!1)};return window.addEventListener("tide-toggle-flat-agents-drawer",t),window.addEventListener("tide-toggle-flat-inspector",n),window.addEventListener("tide-close-flat-side-views",s),window.addEventListener("tide-close-flat-agents-drawer-only",p),window.addEventListener("tide-close-flat-inspector-only",m),()=>{window.removeEventListener("tide-toggle-flat-agents-drawer",t),window.removeEventListener("tide-toggle-flat-inspector",n),window.removeEventListener("tide-close-flat-side-views",s),window.removeEventListener("tide-close-flat-agents-drawer-only",p),window.removeEventListener("tide-close-flat-inspector-only",m)}},[]);const ce=a.useRef(null),$=a.useRef(null),[U,G]=a.useState(()=>{const t=Tt(y.FLAT_MIDDLE_WIDTH,0);return t>=ut?t:null}),[q,Ee]=a.useState(()=>{const t=Tt(y.FLAT_INSPECTOR_WIDTH,0);return t>=Ct?t:null}),B=a.useCallback(t=>{if(typeof window>"u")return t;const n=q!==null?dt+q:0,s=window.innerWidth-zt-dt-Dt-n;return Math.max(ut,Math.min(Math.max(s,ut),t))},[q]),Q=a.useCallback(t=>{var m;if(typeof window>"u")return t;const n=(m=ce.current)==null?void 0:m.querySelector(".flat-middle"),s=(n==null?void 0:n.getBoundingClientRect().width)??ut,p=window.innerWidth-zt-s-dt-Dt-dt;return Math.max(Ct,Math.min(Math.max(p,Ct),t))},[]);a.useEffect(()=>{if(U===null&&q===null)return;const t=()=>{G(n=>{if(n===null)return n;const s=B(n);return s===n?n:s}),Ee(n=>{if(n===null)return n;const s=Q(n);return s===n?n:s})};return window.addEventListener("resize",t),()=>window.removeEventListener("resize",t)},[U,q,B,Q]);const ge=a.useCallback(t=>{var s;if(t.button!==0)return;const n=(s=ce.current)==null?void 0:s.querySelector(".flat-middle");n&&(t.currentTarget.setPointerCapture(t.pointerId),$.current={kind:"middle",startX:t.clientX,startWidth:n.getBoundingClientRect().width,pointerId:t.pointerId},document.body.classList.add("flat-splitter-dragging"))},[]),Ke=a.useCallback(t=>{var s;if(t.button!==0)return;const n=(s=ce.current)==null?void 0:s.querySelector(".flat-inspector");n&&(t.currentTarget.setPointerCapture(t.pointerId),$.current={kind:"inspector",startX:t.clientX,startWidth:n.getBoundingClientRect().width,pointerId:t.pointerId},document.body.classList.add("flat-splitter-dragging"))},[]),de=a.useCallback(t=>{const n=$.current;if(!n||t.pointerId!==n.pointerId)return;const s=t.clientX-n.startX;n.kind==="middle"?G(B(n.startWidth+s)):Ee(Q(n.startWidth-s))},[B,Q]),xe=a.useCallback(t=>{const n=$.current;if(!n||t.pointerId!==n.pointerId)return;try{t.currentTarget.releasePointerCapture(t.pointerId)}catch{}if($.current=null,document.body.classList.remove("flat-splitter-dragging"),!(Math.abs(t.clientX-n.startX)>2))return;const p=t.clientX-n.startX;if(n.kind==="middle"){const m=B(n.startWidth+p);G(m),ct(y.FLAT_MIDDLE_WIDTH,m)}else{const m=Q(n.startWidth-p);Ee(m),ct(y.FLAT_INSPECTOR_WIDTH,m)}},[B,Q]),mt=a.useCallback(()=>{G(null),ct(y.FLAT_MIDDLE_WIDTH,0)},[]),ft=a.useCallback(()=>{Ee(null),ct(y.FLAT_INSPECTOR_WIDTH,0)},[]),[be,ht]=a.useState(()=>St(y.FLAT_INSPECTOR_VIEW)==="tracking"?"tracking":"agent"),Ye=a.useCallback(t=>{ht(t),Mt(y.FLAT_INSPECTOR_VIEW,t)},[]),gt=a.useCallback(()=>{re(t=>{const n=!t;return se(y.FLAT_INSPECTOR_OPEN,n),n})},[]),$e=a.useCallback(()=>{re(!1),se(y.FLAT_INSPECTOR_OPEN,!1)},[]),_e=cn(),ue=a.useCallback((t,n)=>{Re({url:t,name:n})},[]),Be=a.useCallback((t,n)=>{Ge({command:t,output:n,isLive:!1})},[]),ee=a.useCallback((t,n)=>{h.setFileViewerPath(t,n)},[]),Ze=a.useCallback(t=>{},[]),Je=a.useCallback((t,n)=>{le({agentId:t,count:n})},[]),we=a.useCallback(t=>{w?w(t):c(t)},[c,w]),x=a.useMemo(()=>C.size>0?Array.from(C)[0]:null,[C]);a.useEffect(()=>{fe(!1)},[x]);const L=a.useRef([]),X=a.useRef(-1),Se=a.useRef(!1),Fe=a.useRef(null),[Qe,et]=a.useState(!1),[te,tt]=a.useState(!1),pe=a.useRef(!1),ve=a.useRef(null),Me=a.useRef(!1),ne=a.useMemo(()=>new Set(M.map(t=>t.id)),[M]),nt=a.useMemo(()=>{const t=new Map(M.map(s=>[s.id,s])),n=new Map;for(const s of M)if((s.isBoss||s.class==="boss")&&s.subordinateIds&&s.subordinateIds.length>0){const p=s.subordinateIds.map(m=>t.get(m)).filter(m=>m!==void 0);p.length>0&&n.set(s.id,p)}return n},[M]),F=a.useCallback(()=>{const t=L.current,n=X.current;et(n>0),tt(n>=0&&n<t.length-1)},[]),i=a.useCallback(t=>{const n=L.current;if(n.length===0)return;let s=X.current+t;for(;s>=0&&s<n.length;){const p=n[s];if(ne.has(p)){Se.current=!0,X.current=s,F(),h.selectAgent(p);return}s+=t}},[ne,F]),r=a.useCallback(()=>i(-1),[i]),d=a.useCallback(()=>i(1),[i]);Fn(a.useCallback(()=>{const t=L.current,n=X.current;return t.length>0&&n>0?(i(-1),"handled"):"exit"},[i]));const o=a.useCallback((t,n)=>{if(typeof window>"u")return;const s=window.history.state,m={...typeof s=="object"&&s!==null?s:{},__flatAgentNav:{agentId:t}};n==="replace"?window.history.replaceState(m,"",window.location.href):window.history.pushState(m,"",window.location.href)},[]);a.useEffect(()=>{if(!x){pe.current=!1,ve.current=null;return}if(!pe.current){o(x,"replace"),pe.current=!0,ve.current=x;return}if(Me.current){Me.current=!1,ve.current=x;return}ve.current!==x&&(o(x,"push"),ve.current=x)},[x,o]),a.useEffect(()=>{const t=n=>{var b,l;const s=(l=(b=n.state)==null?void 0:b.__flatAgentNav)==null?void 0:l.agentId;if(!s||typeof s!="string"||!ne.has(s)||s===x)return;Me.current=!0,Se.current=!0;const p=L.current,m=p.lastIndexOf(s);m>=0?X.current=m:(p.push(s),X.current=p.length-1),F(),h.selectAgent(s)};return window.addEventListener("popstate",t),()=>window.removeEventListener("popstate",t)},[ne,x,F]),a.useEffect(()=>{if(!x){L.current=[],X.current=-1,F();return}if(Fe.current=x,Se.current){Se.current=!1,F();return}const t=L.current,n=X.current;if(n>=0&&t[n]===x){F();return}const s=n<t.length-1?t.slice(0,n+1):t.slice();s.push(x),s.length>100&&s.shift(),L.current=s,X.current=s.length-1,F()},[x,F]);const Ce=a.useCallback(t=>{_(t),V(!1)},[_]),Te=x??"",Pe=a.useCallback(()=>{},[]),xt=a.useCallback(t=>{Ce(t)},[Ce]),K=he,[Le,O]=a.useState(K),[T,We]=a.useState(K);a.useEffect(()=>{if(K){O(!0);return}We(!1);const t=setTimeout(()=>O(!1),240);return()=>clearTimeout(t)},[K]),a.useEffect(()=>{if(!Le||!K)return;let t=0;const n=requestAnimationFrame(()=>{t=requestAnimationFrame(()=>We(!0))});return()=>{cancelAnimationFrame(n),cancelAnimationFrame(t)}},[Le,K]);const Nt=a.useRef(null);a.useEffect(()=>{if(x)return;const t=n=>{if(n.key!==" "&&n.key!=="Backspace")return;const s=n.target;if(s.tagName==="INPUT"||s.tagName==="TEXTAREA"||s.isContentEditable)return;const p=Fe.current;!p||!ne.has(p)||(n.preventDefault(),h.selectAgent(p))};return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[x,ne]);const[Vt,kt]=a.useState(new Set),Gt=a.useCallback(t=>{kt(n=>{const s=new Set(n);return s.has(t)?s.delete(t):s.add(t),s})},[]),[je,Xt]=a.useState(()=>typeof window<"u"&&window.matchMedia("(max-width: 768px)").matches);a.useEffect(()=>{if(typeof window>"u")return;const t=window.matchMedia("(max-width: 768px)"),n=s=>Xt(s.matches);return t.addEventListener("change",n),()=>t.removeEventListener("change",n)},[]);const[at,Ut]=a.useState(null),qt=a.useCallback(t=>{Ut(n=>n===t?null:t)},[]),bt=Bt(),st=Ft(),[Kt]=dn(),Ne=a.useMemo(()=>{const t=new Map,n=[];for(const f of M){const k=h.getAreaForAgent(f.id);if(!Pt((k==null?void 0:k.id)??null))continue;if(!k||k.archived){n.push(f);continue}const j=t.get(k.id);j?j.push(f):t.set(k.id,[f])}const s=new Map,p=[];for(const f of st.values()){let k=!1;for(const j of bt.values())if(!j.archived&&Lt(j.id)&&h.isPositionInArea(f.position,j)){const ae=s.get(j.id);ae?ae.push(f):s.set(j.id,[f]),k=!0;break}!k&&Pt(null)&&p.push(f)}const m=[];for(const[,f]of bt){if(f.archived||!Lt(f.id))continue;const k=t.get(f.id),j=s.get(f.id)??[];(k&&k.length>0||j.length>0)&&m.push({area:f,agents:k??[],buildings:j})}(n.length>0||p.length>0)&&m.push({area:{id:"__unassigned__",name:"Unassigned",color:"#6272a4",center:{x:0,z:0},type:"circle",radius:0,directories:[],archived:!1,assignedAgentIds:[],zIndex:0},agents:n,buildings:p});const b=m.filter(f=>f.area.id!=="__unassigned__"),l=m.filter(f=>f.area.id==="__unassigned__");let A=1,N=1;const W=new Map;if(b.length>1){let f=1/0,k=-1/0,j=1/0,ae=-1/0;for(const R of b)f=Math.min(f,R.area.center.x),k=Math.max(k,R.area.center.x),j=Math.min(j,R.area.center.z),ae=Math.max(ae,R.area.center.z);const lt=k-f||1,rt=ae-j||1;if(b.length<=4){A=b.length,N=1;const R=[...b].sort((D,_t)=>D.area.center.x-_t.area.center.x);for(let D=0;D<R.length;D++)W.set(R[D].area.id,{row:1,col:D+1})}else{const R=[...b].sort((v,S)=>v.area.center.x-S.area.center.x),D=[];for(let v=1;v<R.length;v++)D.push(R[v].area.center.x-R[v-1].area.center.x);const _t=D.reduce((v,S)=>v+S,0)/D.length||1;let yt=1;for(const v of D)v>_t*1.3&&yt++;A=Math.max(2,Math.min(yt,b.length));const wt=[...b].sort((v,S)=>v.area.center.z-S.area.center.z),ot=[];for(let v=1;v<wt.length;v++)ot.push(wt[v].area.center.z-wt[v-1].area.center.z);const Qt=ot.reduce((v,S)=>v+S,0)/ot.length||1;let At=1;for(const v of ot)v>Qt*1.3&&At++;N=Math.max(2,Math.min(At,b.length)),A=Math.max(A,Math.ceil(b.length/N)),N=Math.max(N,Math.ceil(b.length/A));const en=lt/A,tn=rt/N,vt=new Set;for(const v of b){let S=Math.min(A-1,Math.max(0,Math.floor((v.area.center.x-f)/en))),ke=Math.min(N-1,Math.max(0,Math.floor((v.area.center.z-j)/tn))),He=`${ke},${S}`,It=0;const nn=N*A;for(;vt.has(He)&&It<nn;)S++,S>=A&&(S=0,ke=(ke+1)%N),He=`${ke},${S}`,It++;vt.has(He)&&(ke=N,S=0,He=`${ke},${S}`,N++),vt.add(He),W.set(v.area.id,{row:ke+1,col:S+1})}}}const it=f=>{f.sort((k,j)=>{var lt,rt,R,D;const ae=(((lt=k.position)==null?void 0:lt.z)??0)-(((rt=j.position)==null?void 0:rt.z)??0);return ae!==0?ae:(((R=k.position)==null?void 0:R.x)??0)-(((D=j.position)==null?void 0:D.x)??0)})};for(const f of b)it(f.agents);for(const f of l)it(f.agents);return{groups:[...b,...l],gridCols:A,gridRows:N,positions:W}},[M,bt,st,Kt]),Yt=a.useMemo(()=>{if(!z)return[];const t=M.find(n=>n.id===z.agentId);return t?[{id:"edit-agent",label:"Edit Agent",icon:e.jsx(u,{name:"edit",size:14}),onClick:()=>{window.dispatchEvent(new CustomEvent("tide:open-agent-edit",{detail:{agentId:t.id}}))}},{id:"open-chat",label:"Open Chat",icon:e.jsx(u,{name:"chat",size:14}),onClick:()=>_(t.id)},{id:"delete-agent",label:"Delete Agent",icon:e.jsx(u,{name:"trash",size:14}),danger:!0,onClick:()=>{me({agentId:t.id,name:t.name})}}]:[]},[z,M,_]),Zt=a.useMemo(()=>{var b;if(!J)return[];const t=st.get(J.buildingId);if(!t)return[];const n=[],s=t.type==="server"||t.type==="docker"||t.type==="terminal",p=t.status==="running",m=t.type==="boss";if(n.push({id:"open",label:t.type==="database"?"Open Database":t.type==="folder"?"Open Folder":t.type==="boss"?"View Boss Logs":t.type==="terminal"?"Open Terminal":t.type==="server"&&((b=t.pm2)!=null&&b.enabled)?"View PM2 Logs":"Open",icon:e.jsx(u,{name:t.type==="database"?"database":t.type==="folder"?"folder":t.type==="terminal"?"terminal":"eye",size:14}),onClick:()=>we(t.id)}),s&&(p||n.push({id:"start",label:"Start",icon:e.jsx(u,{name:"play",size:14}),onClick:()=>h.sendBuildingCommand(t.id,"start")}),p&&(n.push({id:"restart",label:"Restart",icon:e.jsx(u,{name:"refresh",size:14}),onClick:()=>h.sendBuildingCommand(t.id,"restart")}),n.push({id:"stop",label:"Stop",icon:e.jsx(u,{name:"stop",size:14}),onClick:()=>h.sendBuildingCommand(t.id,"stop")}))),m&&t.subordinateBuildingIds&&t.subordinateBuildingIds.length>0&&(n.push({id:"start-all",label:"Start All Subordinates",icon:e.jsx(u,{name:"launch",size:14}),onClick:()=>{for(const l of t.subordinateBuildingIds)h.sendBuildingCommand(l,"start")}}),n.push({id:"stop-all",label:"Stop All Subordinates",icon:e.jsx(u,{name:"pause",size:14}),onClick:()=>{for(const l of t.subordinateBuildingIds)h.sendBuildingCommand(l,"stop")}}),n.push({id:"restart-all",label:"Restart All Subordinates",icon:e.jsx(u,{name:"restart",size:14}),onClick:()=>{for(const l of t.subordinateBuildingIds)h.sendBuildingCommand(l,"restart")}})),s&&n.push({id:"health-check",label:"Health Check",icon:e.jsx(u,{name:"health",size:14}),onClick:()=>h.sendBuildingCommand(t.id,"healthCheck")}),n.push({id:"divider-edit",label:"",divider:!0,onClick:()=>{}}),n.push({id:"edit",label:"Edit Building",icon:e.jsx(u,{name:"edit",size:14}),onClick:()=>{window.dispatchEvent(new CustomEvent("tide:building-edit",{detail:{buildingId:t.id}}))}}),n.push({id:"clone",label:"Clone Building",icon:e.jsx(u,{name:"copy",size:14}),onClick:()=>{h.createBuilding({name:`${t.name} (Copy)`,type:t.type,style:t.style,color:t.color,scale:t.scale,position:{x:t.position.x+2,z:t.position.z+2},cwd:t.cwd,folderPath:t.folderPath,commands:t.commands,pm2:t.pm2,docker:t.docker,database:t.database,terminal:t.terminal,urls:t.urls,subordinateBuildingIds:t.subordinateBuildingIds})}}),t.urls&&t.urls.length>0)for(const l of t.urls)n.push({id:`url-${l.label}`,label:l.label,icon:e.jsx(u,{name:"link",size:14}),onClick:()=>window.open(l.url,"_blank","noopener,noreferrer")});return n.push({id:"divider-danger",label:"",divider:!0,onClick:()=>{}}),n.push({id:"delete",label:"Delete Building",icon:e.jsx(u,{name:"trash",size:14}),danger:!0,onClick:()=>h.deleteBuilding(t.id)}),n},[J,st,we]),Jt=a.useCallback(t=>{const n=new Set(Ne.groups.map(s=>s.area.id));n.delete(t),kt(n),requestAnimationFrame(()=>{const s=Nt.current;if(!s)return;const p=s.querySelector(`[data-area-id="${t}"]`);if(!p)return;const m=s.getBoundingClientRect(),l=p.getBoundingClientRect().top-m.top+s.scrollTop-8;s.scrollTo({top:Math.max(0,l),behavior:"smooth"})})},[Ne]);return e.jsxs("div",{ref:ce,className:`flat-view ${K?"flat-view--with-inspector":""} ${x?"flat-view--has-chat":""} ${oe?"flat-view--mobile-sidebar-open":""}`,style:(()=>{if(U===null&&q===null)return;const t={};return U!==null&&(t["--flat-middle-width"]=`${U}px`),q!==null&&(t["--flat-inspector-width"]=`${q}px`),t})(),children:[oe&&e.jsx("div",{className:"flat-mobile-sidebar-backdrop",onClick:qe,"aria-hidden":"true"}),e.jsxs("div",{className:"flat-middle",children:[e.jsx("div",{className:"flat-middle__header",children:e.jsxs("div",{className:"flat-middle__actions",children:[e.jsx("button",{className:"flat-cta-btn flat-cta-btn--agent",onClick:E,title:"Create new agent",children:"+ Agent"}),e.jsx("button",{className:"flat-cta-btn flat-cta-btn--boss",onClick:Y,title:"Create new boss agent",children:"+ Boss"}),e.jsx("button",{className:"flat-cta-btn flat-cta-btn--area",onClick:H,title:"Create new area",children:"+ Area"})]})}),e.jsx("div",{className:"flat-middle__content",children:e.jsx(un,{activeAgentId:Te,onClose:Pe,onSelectAgent:xt,collapsedAreas:Vt,onToggleArea:Gt,agentListRef:Nt})})]}),e.jsx("div",{className:"flat-splitter flat-splitter--middle",role:"separator","aria-orientation":"vertical","aria-label":"Resize agents panel",title:"Drag to resize · Double-click to reset",onPointerDown:ge,onPointerMove:de,onPointerUp:xe,onPointerCancel:xe,onDoubleClick:mt}),e.jsxs("div",{className:"flat-right",children:[e.jsxs("button",{type:"button",className:"flat-mobile-sidebar-toggle","aria-label":oe?"Close agents sidebar":"Open agents sidebar","aria-expanded":oe,onClick:pt,children:[e.jsx(u,{name:"list",size:18}),e.jsx("span",{className:"flat-mobile-sidebar-toggle__label",children:"Agents"})]}),x?e.jsx(Yn,{agentId:x,terminalViewMode:Ue,onTerminalViewModeChange:Ie,inspectorOpen:he,onToggleInspector:gt,onImageClick:ue,onFileClick:ee,onBashClick:Be,onViewMarkdown:Ze,onRequestClearSubordinates:Je,onOpenBuilding:we,keyboard:_e,canNavigateBack:Qe,canNavigateForward:te,onNavigateBack:r,onNavigateForward:d,agentInfoOpen:Ae,onToggleAgentInfo:ze}):e.jsx("div",{className:"flat-chat flat-chat--empty",children:e.jsxs("div",{className:"flat-map",children:[e.jsxs("div",{className:"flat-map__header",children:[e.jsx("span",{className:"flat-map__title",children:"🗺️ Areas"}),e.jsx("span",{className:"flat-map__hint",children:"Click an area to focus it, or an agent to chat"}),e.jsx(Wn,{className:"flat-map__view-mode"})]}),e.jsx("div",{className:"flat-map__grid",style:{gridTemplateColumns:`repeat(${Ne.gridCols}, 1fr)`},children:Ne.groups.length===0?e.jsx("div",{className:"flat-map__empty",children:e.jsx("span",{children:"No areas or agents yet"})}):(()=>{var n;const t=je&&at?((n=Ne.positions.get(at))==null?void 0:n.row)??null:null;return Ne.groups.map(s=>{const p=s.area.id,m=Ne.positions.get(p),b=je&&at!==p;return je&&t!=null&&(m==null?void 0:m.row)===t&&p!==at?null:e.jsxs("div",{className:`flat-map-area-card${b?" flat-map-area-card--collapsed":""}`,style:{"--area-color":s.area.color,gridRow:m==null?void 0:m.row,gridColumn:m==null?void 0:m.col},children:[e.jsxs("button",{type:"button",className:"flat-map-area-card__header",onClick:()=>je?qt(p):Jt(p),title:je?b?`Expand ${s.area.name}`:`Collapse ${s.area.name}`:`Focus ${s.area.name} in left panel`,"aria-expanded":je?!b:void 0,children:[e.jsx("span",{className:"flat-map-area-card__color",style:{background:s.area.color}}),e.jsx("span",{className:"flat-map-area-card__name",children:s.area.name}),e.jsx("span",{className:"flat-map-area-card__count",children:s.agents.length}),je&&e.jsx(u,{name:b?"caret-down":"caret-up",size:11,className:"flat-map-area-card__caret"})]}),e.jsx("div",{className:"flat-map-area-card__agents",children:s.agents.map(l=>{const A=l.isBoss||l.class==="boss",N=A?nt.get(l.id):void 0,W=pn(l),it=W.usedPercent>=80?"#ff4a4a":W.usedPercent>=60?"#ff9e4a":W.usedPercent>=40?"#ffd700":"#4aff9e",f=`Context: ${(W.totalTokens/1e3).toFixed(1)}k / ${(W.contextWindow/1e3).toFixed(1)}k (${W.usedPercent}% used, ${W.freePercent}% free)`,k=l.latestTodos&&l.latestTodos.length>0||N&&N.length>0;return e.jsx(mn,{todos:l.latestTodos,subordinates:N,position:"top",children:e.jsxs("button",{type:"button",className:`flat-map-agent-chip ${l.status}`,onClick:()=>_(l.id),onContextMenu:j=>{j.preventDefault(),j.stopPropagation(),ye({agentId:l.id,position:{x:j.clientX,y:j.clientY}})},title:k?void 0:`${A?"Boss · ":""}Open chat with ${l.name}
|
|
2
|
-
${f}`,children:[e.jsx(Wt,{agent:l,size:16}),A&&e.jsx("span",{className:"flat-map-agent-chip__crown","aria-hidden":"true",children:e.jsx(u,{name:"crown",size:11,color:"#ffd700",weight:"fill"})}),e.jsx("span",{className:"flat-map-agent-chip__name",children:l.name}),e.jsx("img",{src:l.provider==="codex"?"/assets/codex.png":l.provider==="opencode"?"/assets/opencode.png":"/assets/claude.png",alt:l.provider,className:"flat-map-agent-chip__provider-icon",title:l.provider==="codex"?"Codex Agent":l.provider==="opencode"?"OpenCode Agent":"Claude Agent"}),e.jsx("span",{className:"flat-map-agent-chip__dot",style:{backgroundColor:Ht(l.status)}}),l.latestTodos&&l.latestTodos.length>0&&e.jsx(fn,{todos:l.latestTodos,maxDots:6}),A&&N&&N.length>0&&e.jsx(hn,{subordinates:N,maxDots:6}),e.jsx("span",{className:"flat-map-agent-chip__context-bar","aria-hidden":"true",children:e.jsx("span",{className:"flat-map-agent-chip__context-bar-fill",style:{width:`${W.usedPercent}%`,backgroundColor:it}})})]})},l.id)})}),s.buildings.length>0&&e.jsx("div",{className:"flat-map-area-card__buildings",children:s.buildings.map(l=>e.jsxs("button",{type:"button",className:`flat-map-building-chip flat-map-building-chip--${l.status}`,onClick:A=>{if(I){const N=A.currentTarget.getBoundingClientRect();I(l.id,{x:N.right,y:N.top+N.height/2})}else we(l.id)},onContextMenu:A=>{A.preventDefault(),A.stopPropagation(),g({buildingId:l.id,position:{x:A.clientX,y:A.clientY}})},title:`${l.name} · ${l.type} · ${l.status}`,children:[e.jsx(u,{name:gn(l.type),size:12}),e.jsx("span",{className:"flat-map-building-chip__name",children:l.name}),e.jsx("span",{className:"flat-map-building-chip__dot",style:{backgroundColor:xn(l.status)}})]},l.id))})]},p)})})()})]})})]}),K&&e.jsx("div",{className:"flat-splitter flat-splitter--inspector",role:"separator","aria-orientation":"vertical","aria-label":"Resize inspector panel",title:"Drag to resize · Double-click to reset",onPointerDown:Ke,onPointerMove:de,onPointerUp:xe,onPointerCancel:xe,onDoubleClick:ft}),Le&&e.jsxs("aside",{className:`flat-inspector ${T?"flat-inspector--open":"flat-inspector--closing"}`,"aria-label":"Inspector panel",children:[e.jsxs("div",{className:"flat-inspector__header",children:[e.jsxs("div",{className:"flat-inspector__tabs",role:"tablist","aria-label":"Inspector view",children:[e.jsx("button",{type:"button",role:"tab","aria-selected":be==="agent",className:`flat-inspector__tab ${be==="agent"?"flat-inspector__tab--active":""}`,onClick:()=>Ye("agent"),children:"Agent"}),e.jsx("button",{type:"button",role:"tab","aria-selected":be==="tracking",className:`flat-inspector__tab ${be==="tracking"?"flat-inspector__tab--active":""}`,onClick:()=>Ye("tracking"),children:"Tracking"})]}),e.jsx("button",{type:"button",className:"flat-inspector__close",onClick:$e,title:"Close inspector","aria-label":"Close inspector",children:"✕"})]}),e.jsx("div",{className:"flat-inspector__body",children:be==="tracking"?e.jsx(bn,{activeAgentId:x??"",onSelectAgent:t=>{_(t),window.innerWidth<=768&&$e()}}):(()=>{if(!x)return e.jsx("div",{className:"flat-inspector__empty",children:e.jsx("span",{children:"Select an agent to inspect"})});const t=M.find(n=>n.id===x);return t?e.jsx(_n,{agent:t,onFocusAgent:n=>{_(n),window.innerWidth<=768&&$e()},onKillAgent:n=>h.killAgent(n)}):e.jsx("div",{className:"flat-inspector__empty",children:e.jsx("span",{children:"Agent not found"})})})()})]}),Z&&e.jsx(wn,{url:Z.url,name:Z.name,onClose:()=>Re(null)}),Ve&&e.jsx(vn,{state:Ve,onClose:()=>Ge(null)}),De&&e.jsx(Cn,{action:"clear-subordinates",selectedAgentId:De.agentId,subordinateCount:De.count,onClose:()=>le(null),onClearHistory:()=>{}}),e.jsx(jn,{agent:x?M.find(t=>t.id===x)??null:null,isOpen:Ae&&!!x,onClose:Xe}),e.jsx(Rt,{isOpen:z!==null,position:(z==null?void 0:z.position)??{x:0,y:0},worldPosition:{x:0,z:0},actions:Yt,onClose:()=>ye(null)}),e.jsx(Rt,{isOpen:J!==null,position:(J==null?void 0:J.position)??{x:0,y:0},worldPosition:{x:0,z:0},actions:Zt,onClose:()=>g(null)}),e.jsx(Nn,{isOpen:P!==null,title:ie("common:confirm.removeAgentTitle"),message:ie("common:confirm.removeAgentMessage",{name:(P==null?void 0:P.name)??""}),confirmLabel:ie("common:buttons.remove"),cancelLabel:ie("common:buttons.cancel"),variant:"danger",onConfirm:()=>{P&&h.removeAgentFromServer(P.agentId)},onClose:()=>me(null)})]})}export{ea as FlatView};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import{bg as ta,u as E,j as e,aL as v,bj as $s,bk as Fs,aM as He,s as P,bl as Ms,D as Y,I as A,a2 as Hs,aV as Ge,f as na,bm as la,r,J as ia,S as oa,h as ra,bn as Us,aW as Ke}from"./main-BrZe9Zbd.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";const ca=[{value:"",labelKey:"terminal:building.colorDefault"},{value:"#2a2a3a",labelKey:"terminal:building.colorDarkGray"},{value:"#3a2a2a",labelKey:"terminal:building.colorDarkRed"},{value:"#2a3a2a",labelKey:"terminal:building.colorDarkGreen"},{value:"#2a2a4a",labelKey:"terminal:building.colorDarkBlue"},{value:"#3a3a2a",labelKey:"terminal:building.colorDarkYellow"},{value:"#3a2a3a",labelKey:"terminal:building.colorDarkPurple"},{value:"#2a3a3a",labelKey:"terminal:building.colorDarkCyan"},{value:"#4a3a3a",labelKey:"terminal:building.colorWarmBrown"},{value:"#3a4a4a",labelKey:"terminal:building.colorCoolSteel"}];function ma(a){return ta.t(a)}function Ve(a){if(a===0)return"0 B";const l=1024,c=["B","KB","MB","GB"],h=Math.floor(Math.log(a)/Math.log(l));return parseFloat((a/Math.pow(l,h)).toFixed(1))+" "+c[h]}function da(a){const c=Date.now()-a,h=Math.floor(c/(1e3*60*60)),t=Math.floor(c%(1e3*60*60)/(1e3*60));return h>0?`${h}h ${t}m`:`${t}m`}const Ks={30:"#1a1a1a",31:"#e74c3c",32:"#2ecc71",33:"#f39c12",34:"#3498db",35:"#9b59b6",36:"#00bcd4",37:"#ecf0f1",90:"#7f8c8d",91:"#ff6b6b",92:"#4ade80",93:"#fbbf24",94:"#60a5fa",95:"#c084fc",96:"#22d3ee",97:"#ffffff"};function Gs(a){const l=[],c=/\x1B\[([0-9;]*)m/g;let h=0,t=null,o;for(;(o=c.exec(a))!==null;){if(o.index>h){const m=a.slice(h,o.index);t?l.push(e.jsx("span",{style:{color:t},children:m},l.length)):l.push(m)}const g=o[1].split(";").map(Number);for(const m of g)m===0||m===39?t=null:Ks[m]&&(t=Ks[m]);h=c.lastIndex}if(h<a.length){const g=a.slice(h);t?l.push(e.jsx("span",{style:{color:t},children:g},l.length)):l.push(g)}return l.length>0?l:[a]}function ua({buildingName:a,onClose:l,onConfirm:c}){const{t:h}=E(["terminal","common"]);return e.jsx("div",{className:"modal-overlay visible",onClick:l,children:e.jsxs("div",{className:"modal confirm-modal",onClick:t=>t.stopPropagation(),children:[e.jsx("div",{className:"modal-header",children:h("terminal:building.deleteBuilding")}),e.jsxs("div",{className:"modal-body confirm-modal-body",children:[e.jsx("p",{children:h("terminal:building.deleteConfirm",{name:a})}),e.jsx("p",{className:"confirm-modal-note",children:h("terminal:building.deleteNote")})]}),e.jsxs("div",{className:"modal-footer",children:[e.jsx("button",{className:"btn btn-secondary",onClick:l,children:h("common:buttons.cancel")}),e.jsx("button",{className:"btn btn-danger",onClick:c,autoFocus:!0,children:h("common:buttons.delete")})]})]})})}function pa({usePM2:a,setUsePM2:l}){const{t:c}=E(["terminal"]);return e.jsxs("div",{className:"form-section pm2-toggle-section",children:[e.jsxs("label",{className:"toggle-switch",children:[e.jsx("input",{type:"checkbox",className:"toggle-input",checked:a,onChange:h=>l(h.target.checked)}),e.jsx("span",{className:"toggle-track",children:e.jsx("span",{className:"toggle-thumb"})}),e.jsxs("span",{className:"toggle-label",children:[e.jsx("span",{className:"pm2-badge",children:"PM2"}),c("terminal:building.usePM2")]})]}),e.jsx("div",{className:"form-hint",children:c("terminal:building.pm2Hint")})]})}function ha({usePM2:a,pm2Script:l,setPm2Script:c,pm2Args:h,setPm2Args:t,pm2Interpreter:o,setPm2Interpreter:g,pm2InterpreterArgs:m,setPm2InterpreterArgs:d,pm2Env:s,setPm2Env:u,isEditMode:b,building:x,handleCommand:N}){var y;const{t:p}=E(["terminal","common"]);return a?e.jsxs("div",{className:"form-section pm2-config-section",children:[e.jsx("label",{className:"form-label",children:p("terminal:building.pm2Configuration")}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:[p("terminal:building.pm2Script"),e.jsx(v,{text:p("terminal:building.helpPm2Script"),title:p("terminal:building.pm2Script"),position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:l,onChange:j=>c(j.target.value),placeholder:"npm, java, python, ./app.js",required:a})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:[p("terminal:building.pm2Arguments"),e.jsx(v,{text:p("terminal:building.helpPm2Arguments"),title:p("terminal:building.pm2Arguments"),position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:h,onChange:j=>t(j.target.value),placeholder:"run dev, -jar app.jar, app.py"})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:[p("terminal:building.pm2Interpreter"),e.jsx(v,{text:p("terminal:building.helpPm2Interpreter"),title:p("terminal:building.pm2Interpreter"),position:"top",size:"sm"})]}),e.jsx("select",{className:"form-input form-select",value:o,onChange:j=>g(j.target.value),children:Object.keys($s).map(j=>e.jsx("option",{value:j,children:$s[j].label},j))})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:[p("terminal:building.pm2InterpArgs"),e.jsx(v,{text:p("terminal:building.helpPm2InterpArgs"),title:p("terminal:building.pm2InterpArgs"),position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:m,onChange:j=>d(j.target.value),placeholder:"-jar (for Java)"})]}),e.jsxs("div",{className:"command-row env-row",children:[e.jsxs("span",{className:"command-label",children:[p("terminal:building.pm2Environment"),e.jsx(v,{text:p("terminal:building.helpPm2Environment"),title:p("terminal:building.pm2Environment"),position:"top",size:"sm"})]}),e.jsx("textarea",{className:"form-input form-textarea",value:s,onChange:j=>u(j.target.value),placeholder:`KEY=value
|
|
2
|
-
SERVER_PORT=7201
|
|
3
|
-
NODE_ENV=production`,rows:3})]}),e.jsx("div",{className:"pm2-examples",children:e.jsxs("details",{children:[e.jsx("summary",{children:p("terminal:building.pm2Examples")}),e.jsxs("div",{className:"pm2-examples-content",children:[e.jsxs("div",{className:"pm2-example",children:[e.jsx("strong",{children:"Node.js:"})," Script: ",e.jsx("code",{children:"npm"}),", Args: ",e.jsx("code",{children:"run dev"})]}),e.jsxs("div",{className:"pm2-example",children:[e.jsx("strong",{children:"Symfony:"})," Script: ",e.jsx("code",{children:"symfony"}),", Args: ",e.jsx("code",{children:"serve --no-daemon"}),", Interpreter: ",e.jsx("code",{children:"None"})]}),e.jsxs("div",{className:"pm2-example",children:[e.jsx("strong",{children:"Java JAR:"})," Script: ",e.jsx("code",{children:"app.jar"}),", Interpreter: ",e.jsx("code",{children:"Java"}),", Interp. Args: ",e.jsx("code",{children:"-jar"})]}),e.jsxs("div",{className:"pm2-example",children:[e.jsx("strong",{children:"Python:"})," Script: ",e.jsx("code",{children:"app.py"}),", Interpreter: ",e.jsx("code",{children:"Python 3"})]})]})]})}),b&&(x==null?void 0:x.pm2Status)&&e.jsx("div",{className:"pm2-status-display",children:e.jsxs("div",{className:"pm2-status-row",children:[e.jsxs("span",{className:"pm2-metric",children:[e.jsx("span",{className:"pm2-metric-label",children:"PID"}),e.jsx("span",{className:"pm2-metric-value",children:x.pm2Status.pid||"-"})]}),e.jsxs("span",{className:"pm2-metric",children:[e.jsx("span",{className:"pm2-metric-label",children:"CPU"}),e.jsxs("span",{className:"pm2-metric-value",children:[((y=x.pm2Status.cpu)==null?void 0:y.toFixed(1))||"0","%"]})]}),e.jsxs("span",{className:"pm2-metric",children:[e.jsx("span",{className:"pm2-metric-label",children:"MEM"}),e.jsx("span",{className:"pm2-metric-value",children:Ve(x.pm2Status.memory||0)})]}),e.jsxs("span",{className:"pm2-metric",children:[e.jsx("span",{className:"pm2-metric-label",children:"Restarts"}),e.jsx("span",{className:"pm2-metric-value",children:x.pm2Status.restarts||0})]}),x.pm2Status.uptime&&e.jsxs("span",{className:"pm2-metric",children:[e.jsx("span",{className:"pm2-metric-label",children:"Uptime"}),e.jsx("span",{className:"pm2-metric-value",children:da(x.pm2Status.uptime)})]})]})}),b&&e.jsxs("div",{className:"pm2-actions",children:[e.jsx("button",{type:"button",className:"btn btn-sm btn-success",onClick:()=>N("start"),children:p("common:buttons.start")}),e.jsx("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>N("stop"),children:p("common:buttons.stop")}),e.jsx("button",{type:"button",className:"btn btn-sm btn-warning",onClick:()=>N("restart"),children:p("terminal:buildingAction.restart")}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>N("logs"),children:p("terminal:logs.title")})]})]}):null}function xa({dockerMode:a,setDockerMode:l,dockerImage:c,setDockerImage:h,dockerContainerName:t,setDockerContainerName:o,dockerCommand:g,setDockerCommand:m,dockerPorts:d,setDockerPorts:s,dockerVolumes:u,setDockerVolumes:b,dockerNetwork:x,setDockerNetwork:N,dockerRestart:p,setDockerRestart:y,dockerPull:j,setDockerPull:F,dockerEnv:M,setDockerEnv:R,dockerComposePath:J,setDockerComposePath:U,dockerComposeProject:W,setDockerComposeProject:K,dockerComposeServices:Z,setDockerComposeServices:H,selectedExistingContainer:O,setSelectedExistingContainer:G,dockerContainersList:T,isEditMode:I,building:k,handleCommand:L}){const{t:z}=E(["config","common"]);return e.jsxs("div",{className:"form-section docker-config-section",children:[e.jsx("label",{className:"form-label",children:z("config:buildings.dockerConfig")}),e.jsxs("div",{className:"docker-mode-selector",children:[e.jsxs("label",{className:`docker-mode-option ${a==="container"?"active":""}`,children:[e.jsx("input",{type:"radio",name:"dockerMode",value:"container",checked:a==="container",onChange:()=>l("container")}),e.jsx("span",{className:"docker-mode-icon",children:"📦"}),e.jsx("span",{className:"docker-mode-label",children:"Container"}),e.jsx("span",{className:"docker-mode-desc",children:"Create a new container"})]}),e.jsxs("label",{className:`docker-mode-option ${a==="compose"?"active":""}`,children:[e.jsx("input",{type:"radio",name:"dockerMode",value:"compose",checked:a==="compose",onChange:()=>l("compose")}),e.jsx("span",{className:"docker-mode-icon",children:"🛠"}),e.jsx("span",{className:"docker-mode-label",children:"Compose"}),e.jsx("span",{className:"docker-mode-desc",children:"Manage multiple services"})]}),e.jsxs("label",{className:`docker-mode-option ${a==="existing"?"active":""}`,children:[e.jsx("input",{type:"radio",name:"dockerMode",value:"existing",checked:a==="existing",onChange:()=>l("existing")}),e.jsx("span",{className:"docker-mode-icon",children:"🔎"}),e.jsx("span",{className:"docker-mode-label",children:"Existing"}),e.jsx("span",{className:"docker-mode-desc",children:"Adopt existing container"})]})]}),a==="container"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:["Image:",e.jsx(v,{text:"Docker image to run, e.g., nginx:latest, redis:alpine, my-app:v1",title:"Image",position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:c,onChange:n=>h(n.target.value),placeholder:"nginx:latest",required:!0})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:["Container Name:",e.jsx(v,{text:"Custom name for the container. If empty, auto-generated based on building name.",title:"Container Name",position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:t,onChange:n=>o(n.target.value),placeholder:"Auto-generated (tc-{name}-{id})"})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:["Command:",e.jsx(v,{text:"Override the default container command. Leave empty to use image's CMD.",title:"Command Override",position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:g,onChange:n=>m(n.target.value),placeholder:"Optional command override"})]}),e.jsxs("div",{className:"form-section docker-ports-section",children:[e.jsxs("label",{className:"form-label",children:["Port Mappings",e.jsx("button",{type:"button",className:"btn btn-sm btn-add",onClick:()=>s([...d,""]),children:"+ Add"})]}),d.map((n,C)=>e.jsxs("div",{className:"docker-mapping-row",children:[e.jsx("input",{type:"text",className:"form-input",value:n,onChange:B=>{const D=[...d];D[C]=B.target.value,s(D)},placeholder:"8080:80 or 3000"}),e.jsx("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>s(d.filter((B,D)=>D!==C)),children:"x"})]},C)),d.length===0&&e.jsx("div",{className:"form-hint",children:"Format: host:container (e.g., 8080:80) or same port (e.g., 3000)"})]}),e.jsxs("div",{className:"form-section docker-volumes-section",children:[e.jsxs("label",{className:"form-label",children:["Volume Mounts",e.jsx("button",{type:"button",className:"btn btn-sm btn-add",onClick:()=>b([...u,""]),children:"+ Add"})]}),u.map((n,C)=>e.jsxs("div",{className:"docker-mapping-row",children:[e.jsx("input",{type:"text",className:"form-input",value:n,onChange:B=>{const D=[...u];D[C]=B.target.value,b(D)},placeholder:"./data:/app/data or /host/path:/container/path"}),e.jsx("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>b(u.filter((B,D)=>D!==C)),children:"x"})]},C)),u.length===0&&e.jsx("div",{className:"form-hint",children:"Format: host_path:container_path (relative paths resolved from working directory)"})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:["Network:",e.jsx(v,{text:"Docker network to connect to. Leave empty for default bridge network.",title:"Network",position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:x,onChange:n=>N(n.target.value),placeholder:"bridge (default)"})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:["Restart Policy:",e.jsx(v,{text:"When should Docker restart the container automatically?",title:"Restart Policy",position:"top",size:"sm"})]}),e.jsx("select",{className:"form-input form-select",value:p,onChange:n=>y(n.target.value),children:Object.keys(Fs).map(n=>e.jsx("option",{value:n,children:Fs[n].label},n))})]})]}),a==="compose"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:["Compose File:",e.jsx(v,{text:"Path to docker-compose.yml file, relative to working directory.",title:"Compose File",position:"top",size:"sm"})]}),e.jsx(He,{value:J,onChange:U,placeholder:"docker-compose.yml",className:"form-input",directoriesOnly:!1})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:["Project Name:",e.jsx(v,{text:"Override the compose project name. Leave empty for auto-generated name.",title:"Project Name",position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:W,onChange:n=>K(n.target.value),placeholder:"Auto-generated"})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:["Services:",e.jsx(v,{text:"Specific services to manage (comma-separated). Leave empty for all services.",title:"Services",position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:Z,onChange:n=>H(n.target.value),placeholder:"All services (or: api, db, redis)"})]})]}),a==="existing"&&e.jsxs("div",{className:"docker-existing-section",children:[e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:["Select Container:",e.jsx(v,{text:"Choose an existing Docker container to monitor and control. The container will not be deleted when removing the building.",title:"Existing Container",position:"top",size:"sm"})]}),e.jsxs("div",{className:"docker-existing-select-wrapper",children:[e.jsxs("select",{className:"form-input form-select",value:O,onChange:n=>G(n.target.value),required:a==="existing",children:[e.jsx("option",{value:"",children:"Select a container..."}),T.map(n=>e.jsxs("option",{value:n.name,children:[n.name," (",n.image,") - ",n.state]},n.id))]}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>P.requestDockerContainersList(),title:"Refresh container list",children:"↻"})]})]}),T.length===0&&e.jsx("div",{className:"form-hint docker-existing-hint",children:"No containers found. Make sure Docker is running and you have containers available."}),O&&e.jsx("div",{className:"docker-existing-info",children:(()=>{const n=T.find(C=>C.name===O);return n?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"docker-existing-info-row",children:[e.jsx("span",{className:"docker-existing-info-label",children:"Image:"}),e.jsx("span",{className:"docker-existing-info-value",children:n.image})]}),e.jsxs("div",{className:"docker-existing-info-row",children:[e.jsx("span",{className:"docker-existing-info-label",children:"Status:"}),e.jsx("span",{className:`docker-existing-info-value docker-status-${n.status}`,children:n.state})]}),e.jsxs("div",{className:"docker-existing-info-row",children:[e.jsx("span",{className:"docker-existing-info-label",children:"ID:"}),e.jsx("span",{className:"docker-existing-info-value",children:n.id.slice(0,12)})]}),n.ports.length>0&&e.jsxs("div",{className:"docker-existing-info-row",children:[e.jsx("span",{className:"docker-existing-info-label",children:"Ports:"}),e.jsx("span",{className:"docker-existing-info-value",children:n.ports.map(C=>`${C.host}:${C.container}/${C.protocol}`).join(", ")})]})]}):null})()}),e.jsx("div",{className:"form-hint",children:"Note: Existing containers will not be deleted when you remove this building."})]}),a!=="existing"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:["Pull Policy:",e.jsx(v,{text:"When to pull images: always, only if missing, or never.",title:"Pull Policy",position:"top",size:"sm"})]}),e.jsx("select",{className:"form-input form-select",value:j,onChange:n=>F(n.target.value),children:Object.keys(Ms).map(n=>e.jsx("option",{value:n,children:Ms[n].label},n))})]}),e.jsxs("div",{className:"command-row env-row",children:[e.jsxs("span",{className:"command-label",children:["Environment:",e.jsx(v,{text:"Environment variables in KEY=value format, one per line.",title:"Environment Variables",position:"top",size:"sm"})]}),e.jsx("textarea",{className:"form-input form-textarea",value:M,onChange:n=>R(n.target.value),placeholder:`KEY=value
|
|
4
|
-
DATABASE_URL=postgres://...
|
|
5
|
-
NODE_ENV=production`,rows:3})]})]}),I&&(k==null?void 0:k.dockerStatus)&&e.jsxs("div",{className:"docker-status-display",children:[e.jsxs("div",{className:"docker-status-row",children:[e.jsxs("span",{className:"docker-metric",children:[e.jsx("span",{className:"docker-metric-label",children:"ID"}),e.jsx("span",{className:"docker-metric-value",children:k.dockerStatus.containerId||"-"})]}),e.jsxs("span",{className:"docker-metric",children:[e.jsx("span",{className:"docker-metric-label",children:"Status"}),e.jsx("span",{className:"docker-metric-value",children:k.dockerStatus.status||"-"})]}),k.dockerStatus.health&&k.dockerStatus.health!=="none"&&e.jsxs("span",{className:"docker-metric",children:[e.jsx("span",{className:"docker-metric-label",children:"Health"}),e.jsx("span",{className:"docker-metric-value",children:k.dockerStatus.health})]}),k.dockerStatus.cpu!==void 0&&e.jsxs("span",{className:"docker-metric",children:[e.jsx("span",{className:"docker-metric-label",children:"CPU"}),e.jsxs("span",{className:"docker-metric-value",children:[k.dockerStatus.cpu.toFixed(1),"%"]})]}),k.dockerStatus.memory!==void 0&&e.jsxs("span",{className:"docker-metric",children:[e.jsx("span",{className:"docker-metric-label",children:"MEM"}),e.jsxs("span",{className:"docker-metric-value",children:[Ve(k.dockerStatus.memory),k.dockerStatus.memoryLimit?` / ${Ve(k.dockerStatus.memoryLimit)}`:""]})]})]}),k.dockerStatus.ports&&k.dockerStatus.ports.length>0&&e.jsxs("div",{className:"docker-ports-row",children:[e.jsx("span",{className:"docker-metric-label",children:"Ports:"}),k.dockerStatus.ports.map((n,C)=>e.jsxs("a",{href:`http://${window.location.hostname}:${n.host}`,target:"_blank",rel:"noopener noreferrer",className:"docker-port-link",children:[n.host,":",n.container,"/",n.protocol]},C))]}),k.dockerStatus.services&&k.dockerStatus.services.length>0&&e.jsxs("div",{className:"docker-services-status",children:[e.jsx("span",{className:"docker-metric-label",children:"Services:"}),e.jsx("div",{className:"docker-services-grid",children:k.dockerStatus.services.map((n,C)=>e.jsxs("div",{className:"docker-service-item",children:[e.jsx("span",{className:"docker-service-indicator",style:{backgroundColor:n.status==="running"?"#4ade80":"#f87171"}}),e.jsx("span",{className:"docker-service-name",children:n.name}),e.jsx("span",{className:"docker-service-status",children:n.status})]},C))})]})]}),I&&e.jsxs("div",{className:"docker-actions",children:[e.jsx("button",{type:"button",className:"btn btn-sm btn-success",onClick:()=>L("start"),children:"Start"}),e.jsx("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>L("stop"),children:"Stop"}),e.jsx("button",{type:"button",className:"btn btn-sm btn-warning",onClick:()=>L("restart"),children:"Restart"}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>L("logs"),children:"Logs"})]})]})}function ba({dbConnections:a,setDbConnections:l,activeDbConnectionId:c,setActiveDbConnectionId:h}){const{t}=E(["terminal","common"]);return e.jsxs("div",{className:"form-section database-config-section",children:[e.jsxs("label",{className:"form-label",children:[t("terminal:building.dbConnections"),e.jsx(v,{text:t("terminal:building.helpDbConnections"),title:t("terminal:building.dbConnections"),position:"top",size:"sm"}),e.jsx("button",{type:"button",className:"btn btn-sm btn-add",onClick:()=>{const o={id:`conn_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,name:`Connection ${a.length+1}`,engine:"mysql",host:"localhost",port:3306,username:"root"};l([...a,o]),c||h(o.id)},children:t("terminal:database.addConnection")})]}),a.length===0&&e.jsx("div",{className:"form-hint",children:t("terminal:building.dbGetStarted")}),a.map((o,g)=>e.jsxs("div",{className:"db-connection-card",children:[e.jsxs("div",{className:"db-connection-header",children:[e.jsxs("label",{className:"db-connection-active",children:[e.jsx("input",{type:"radio",name:"activeConnection",checked:c===o.id,onChange:()=>h(o.id)}),t("common:labels.default"),e.jsx(v,{text:t("terminal:building.helpDbDefault"),position:"top",size:"sm"})]}),e.jsx("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>{const m=a.filter(d=>d.id!==o.id);l(m),c===o.id&&m.length>0?h(m[0].id):m.length===0&&h(void 0)},children:t("common:buttons.remove")})]}),e.jsxs("div",{className:"db-connection-row",children:[e.jsxs("div",{className:"db-field",children:[e.jsx("label",{children:t("common:labels.name")}),e.jsx("input",{type:"text",className:"form-input",value:o.name,onChange:m=>{const d=[...a];d[g]={...o,name:m.target.value},l(d)},placeholder:"My Database"})]}),e.jsxs("div",{className:"db-field db-field--small",children:[e.jsx("label",{children:t("terminal:building.dbEngine")}),e.jsx("select",{className:"form-input form-select",value:o.engine,onChange:m=>{const d=m.target.value,s=[...a];s[g]={...o,engine:d,port:Y[d].defaultPort},l(s)},children:Object.keys(Y).map(m=>e.jsxs("option",{value:m,children:[Y[m].icon," ",Y[m].label]},m))})]})]}),o.engine==="sqlite"?e.jsx("div",{className:"db-connection-row",children:e.jsxs("div",{className:"db-field db-field--grow",children:[e.jsx("label",{children:t("terminal:building.dbFilepath")}),e.jsx("input",{type:"text",className:"form-input",value:o.filepath||"",onChange:m=>{const d=[...a];d[g]={...o,filepath:m.target.value||void 0},l(d)},placeholder:"/path/to/database.db"})]})}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"db-connection-row",children:[e.jsxs("div",{className:"db-field db-field--grow",children:[e.jsx("label",{children:t("terminal:building.dbHost")}),e.jsx("input",{type:"text",className:"form-input",value:o.host,onChange:m=>{const d=[...a];d[g]={...o,host:m.target.value},l(d)},placeholder:"localhost"})]}),e.jsxs("div",{className:"db-field db-field--small",children:[e.jsx("label",{children:t("terminal:building.dbPort")}),e.jsx("input",{type:"number",className:"form-input",value:o.port,onChange:m=>{const d=[...a];d[g]={...o,port:parseInt(m.target.value)||Y[o.engine].defaultPort},l(d)}})]})]}),e.jsxs("div",{className:"db-connection-row",children:[e.jsxs("div",{className:"db-field",children:[e.jsx("label",{children:t("terminal:building.dbUsername")}),e.jsx("input",{type:"text",className:"form-input",value:o.username,onChange:m=>{const d=[...a];d[g]={...o,username:m.target.value},l(d)},placeholder:"root"})]}),e.jsxs("div",{className:"db-field",children:[e.jsx("label",{children:t("terminal:building.dbPassword")}),e.jsx("input",{type:"password",className:"form-input",value:o.password||"",onChange:m=>{const d=[...a];d[g]={...o,password:m.target.value||void 0},l(d)},placeholder:"Optional"})]})]}),e.jsxs("div",{className:"db-connection-row",children:[e.jsxs("div",{className:"db-field db-field--grow",children:[e.jsx("label",{children:t("terminal:building.dbDefaultDatabase")}),e.jsx("input",{type:"text",className:"form-input",value:o.database||"",onChange:m=>{const d=[...a];d[g]={...o,database:m.target.value||void 0},l(d)},placeholder:"Optional - select after connecting"})]}),e.jsxs("div",{className:"db-field db-field--small",children:[e.jsxs("label",{children:["SSL",e.jsx(v,{text:t("terminal:building.helpDbSsl"),position:"top",size:"sm"})]}),e.jsxs("label",{className:"toggle-switch toggle-switch--small",children:[e.jsx("input",{type:"checkbox",checked:o.ssl||!1,onChange:m=>{const d=[...a];d[g]={...o,ssl:m.target.checked},l(d)}}),e.jsx("span",{className:"toggle-track",children:e.jsx("span",{className:"toggle-thumb"})})]})]})]})]})]},o.id)),a.length>0&&e.jsx("div",{className:"form-hint",children:t("terminal:building.dbAfterSaving")})]})}function ja({buildings:a,buildingId:l,subordinateBuildingIds:c,setSubordinateBuildingIds:h,isEditMode:t,showBossLogs:o,setShowBossLogs:g,currentBossLogs:m,bossLogsContainerRef:d}){const{t:s}=E(["terminal","common"]);return e.jsxs("div",{className:"form-section boss-building-section",children:[e.jsxs("label",{className:"form-label",children:[s("terminal:building.managedBuildings"),e.jsx(v,{text:s("terminal:building.helpManagedBuildings"),title:s("terminal:building.managedBuildings"),position:"top",size:"sm"})]}),e.jsx("div",{className:"form-hint",children:s("terminal:building.managedBuildingsHint")}),e.jsxs("div",{className:"subordinate-buildings-list",children:[Array.from(a.values()).filter(u=>u.id!==l&&u.type!=="boss"&&u.type!=="link"&&u.type!=="folder").map(u=>e.jsxs("label",{className:"subordinate-building-item",children:[e.jsx("input",{type:"checkbox",checked:c.includes(u.id),onChange:b=>{b.target.checked?h([...c,u.id]):h(c.filter(x=>x!==u.id))}}),e.jsx("span",{className:"subordinate-building-icon",children:e.jsx(A,{name:Hs(u.type),size:14})}),e.jsx("span",{className:"subordinate-building-name",children:u.name}),e.jsx("span",{className:"subordinate-building-status",style:{backgroundColor:Ge[u.status]}})]},u.id)),Array.from(a.values()).filter(u=>u.id!==l&&u.type!=="boss"&&u.type!=="link"&&u.type!=="folder").length===0&&e.jsx("div",{className:"form-hint no-buildings-hint",children:s("terminal:building.noManageableBuildings")})]}),t&&c.length>0&&e.jsxs("div",{className:"boss-building-actions",children:[e.jsxs("div",{className:"boss-actions-header",children:[s("terminal:building.bulkActions"),e.jsx(v,{text:s("terminal:building.helpBulkActions"),position:"top",size:"sm"})]}),e.jsxs("div",{className:"boss-actions-row",children:[e.jsx("button",{type:"button",className:"btn btn-sm btn-success",onClick:()=>P.sendBossBuildingCommand(l,"start_all"),children:s("terminal:building.startAll")}),e.jsx("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>P.sendBossBuildingCommand(l,"stop_all"),children:s("terminal:building.stopAll")}),e.jsx("button",{type:"button",className:"btn btn-sm btn-warning",onClick:()=>P.sendBossBuildingCommand(l,"restart_all"),children:s("terminal:building.restartAll")}),e.jsx("button",{type:"button",className:`btn btn-sm ${o?"btn-primary":""}`,onClick:()=>{o?(P.stopBossLogStreaming(l),g(!1)):(P.startBossLogStreaming(l),g(!0))},children:s(o?"terminal:building.hideLogs":"terminal:building.unifiedLogs")})]}),e.jsxs("div",{className:"boss-subordinates-status",children:[e.jsx("div",{className:"boss-status-header",children:s("terminal:building.statusOverview")}),e.jsx("div",{className:"boss-status-grid",children:c.map(u=>{const b=a.get(u);return b?e.jsxs("div",{className:"boss-status-item",children:[e.jsx("span",{className:"boss-status-indicator",style:{backgroundColor:Ge[b.status]}}),e.jsx("span",{className:"boss-status-name",children:b.name}),e.jsx("span",{className:"boss-status-label",children:b.status})]},u):null})})]})]}),t&&o&&e.jsxs("div",{className:"form-section boss-logs-section",children:[e.jsxs("label",{className:"form-label",children:[s("terminal:building.unifiedLogs"),e.jsx(v,{text:s("terminal:building.helpUnifiedLogs"),position:"top",size:"sm"}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>P.clearBossStreamingLogs(l),children:s("common:buttons.clear")})]}),e.jsxs("div",{className:"boss-logs-container",ref:d,children:[m.map((u,b)=>e.jsxs("div",{className:"boss-log-entry",children:[e.jsxs("span",{className:"boss-log-source",children:["[",u.subordinateName,"]"]}),e.jsx("span",{className:"boss-log-content",children:Gs(u.chunk)})]},b)),m.length===0&&e.jsx("div",{className:"boss-logs-empty",children:s("terminal:building.waitingForLogs")})]})]})]})}function ga({startCmd:a,setStartCmd:l,stopCmd:c,setStopCmd:h,restartCmd:t,setRestartCmd:o,healthCheckCmd:g,setHealthCheckCmd:m,logsCmd:d,setLogsCmd:s,isEditMode:u,handleCommand:b}){const{t:x}=E(["terminal","common"]);return e.jsxs("div",{className:"form-section commands-section",children:[e.jsxs("label",{className:"form-label",children:[x("terminal:building.commands"),e.jsx(v,{text:x("terminal:building.helpCommands"),title:x("terminal:building.commands"),position:"top",size:"sm"})]}),e.jsxs("div",{className:"command-inputs",children:[e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:[x("terminal:building.cmdStart"),e.jsx(v,{text:x("terminal:building.helpCmdStart"),position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:a,onChange:N=>l(N.target.value),placeholder:"npm run dev"}),u&&e.jsx("button",{type:"button",className:"btn btn-sm btn-success",onClick:()=>b("start"),disabled:!a,children:x("common:buttons2.run")})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:[x("terminal:building.cmdStop"),e.jsx(v,{text:x("terminal:building.helpCmdStop"),position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:c,onChange:N=>h(N.target.value),placeholder:"pkill -f 'npm run dev'"}),u&&e.jsx("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>b("stop"),disabled:!c,children:x("common:buttons2.run")})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:[x("terminal:building.cmdRestart"),e.jsx(v,{text:x("terminal:building.helpCmdRestart"),position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:t,onChange:N=>o(N.target.value),placeholder:"npm run restart"}),u&&e.jsx("button",{type:"button",className:"btn btn-sm btn-warning",onClick:()=>b("restart"),disabled:!t,children:x("common:buttons2.run")})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:[x("terminal:building.cmdHealthCheck"),e.jsx(v,{text:x("terminal:building.helpCmdHealthCheck"),position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:g,onChange:N=>m(N.target.value),placeholder:"curl -s http://localhost:3000/health"}),u&&e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>b("healthCheck"),disabled:!g,children:x("terminal:building.check")})]}),e.jsxs("div",{className:"command-row",children:[e.jsxs("span",{className:"command-label",children:[x("terminal:building.cmdLogs"),e.jsx(v,{text:x("terminal:building.helpCmdLogs"),position:"top",size:"sm"})]}),e.jsx("input",{type:"text",className:"form-input",value:d,onChange:N=>s(N.target.value),placeholder:"tail -n 100 /var/log/app.log"}),u&&e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>b("logs"),children:x("terminal:building.fetch")})]})]})]})}const va=[{value:"",label:"Default ($SHELL)"},{value:"/bin/bash",label:"Bash"},{value:"/bin/zsh",label:"Zsh"},{value:"/usr/bin/fish",label:"Fish"},{value:"/bin/sh",label:"sh"}];function Na({terminalShell:a,setTerminalShell:l,terminalPort:c,setTerminalPort:h,terminalSaveSession:t,setTerminalSaveSession:o,terminalArgs:g,setTerminalArgs:m,isEditMode:d,building:s,handleCommand:u,onOpenTerminal:b,onOpenBelow:x}){const{t:N}=E(["config"]),p=(s==null?void 0:s.status)==="running",y=s==null?void 0:s.terminalStatus;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-section",children:[e.jsx("label",{className:"form-label",children:N("config:buildings.terminalConfig",{defaultValue:"Terminal Configuration"})}),e.jsxs("div",{className:"form-row",children:[e.jsxs("div",{className:"form-field",children:[e.jsx("label",{className:"form-sublabel",children:N("config:buildings.terminalShell",{defaultValue:"Shell"})}),e.jsx("select",{className:"form-input",value:a,onChange:j=>l(j.target.value),children:va.map(j=>e.jsx("option",{value:j.value,children:j.label},j.value))})]}),e.jsxs("div",{className:"form-field",children:[e.jsx("label",{className:"form-sublabel",children:N("config:buildings.terminalPort",{defaultValue:"Port"})}),e.jsx("input",{type:"number",className:"form-input",value:c,onChange:j=>h(j.target.value),placeholder:"Auto",min:1024,max:65535})]})]}),e.jsx("div",{className:"form-row",style:{marginTop:"8px"},children:e.jsxs("label",{className:"form-checkbox-label",children:[e.jsx("input",{type:"checkbox",checked:t,onChange:j=>o(j.target.checked)}),e.jsx("span",{children:N("config:buildings.terminalSaveSession",{defaultValue:"Persist session (tmux)"})})]})}),e.jsxs("div",{style:{marginTop:"8px"},children:[e.jsx("label",{className:"form-sublabel",children:N("config:buildings.terminalArgs",{defaultValue:"Extra ttyd args"})}),e.jsx("input",{type:"text",className:"form-input",value:g,onChange:j=>m(j.target.value),placeholder:"--client-option titleFixed=Terminal"}),e.jsx("div",{className:"form-hint",children:"Additional command-line arguments passed to ttyd"})]})]}),d&&s&&e.jsxs("div",{className:"form-section",children:[e.jsx("label",{className:"form-label",children:N("config:buildings.terminalControls",{defaultValue:"Terminal Controls"})}),y&&e.jsxs("div",{className:"building-runtime-info",children:[e.jsxs("div",{className:"runtime-row",children:[e.jsx("span",{className:"runtime-label",children:"Proxy"}),e.jsx("span",{className:"runtime-value",style:{color:"#4a9eff"},children:y.url})]}),e.jsxs("div",{className:"runtime-row",children:[e.jsx("span",{className:"runtime-label",children:"PID"}),e.jsx("span",{className:"runtime-value",children:y.pid})]}),e.jsxs("div",{className:"runtime-row",children:[e.jsx("span",{className:"runtime-label",children:"Port"}),e.jsx("span",{className:"runtime-value",children:y.port})]}),y.tmuxSession&&e.jsxs("div",{className:"runtime-row",children:[e.jsx("span",{className:"runtime-label",children:"Session"}),e.jsx("span",{className:"runtime-value",children:y.tmuxSession})]})]}),e.jsxs("div",{className:"building-actions",style:{marginTop:"8px"},children:[!p&&e.jsxs("button",{type:"button",className:"btn btn-sm btn-success",onClick:()=>u("start"),children:[e.jsx(A,{name:"play",size:12})," Start"]}),p&&e.jsxs(e.Fragment,{children:[e.jsxs("button",{type:"button",className:"btn btn-sm btn-warning",onClick:()=>u("restart"),children:[e.jsx(A,{name:"refresh",size:12})," Restart"]}),e.jsxs("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>u("stop"),children:[e.jsx(A,{name:"stop",size:12})," Stop"]}),(y==null?void 0:y.url)&&e.jsxs(e.Fragment,{children:[b&&e.jsxs("button",{type:"button",className:"btn btn-sm btn-primary",onClick:()=>b(y.url),children:[e.jsx(A,{name:"desktop",size:12})," Modal"]}),x&&s&&e.jsxs("button",{type:"button",className:"btn btn-sm btn-primary",onClick:()=>x(s.id),children:[e.jsx(A,{name:"arrow-down",size:12})," Below"]})]})]})]})]})]})}function fa({logs:a,buildingId:l,logsContainerRef:c}){return e.jsxs("div",{className:"form-section logs-section",children:[e.jsxs("label",{className:"form-label",children:["Logs",e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>P.clearBuildingLogs(l),children:"Clear"})]}),e.jsx("div",{className:"logs-container",ref:c,children:a.map((h,t)=>e.jsx("pre",{className:"log-entry",children:Gs(h)},t))})]})}function Sa({isOpen:a,onClose:l,buildingId:c,initialPosition:h}){const{t}=E(["config","common"]),{buildings:o,buildingLogs:g,bossStreamingLogs:m}=na(),d=la(),s=c?o.get(c):null,u=c?m.get(c)||[]:[],b=!!s,[x,N]=r.useState(""),[p,y]=r.useState("server"),[j,F]=r.useState("server-rack"),[M,R]=r.useState(""),[J,U]=r.useState(""),[W,K]=r.useState(""),[Z,H]=r.useState(""),[O,G]=r.useState(""),[T,I]=r.useState(""),[k,L]=r.useState(""),[z,n]=r.useState([]),[C,B]=r.useState(!1),[D,se]=r.useState(""),[V,Q]=r.useState(1),[q,ae]=r.useState(!1),[qe,te]=r.useState(""),[Ye,ne]=r.useState(""),[Je,le]=r.useState(""),[We,ie]=r.useState(""),[Ze,oe]=r.useState(""),[Vs,re]=r.useState(!1),[w,ce]=r.useState("container"),[me,de]=r.useState(""),[Qe,ue]=r.useState(""),[pe,he]=r.useState(""),[xe,be]=r.useState([]),[je,ge]=r.useState([]),[Xe,ve]=r.useState(""),[Ne,fe]=r.useState(""),[ke,ye]=r.useState(""),[es,Ce]=r.useState("unless-stopped"),[ss,Se]=r.useState("missing"),[we,Pe]=r.useState(""),[De,Ee]=r.useState(""),[Le,ze]=r.useState(""),[Ae,Be]=r.useState([]),[qs,Ys]=r.useState(!1),[Re,Oe]=r.useState([]),[as,Te]=r.useState(void 0),[ts,Ie]=r.useState(""),[_e,$e]=r.useState(""),[ns,Fe]=r.useState(!1),[ls,Me]=r.useState(""),is=r.useRef(null),Js=r.useRef(null),X=r.useRef(null);r.useEffect(()=>{var i,f,S,_,ms,ds,us,ps,hs,xs,bs,js,gs,vs,Ns,fs,ks,ys,Cs,Ss,ws,Ps,Ds,Es,Ls,zs,As,Bs,Rs,Os,Ts,Is,_s;a&&(s?(N(s.name),y(s.type),F(s.style||"server-rack"),R(s.color||""),U(s.cwd||""),K(((i=s.commands)==null?void 0:i.start)||""),H(((f=s.commands)==null?void 0:f.stop)||""),G(((S=s.commands)==null?void 0:S.restart)||""),I(((_=s.commands)==null?void 0:_.healthCheck)||""),L(((ms=s.commands)==null?void 0:ms.logs)||""),n(s.urls||[]),se(s.folderPath||""),Q(s.scale||1),ae(((ds=s.pm2)==null?void 0:ds.enabled)||!1),te(((us=s.pm2)==null?void 0:us.script)||""),ne(((ps=s.pm2)==null?void 0:ps.args)||""),le(((hs=s.pm2)==null?void 0:hs.interpreter)||""),ie(((xs=s.pm2)==null?void 0:xs.interpreterArgs)||""),oe((bs=s.pm2)!=null&&bs.env?Object.entries(s.pm2.env).map(([$,Ue])=>`${$}=${Ue}`).join(`
|
|
6
|
-
`):""),ce(((js=s.docker)==null?void 0:js.mode)||"container"),de(((gs=s.docker)==null?void 0:gs.mode)==="existing"&&((vs=s.docker)==null?void 0:vs.containerName)||""),ue(((Ns=s.docker)==null?void 0:Ns.image)||""),he(((fs=s.docker)==null?void 0:fs.containerName)||""),be(((ks=s.docker)==null?void 0:ks.ports)||[]),ge(((ys=s.docker)==null?void 0:ys.volumes)||[]),ve((Cs=s.docker)!=null&&Cs.env?Object.entries(s.docker.env).map(([$,Ue])=>`${$}=${Ue}`).join(`
|
|
7
|
-
`):""),fe(((Ss=s.docker)==null?void 0:Ss.network)||""),ye(((ws=s.docker)==null?void 0:ws.command)||""),Ce(((Ps=s.docker)==null?void 0:Ps.restart)||"unless-stopped"),Se(((Ds=s.docker)==null?void 0:Ds.pull)||"missing"),Pe(((Es=s.docker)==null?void 0:Es.composePath)||""),Ee(((Ls=s.docker)==null?void 0:Ls.composeProject)||""),ze(((As=(zs=s.docker)==null?void 0:zs.services)==null?void 0:As.join(", "))||""),Be(s.subordinateBuildingIds||[]),Oe(((Bs=s.database)==null?void 0:Bs.connections)||[]),Te((Rs=s.database)==null?void 0:Rs.activeConnectionId),Ie(((Os=s.terminal)==null?void 0:Os.shell)||""),$e((Ts=s.terminal)!=null&&Ts.port?String(s.terminal.port):""),Fe(((Is=s.terminal)==null?void 0:Is.saveSession)||!1),Me(((_s=s.terminal)==null?void 0:_s.args)||"")):(N("New Server"),y("server"),F("server-rack"),R(""),U(ia(oa.LAST_CWD)),K(""),H(""),G(""),I(""),L(""),n([]),se(""),Q(1),ae(!1),te(""),ne(""),le(""),ie(""),oe(""),ce("container"),de(""),ue(""),he(""),be([]),ge([]),ve(""),fe(""),ye(""),Ce("unless-stopped"),Se("missing"),Pe(""),Ee(""),ze(""),Be([]),Oe([]),Te(void 0),Ie(""),$e(""),Fe(!1),Me("")),setTimeout(()=>{var $;return($=is.current)==null?void 0:$.focus()},100))},[a,s]),r.useEffect(()=>{X.current&&(X.current.scrollTop=X.current.scrollHeight)},[g]),r.useEffect(()=>{p==="docker"&&w==="existing"&&P.requestDockerContainersList()},[p,w]);const os=i=>{if(i.trim())return Object.fromEntries(i.trim().split(`
|
|
8
|
-
`).map(f=>f.trim()).filter(f=>f&&f.includes("=")).map(f=>{const S=f.indexOf("=");return[f.slice(0,S),f.slice(S+1)]}))},Ws=i=>{i.preventDefault();const f={name:x,type:p,style:j,color:M||void 0,position:h||(s==null?void 0:s.position)||{x:0,z:0},cwd:J||void 0,folderPath:D||void 0,commands:q?void 0:{start:W||void 0,stop:Z||void 0,restart:O||void 0,healthCheck:T||void 0,logs:k||void 0},pm2:q?{enabled:!0,script:qe,args:Ye||void 0,interpreter:Je||void 0,interpreterArgs:We||void 0,env:os(Ze)}:void 0,docker:p==="docker"?{enabled:!0,mode:w,image:w==="container"?Qe:void 0,containerName:w==="container"&&pe?pe:w==="existing"&&me?me:void 0,ports:w==="container"&&xe.length>0?xe:void 0,volumes:w==="container"&&je.length>0?je:void 0,env:os(Xe),network:w==="container"&&Ne?Ne:void 0,command:w==="container"&&ke?ke:void 0,restart:w==="container"?es:void 0,pull:w!=="existing"?ss:void 0,composePath:w==="compose"&&we?we:void 0,composeProject:w==="compose"&&De?De:void 0,services:w==="compose"&&Le?Le.split(",").map(S=>S.trim()).filter(S=>S):void 0}:void 0,urls:z.length>0?z:void 0,scale:V!==1?V:void 0,subordinateBuildingIds:p==="boss"&&Ae.length>0?Ae:void 0,database:p==="database"&&Re.length>0?{connections:Re,activeConnectionId:as}:void 0,terminal:p==="terminal"?{enabled:!0,shell:ts||void 0,port:_e?parseInt(_e,10):void 0,saveSession:ns||void 0,args:ls||void 0}:void 0};b&&c?P.updateBuilding(c,f):P.createBuilding(f),l()},Zs=()=>{re(!0)},Qs=()=>{c&&(P.deleteBuilding(c),re(!1),l())},ee=i=>{c&&(P.sendBuildingCommand(c,i),i==="logs"&&B(!0))},Xs=()=>{n([...z,{label:"",url:""}])},ea=i=>{n(z.filter((f,S)=>S!==i))},rs=(i,f,S)=>{const _=[...z];_[i]={..._[i],[f]:S},n(_)},{handleMouseDown:sa,handleClick:aa}=ra(l);if(!a)return null;const cs=c?P.getBuildingLogs(c):[];return e.jsxs("div",{className:"modal-overlay visible",onMouseDown:sa,onClick:aa,children:[e.jsxs("div",{className:"modal building-config-modal",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("span",{children:t(b?"config:buildings.editBuilding":"config:buildings.addBuilding")}),b&&s&&e.jsx("span",{className:"building-status-badge",style:{backgroundColor:Ge[s.status]},children:s.status})]}),e.jsxs("form",{onSubmit:Ws,children:[e.jsxs("div",{className:"modal-body",children:[e.jsxs("div",{className:"form-section",children:[e.jsx("label",{className:"form-label",children:t("common:labels.name")}),e.jsx("input",{ref:is,type:"text",className:"form-input",value:x,onChange:i=>N(i.target.value),placeholder:t("config:buildings.namePlaceholder"),required:!0})]}),e.jsxs("div",{className:"form-section",children:[e.jsx("label",{className:"form-label",children:t("common:labels.type")}),e.jsx("div",{className:"building-type-selector",children:Object.keys(Us).map(i=>e.jsxs("button",{type:"button",className:`building-type-btn ${p===i?"active":""}`,onClick:()=>y(i),title:Us[i].description,children:[e.jsx("span",{className:"building-type-icon",children:e.jsx(A,{name:Hs(i),size:16})}),e.jsx("span",{className:"building-type-name",children:i})]},i))})]}),e.jsxs("div",{className:"form-section",children:[e.jsx("label",{className:"form-label",children:t("config:buildings.style")}),e.jsx("div",{className:"building-style-selector",children:Object.keys(Ke).map(i=>e.jsxs("button",{type:"button",className:`building-style-btn ${j===i?"active":""}`,onClick:()=>F(i),title:Ke[i].description,children:[e.jsx("span",{className:"building-style-preview","data-style":i}),e.jsx("span",{className:"building-style-name",children:Ke[i].label})]},i))})]}),e.jsxs("div",{className:"form-section",children:[e.jsx("label",{className:"form-label",children:t("common:labels.color")}),e.jsxs("div",{className:"building-color-selector",children:[ca.map(i=>e.jsx("button",{type:"button",className:`building-color-btn ${M===i.value?"active":""}`,onClick:()=>R(i.value),title:ma(i.labelKey),style:i.value?{backgroundColor:i.value}:void 0,children:!i.value&&e.jsx("span",{className:"color-default-icon",children:e.jsx(A,{name:"gear",size:12})})},i.value||"default")),e.jsx("input",{type:"color",className:"building-color-picker",value:M||"#2a2a3a",onChange:i=>R(i.target.value),title:"Custom color"})]})]}),e.jsxs("div",{className:"form-section",children:[e.jsx("label",{className:"form-label",children:t("common:labels.size")}),e.jsxs("div",{className:"building-size-control",children:[e.jsxs("div",{className:"size-slider-row",children:[e.jsx("input",{type:"range",className:"size-slider",min:"0",max:"100",step:"1",value:Math.log(V/.1)/Math.log(100)*100,onChange:i=>{const f=parseFloat(i.target.value),S=.1*Math.pow(100,f/100);Q(Math.round(S*100)/100)}}),e.jsxs("span",{className:"size-value",children:[V.toFixed(2),"x"]})]}),e.jsx("div",{className:"size-presets",children:[.5,.75,1,1.25,1.5,2].map(i=>e.jsxs("button",{type:"button",className:`size-preset-btn ${V===i?"active":""}`,onClick:()=>Q(i),children:[i,"x"]},i))})]})]}),e.jsxs("div",{className:"form-section",children:[e.jsx("label",{className:"form-label",children:t("config:buildings.directory")}),e.jsx(He,{value:J,onChange:U,placeholder:"/path/to/project",className:"form-input",directoriesOnly:!0})]}),p==="folder"&&e.jsxs("div",{className:"form-section",children:[e.jsx("label",{className:"form-label",children:t("config:buildings.folderPath")}),e.jsx(He,{value:D,onChange:se,placeholder:"/path/to/folder",className:"form-input",directoriesOnly:!0}),e.jsx("div",{className:"form-hint",children:"Click this building to open the file explorer at this path"})]}),p==="boss"&&e.jsx(ja,{buildings:o,buildingId:c,subordinateBuildingIds:Ae,setSubordinateBuildingIds:Be,isEditMode:b,showBossLogs:qs,setShowBossLogs:Ys,currentBossLogs:u,bossLogsContainerRef:Js}),p==="database"&&e.jsx(ba,{dbConnections:Re,setDbConnections:Oe,activeDbConnectionId:as,setActiveDbConnectionId:Te}),p==="server"&&e.jsx(pa,{usePM2:q,setUsePM2:ae}),p==="server"&&e.jsx(ha,{usePM2:q,pm2Script:qe,setPm2Script:te,pm2Args:Ye,setPm2Args:ne,pm2Interpreter:Je,setPm2Interpreter:le,pm2InterpreterArgs:We,setPm2InterpreterArgs:ie,pm2Env:Ze,setPm2Env:oe,isEditMode:b,building:s??null,handleCommand:ee}),p==="docker"&&e.jsx(xa,{dockerMode:w,setDockerMode:ce,dockerImage:Qe,setDockerImage:ue,dockerContainerName:pe,setDockerContainerName:he,dockerCommand:ke,setDockerCommand:ye,dockerPorts:xe,setDockerPorts:be,dockerVolumes:je,setDockerVolumes:ge,dockerNetwork:Ne,setDockerNetwork:fe,dockerRestart:es,setDockerRestart:Ce,dockerPull:ss,setDockerPull:Se,dockerEnv:Xe,setDockerEnv:ve,dockerComposePath:we,setDockerComposePath:Pe,dockerComposeProject:De,setDockerComposeProject:Ee,dockerComposeServices:Le,setDockerComposeServices:ze,selectedExistingContainer:me,setSelectedExistingContainer:de,dockerContainersList:d,isEditMode:b,building:s??null,handleCommand:ee}),p==="terminal"&&e.jsx(Na,{terminalShell:ts,setTerminalShell:Ie,terminalPort:_e,setTerminalPort:$e,terminalSaveSession:ns,setTerminalSaveSession:Fe,terminalArgs:ls,setTerminalArgs:Me,isEditMode:b,building:s??null,handleCommand:ee,onOpenTerminal:()=>{s!=null&&s.id&&window.dispatchEvent(new CustomEvent("tide:open-iframe-modal",{detail:{buildingId:s.id}}))},onOpenBelow:i=>{window.dispatchEvent(new CustomEvent("tide:open-bottom-terminal",{detail:{buildingId:i}}))}}),p==="server"&&!q&&e.jsx(ga,{startCmd:W,setStartCmd:K,stopCmd:Z,setStopCmd:H,restartCmd:O,setRestartCmd:G,healthCheckCmd:T,setHealthCheckCmd:I,logsCmd:k,setLogsCmd:L,isEditMode:b,handleCommand:ee}),e.jsxs("div",{className:"form-section",children:[e.jsxs("label",{className:"form-label",children:[t("config:buildings.links"),e.jsxs("button",{type:"button",className:"btn btn-sm btn-add",onClick:Xs,children:["+ ",t("common:buttons.add")]})]}),z.map((i,f)=>e.jsxs("div",{className:"url-row",children:[e.jsx("input",{type:"text",className:"form-input url-label",value:i.label,onChange:S=>rs(f,"label",S.target.value),placeholder:"Label"}),e.jsx("input",{type:"text",className:"form-input url-value",value:i.url,onChange:S=>rs(f,"url",S.target.value),placeholder:"https://..."}),e.jsx("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>ea(f),children:"x"})]},f))]}),b&&C&&cs.length>0&&e.jsx(fa,{logs:cs,buildingId:c,logsContainerRef:X})]}),e.jsxs("div",{className:"modal-footer",children:[b&&e.jsx("button",{type:"button",className:"btn btn-danger",onClick:Zs,children:t("common:buttons.delete")}),e.jsx("div",{className:"footer-spacer"}),e.jsx("button",{type:"button",className:"btn btn-secondary",onClick:l,children:t("common:buttons.cancel")}),e.jsx("button",{type:"submit",className:"btn btn-primary",children:t(b?"common:buttons.save":"common:buttons.create")})]})]})]}),Vs&&s&&e.jsx(ua,{buildingName:s.name,onClose:()=>re(!1),onConfirm:Qs})]})}export{Sa as BuildingConfigModal};
|