tide-commander 1.95.0 → 1.97.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/assets/{BossLogsModal-BNfB6g0E.js → BossLogsModal-CT25hD17.js} +1 -1
  2. package/dist/assets/{BossSpawnModal-BIcCbrjM.js → BossSpawnModal-9rS7AFkZ.js} +1 -1
  3. package/dist/assets/{ControlsModal-CS5jOEdY.js → ControlsModal-D-mymoM7.js} +1 -1
  4. package/dist/assets/{DockerLogsModal-B6sUNqY_.js → DockerLogsModal-Ae-ZCeeP.js} +1 -1
  5. package/dist/assets/EmbeddedEditor-DLOOpM0K.js +33 -0
  6. package/dist/assets/{GmailOAuthSetup-OPmwhJyE.js → GmailOAuthSetup-C9NLhWLo.js} +1 -1
  7. package/dist/assets/{GoogleOAuthSetup-BEc7lAua.js → GoogleOAuthSetup-1kzgrPV6.js} +1 -1
  8. package/dist/assets/{IframeModal-VrlQUMlO.js → IframeModal-DKS0IFsr.js} +1 -1
  9. package/dist/assets/{IntegrationsPanel-ta1yp-s4.js → IntegrationsPanel-CBvKOeud.js} +2 -2
  10. package/dist/assets/{LogViewerModal-B_4ke-1p.js → LogViewerModal-Dlt8JfVg.js} +1 -1
  11. package/dist/assets/{MonitoringModal-BHAuVdYA.js → MonitoringModal-BM1IEZv6.js} +1 -1
  12. package/dist/assets/{PM2LogsModal-BfKic3hD.js → PM2LogsModal-B1-HUHWZ.js} +1 -1
  13. package/dist/assets/{RestoreArchivedAreaModal-Bxk9GcPa.js → RestoreArchivedAreaModal-DXmYo7fp.js} +1 -1
  14. package/dist/assets/{Scene2DCanvas-COVSkNbV.js → Scene2DCanvas-CuUxSaPb.js} +1 -1
  15. package/dist/assets/{SceneManager-DWVI2idg.js → SceneManager-UD3IHY20.js} +1 -1
  16. package/dist/assets/{SkillsPanel-BnKqbJyg.js → SkillsPanel-DjRBVrO2.js} +1 -1
  17. package/dist/assets/SlackMultiInstanceSetup-Csp81Dqn.js +2 -0
  18. package/dist/assets/{SpawnModal-ClZUpgWy.js → SpawnModal-dg0mH3d9.js} +1 -1
  19. package/dist/assets/{SubordinateAssignmentModal-Dn8tejNU.js → SubordinateAssignmentModal-CeBPRNNX.js} +1 -1
  20. package/dist/assets/{TriggerManagerPanel-oBoHJdcv.js → TriggerManagerPanel-D1QPpFhP.js} +1 -1
  21. package/dist/assets/{WorkflowEditorPanel-Bwju9-46.js → WorkflowEditorPanel-IIsptZgp.js} +1 -1
  22. package/dist/assets/{index-Bu_n7vgB.js → index-BGh9tRSy.js} +1 -1
  23. package/dist/assets/{index-CfliOGe8.js → index-CIqkVLo1.js} +1 -1
  24. package/dist/assets/{index-CBh6qNCb.js → index-CNDUxsGy.js} +1 -1
  25. package/dist/assets/{index-umTVv-4x.js → index-CR9w26tq.js} +1 -1
  26. package/dist/assets/{index-DMUs4kjY.js → index-CsyPNc8u.js} +1 -1
  27. package/dist/assets/{index-DvBhO5je.js → index-DEI-vrXk.js} +1 -1
  28. package/dist/assets/{index-DgwVJN80.js → index-h-IcmGfB.js} +2 -2
  29. package/dist/assets/index-sDgBtEgH.js +19 -0
  30. package/dist/assets/{index-fIzifjgU.js → index-vJkimYqD.js} +1 -1
  31. package/dist/assets/main-BV_IuaBg.css +1 -0
  32. package/dist/assets/main-klWBzHh0.js +214 -0
  33. package/dist/assets/{web-Cp8n5FK3.js → web-BgPjNMBK.js} +1 -1
  34. package/dist/assets/{web-pfDqogx0.js → web-BmPSJLwQ.js} +1 -1
  35. package/dist/assets/{web-BD4VGICh.js → web-Dggt4D4N.js} +1 -1
  36. package/dist/index.html +2 -2
  37. package/dist/src/packages/server/data/builtin-skills/create-building.js +521 -484
  38. package/dist/src/packages/server/integrations/slack/slack-config.js +13 -0
  39. package/dist/src/packages/server/integrations/slack/slack-trigger-handler.js +12 -4
  40. package/dist/src/packages/server/routes/buildings.js +298 -0
  41. package/dist/src/packages/server/routes/index.js +3 -1
  42. package/dist/src/packages/server/services/building-service.js +400 -85
  43. package/dist/src/packages/server/websocket/handler.js +2 -4
  44. package/package.json +1 -1
  45. package/dist/assets/EmbeddedEditor-DiXmHZpX.js +0 -1
  46. package/dist/assets/SlackMultiInstanceSetup-BuA87Vlm.js +0 -2
  47. package/dist/assets/index-CXBrQLNP.js +0 -51
  48. package/dist/assets/main-BaGMbjuZ.js +0 -214
  49. package/dist/assets/main-BfT_95fk.css +0 -1
