tide-commander 1.159.0 → 1.159.2

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 (42) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/assets/{BossLogsModal-B1efaCOD.js → BossLogsModal-D7DRbxuN.js} +1 -1
  3. package/dist/assets/{BossSpawnModal-CsEylDz3.js → BossSpawnModal-qWqV6cXb.js} +1 -1
  4. package/dist/assets/{ControlsModal-VoXduUsZ.js → ControlsModal-Dx4Sd-zd.js} +1 -1
  5. package/dist/assets/{DockerLogsModal-C6sMnLBl.js → DockerLogsModal-DnBm69YT.js} +1 -1
  6. package/dist/assets/{EmbeddedEditor-Cph0We_D.js → EmbeddedEditor-egK0IcwH.js} +1 -1
  7. package/dist/assets/{GmailOAuthSetup-BLRlfaUq.js → GmailOAuthSetup-Bi51Jkf8.js} +1 -1
  8. package/dist/assets/{GoogleOAuthSetup-D3QpuVDO.js → GoogleOAuthSetup-BAREZ_c-.js} +1 -1
  9. package/dist/assets/{IframeModal-85pHW-pq.js → IframeModal-Rh1yC6CF.js} +1 -1
  10. package/dist/assets/{IntegrationsPanel-CD67Zpbe.js → IntegrationsPanel-BPmG30Kf.js} +2 -2
  11. package/dist/assets/{LogViewerModal-BwxMq9Ut.js → LogViewerModal-V3LGKLOd.js} +1 -1
  12. package/dist/assets/{MonitoringModal-CMEOZ95G.js → MonitoringModal-D5ObJhXH.js} +1 -1
  13. package/dist/assets/{PM2LogsModal-B8U7Twg5.js → PM2LogsModal-DyNAmc5D.js} +1 -1
  14. package/dist/assets/{RestoreArchivedAreaModal-Djc-HI0I.js → RestoreArchivedAreaModal-C1afIOVX.js} +1 -1
  15. package/dist/assets/{Scene2DCanvas-3ELgvFj7.js → Scene2DCanvas-C7weuP-e.js} +1 -1
  16. package/dist/assets/{SceneManager-DGDAQjiM.js → SceneManager-Cub1EW5Y.js} +1 -1
  17. package/dist/assets/{SkillsPanel-C_VJxYq6.js → SkillsPanel-C3PG0A6A.js} +1 -1
  18. package/dist/assets/{SlackMultiInstanceSetup-CU_ciZt8.js → SlackMultiInstanceSetup-vq1FipyR.js} +1 -1
  19. package/dist/assets/{SpawnModal-4UWGDXA5.js → SpawnModal-Df2Vp-HA.js} +1 -1
  20. package/dist/assets/{StatisticsModal-t3BmlLeA.js → StatisticsModal-D0yo2rbm.js} +1 -1
  21. package/dist/assets/{SubordinateAssignmentModal-DadewDiC.js → SubordinateAssignmentModal-BHQS1Xc_.js} +1 -1
  22. package/dist/assets/{TriggerManagerPanel-CsRxQshw.js → TriggerManagerPanel-CEVMReTJ.js} +1 -1
  23. package/dist/assets/{WorkflowEditorPanel-D8HdloWl.js → WorkflowEditorPanel-BQbr0HYZ.js} +1 -1
  24. package/dist/assets/{area-logos-DT0p0ZNy.js → area-logos-CbdG7b49.js} +1 -1
  25. package/dist/assets/{index-DZ1dDpMc.js → index--FFJ9DPS.js} +1 -1
  26. package/dist/assets/{index-DxzEz7Wq.js → index-B4PPDHAS.js} +1 -1
  27. package/dist/assets/{index-CXV0mjYb.js → index-BvEk2Spw.js} +3 -3
  28. package/dist/assets/{index-CNb62smT.js → index-C57r58R1.js} +1 -1
  29. package/dist/assets/{index-COzjdZHI.js → index-CxUhEi9L.js} +1 -1
  30. package/dist/assets/{index-BeP_1e9F.js → index-DN1jWADn.js} +1 -1
  31. package/dist/assets/{index-BWeUgDS_.js → index-EAqEvdMn.js} +2 -2
  32. package/dist/assets/{index-sqLiegdk.js → index-Vee1Cpl9.js} +1 -1
  33. package/dist/assets/{index-pnFcxt52.js → index-fFR_58oB.js} +1 -1
  34. package/dist/assets/{main-DM6oMRZH.js → main-Btdl34Y5.js} +8 -8
  35. package/dist/assets/{web-bc8PmuWG.js → web-Brq808vy.js} +1 -1
  36. package/dist/assets/{web-UIwBVJek.js → web-CACmzQOn.js} +1 -1
  37. package/dist/assets/{web-63aqCy2N.js → web-DPUDmaxp.js} +1 -1
  38. package/dist/build-info.json +1 -1
  39. package/dist/index.html +1 -1
  40. package/dist/src/packages/server/cli.js +22 -1
  41. package/dist/src/packages/server/services/self-update-service.js +50 -8
  42. package/package.json +1 -1
