tide-commander 0.53.0 → 0.53.3

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/index.html CHANGED
@@ -19,7 +19,7 @@
19
19
  <meta name="apple-mobile-web-app-title" content="Tide CMD" />
20
20
  <link rel="apple-touch-icon" href="/assets/icons/icon-192.png" />
21
21
  <title>Tide Commander</title>
22
- <script type="module" crossorigin src="/assets/main-B8eX8FW7.js"></script>
22
+ <script type="module" crossorigin src="/assets/main-CcEFu9h1.js"></script>
23
23
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-uS-d4TUT.js">
24
24
  <link rel="modulepreload" crossorigin href="/assets/vendor-three-4iQNXcoo.js">
25
25
  <link rel="stylesheet" crossorigin href="/assets/main-BIpLsrUu.css">
@@ -15,6 +15,7 @@ Usage:
15
15
  tide-commander stop
16
16
  tide-commander status
17
17
  tide-commander logs [--lines <n>] [--follow]
18
+ tide-commander version
18
19
 
19
20
  Options:
20
21
  -p, --port <port> Set server port (default: 5174)
@@ -32,7 +33,7 @@ function parseArgs(argv) {
32
33
  for (let i = 0; i < argv.length; i += 1) {
33
34
  const arg = argv[i];
34
35
  if (!arg.startsWith('-') && !commandParsed) {
35
- if (arg === 'start' || arg === 'stop' || arg === 'status' || arg === 'logs') {
36
+ if (arg === 'start' || arg === 'stop' || arg === 'status' || arg === 'logs' || arg === 'version') {
36
37
  options.command = arg;
37
38
  commandParsed = true;
38
39
  continue;
@@ -93,6 +94,10 @@ function parseArgs(argv) {
93
94
  case '--help':
94
95
  options.help = true;
95
96
  break;
97
+ case '-v':
98
+ case '--version':
99
+ options.command = 'version';
100
+ break;
96
101
  default:
97
102
  throw new Error(`Unknown argument: ${arg}`);
98
103
  }
@@ -155,17 +160,37 @@ function stopCommand() {
155
160
  return 0;
156
161
  }
157
162
  function statusCommand() {
163
+ // ANSI color codes
164
+ const cyan = '\x1b[36m';
165
+ const green = '\x1b[32m';
166
+ const red = '\x1b[31m';
167
+ const bright = '\x1b[1m';
168
+ const reset = '\x1b[0m';
169
+ const blue = '\x1b[34m';
158
170
  const pid = readPidFile();
159
171
  if (!pid) {
160
- console.log('Tide Commander is stopped');
172
+ console.log(`\n${red}${bright}⨯ Tide Commander is stopped${reset}\n`);
161
173
  return 1;
162
174
  }
163
175
  if (!isRunning(pid)) {
164
176
  clearPidFile();
165
- console.log('Tide Commander is stopped (stale PID file removed)');
177
+ console.log(`\n${red}${bright}⨯ Tide Commander is stopped${reset} (stale PID file removed)\n`);
166
178
  return 1;
167
179
  }
168
- console.log(`Tide Commander is running (PID: ${pid})`);
180
+ const port = process.env.PORT || '5174';
181
+ const host = process.env.HOST || 'localhost';
182
+ const url = `http://${host}:${port}`;
183
+ const uptime = getProcessUptime(pid);
184
+ const version = getPackageVersion();
185
+ console.log(`\n${cyan}${bright}🌊 Tide Commander Status${reset}`);
186
+ console.log(`${cyan}${'═'.repeat(60)}${reset}`);
187
+ console.log(`${green}✓ Running${reset} (PID: ${pid})`);
188
+ console.log(`${blue}${bright}🚀 Access: ${url}${reset}`);
189
+ console.log(` Version: ${version}`);
190
+ if (uptime) {
191
+ console.log(` Uptime: ${uptime}`);
192
+ }
193
+ console.log(`${cyan}${'═'.repeat(60)}${reset}\n`);
169
194
  return 0;
170
195
  }
171
196
  async function logsCommand(options) {
@@ -190,12 +215,65 @@ async function logsCommand(options) {
190
215
  });
191
216
  });
192
217
  }
218
+ function getPackageVersion() {
219
+ try {
220
+ const cliDir = path.dirname(fileURLToPath(import.meta.url));
221
+ const packagePath = path.join(cliDir, '..', '..', '..', '..', 'package.json');
222
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
223
+ return packageJson.version;
224
+ }
225
+ catch {
226
+ return 'unknown';
227
+ }
228
+ }
229
+ function getProcessUptime(pid) {
230
+ try {
231
+ // Try to get process start time from /proc/[pid]/stat (Linux)
232
+ if (fs.existsSync(`/proc/${pid}/stat`)) {
233
+ const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf8').split(' ');
234
+ const starttime = Number(stat[21]); // starttime in jiffies
235
+ const uptimeFile = fs.readFileSync('/proc/uptime', 'utf8').split(' ')[0];
236
+ const systemUptimeJiffies = Number(uptimeFile) * 100; // convert to jiffies (assuming 100 Hz)
237
+ const processUptimeJiffies = systemUptimeJiffies - starttime;
238
+ const processUptimeSeconds = Math.floor(processUptimeJiffies / 100);
239
+ const hours = Math.floor(processUptimeSeconds / 3600);
240
+ const minutes = Math.floor((processUptimeSeconds % 3600) / 60);
241
+ const seconds = processUptimeSeconds % 60;
242
+ if (hours > 0) {
243
+ return `${hours}h ${minutes}m ${seconds}s`;
244
+ }
245
+ else if (minutes > 0) {
246
+ return `${minutes}m ${seconds}s`;
247
+ }
248
+ else {
249
+ return `${seconds}s`;
250
+ }
251
+ }
252
+ }
253
+ catch {
254
+ // Uptime not available (not on Linux or /proc not available)
255
+ }
256
+ return null;
257
+ }
258
+ function versionCommand() {
259
+ try {
260
+ const version = getPackageVersion();
261
+ console.log(`Tide Commander v${version}`);
262
+ }
263
+ catch {
264
+ console.error('Failed to read version information');
265
+ }
266
+ }
193
267
  async function main() {
194
268
  const options = parseArgs(process.argv.slice(2));
195
269
  if (options.help) {
196
270
  printHelp();
197
271
  return;
198
272
  }
273
+ if (options.command === 'version') {
274
+ versionCommand();
275
+ return;
276
+ }
199
277
  if (options.command === 'stop') {
200
278
  process.exit(stopCommand());
201
279
  }
@@ -221,7 +299,11 @@ async function main() {
221
299
  const runInForeground = options.foreground === true || process.env.TIDE_COMMANDER_FOREGROUND === '1';
222
300
  const existingPid = readPidFile();
223
301
  if (existingPid && isRunning(existingPid)) {
224
- console.log(`Tide Commander is already running (PID: ${existingPid})`);
302
+ const port = process.env.PORT || '5174';
303
+ const host = process.env.HOST || 'localhost';
304
+ const url = `http://${host}:${port}`;
305
+ console.log(`\n🌊 Tide Commander is already running (PID: ${existingPid})`);
306
+ console.log(`🚀 Open: ${url}\n`);
225
307
  return;
226
308
  }
227
309
  clearPidFile();
@@ -239,7 +321,22 @@ async function main() {
239
321
  writePidFile(child.pid);
240
322
  }
241
323
  child.unref();
242
- console.log(`Tide Commander started in background (PID: ${child.pid ?? 'unknown'})`);
324
+ const port = process.env.PORT || '5174';
325
+ const host = process.env.HOST || 'localhost';
326
+ const url = `http://${host}:${port}`;
327
+ // ANSI color codes for beautiful output
328
+ const cyan = '\x1b[36m';
329
+ const green = '\x1b[32m';
330
+ const bright = '\x1b[1m';
331
+ const reset = '\x1b[0m';
332
+ const blue = '\x1b[34m';
333
+ console.log(`\n${cyan}${bright}🌊 Tide Commander${reset}`);
334
+ console.log(`${cyan}${'═'.repeat(60)}${reset}`);
335
+ console.log(`${green}✓${reset} Started in background (PID: ${child.pid ?? 'unknown'})`);
336
+ console.log(`${blue}${bright}🚀 Open: ${url}${reset}`);
337
+ console.log(` Version: ${getPackageVersion()}`);
338
+ console.log(`${green}📝 Logs${reset}: tail -f logs/server.log`);
339
+ console.log(`${cyan}${'═'.repeat(60)}${reset}\n`);
243
340
  return;
244
341
  }
245
342
  if (child.pid) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tide-commander",
3
- "version": "0.53.0",
3
+ "version": "0.53.3",
4
4
  "description": "Visual multi-agent orchestrator and manager for Claude Code with 3D/2D interface",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,20 +27,10 @@
27
27
  "test:ci": "vitest run --exclude src/packages/client/hooks/__tests__/useSnapshots.test.ts --exclude src/packages/client/hooks/__tests__/useKeyboardShortcuts.test.ts",
28
28
  "test:watch": "vitest",
29
29
  "test:coverage": "vitest run --coverage",
30
- "prepack": "npm run build",
31
- "cap:sync": "npx cap sync android",
32
- "cap:open": "npx cap open android",
33
- "cap:build": "npm run build && npx cap sync android",
34
- "android": "npm run build && npx cap sync android && npx cap open android"
30
+ "prepack": "npm run build"
35
31
  },
36
32
  "dependencies": {
37
33
  "@anthropic-ai/sdk": "^0.71.2",
38
- "@capacitor/android": "^8.0.1",
39
- "@capacitor/cli": "^8.0.1",
40
- "@capacitor/core": "^8.0.1",
41
- "@capacitor/haptics": "^8.0.0",
42
- "@capacitor/local-notifications": "^8.0.0",
43
- "@capawesome/capacitor-background-task": "^8.0.0",
44
34
  "@tanstack/react-virtual": "^3.13.18",
45
35
  "@types/oracledb": "^6.10.1",
46
36
  "archiver": "^7.0.1",
@@ -1 +0,0 @@
1
- import{W as a,I as i,N as r}from"./main-B8eX8FW7.js";import"./vendor-react-uS-d4TUT.js";import"./vendor-three-4iQNXcoo.js";class l 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{l as HapticsWeb};
@@ -1 +0,0 @@
1
- import{W as s}from"./main-B8eX8FW7.js";import"./vendor-react-uS-d4TUT.js";import"./vendor-three-4iQNXcoo.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};