tide-commander 1.136.2 → 1.137.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.
- package/dist/assets/{BossLogsModal-B4p16n9B.js → BossLogsModal-CpuefTyK.js} +1 -1
- package/dist/assets/{BossSpawnModal-BHQ7sxeu.js → BossSpawnModal-DBYWz7ah.js} +1 -1
- package/dist/assets/{ControlsModal-BcP5-m0h.js → ControlsModal-C3GRWgGe.js} +1 -1
- package/dist/assets/{DockerLogsModal-C_Gd6YLn.js → DockerLogsModal-DaRM5UiK.js} +1 -1
- package/dist/assets/{EmbeddedEditor-GHVeXIn5.js → EmbeddedEditor-CX-nzneN.js} +1 -1
- package/dist/assets/{GmailOAuthSetup-VjAKcJf9.js → GmailOAuthSetup-CR7okjRo.js} +1 -1
- package/dist/assets/{GoogleOAuthSetup-DFbaN0Ry.js → GoogleOAuthSetup-SwPiACBu.js} +1 -1
- package/dist/assets/{IframeModal-BaoVOZTf.js → IframeModal-Cxtp-ueE.js} +1 -1
- package/dist/assets/{IntegrationsPanel-Cg4TxOfh.js → IntegrationsPanel-CxQNBUbz.js} +2 -2
- package/dist/assets/{LogViewerModal-CN2GYpgr.js → LogViewerModal-C-v5KNZB.js} +1 -1
- package/dist/assets/{MonitoringModal-oN_JjoC2.js → MonitoringModal-D4lsbxyv.js} +1 -1
- package/dist/assets/{PM2LogsModal-BOQ1Im-i.js → PM2LogsModal-D2aMvfE8.js} +1 -1
- package/dist/assets/{RestoreArchivedAreaModal-DYcjqjbA.js → RestoreArchivedAreaModal-DN1dfoEV.js} +1 -1
- package/dist/assets/{Scene2DCanvas-CsBA5ERQ.js → Scene2DCanvas-Vh46WP-a.js} +1 -1
- package/dist/assets/{SceneManager-BqVfBAQc.js → SceneManager-xCUdKUef.js} +1 -1
- package/dist/assets/{SkillsPanel-CtfixcgQ.js → SkillsPanel-UKPyruKQ.js} +1 -1
- package/dist/assets/{SlackMultiInstanceSetup-3nGO_xs6.js → SlackMultiInstanceSetup-CYP8zyzf.js} +1 -1
- package/dist/assets/{SpawnModal-BvUHN-Q1.js → SpawnModal-D-zYj2M1.js} +1 -1
- package/dist/assets/{StatisticsModal-DIx8l3F0.js → StatisticsModal-Bi8uR8cs.js} +1 -1
- package/dist/assets/{SubordinateAssignmentModal-Bw-V4i4-.js → SubordinateAssignmentModal-LM86Vilv.js} +1 -1
- package/dist/assets/{TriggerManagerPanel-C2Mz8wVK.js → TriggerManagerPanel-D_LhL4en.js} +1 -1
- package/dist/assets/{WorkflowEditorPanel-C2RHV8Dx.js → WorkflowEditorPanel-DltPT1Ro.js} +1 -1
- package/dist/assets/{area-logos-aaW_jqzI.js → area-logos-D-61IPfo.js} +1 -1
- package/dist/assets/{index-BGz62M0g.js → index-3OpJhUCJ.js} +1 -1
- package/dist/assets/{index-BvR0it5l.js → index-B6YEcn8f.js} +3 -3
- package/dist/assets/{index-D6r1xAEg.js → index-BTEbN23z.js} +1 -1
- package/dist/assets/{index-BIUEhCXu.js → index-Bff5Z_AU.js} +1 -1
- package/dist/assets/{index-BzCUPOjQ.js → index-BimTXVqB.js} +1 -1
- package/dist/assets/{index-B4JG--zt.js → index-C9cjD5mx.js} +2 -2
- package/dist/assets/{index-DidVGiaJ.js → index-CibDE82j.js} +1 -1
- package/dist/assets/index-DTWKufiJ.js +11 -0
- package/dist/assets/{index-CmGwjdPh.js → index-NiaRnbPo.js} +1 -1
- package/dist/assets/{main-rDQDtv_U.js → main-BVsJe5cx.js} +5 -5
- package/dist/assets/{web-Dy1328BB.js → web-CVeNIuF9.js} +1 -1
- package/dist/assets/{web-DojkIxYY.js → web-D70qwA27.js} +1 -1
- package/dist/assets/{web-B5Ma_-eu.js → web-DcEvjmf6.js} +1 -1
- package/dist/index.html +1 -1
- package/dist/locales/en/config.json +2 -1
- package/dist/src/packages/server/cli.js +8 -1
- package/dist/src/packages/server/routes/system.js +28 -11
- package/dist/src/packages/server/services/self-update-service.js +52 -0
- package/package.json +1 -1
- package/dist/assets/index-BT7u2ftY.js +0 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
import{cO as s}from"./main-
|
|
1
|
+
import{cO as s}from"./main-BVsJe5cx.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{cO as t}from"./main-
|
|
1
|
+
import{cO as t}from"./main-BVsJe5cx.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
|
-
import{cO as a}from"./main-
|
|
1
|
+
import{cO as a}from"./main-BVsJe5cx.js";import{ImpactStyle as i,NotificationType as r}from"./index-C9cjD5mx.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};
|
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-
|
|
25
|
+
<script type="module" crossorigin src="/assets/main-BVsJe5cx.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-Ba3wdQK_.css">
|
|
@@ -554,13 +554,14 @@
|
|
|
554
554
|
"autoUpdateButton": "Update now",
|
|
555
555
|
"autoUpdateRunning": "Installing update...",
|
|
556
556
|
"autoUpdateConfirmTitle": "Update Tide Commander?",
|
|
557
|
-
"autoUpdateConfirmBody": "This will run npm install -g tide-commander@latest and then
|
|
557
|
+
"autoUpdateConfirmBody": "This will run npm install -g tide-commander@latest and then automatically restart the server. The UI will reconnect on its own once it is back up.",
|
|
558
558
|
"autoUpdateConfirm": "Yes, update",
|
|
559
559
|
"autoUpdateCancel": "Cancel",
|
|
560
560
|
"autoUpdateClose": "Close",
|
|
561
561
|
"autoUpdateOutput": "Install log",
|
|
562
562
|
"autoUpdateSuccess": "Update installed.",
|
|
563
563
|
"autoUpdateRestartHint": "Please restart Tide Commander from your terminal (run: tide-commander).",
|
|
564
|
+
"autoUpdateReconnectHint": "Restarting automatically — reconnecting shortly...",
|
|
564
565
|
"autoUpdateFailed": "Update failed.",
|
|
565
566
|
"autoUpdateDevMode": "Auto-update is unavailable in dev mode.",
|
|
566
567
|
"autoUpdateManualCommand": "Run this in your terminal to update manually:",
|
|
@@ -53,6 +53,7 @@ Options:
|
|
|
53
53
|
current terminal so logs print here and Ctrl+C stops it.
|
|
54
54
|
--lines <n> Number of log lines for logs command (default: 100)
|
|
55
55
|
--follow Follow logs stream (like tail -f)
|
|
56
|
+
--restart Restart a running server, reusing its current config
|
|
56
57
|
-h, --help Show this help message
|
|
57
58
|
`);
|
|
58
59
|
}
|
|
@@ -143,6 +144,9 @@ function parseArgs(argv) {
|
|
|
143
144
|
case '--follow':
|
|
144
145
|
options.follow = true;
|
|
145
146
|
break;
|
|
147
|
+
case '--restart':
|
|
148
|
+
options.restart = true;
|
|
149
|
+
break;
|
|
146
150
|
case '--lines': {
|
|
147
151
|
const value = argv[i + 1];
|
|
148
152
|
if (!value || value.startsWith('-')) {
|
|
@@ -646,6 +650,9 @@ async function main() {
|
|
|
646
650
|
|| options.authToken !== undefined
|
|
647
651
|
|| options.generateAuthToken === true
|
|
648
652
|
|| options.foreground === true;
|
|
653
|
+
// An explicit --restart (used by the post-update auto-restart) forces a clean
|
|
654
|
+
// restart of the running server even when no config overrides were passed.
|
|
655
|
+
const shouldRestartExisting = hasStartupOverrides || options.restart === true;
|
|
649
656
|
if (existingPid && isRunning(existingPid)) {
|
|
650
657
|
if (runInForeground) {
|
|
651
658
|
// In foreground mode (PM2 managed), the process manager handles lifecycle.
|
|
@@ -663,7 +670,7 @@ async function main() {
|
|
|
663
670
|
clearPidFile();
|
|
664
671
|
clearServerMeta();
|
|
665
672
|
}
|
|
666
|
-
else if (
|
|
673
|
+
else if (shouldRestartExisting) {
|
|
667
674
|
try {
|
|
668
675
|
process.kill(existingPid, 'SIGTERM');
|
|
669
676
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Router } from 'express';
|
|
6
6
|
import { createLogger } from '../utils/logger.js';
|
|
7
7
|
import { fetchLatestNpmVersion, getVersionRelation } from '../../shared/version.js';
|
|
8
|
-
import { getInstallInfo, isAutoUpdateSupported, runNpmGlobalUpdate, } from '../services/self-update-service.js';
|
|
8
|
+
import { getInstallInfo, isAutoUpdateSupported, runNpmGlobalUpdate, schedulePostUpdateRestart, } from '../services/self-update-service.js';
|
|
9
9
|
const log = createLogger('SystemRoutes');
|
|
10
10
|
const router = Router();
|
|
11
11
|
const PACKAGE_NAME = 'tide-commander';
|
|
@@ -56,8 +56,9 @@ router.get('/install-info', async (_req, res) => {
|
|
|
56
56
|
* - done { success, exitCode, newVersion, requiresRestart }
|
|
57
57
|
* - error { message, permissionDenied, suggestedManualCommand }
|
|
58
58
|
*
|
|
59
|
-
* On success the server
|
|
60
|
-
* the new binary
|
|
59
|
+
* On success the server relaunches itself (detached `tide-commander start
|
|
60
|
+
* --restart`) so the new binary comes up automatically; if that can't be
|
|
61
|
+
* scheduled it falls back to exiting for a manual restart.
|
|
61
62
|
*/
|
|
62
63
|
router.post('/self-update', async (_req, res) => {
|
|
63
64
|
const info = getInstallInfo();
|
|
@@ -107,21 +108,37 @@ router.post('/self-update', async (_req, res) => {
|
|
|
107
108
|
clearInterval(keepalive);
|
|
108
109
|
if (result.exitCode === 0) {
|
|
109
110
|
const newVersion = (await fetchLatestNpmVersion(PACKAGE_NAME)) ?? null;
|
|
111
|
+
// Try to bring the new binary up automatically. The relauncher will
|
|
112
|
+
// SIGTERM this process, so we must NOT exit ourselves when it's scheduled.
|
|
113
|
+
const autoRestart = schedulePostUpdateRestart();
|
|
110
114
|
send('done', {
|
|
111
115
|
success: true,
|
|
112
116
|
exitCode: 0,
|
|
113
117
|
newVersion,
|
|
114
118
|
requiresRestart: true,
|
|
115
|
-
|
|
119
|
+
autoRestart,
|
|
120
|
+
message: autoRestart
|
|
121
|
+
? 'Update installed — Tide Commander is restarting automatically. The UI will reconnect in a few seconds.'
|
|
122
|
+
: 'Update installed. Please restart Tide Commander from your terminal.',
|
|
116
123
|
});
|
|
117
124
|
res.end();
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
if (autoRestart) {
|
|
126
|
+
log.log('Update succeeded — detached relauncher scheduled; awaiting takeover.');
|
|
127
|
+
// Safety net: if the relauncher never takes over, don't stay locked.
|
|
128
|
+
setTimeout(() => {
|
|
129
|
+
log.warn('Relauncher did not take over within 30s — clearing update lock.');
|
|
130
|
+
updateInProgress = false;
|
|
131
|
+
}, 30000).unref?.();
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// Couldn't schedule an auto-restart — fall back to the old behaviour:
|
|
135
|
+
// exit so the next manual launch picks up the new binary.
|
|
136
|
+
log.log('Auto-restart unavailable — scheduling exit in 1500ms for manual restart.');
|
|
137
|
+
setTimeout(() => {
|
|
138
|
+
log.log('Exiting after successful update. Restart manually with: tide-commander');
|
|
139
|
+
process.exit(0);
|
|
140
|
+
}, 1500);
|
|
141
|
+
}
|
|
125
142
|
}
|
|
126
143
|
else {
|
|
127
144
|
const errMsg = result.permissionDenied
|
|
@@ -189,3 +189,55 @@ export function runNpmGlobalUpdate(callbacks = {}) {
|
|
|
189
189
|
});
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* After a successful global update, bring up the freshly installed binary
|
|
194
|
+
* without the user having to relaunch by hand.
|
|
195
|
+
*
|
|
196
|
+
* Spawns a fully detached `tide-commander start --restart` that inherits the
|
|
197
|
+
* current server's environment (same PORT/HOST/AUTH_TOKEN/HTTPS). That process
|
|
198
|
+
* SIGTERMs the still-running old server (triggering its graceful shutdown so the
|
|
199
|
+
* port is released), waits for it to exit, then starts the new server and
|
|
200
|
+
* rewrites the PID file. The caller MUST NOT exit — the relauncher drives the
|
|
201
|
+
* handoff.
|
|
202
|
+
*
|
|
203
|
+
* Returns true if the relauncher was scheduled, false if it could not be
|
|
204
|
+
* (in which case the caller should fall back to exiting for a manual restart).
|
|
205
|
+
*/
|
|
206
|
+
export function schedulePostUpdateRestart(delayMs = 600) {
|
|
207
|
+
let cliPath;
|
|
208
|
+
try {
|
|
209
|
+
// self-update-service.js lives at dist/.../server/services/, the CLI entry
|
|
210
|
+
// at dist/.../server/cli.js — one level up.
|
|
211
|
+
cliPath = fileURLToPath(new URL('../cli.js', import.meta.url));
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
log.error(`Cannot resolve CLI path for auto-restart: ${err.message}`);
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
if (!fs.existsSync(cliPath)) {
|
|
218
|
+
log.error(`CLI entrypoint not found for auto-restart: ${cliPath}`);
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
// Small delay so the SSE 'done' frame flushes to the client before the
|
|
222
|
+
// relauncher SIGTERMs us.
|
|
223
|
+
const timer = setTimeout(() => {
|
|
224
|
+
try {
|
|
225
|
+
const child = spawn(process.execPath, [cliPath, 'start', '--restart'], {
|
|
226
|
+
detached: true,
|
|
227
|
+
stdio: 'ignore',
|
|
228
|
+
env: process.env,
|
|
229
|
+
cwd: process.cwd(),
|
|
230
|
+
});
|
|
231
|
+
child.on('error', (err) => {
|
|
232
|
+
log.error(`Auto-restart relauncher failed to spawn: ${err.message}`);
|
|
233
|
+
});
|
|
234
|
+
child.unref();
|
|
235
|
+
log.log('Spawned detached relauncher: tide-commander start --restart');
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
log.error(`Failed to spawn auto-restart relauncher: ${err.message}`);
|
|
239
|
+
}
|
|
240
|
+
}, delayMs);
|
|
241
|
+
timer.unref?.();
|
|
242
|
+
return true;
|
|
243
|
+
}
|