@@ -1 +1 @@
1
- import{df as a}from"./main-DM6oMRZH.js";import{ImpactStyle as i,NotificationType as r}from"./index-BWeUgDS_.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class h extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{h as HapticsWeb};
1
+ import{df as a}from"./main-Btdl34Y5.js";import{ImpactStyle as i,NotificationType as r}from"./index-EAqEvdMn.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class h extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{h as HapticsWeb};
@@ -1 +1 @@
1
- import{df as s}from"./main-DM6oMRZH.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class l extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{l as LocalNotificationsWeb};
1
+ import{df as s}from"./main-Btdl34Y5.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class l extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{l as LocalNotificationsWeb};
@@ -1 +1 @@
1
- import{df as t}from"./main-DM6oMRZH.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class o extends t{constructor(){super(),this.handleVisibilityChange=()=>{const e={isActive:document.hidden!==!0};this.notifyListeners("appStateChange",e),document.hidden?this.notifyListeners("pause",null):this.notifyListeners("resume",null)},document.addEventListener("visibilitychange",this.handleVisibilityChange,!1)}exitApp(){throw this.unimplemented("Not implemented on web.")}async getInfo(){throw this.unimplemented("Not implemented on web.")}async getLaunchUrl(){return{url:""}}async getState(){return{isActive:document.hidden!==!0}}async minimizeApp(){throw this.unimplemented("Not implemented on web.")}async toggleBackButtonHandler(){throw this.unimplemented("Not implemented on web.")}async getAppLanguage(){return{value:navigator.language.split("-")[0].toLowerCase()}}}export{o as AppWeb};
1
+ import{df as t}from"./main-Btdl34Y5.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class o extends t{constructor(){super(),this.handleVisibilityChange=()=>{const e={isActive:document.hidden!==!0};this.notifyListeners("appStateChange",e),document.hidden?this.notifyListeners("pause",null):this.notifyListeners("resume",null)},document.addEventListener("visibilitychange",this.handleVisibilityChange,!1)}exitApp(){throw this.unimplemented("Not implemented on web.")}async getInfo(){throw this.unimplemented("Not implemented on web.")}async getLaunchUrl(){return{url:""}}async getState(){return{isActive:document.hidden!==!0}}async minimizeApp(){throw this.unimplemented("Not implemented on web.")}async toggleBackButtonHandler(){throw this.unimplemented("Not implemented on web.")}async getAppLanguage(){return{value:navigator.language.split("-")[0].toLowerCase()}}}export{o as AppWeb};
@@ -1 +1 @@
1
- {"version":"1.159.0"}
1
+ {"version":"1.159.2"}
package/dist/index.html CHANGED
@@ -22,7 +22,7 @@
22
22
  <link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16x16.png" />
23
23
  <link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png" />
24
24
  <title>Tide Commander</title>
25
- <script type="module" crossorigin src="/assets/main-DM6oMRZH.js"></script>
25
+ <script type="module" crossorigin src="/assets/main-Btdl34Y5.js"></script>
26
26
  <link rel="modulepreload" crossorigin href="/assets/vendor-react--Eh9ivFN.js">
27
27
  <link rel="modulepreload" crossorigin href="/assets/vendor-three-Chj50gSY.js">
28
28
  <link rel="stylesheet" crossorigin href="/assets/main-BZcOdtO_.css">
@@ -318,14 +318,35 @@ function readPidFile() {
318
318
  return null;
319
319
  }
320
320
  }
321
+ /**
322
+ * True only if `pid` is a *live* process. A bare `kill(pid, 0)` probe is not
323
+ * enough: on Linux a zombie (State: Z — exited but not yet reaped by its parent)
324
+ * still occupies the process table, so the probe succeeds for it too. In
325
+ * containers whose PID 1 doesn't reap children, an unreaped launcher would then
326
+ * be mistaken for a running server — the startup guard waits on it forever, the
327
+ * follow-up SIGKILL no-ops, and the launch crash-loops. Treat zombies as dead by
328
+ * inspecting /proc/<pid>/stat; if /proc is unavailable (non-Linux) or the read
329
+ * races, fall back to trusting the signal probe.
330
+ */
321
331
  function isRunning(pid) {
322
332
  try {
323
333
  process.kill(pid, 0);
324
- return true;
325
334
  }
326
335
  catch {
327
336
  return false;
328
337
  }
338
+ try {
339
+ const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf8');
340
+ // Format: "pid (comm) state ...". comm may contain spaces or ')', so key off
341
+ // the final ')' to locate the single-char state field that follows it.
342
+ const state = stat.slice(stat.lastIndexOf(')') + 1).trim()[0];
343
+ if (state === 'Z')
344
+ return false;
345
+ }
346
+ catch {
347
+ // /proc missing (non-Linux) or the process vanished mid-read — trust kill(0).
348
+ }
349
+ return true;
329
350
  }