@@ -3,667 +3,704 @@ const BT3 = '```';
3
3
  export const createBuilding = {
4
4
  slug: 'create-building',
5
5
  name: 'Create Building',
6
- description: 'Create and manage buildings and areas in Tide Commander with full control over configuration and placement',
7
- allowedTools: ['Bash(jq:*)', 'Bash(curl:*)', 'Bash(cat:*)'],
6
+ description: 'Create, configure, control, and inspect buildings in Tide Commander via the /api/buildings REST API',
7
+ allowedTools: ['Bash(curl:*)', 'Bash(jq:*)'],
8
8
  content: `# Create Building Skill
9
9
 
10
- This skill enables you to create, configure, and manage buildings in Tide Commander's battlefield.
10
+ This skill manages buildings in Tide Commander's battlefield through the
11
+ REST API. The server validates input, assigns IDs, encrypts credentials,
12
+ broadcasts updates to connected clients, and reconciles PM2 / Docker /
13
+ Terminal runtime state. **Do not edit ${BT}buildings.json${BT} directly** — the
14
+ server is the authority for that file.
11
15
 
12
- ## IMPORTANT: Use PM2 Mode for All Server Buildings
16
+ ## API Calling Convention
13
17
 
14
- **Always use PM2 mode when possible** - it provides:
15
- - Auto-restart on crash
16
- - CPU/memory/PID tracking
17
- - Port auto-detection
18
- - Process persistence across restarts
19
- - Unified log streaming
20
- - Status monitoring
18
+ Every call uses the standard scaffolding from your system prompt:
21
19
 
22
- Only use custom commands if PM2 cannot handle your use case.
23
-
24
- ## Step 1: Explore Existing Buildings First
20
+ ${BT3}bash
21
+ curl -s -X <METHOD> -H "X-Auth-Token: <TOKEN>" \\
22
+ http://localhost:5174/api/buildings<path> \\
23
+ -H "Content-Type: application/json" -d '<json-body>'
24
+ ${BT3}
25
25
 
26
- Before creating a new building, ALWAYS examine existing ones for patterns and positioning:
26
+ The substitutions on every call:
27
+ - ${BT}<METHOD>${BT} — HTTP verb (GET, POST, PATCH, DELETE)
28
+ - ${BT}<path>${BT} — endpoint path (begins with ${BT}/${BT})
29
+ - ${BT}<json-body>${BT} — JSON body (omit for GET/DELETE)
30
+ - ${BT}<TOKEN>${BT} — the auth token from your system prompt
31
+ - **No exclamation marks** anywhere in the command — bash history expansion will corrupt it.
32
+
33
+ ## Endpoint Reference
34
+
35
+ | Method | Path | Purpose |
36
+ |--------|------|---------|
37
+ | GET | ${BT}/api/buildings${BT} | List all buildings (secrets redacted) |
38
+ | GET | ${BT}/api/buildings/:id${BT} | Get one building (secrets redacted) |
39
+ | POST | ${BT}/api/buildings${BT} | Create a building |
40
+ | PATCH | ${BT}/api/buildings/:id${BT} | Partial update |
41
+ | DELETE | ${BT}/api/buildings/:id?cleanup=false${BT} | Delete (default: tear down PM2/Docker/etc.) |
42
+ | POST | ${BT}/api/buildings/:id/command${BT} | ${BT}{"command":"start|stop|restart|healthCheck|logs|delete"}${BT} |
43
+ | GET | ${BT}/api/buildings/:id/logs?lines=200&service=foo${BT} | Snapshot logs (PM2/Docker/custom) |
44
+ | POST | ${BT}/api/buildings/:id/sync-status${BT} | Force PM2/Docker status refresh |
45
+ | POST | ${BT}/api/buildings/:id/subordinates${BT} | ${BT}{"subordinateBuildingIds":[...]}${BT} (boss only) |
46
+ | POST | ${BT}/api/buildings/boss/:id/command${BT} | ${BT}{"command":"start_all|stop_all|restart_all"}${BT} |
47
+ | GET | ${BT}/api/buildings/docker/containers${BT} | List adoptable Docker containers and compose projects |
48
+
49
+ The server assigns ${BT}id${BT}, ${BT}createdAt${BT}, ${BT}lastActivity${BT}, and initial
50
+ ${BT}status${BT}. Do not send them. POST returns the full building (201). PATCH
51
+ returns the merged building. DELETE returns ${BT}{"deleted":true}${BT}.
52
+
53
+ Validation failures return ${BT}400${BT} with ${BT}{"error":"Validation failed","errors":[...]}${BT}.
54
+
55
+ ## Step 1: Inspect what's there
27
56
 
28
57
  ${BT3}bash
29
- # List all buildings with their main properties
30
- jq '.buildings | map({name, type, cwd, "pm2_script": .pm2.script, status})' ~/.local/share/tide-commander/buildings.json
58
+ # List all buildings — filter with jq for readability
59
+ curl -s -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
60
+ | jq '.buildings | map({id, name, type, status, cwd})'
31
61
 
32
- # View a specific building's full config (use as template)
33
- jq '.buildings[] | select(.name == "Navi Back")' ~/.local/share/tide-commander/buildings.json
62
+ # One building's full config
63
+ curl -s -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings/<id>
34
64
 
35
- # See all PM2 configurations
36
- jq '.buildings[] | select(.pm2.enabled == true) | {name, cwd, pm2}' ~/.local/share/tide-commander/buildings.json
65
+ # All PM2 buildings
66
+ curl -s -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
67
+ | jq '.buildings[] | select(.pm2.enabled == true) | {name, port: .pm2.env.PORT, status}'
37
68
 
38
- # See all boss buildings and their subordinates
39
- jq '.buildings[] | select(.type == "boss") | {name, subordinateBuildingIds}' ~/.local/share/tide-commander/buildings.json
69
+ # Existing Docker containers ready to be adopted (mode "existing")
70
+ curl -s -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings/docker/containers \\
71
+ | jq '.containers | map({id: .id[0:12], name, image, status})'
72
+ ${BT3}
40
73
 
41
- # Find buildings listening on specific ports
42
- jq '.buildings[] | select(.pm2.env.PORT != null) | {name, port: .pm2.env.PORT}' ~/.local/share/tide-commander/buildings.json
74
+ ## Step 2: Building schema
43
75
 
44
- # Count buildings by type
45
- jq '[.buildings[].type] | group_by(.) | map({type: .[0], count: length})' ~/.local/share/tide-commander/buildings.json
76
+ These fields are accepted by ${BT}POST /api/buildings${BT}. ${BT}name${BT}, ${BT}type${BT}, and
77
+ ${BT}position${BT} are always required. Style defaults per type if omitted.
46
78
 
47
- # List all areas with positions (to know where to place buildings)
48
- jq '.areas | map({name, center, width, height})' ~/.local/share/tide-commander/areas.json
79
+ ${BT3}typescript
80
+ {
81
+ name: string, // Display name
82
+ type: 'server'|'link'|'database'|'docker'|'monitor'|'folder'|'boss'|'terminal',
83
+ position: { x: number, z: number },
84
+ style?: 'server-rack'|'tower'|'dome'|'pyramid'|'desktop'
85
+ | 'filing-cabinet'|'satellite'|'crystal'|'factory'|'command-center',
86
+ color?: string, // Hex (e.g. "#4a90d9")
87
+ scale?: number, // ~0.5 small, 1.0 large
88
+ cwd?: string, // Working directory
89
+ pm2?: { ... }, // Server type — see below
90
+ docker?: { ... }, // Docker type — see below
91
+ database?: { connections: [...] }, // Database type
92
+ terminal?: { ... }, // Terminal type
93
+ folderPath?: string, // Folder type — required
94
+ urls?: [{ label, url }], // Link type — required
95
+ commands?: { start, stop, restart, healthCheck, logs }, // Non-PM2 server custom commands
96
+ subordinateBuildingIds?: string[], // Boss type
97
+ }
49
98
  ${BT3}
50
99
 
51
- ## Step 2: Create the Building
100
+ ### PM2 sub-schema (server buildings)
101
+
102
+ ${BT3}typescript
103
+ pm2: {
104
+ enabled: true,
105
+ script: string, // REQUIRED
106
+ args?: string,
107
+ interpreter?: ''|'node'|'bun'|'python3'|'python'|'java'|'php'|'bash'|'none',
108
+ interpreterArgs?: string,
109
+ env?: Record<string, string>,
110
+ instances?: number, // Cluster mode (default 1)
111
+ autorestart?: boolean, // Default true
112
+ maxRestarts?: number, // Default 10
113
+ name?: string, // Custom PM2 app name
114
+ }
115
+ ${BT3}
52
116
 
53
- ### Building Types
117
+ ### Docker sub-schema
54
118
 
55
- - **server**: PM2-managed service with start/stop/restart and log streaming
56
- - **database**: Database connection (MySQL 3306, PostgreSQL 5432, Oracle 1521)
57
- - **docker**: Docker container/compose management (container, compose, or existing mode)
58
- - **link**: Quick URL shortcuts
59
- - **folder**: Opens file explorer at configured path
60
- - **boss**: Manages group of subordinate buildings with unified controls
61
- - **monitor**: System metrics display
119
+ ${BT3}typescript
120
+ docker: {
121
+ enabled: true,
122
+ mode: 'container' | 'compose' | 'existing',
123
+
124
+ // mode === 'container' (REQUIRED: image)
125
+ image?: string,
126
+ containerName?: string,
127
+ ports?: string[], // ["3000:3000"]
128
+ volumes?: string[], // ["/host:/container"]
129
+ env?: Record<string, string>,
130
+ network?: string,
131
+ command?: string,
132
+ restart?: 'no'|'always'|'unless-stopped'|'on-failure',
133
+ pull?: 'always'|'missing'|'never',
134
+
135
+ // mode === 'compose' (REQUIRED: composePath)
136
+ composePath?: string, // Relative to cwd
137
+ services?: string[],
138
+ composeProject?: string,
139
+
140
+ // mode === 'existing' (REQUIRED: containerName from /docker/containers)
141
+ }
142
+ ${BT3}
62
143
 
63
- ### Building Styles
144
+ ### Database connection sub-schema
64
145
 
65
- server-rack, tower, dome, pyramid, desktop, filing-cabinet, satellite, crystal, factory, command-center
146
+ ${BT3}typescript
147
+ database: {
148
+ activeConnectionId?: string,
149
+ activeDatabase?: string,
150
+ connections: [{
151
+ id: string,
152
+ name: string,
153
+ engine: 'mysql'|'postgresql'|'oracle'|'sqlite'|'mssql',
154
+ host: string, // omit for sqlite
155
+ port: number, // omit for sqlite
156
+ username?: string,
157
+ password?: string, // Encrypted at rest
158
+ database?: string, // Service/PDB name for Oracle
159
+ filepath?: string, // REQUIRED for sqlite
160
+ ssl?: boolean,
161
+ sslConfig?: { rejectUnauthorized, ca, cert, key },
162
+ ssh?: { // Optional SSH tunnel
163
+ enabled: true,
164
+ host, port, username,
165
+ authMethod: 'password'|'privateKey',
166
+ password?, privateKey?, privateKeyPath?, passphrase?,
167
+ localPort?, keepaliveIntervalMs?, readyTimeoutMs?,
168
+ },
169
+ }],
170
+ }
171
+ ${BT3}
66
172
 
67
- ## Real Examples from Existing Buildings
173
+ ### Terminal sub-schema
68
174
 
69
- ### Bun/Node.js Service (Navi Back - Port 8008)
175
+ ${BT3}typescript
176
+ terminal: {
177
+ enabled: true, // REQUIRED for type 'terminal'
178
+ shell?: string, // Defaults to $SHELL or bash
179
+ port?: number, // Auto-assigned from 7681+
180
+ args?: string, // Extra ttyd args
181
+ saveSession?: boolean, // tmux-backed persistence
182
+ sessionName?: string,
183
+ }
184
+ ${BT3}
185
+
186
+ Default ports: MySQL 3306, PostgreSQL 5432, Oracle 1521, SQL Server 1433.
187
+
188
+ ## Step 3: Create the building
189
+
190
+ ### Bun/Node service with PM2
70
191
 
71
192
  ${BT3}bash
72
- jq '.buildings += [{
73
- "name": "Navi Back",
193
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
194
+ -H "Content-Type: application/json" -d '{
195
+ "name": "Wind Front",
74
196
  "type": "server",
75
- "style": "server-rack",
76
- "color": "#2a4a3a",
77
- "position": {"x": 9.66, "z": -7.87},
78
- "cwd": "/home/riven/d/navi/back",
197
+ "style": "desktop",
198
+ "color": "#4a3a2a",
199
+ "position": {"x": -3.5, "z": -8.0},
200
+ "cwd": "/home/user/projects/wind/front",
79
201
  "pm2": {
80
202
  "enabled": true,
81
- "script": "/home/riven/.bun/bin/bun",
203
+ "script": "/home/user/.bun/bin/bun",
82
204
  "args": "run dev",
83
205
  "interpreter": "none",
84
- "env": {"PORT": "8008"}
206
+ "env": {"PORT": "6205"}
85
207
  },
86
- "scale": 0.75,
87
- "id": "building_1707471234567_navi_back",
88
- "status": "stopped",
89
- "createdAt": 1707471234567,
90
- "lastActivity": 1707471234567
91
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
208
+ "scale": 0.75
209
+ }'
92
210
  ${BT3}
93
211
 
94
- Key: Full path to Bun binary, interpreter "none", PORT via env var.
212
+ For Vite frontends, the project's ${BT}vite.config.*${BT} must honour ${BT}process.env.PORT${BT}
213
+ (otherwise PM2 sets the var but Vite ignores it).
95
214
 
96
- ### Symfony Service (MDO Back - Port 7200)
215
+ ### Bun with port passed in args (no env var needed)
97
216
 
98
217
  ${BT3}bash
99
- jq '.buildings += [{
100
- "name": "MDO back",
218
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
219
+ -H "Content-Type: application/json" -d '{
220
+ "name": "MDO Front",
221
+ "type": "server",
222
+ "position": {"x": -9.5, "z": 2.55},
223
+ "cwd": "/home/user/projects/mdo/front",
224
+ "pm2": { "enabled": true, "script": "bun", "args": "dev --port 6200", "interpreter": "none" }
225
+ }'
226
+ ${BT3}
227
+
228
+ ### Symfony service (port in args, no --daemon)
229
+
230
+ ${BT3}bash
231
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
232
+ -H "Content-Type: application/json" -d '{
233
+ "name": "MDO Back",
101
234
  "type": "server",
102
- "style": "server-rack",
103
- "color": "#2a3a3a",
104
235
  "position": {"x": -11.67, "z": 2.55},
105
- "cwd": "/home/riven/d/mdo/back",
236
+ "cwd": "/home/user/projects/mdo/back",
106
237
  "pm2": {
107
238
  "enabled": true,
108
239
  "script": "symfony",
109
240
  "args": "server:start --allow-http --port=7200",
110
241
  "interpreter": "none"
111
- },
112
- "scale": 0.75,
113
- "id": "building_1769553740335_mdo_back",
114
- "status": "stopped",
115
- "createdAt": 1769553740335
116
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
117
- ${BT3}
118
-
119
- **Symfony-Specific Instructions:**
120
- - Script: "symfony" (requires Symfony CLI installed and in PATH)
121
- - Args: "server:start --allow-http --port=XXXX --no-tls"
122
- - --allow-http: Allows HTTP (use for dev). Remove for HTTPS
123
- - --no-tls: Disable TLS (useful for local dev behind proxy)
124
- - **IMPORTANT: Do NOT use --daemon flag** - PM2 needs the process to run in foreground. The --daemon flag causes Symfony to fork and exit, which PM2 interprets as a crash
125
- - Port goes in args, not env vars
126
- - PM2 auto-detects port from startup output
127
- - Note: Symfony server opens an extra port (42421 in example) for the server monitor
128
- - Tip: If PM2 shows "errored", check if a Symfony daemon is already running with: symfony server:status. Stop it with: symfony server:stop
129
-
130
- ### PHP Built-in Server (Example - Port 7205)
242
+ }
243
+ }'
244
+ ${BT3}
245
+
246
+ **Symfony notes:** never use ${BT}--daemon${BT} — Symfony forks and exits, PM2 marks it errored.
247
+ If PM2 shows errored with "already running", stop the external daemon first:
248
+ ${BT}symfony server:stop${BT} from the project directory, then ${BT}POST .../command { start }${BT}.
249
+
250
+ ### PHP built-in server
131
251
 
132
252
  ${BT3}bash
133
- jq '.buildings += [{
134
- "name": "My PHP App",
253
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
254
+ -H "Content-Type: application/json" -d '{
255
+ "name": "Laravel App",
135
256
  "type": "server",
136
- "style": "server-rack",
137
- "color": "#2a3a4a",
138
257
  "position": {"x": 0.77, "z": 3.96},
139
- "cwd": "/home/riven/d/myapp",
140
- "pm2": {
141
- "enabled": true,
142
- "script": "php",
143
- "args": "-S 0.0.0.0:7205 -t public",
144
- "interpreter": "none"
145
- },
146
- "scale": 0.75,
147
- "id": "building_1770769766821_myapp",
148
- "status": "stopped",
149
- "createdAt": 1770769766821
150
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
258
+ "cwd": "/home/user/projects/laravel-app",
259
+ "pm2": { "enabled": true, "script": "php", "args": "-S 0.0.0.0:7205 -t public", "interpreter": "none" }
260
+ }'
151
261
  ${BT3}
152
262
 
153
- **PHP Server-Specific Instructions:**
154
- - Script: "php" (built-in web server, no extra tools needed)
155
- - Args: "-S 0.0.0.0:PORT -t DOCROOT"
156
- - -S: Start server on address:port
157
- - -t: Document root directory
158
- - Use 0.0.0.0 to listen on all interfaces (accessible from network)
159
- - Port goes in args after -S flag
160
-
161
- ### Maven Java Project (Pagamento)
263
+ ### Maven / Spring Boot
162
264
 
163
265
  ${BT3}bash
164
- jq '.buildings += [{
266
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
267
+ -H "Content-Type: application/json" -d '{
165
268
  "name": "Pagamento",
166
269
  "type": "server",
167
- "style": "server-rack",
168
- "color": "#3a2a3a",
169
270
  "position": {"x": -11.85, "z": 9.59},
170
- "cwd": "/home/riven/d/pagamento",
271
+ "cwd": "/home/user/projects/pagamento",
171
272
  "pm2": {
172
- "enabled": true,
173
- "script": "mvn",
174
- "args": "spring-boot:run -Dspring-boot.run.fork=false -Dspring-boot.run.profiles=dev",
175
- "interpreter": "none"
176
- },
177
- "scale": 0.75,
178
- "id": "building_1769555952700_pagamento",
179
- "status": "stopped",
180
- "createdAt": 1769555952700
181
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
273
+ "enabled": true, "script": "mvn", "interpreter": "none",
274
+ "args": "spring-boot:run -Dspring-boot.run.fork=false -Dspring-boot.run.profiles=dev"
275
+ }
276
+ }'
182
277
  ${BT3}
183
278
 
184
- Key: Script "mvn" (Maven), PM2 auto-detects port from Spring Boot logs.
185
-
186
- ### Shell Script Binary (ActiveMQ)
279
+ ### Shell-script server (ActiveMQ)
187
280
 
188
281
  ${BT3}bash
189
- jq '.buildings += [{
282
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
283
+ -H "Content-Type: application/json" -d '{
190
284
  "name": "ActiveMQ",
191
285
  "type": "server",
192
286
  "style": "filing-cabinet",
193
- "color": "#2a2a4a",
194
287
  "position": {"x": -7.30, "z": -0.15},
195
288
  "cwd": "/opt/apache-activemq-6.2.0",
196
- "pm2": {
197
- "enabled": true,
198
- "script": "./bin/activemq",
199
- "args": "console",
200
- "interpreter": "bash"
201
- },
202
- "scale": 0.5,
203
- "id": "building_1769556341280_activemq",
204
- "status": "stopped",
205
- "createdAt": 1769556341280
206
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
289
+ "pm2": { "enabled": true, "script": "./bin/activemq", "args": "console", "interpreter": "bash" }
290
+ }'
207
291
  ${BT3}
208
292
 
209
- Key: Relative path script, interpreter "bash" for shell scripts.
293
+ ### Custom-command server (no PM2)
210
294
 
211
- ### Concurrently (Tide Commander itself - Client + Server)
295
+ For servers where PM2 doesn't fit, define ${BT}commands${BT} directly. Each command runs in
296
+ ${BT}cwd${BT}. Status transitions happen on command completion.
212
297
 
213
298
  ${BT3}bash
214
- jq '.buildings += [{
215
- "name": "Tide Commander",
299
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
300
+ -H "Content-Type: application/json" -d '{
301
+ "name": "Legacy Service",
216
302
  "type": "server",
217
- "style": "command-center",
218
- "color": "#6a4a9a",
219
- "position": {"x": 6.57, "z": 10.80},
220
- "cwd": "/home/riven/d/tide-commander",
221
- "pm2": {
222
- "enabled": true,
223
- "script": "/home/riven/.bun/bin/bun",
224
- "args": "run dev",
225
- "interpreter": "none",
226
- "env": {"PORT": "5174", "LISTEN_ALL_INTERFACES": "1"}
227
- },
228
- "scale": 1.0,
229
- "id": "building_1707471234571_tide_commander",
230
- "status": "stopped",
231
- "createdAt": 1707471234571
232
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
303
+ "position": {"x": 5, "z": 5},
304
+ "cwd": "/srv/legacy",
305
+ "commands": {
306
+ "start": "./bin/start.sh",
307
+ "stop": "./bin/stop.sh",
308
+ "restart": "./bin/restart.sh",
309
+ "healthCheck": "curl -fs http://localhost:9000/health",
310
+ "logs": "tail -n 200 /srv/legacy/log/app.log"
311
+ }
312
+ }'
233
313
  ${BT3}
234
314
 
235
- Key: Full bun path, multiple env vars, uses concurrently internally.
236
-
237
- ### Bun Frontend with Port in Args (MDO Front - Port 6200)
315
+ ### Docker new container
238
316
 
239
317
  ${BT3}bash
240
- jq '.buildings += [{
241
- "name": "MDO front",
242
- "type": "server",
243
- "style": "desktop",
244
- "color": "#3a3a4a",
245
- "position": {"x": -9.5, "z": 2.55},
246
- "cwd": "/home/riven/d/mdo/front",
247
- "pm2": {
318
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
319
+ -H "Content-Type: application/json" -d '{
320
+ "name": "Redis",
321
+ "type": "docker",
322
+ "style": "dome",
323
+ "position": {"x": -8, "z": -3},
324
+ "cwd": "/home/user/projects/tide-commander",
325
+ "docker": {
248
326
  "enabled": true,
249
- "script": "bun",
250
- "args": "dev --port 6200",
251
- "interpreter": "none"
252
- },
253
- "scale": 0.75,
254
- "id": "building_1769553790570_mdo_front",
255
- "status": "stopped",
256
- "createdAt": 1769553790570
257
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
327
+ "mode": "container",
328
+ "image": "redis:7-alpine",
329
+ "ports": ["6379:6379"],
330
+ "restart": "unless-stopped"
331
+ }
332
+ }'
258
333
  ${BT3}
259
334
 
260
- **Bun with Port in Args:**
261
- - Script: "bun" (short name, assumes bun is in PATH)
262
- - Args: "dev --port XXXX" passes port directly to the dev server
263
- - No env var needed when the framework CLI accepts --port flag
264
- - Works with frameworks like Vite, Next.js, Nuxt where ${BT}bun dev --port${BT} is supported
265
- - Alternative: Use full path ${BT}/home/riven/.bun/bin/bun${BT} if bun is not in PATH
266
-
267
- ### Vite + Bun Frontend (Wind Front - Port 6205)
335
+ ### Docker compose project
268
336
 
269
337
  ${BT3}bash
270
- jq '.buildings += [{
271
- "name": "Wind Front",
272
- "type": "server",
273
- "style": "desktop",
274
- "color": "#4a3a2a",
275
- "position": {"x": -3.5, "z": -8.0},
276
- "cwd": "/home/riven/d/wind/front",
277
- "pm2": {
338
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
339
+ -H "Content-Type: application/json" -d '{
340
+ "name": "App Stack",
341
+ "type": "docker",
342
+ "position": {"x": -10, "z": 0},
343
+ "cwd": "/home/user/projects/app",
344
+ "docker": {
278
345
  "enabled": true,
279
- "script": "/home/riven/.bun/bin/bun",
280
- "args": "run dev",
281
- "interpreter": "none",
282
- "env": {"PORT": "6205"}
283
- },
284
- "scale": 0.75,
285
- "id": "building_1707471234572_wind_front",
286
- "status": "stopped",
287
- "createdAt": 1707471234572
288
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
346
+ "mode": "compose",
347
+ "composePath": "docker-compose.yml",
348
+ "services": ["web", "worker"]
349
+ }
350
+ }'
289
351
  ${BT3}
290
352
 
291
- **Vite Frontend Configuration:**
292
- - Script: Full path to bun binary (or "npm" if using npm)
293
- - Args: "run dev" (Vite dev server command)
294
- - **IMPORTANT: Update vite.config.mjs to read PORT env var:**
295
- - Add to server config: ${BT}port: parseInt(process.env.PORT || "6205", 10)${BT}
296
- - Add: ${BT}host: true${BT} to allow network access
297
- - Set ${BT}open: false${BT} to prevent auto-opening browser
298
- - Port passed via env var, not args
299
- - Tip: Check config with: cat vite.config.mjs | grep -A 5 "server:"
353
+ ### Docker — adopt existing container
300
354
 
301
- ### Boss Building (Navi - Manages Back & Front)
355
+ First discover ${BT}containerName${BT}:
302
356
 
303
357
  ${BT3}bash
304
- jq '.buildings += [{
305
- "name": "Navi",
306
- "type": "boss",
307
- "style": "command-center",
308
- "color": "#4a4a6a",
309
- "position": {"x": 11.36, "z": -9.77},
310
- "cwd": "/home/riven/d/navi",
311
- "commands": {},
312
- "subordinateBuildingIds": [
313
- "building_1707471234567_navi_back",
314
- "building_1707471234568_navi_front"
315
- ],
316
- "scale": 0.6,
317
- "id": "building_1707471234570_navi_boss",
318
- "status": "running",
319
- "createdAt": 1707471234570
320
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
358
+ curl -s -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings/docker/containers \\
359
+ | jq '.containers | map({name, image, status})'
321
360
  ${BT3}
322
361
 
323
- Key: subordinateBuildingIds must contain exact IDs of existing buildings.
324
-
325
- ### Docker Existing Container (Postgres 18)
362
+ Then adopt:
326
363
 
327
364
  ${BT3}bash
328
- jq '.buildings += [{
365
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
366
+ -H "Content-Type: application/json" -d '{
329
367
  "name": "Postgres 18",
330
368
  "type": "docker",
331
369
  "style": "dome",
332
370
  "color": "#336699",
333
371
  "position": {"x": -11.49, "z": -2.31},
334
- "cwd": "/home/riven/d/tide-commander",
335
- "docker": {
336
- "enabled": true,
337
- "mode": "existing",
338
- "containerId": "fc1e2a1e0481",
339
- "containerName": "postgres18"
340
- },
341
- "scale": 0.6,
342
- "id": "building_1707471234569_postgres",
343
- "status": "stopped",
344
- "createdAt": 1707471234569
345
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
372
+ "cwd": "/home/user/projects/tide-commander",
373
+ "docker": { "enabled": true, "mode": "existing", "containerName": "postgres18" }
374
+ }'
346
375
  ${BT3}
347
376
 
348
- Key: mode "existing" = monitor-only (won't delete container if building removed). Get containerId from "docker ps -a".
377
+ Mode ${BT}existing${BT} is monitor-only: deleting the building never removes the container.
349
378
 
350
- ### Database Building (MySQL)
379
+ ### Database MySQL
351
380
 
352
381
  ${BT3}bash
353
- jq '.buildings += [{
354
- "name": "MySql",
382
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
383
+ -H "Content-Type: application/json" -d '{
384
+ "name": "MySQL",
355
385
  "type": "database",
356
386
  "style": "dome",
357
387
  "position": {"x": -9.78, "z": -0.34},
358
- "cwd": "/home/riven/d/tide-commander",
359
- "commands": {},
360
388
  "database": {
361
389
  "connections": [{
362
- "id": "conn_1769620529754_db",
363
- "name": "Connection 1",
390
+ "id": "conn_mysql_prod",
391
+ "name": "Primary",
364
392
  "engine": "mysql",
365
393
  "host": "localhost",
366
394
  "port": 3306,
367
395
  "username": "root",
368
396
  "password": "root"
369
397
  }],
370
- "activeConnectionId": "conn_1769620529754_db"
371
- },
372
- "id": "building_1769620533827_mysql",
373
- "status": "stopped",
374
- "createdAt": 1769620533827
375
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
398
+ "activeConnectionId": "conn_mysql_prod"
399
+ }
400
+ }'
376
401
  ${BT3}
377
402
 
378
- Key: Engines: mysql, postgresql, oracle. Each with host/port/username/password.
403
+ ### Database PostgreSQL
379
404
 
380
- ### Database Building (Oracle)
405
+ ${BT3}bash
406
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
407
+ -H "Content-Type: application/json" -d '{
408
+ "name": "Postgres",
409
+ "type": "database",
410
+ "position": {"x": -8, "z": -0.34},
411
+ "database": {
412
+ "connections": [{
413
+ "id": "conn_pg_dev",
414
+ "name": "Dev",
415
+ "engine": "postgresql",
416
+ "host": "localhost",
417
+ "port": 5432,
418
+ "username": "postgres",
419
+ "password": "postgres",
420
+ "database": "appdb"
421
+ }]
422
+ }
423
+ }'
424
+ ${BT3}
425
+
426
+ ### Database — Oracle
381
427
 
382
428
  ${BT3}bash
383
- jq '.buildings += [{
429
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
430
+ -H "Content-Type: application/json" -d '{
384
431
  "name": "Oracle",
385
432
  "type": "database",
386
433
  "style": "factory",
387
- "position": {"x": -8.0, "z": -0.34},
388
- "cwd": "/home/riven/d/tide-commander",
389
- "commands": {},
434
+ "position": {"x": -7, "z": -0.34},
390
435
  "database": {
391
436
  "connections": [{
392
- "id": "conn_1769624485179_oracle",
393
- "name": "Connection 1",
437
+ "id": "conn_ora_dev",
438
+ "name": "Dev",
394
439
  "engine": "oracle",
395
440
  "host": "127.0.0.1",
396
441
  "port": 1521,
397
- "username": "MY_USER",
398
- "password": "my_password",
442
+ "username": "APP_USER",
443
+ "password": "secret",
399
444
  "database": "ORCLPDB1"
400
- }],
401
- "activeConnectionId": "conn_1769624485179_oracle"
402
- },
403
- "id": "building_1769624489000_oracle",
404
- "status": "stopped",
405
- "createdAt": 1769624489000
406
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
445
+ }]
446
+ }
447
+ }'
407
448
  ${BT3}
408
449
 
409
- **Oracle-Specific:**
410
- - Engine: "oracle", default port: 1521
411
- - ${BT}database${BT} field: the PDB/service name (e.g., "ORCLPDB1")
412
- - Host: typically 127.0.0.1 for local Oracle XE/Docker instances
450
+ ### Database — SQLite
451
+
452
+ ${BT3}bash
453
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
454
+ -H "Content-Type: application/json" -d '{
455
+ "name": "Local Cache",
456
+ "type": "database",
457
+ "position": {"x": -6, "z": -0.34},
458
+ "database": {
459
+ "connections": [{
460
+ "id": "conn_sqlite",
461
+ "name": "cache.db",
462
+ "engine": "sqlite",
463
+ "filepath": "/home/user/projects/app/cache.db"
464
+ }]
465
+ }
466
+ }'
467
+ ${BT3}
413
468
 
414
- ### Terminal Building (ttyd Web Terminal)
469
+ ### Database with SSH tunnel
415
470
 
416
471
  ${BT3}bash
417
- jq '.buildings += [{
472
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
473
+ -H "Content-Type: application/json" -d '{
474
+ "name": "Prod MySQL via Bastion",
475
+ "type": "database",
476
+ "position": {"x": -5, "z": -0.34},
477
+ "database": {
478
+ "connections": [{
479
+ "id": "conn_prod_via_ssh",
480
+ "name": "Prod",
481
+ "engine": "mysql",
482
+ "host": "10.0.0.5",
483
+ "port": 3306,
484
+ "username": "appuser",
485
+ "password": "secret",
486
+ "ssh": {
487
+ "enabled": true,
488
+ "host": "bastion.example.com",
489
+ "port": 22,
490
+ "username": "ops",
491
+ "authMethod": "privateKey",
492
+ "privateKeyPath": "/home/user/.ssh/bastion_ed25519"
493
+ }
494
+ }]
495
+ }
496
+ }'
497
+ ${BT3}
498
+
499
+ The ${BT}host${BT}/${BT}port${BT} are as seen *from the SSH server*. The server allocates a
500
+ local forwarded port automatically unless you set ${BT}ssh.localPort${BT}.
501
+
502
+ ### Terminal (ttyd web shell)
503
+
504
+ ${BT3}bash
505
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
506
+ -H "Content-Type: application/json" -d '{
418
507
  "name": "Dev Terminal",
419
508
  "type": "terminal",
420
509
  "style": "desktop",
421
510
  "color": "#a855f7",
422
- "position": {"x": -8.0, "z": 1.5},
423
- "cwd": "/home/riven/d/my-project",
424
- "terminal": {
425
- "enabled": true,
426
- "shell": "/bin/zsh",
427
- "saveSession": true
428
- },
429
- "id": "building_1707471234569_devterm",
430
- "status": "stopped",
431
- "createdAt": 1707471234569
432
- }]' ~/.local/share/tide-commander/buildings.json > /tmp/b.json && mv /tmp/b.json ~/.local/share/tide-commander/buildings.json
511
+ "position": {"x": -8, "z": 1.5},
512
+ "cwd": "/home/user/projects/my-project",
513
+ "terminal": { "enabled": true, "shell": "/bin/zsh", "saveSession": true }
514
+ }'
433
515
  ${BT3}
434
516
 
435
- Key: Requires ${BT}ttyd${BT} installed. ${BT}saveSession: true${BT} uses tmux for session persistence (requires ${BT}tmux${BT}). Port auto-assigned from 7681+. Click running terminal building to open in browser.
517
+ Requires ${BT}ttyd${BT} installed; ${BT}saveSession: true${BT} also needs ${BT}tmux${BT}.
436
518
 
437
- ## Step 3: Verify
519
+ ### Folder shortcut
438
520
 
439
521
  ${BT3}bash
440
- # Validate JSON
441
- jq empty ~/.local/share/tide-commander/buildings.json && echo "Valid JSON"
442
-
443
- # Count buildings
444
- jq '.buildings | length' ~/.local/share/tide-commander/buildings.json
445
-
446
- # Check the new building
447
- jq '.buildings[-1] | {name, type, status}' ~/.local/share/tide-commander/buildings.json
522
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
523
+ -H "Content-Type: application/json" -d '{
524
+ "name": "Projects",
525
+ "type": "folder",
526
+ "style": "filing-cabinet",
527
+ "position": {"x": 8, "z": -2},
528
+ "folderPath": "/home/user/projects"
529
+ }'
448
530
  ${BT3}
449
531
 
450
- ## Framework-Specific Configuration
451
-
452
- ### Symfony (PHP Framework)
453
-
454
- **Requirements:**
455
- - Symfony CLI must be installed and in PATH
456
- - Use "server:start" command (Symfony local web server)
532
+ ### Link shortcut
457
533
 
458
- **Configuration:**
459
534
  ${BT3}bash
460
- "pm2": {
461
- "enabled": true,
462
- "script": "symfony",
463
- "args": "server:start --allow-http --port=7200",
464
- "interpreter": "none"
465
- }
535
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
536
+ -H "Content-Type: application/json" -d '{
537
+ "name": "Docs",
538
+ "type": "link",
539
+ "style": "tower",
540
+ "position": {"x": 10, "z": 0},
541
+ "urls": [{"label": "Internal Wiki", "url": "https://wiki.example.com"}]
542
+ }'
466
543
  ${BT3}
467
544
 
468
- **Key Options:**
469
- - server:start: Start the Symfony local web server (runs in foreground - required for PM2)
470
- - --allow-http: Allow HTTP (remove for production/HTTPS)
471
- - --no-tls: Disable TLS certificate generation
472
- - --port=XXXX: Listening port
473
- - **NEVER use --daemon**: This forks the process and PM2 loses track of it
474
- - Extra ports: Symfony opens additional monitoring ports (e.g., 42421)
475
- - Auto-detects port from startup logs
545
+ ### Monitor
476
546
 
477
- **Debugging Symfony with PM2:**
478
547
  ${BT3}bash
479
- # Check if symfony CLI is installed
480
- symfony --version
481
-
482
- # Check if a daemon is already running (common cause of PM2 "errored" status)
483
- cd /path/to/symfony/project && symfony server:status
548
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
549
+ -H "Content-Type: application/json" -d '{
550
+ "name": "Host Metrics",
551
+ "type": "monitor",
552
+ "style": "satellite",
553
+ "position": {"x": 12, "z": 4}
554
+ }'
555
+ ${BT3}
484
556
 
485
- # Stop any existing daemon before PM2 can manage it
486
- cd /path/to/symfony/project && symfony server:stop
557
+ ### Boss building
487
558
 
488
- # Run manually to debug issues (foreground - same as PM2 will run it)
489
- cd /path/to/symfony/project && symfony server:start --allow-http --port=7200
559
+ Subordinates must already exist. Get their IDs from a ${BT}GET /api/buildings${BT} list first.
490
560
 
491
- # View PM2 logs
492
- pm2 logs [building_name_from_pm2_list]
561
+ ${BT3}bash
562
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings \\
563
+ -H "Content-Type: application/json" -d '{
564
+ "name": "Navi",
565
+ "type": "boss",
566
+ "style": "command-center",
567
+ "position": {"x": 11.36, "z": -9.77},
568
+ "subordinateBuildingIds": ["building_..._navi_back", "building_..._navi_front"]
569
+ }'
493
570
  ${BT3}
494
571
 
495
- ### PHP Built-in Server
572
+ To change the subordinate list later:
496
573
 
497
- **Requirements:**
498
- - PHP installed and in PATH
499
- - No extra tools needed
500
-
501
- **Configuration:**
502
574
  ${BT3}bash
503
- "pm2": {
504
- "enabled": true,
505
- "script": "php",
506
- "args": "-S 0.0.0.0:7205 -t public",
507
- "interpreter": "none"
508
- }
575
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" \\
576
+ http://localhost:5174/api/buildings/<boss-id>/subordinates \\
577
+ -H "Content-Type: application/json" \\
578
+ -d '{"subordinateBuildingIds": ["<id1>", "<id2>"]}'
509
579
  ${BT3}
510
580
 
511
- **Key Options:**
512
- - -S address:port: Bind server to address and port
513
- - 0.0.0.0: Listen on all interfaces (accessible from network)
514
- - localhost: Only accessible locally
515
- - -t docroot: Document root (where index.php is)
516
-
517
- **Ideal for:**
518
- - Laravel projects (document root: "public")
519
- - Custom PHP apps
520
- - Quick prototypes
521
- - Development only (not production-grade)
522
-
523
- ## Lessons Learned from Real Deployments
524
-
525
- ### Symfony Server with PM2
526
- - **Problem**: Symfony server with ${BT}--daemon${BT} forks to background and exits immediately. PM2 sees the parent exit and marks the process as "errored" or "stopped"
527
- - **Solution**: Do NOT use ${BT}--daemon${BT} flag. PM2 must be the process manager, so Symfony must run in foreground: ${BT}server:start --allow-http --port=7200${BT}
528
- - **Debugging**: If PM2 shows "errored" with "already running" in logs, a Symfony daemon is running outside PM2. Stop it first: ${BT}cd /project/dir && symfony server:stop${BT}, then restart via PM2
529
- - **Port Monitoring**: Opens main port + monitor port (e.g., 7205 + 42421)
530
-
531
- ### Vite Configuration for Environment Variables
532
- - **Problem**: PORT env var set in PM2 but Vite ignores it (uses hardcoded port)
533
- - **Solution**: Update vite.config.mjs to read PORT from process.env:
534
- - ${BT3}javascript
535
- - server: {
536
- - port: parseInt(process.env.PORT || "6205", 10),
537
- - open: false,
538
- - host: true,
539
- - }
540
- - ${BT3}
541
- - **Verification**: ${BT}ss -tlnp | grep PORT_NUMBER${BT} shows process listening
542
- - **Tip**: Set ${BT}open: false${BT} to prevent browser pop-ups in headless environments
543
-
544
- ### Binary Corruption Issues
545
- - **Problem**: Bun binary shows "cannot execute binary file" errors
546
- - **Solution**: Reinstall with ${BT}curl -fsSL https://bun.sh/install | bash${BT}
547
- - **Verification**: ${BT}bun --version${BT} returns version number
548
-
549
- ## PM2 Configuration Rules
550
-
551
- 1. **Always use PM2 mode** for server buildings (pm2.enabled: true)
552
- 2. **Script paths**:
553
- - Full path for binaries not in PATH: /home/riven/.bun/bin/bun
554
- - Short name for PATH tools: symfony, php, mvn, node, bun
555
- - Relative path for project scripts: ./bin/activemq
556
- 3. **Interpreter values**:
557
- - "none": Direct binary execution (most common - php, mvn, symfony, bun)
558
- - "bash": Shell scripts needing interpretation
559
- - "node": Explicitly running a .js file
560
- 4. **Port strategy**:
561
- - Vite/Node apps: set via env var (PORT)
562
- - PHP/Symfony/Java: set via args (--port=XXXX or -S ADDR:PORT)
563
- - PM2 auto-detects ports from console output
564
- 5. **Special cases**:
565
- - Symfony: Do NOT use --daemon (PM2 needs foreground process)
566
- - Vite: Update vite.config.mjs to read PORT env var
567
- - Full bun path: Use /home/riven/.bun/bin/bun (not just "bun")
568
-
569
- ## Important Notes
570
-
571
- - File: ~/.local/share/tide-commander/buildings.json
572
- - IDs must be unique: building_<timestamp>_<name>
573
- - Scale: 0.5 (small), 0.75 (normal), 1.0 (large)
574
- - Always validate JSON after modifications
575
- - Refresh Tide Commander UI to see new buildings
576
- - Check "pm2 list" to verify building started correctly
577
- - Position buildings inside their designated area (check areas.json for coordinates)
578
-
579
- ---
580
-
581
- ## Area Management
582
-
583
- Areas are project zones on the battlefield that group agents and buildings. File: ~/.local/share/tide-commander/areas.json
584
-
585
- ### Area Schema (DrawingArea)
586
-
587
- **CRITICAL: Follow this schema exactly. Incorrect fields will crash the application.**
581
+ ## Step 4: Control buildings
588
582
 
589
- ${BT3}typescript
590
- {
591
- "id": string, // Unique ID (e.g., "my-project-area")
592
- "name": string, // Display name
593
- "type": "rectangle" | "circle", // REQUIRED - shape type
594
- "center": { "x": number, "z": number }, // REQUIRED - center position (NOT flat x/z)
595
- "width": number, // Rectangle only - width in world units
596
- "height": number, // Rectangle only - height in world units (NOT "depth")
597
- "radius": number, // Circle only - radius in world units
598
- "color": string, // Hex color (e.g., "#4a90d9")
599
- "zIndex": number, // Stacking order (0 = bottom, higher = on top)
600
- "assignedAgentIds": string[], // Agent IDs assigned to this area
601
- "directories": string[], // Associated directory paths
602
- "prompt": string // Optional - area-level system prompt for assigned agents
603
- }
583
+ ### Start / stop / restart
584
+
585
+ ${BT3}bash
586
+ # Start a single building
587
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" \\
588
+ http://localhost:5174/api/buildings/<id>/command \\
589
+ -H "Content-Type: application/json" -d '{"command":"start"}'
590
+
591
+ # Stop
592
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" \\
593
+ http://localhost:5174/api/buildings/<id>/command \\
594
+ -H "Content-Type: application/json" -d '{"command":"stop"}'
595
+
596
+ # Restart
597
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" \\
598
+ http://localhost:5174/api/buildings/<id>/command \\
599
+ -H "Content-Type: application/json" -d '{"command":"restart"}'
604
600
  ${BT3}
605
601
 
606
- **Common mistakes to avoid:**
607
- - Do NOT use flat ${BT}"x"${BT} and ${BT}"z"${BT} at root level — use ${BT}"center": {"x": ..., "z": ...}${BT}
608
- - Do NOT use ${BT}"depth"${BT} — use ${BT}"height"${BT}
609
- - Do NOT omit ${BT}"type"${BT} — always specify ${BT}"rectangle"${BT} or ${BT}"circle"${BT}
602
+ Response: ${BT}{"success": true|false, "error?": "..."}${BT}. Status updates broadcast to
603
+ the UI separately the response only confirms the command was dispatched.
610
604
 
611
- ### Create a Rectangle Area
605
+ ### Health check
612
606
 
613
607
  ${BT3}bash
614
- jq '.areas += [{
615
- "id": "my-project-area",
616
- "name": "My Project",
617
- "type": "rectangle",
618
- "center": {"x": 0, "z": 0},
619
- "width": 12,
620
- "height": 10,
621
- "color": "#4a90d9",
622
- "zIndex": 0,
623
- "assignedAgentIds": [],
624
- "directories": []
625
- }]' ~/.local/share/tide-commander/areas.json > /tmp/a.json && mv /tmp/a.json ~/.local/share/tide-commander/areas.json
626
- ${BT3}
627
-
628
- ### Create a Circle Area
608
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" \\
609
+ http://localhost:5174/api/buildings/<id>/command \\
610
+ -H "Content-Type: application/json" -d '{"command":"healthCheck"}'
611
+ ${BT3}
612
+
613
+ For PM2 buildings this checks the process is ${BT}online${BT}. For Docker buildings it
614
+ checks ${BT}status === 'running'${BT} and health check passing. For custom-command
615
+ buildings it runs ${BT}commands.healthCheck${BT}.
616
+
617
+ ### Refresh status without running a command
629
618
 
630
619
  ${BT3}bash
631
- jq '.areas += [{
632
- "id": "ops-area",
633
- "name": "Operations",
634
- "type": "circle",
635
- "center": {"x": 10, "z": -5},
636
- "radius": 6,
637
- "color": "#d94a4a",
638
- "zIndex": 0,
639
- "assignedAgentIds": [],
640
- "directories": []
641
- }]' ~/.local/share/tide-commander/areas.json > /tmp/a.json && mv /tmp/a.json ~/.local/share/tide-commander/areas.json
620
+ # Pulls the latest PM2/Docker/Terminal status now, updates the building, broadcasts
621
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" \\
622
+ http://localhost:5174/api/buildings/<id>/sync-status
642
623
  ${BT3}
643
624
 
644
- ### List Existing Areas
625
+ ### Boss controls (start_all / stop_all / restart_all)
645
626
 
646
627
  ${BT3}bash
647
- jq '.areas | map({id, name, type, center, width, height, radius})' ~/.local/share/tide-commander/areas.json
628
+ curl -s -X POST -H "X-Auth-Token: <TOKEN>" \\
629
+ http://localhost:5174/api/buildings/boss/<boss-id>/command \\
630
+ -H "Content-Type: application/json" -d '{"command":"start_all"}'
648
631
  ${BT3}
649
632
 
650
- ### Assign Agents to an Area
633
+ ## Step 5: Inspect logs
651
634
 
652
635
  ${BT3}bash
653
- jq '(.areas[] | select(.id == "my-project-area")).assignedAgentIds += ["agent-id-here"]' ~/.local/share/tide-commander/areas.json > /tmp/a.json && mv /tmp/a.json ~/.local/share/tide-commander/areas.json
636
+ # Snapshot the last 200 lines (default), works for PM2, Docker, and custom-command buildings
637
+ curl -s -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings/<id>/logs
638
+
639
+ # Last N lines (capped at 5000)
640
+ curl -s -H "X-Auth-Token: <TOKEN>" "http://localhost:5174/api/buildings/<id>/logs?lines=500"
641
+
642
+ # Compose-specific service
643
+ curl -s -H "X-Auth-Token: <TOKEN>" \\
644
+ "http://localhost:5174/api/buildings/<id>/logs?lines=200&service=web"
654
645
  ${BT3}
655
646
 
656
- ### Add Area-Level Prompt
647
+ Response: ${BT}{"source": "pm2"|"docker"|"custom"|"none", "logs": "...", "lines": N}${BT}.
648
+
649
+ Live tail-following is **not** exposed over REST — the UI uses WebSocket
650
+ streaming for that. Use the snapshot endpoint for debugging.
651
+
652
+ ## Step 6: Update or delete
657
653
 
658
654
  ${BT3}bash
659
- jq '(.areas[] | select(.id == "my-project-area")).prompt = "Always run tests before committing"' ~/.local/share/tide-commander/areas.json > /tmp/a.json && mv /tmp/a.json ~/.local/share/tide-commander/areas.json
655
+ # Partial update only send the fields that change
656
+ curl -s -X PATCH -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings/<id> \\
657
+ -H "Content-Type: application/json" -d '{"position": {"x": 5.0, "z": -2.5}}'
658
+
659
+ # Change a PM2 env var (the server will restart the process if it was running)
660
+ curl -s -X PATCH -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings/<id> \\
661
+ -H "Content-Type: application/json" \\
662
+ -d '{"pm2": {"enabled": true, "script": "bun", "args": "run dev", "env": {"PORT": "6206"}}}'
663
+
664
+ # Delete (default: tears down PM2 process, Docker container, terminal, DB tunnel)
665
+ curl -s -X DELETE -H "X-Auth-Token: <TOKEN>" http://localhost:5174/api/buildings/<id>
666
+
667
+ # Delete record only, leave runtime artefacts (e.g. when adopting elsewhere)
668
+ curl -s -X DELETE -H "X-Auth-Token: <TOKEN>" \\
669
+ "http://localhost:5174/api/buildings/<id>?cleanup=false"
660
670
  ${BT3}
661
671
 
662
- ### Verify
672
+ PATCH triggers reconciliation: if you change ${BT}pm2.script${BT}, ${BT}pm2.args${BT},
673
+ ${BT}pm2.env${BT}, ${BT}cwd${BT}, or anything the PM2 process name derives from, the running
674
+ process is removed and restarted (if it was online). Docker container changes
675
+ behave the same way. DB tunnel SSH/host/port changes close the tunnel.
663
676
 
664
- ${BT3}bash
665
- jq empty ~/.local/share/tide-commander/areas.json && echo "Valid JSON"
666
- jq '.areas | length' ~/.local/share/tide-commander/areas.json
677
+ ## Validation
678
+
679
+ Validation errors come back as ${BT}400${BT} with a list:
680
+
681
+ ${BT3}json
682
+ {
683
+ "error": "Validation failed",
684
+ "errors": [
685
+ "pm2.script is required when pm2.enabled is true",
686
+ "position is required ({x: number, z: number})"
687
+ ]
688
+ }
667
689
  ${BT3}
690
+
691
+ Cross-building checks (e.g. dangling ${BT}subordinateBuildingIds${BT}) also fail at 400.
692
+
693
+ ## Conventions and tips
694
+
695
+ - **IDs** are server-assigned: ${BT}building_<timestamp>_<name-slug>${BT}. Don't pass them on POST.
696
+ - **${BT}status${BT}** is also server-managed — agents don't set it. Use the command
697
+ endpoint to change runtime state.
698
+ - **${BT}scale${BT}** is a free number; typical values 0.5 / 0.75 / 1.0 are guidance, not a constraint.
699
+ - **Position** should fall inside the building's intended area. Inspect zones
700
+ with ${BT}curl /api/areas | jq '.[] | {id, name, center, width, height, radius}'${BT}.
701
+ - **Credentials** (DB passwords, SSH keys) are encrypted at rest. Send plaintext
702
+ in the body; GET responses return ${BT}hasPassword: true${BT} flags instead of the value.
703
+ - **${BT}buildings.json${BT}** is server-owned. Reading it directly is fine; writing it
704
+ is not — your edits will be overwritten by the next client sync.
668
705
  `,
669
706
  };