330
351
  async function waitForProcessExit(pid, timeoutMs = 8000) {
331
352
  const started = Date.now();
@@ -228,21 +228,63 @@ export function runNpmGlobalUpdate(callbacks = {}) {
228
228
  });
229
229
  });
230
230
  }
231
+ /**
232
+ * Detect a process supervisor that already restarts us on exit.
233
+ *
234
+ * Under PM2 (the common `tide-commander --foreground` deployment) spawning our
235
+ * own detached relauncher is actively harmful: PM2 ALSO restarts the process the
236
+ * moment the old server exits, so the relauncher's new server and PM2's fresh
237
+ * server race for the same port. The loser dies with EADDRINUSE and — in
238
+ * containers whose PID 1 doesn't reap — lingers as a zombie that then trips the
239
+ * launcher's port guard on the next boot (the multi-day crash loop).
240
+ *
241
+ * PM2 injects pm_id / PM2_HOME into every managed process, and the launcher
242
+ * passes its env straight to the server child, so these are visible here. An
243
+ * explicit TIDE_COMMANDER_SUPERVISED=1 lets other auto-restarting supervisors
244
+ * (systemd Restart=, docker restart-policy) opt into the same behaviour.
245
+ *
246
+ * NOTE: we deliberately do NOT key on TIDE_COMMANDER_FOREGROUND — foreground is
247
+ * not the same as supervised. A bare `--foreground` attached in a terminal has
248
+ * nothing to restart it, so there the detached relauncher must stay.
249
+ */
250
+ function isSupervisedRestart() {
251
+ return (process.env.pm_id !== undefined ||
252
+ Boolean(process.env.PM2_HOME) ||
253
+ process.env.TIDE_COMMANDER_SUPERVISED === '1');
254
+ }
231
255
  /**
232
256
  * After a successful global update, bring up the freshly installed binary
233
257
  * without the user having to relaunch by hand.
234
258
  *
235
- * Spawns a fully detached `tide-commander start --restart` that inherits the
236
- * current server's environment (same PORT/HOST/AUTH_TOKEN/HTTPS). That process
237
- * SIGTERMs the still-running old server (triggering its graceful shutdown so the
238
- * port is released), waits for it to exit, then starts the new server and
239
- * rewrites the PID file. The caller MUST NOT exit — the relauncher drives the
240
- * handoff.
259
+ * When supervised (PM2/systemd/docker see isSupervisedRestart), we simply exit:
260
+ * the supervisor restarts the process into the already-on-disk new code, and
261
+ * spawning our own relauncher would only race it for the port.
262
+ *
263
+ * Otherwise (standalone install) spawns a fully detached
264
+ * `tide-commander start --restart` that inherits the current server's
265
+ * environment (same PORT/HOST/AUTH_TOKEN/HTTPS). That process SIGTERMs the
266
+ * still-running old server (triggering its graceful shutdown so the port is
267
+ * released), waits for it to exit, then starts the new server and rewrites the
268
+ * PID file. The caller MUST NOT exit — the relauncher (or, when supervised, our
269
+ * own scheduled exit) drives the handoff.
241
270
  *
242
- * Returns true if the relauncher was scheduled, false if it could not be
243
- * (in which case the caller should fall back to exiting for a manual restart).
271
+ * Returns true if a restart was scheduled (relauncher spawned, or supervised
272
+ * exit queued), false if it could not be (in which case the caller should fall
273
+ * back to exiting for a manual restart).
244
274
  */
245
275
  export function schedulePostUpdateRestart(delayMs = 600) {
276
+ // Supervised deployment: don't spawn a competing relauncher. Exit after the
277
+ // same flush grace so any in-flight SSE 'done' frame reaches the client, then
278
+ // let the process manager restart us into the freshly-installed build.
279
+ if (isSupervisedRestart()) {
280
+ log.log('Supervised restart (PM2/systemd/docker) detected — exiting for the process manager to restart into the updated build.');
281
+ const timer = setTimeout(() => {
282
+ log.log('Exiting now; the process manager will restart Tide Commander.');
283
+ process.exit(0);
284
+ }, delayMs);
285
+ timer.unref?.();
286
+ return true;
287
+ }
246
288
  let cliPath;
247
289
  try {
248
290
  // self-update-service.js lives at dist/.../server/services/, the CLI entry
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tide-commander",
3
- "version": "1.159.0",
3
+ "version": "1.159.2",
4
4
  "description": "Visual multi-agent orchestrator and manager for Claude Code with 3D/2D interface",
5
5
  "repository": {
6
6
  "type": "git",