agendex-cli 0.5.0 → 0.6.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 (2) hide show
  1. package/dist/cli.js +87 -51
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2127,11 +2127,13 @@ function normalizeStoredConfig(raw) {
2127
2127
  const token = typeof raw.token === "string" && raw.token.trim() ? raw.token : undefined;
2128
2128
  const cloudToken = typeof raw.cloudToken === "string" && raw.cloudToken.trim() ? raw.cloudToken : undefined;
2129
2129
  const convexUrl = typeof raw.convexUrl === "string" && raw.convexUrl.trim() ? raw.convexUrl : undefined;
2130
+ const deviceId = typeof raw.deviceId === "string" && raw.deviceId.trim() ? raw.deviceId : undefined;
2130
2131
  return {
2131
2132
  configVersion: 3,
2132
2133
  token,
2133
2134
  cloudToken,
2134
2135
  convexUrl,
2136
+ deviceId,
2135
2137
  enabledAdapters: normalizeAdapterIds(raw.enabledAdapters)
2136
2138
  };
2137
2139
  }
@@ -2145,6 +2147,7 @@ function saveConfig(config) {
2145
2147
  token: config.token,
2146
2148
  cloudToken: config.cloudToken,
2147
2149
  convexUrl: config.convexUrl,
2150
+ deviceId: config.deviceId,
2148
2151
  enabledAdapters: sanitizeEnabledAdapterIds(config.enabledAdapters)
2149
2152
  };
2150
2153
  writeFileSync(configPath, JSON.stringify(payload, null, 2));
@@ -2170,6 +2173,19 @@ function loadOrCreateToken() {
2170
2173
  `);
2171
2174
  return token;
2172
2175
  }
2176
+ function loadOrCreateDeviceId() {
2177
+ const existing = loadConfig();
2178
+ if (existing?.deviceId)
2179
+ return existing.deviceId;
2180
+ const deviceId = randomBytes(16).toString("hex");
2181
+ saveConfig({
2182
+ ...existing ?? {},
2183
+ configVersion: 3,
2184
+ deviceId,
2185
+ enabledAdapters: existing?.enabledAdapters ?? []
2186
+ });
2187
+ return deviceId;
2188
+ }
2173
2189
  async function loadOrInitConfig(options = {}) {
2174
2190
  const configureAdapters = Boolean(options.configureAdapters);
2175
2191
  const existing = loadConfig();
@@ -2195,11 +2211,13 @@ async function loadOrInitConfig(options = {}) {
2195
2211
  if (enabledAdapters.length === 0)
2196
2212
  enabledAdapters = getDefaultAdapterIds();
2197
2213
  }
2214
+ const deviceId = existing?.deviceId || randomBytes(16).toString("hex");
2198
2215
  const nextConfig = {
2199
2216
  configVersion: 3,
2200
2217
  token: tokenFromEnv ? existing?.token : currentToken,
2201
2218
  cloudToken: existing?.cloudToken,
2202
2219
  convexUrl: existing?.convexUrl,
2220
+ deviceId,
2203
2221
  enabledAdapters
2204
2222
  };
2205
2223
  saveConfig(nextConfig);
@@ -2477,11 +2495,17 @@ function startWatching(onChange) {
2477
2495
  // src/auth.ts
2478
2496
  import { spawn } from "node:child_process";
2479
2497
  import { createServer } from "node:http";
2480
- var DEFAULT_SITE_URL = "https://app.agendex.dev";
2498
+ var PROD_SITE_URL = "https://app.agendex.dev";
2499
+ var DEV_SITE_URL = "http://app.agendex.local:5174";
2500
+ function getDefaultSiteUrl() {
2501
+ if (process.env.AGENDEX_SITE_URL)
2502
+ return process.env.AGENDEX_SITE_URL;
2503
+ return process.env.AGENDEX_DEV === "1" ? DEV_SITE_URL : PROD_SITE_URL;
2504
+ }
2481
2505
  async function login(siteUrlOverride) {
2482
2506
  const { port, result } = await startCallbackServer();
2483
2507
  const callbackUrl = `http://127.0.0.1:${port}/callback`;
2484
- const siteUrl = siteUrlOverride ?? DEFAULT_SITE_URL;
2508
+ const siteUrl = siteUrlOverride ?? getDefaultSiteUrl();
2485
2509
  const authUrl = `${siteUrl}/auth/cli?callback=${encodeURIComponent(callbackUrl)}`;
2486
2510
  console.log(`[agendex] Opening browser for authentication...`);
2487
2511
  console.log(`[agendex] If it doesn't open, visit: ${authUrl}`);
@@ -2670,6 +2694,56 @@ import { fileURLToPath } from "node:url";
2670
2694
  // src/api.ts
2671
2695
  import { request as httpRequest } from "node:http";
2672
2696
  import { request as httpsRequest } from "node:https";
2697
+ import { hostname as osHostname } from "node:os";
2698
+
2699
+ // src/pid.ts
2700
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
2701
+ import { homedir as homedir9, hostname } from "node:os";
2702
+ import { dirname, join as join10 } from "node:path";
2703
+ var pidPath = join10(homedir9(), ".agendex", "daemon.pid");
2704
+ function writePid() {
2705
+ mkdirSync2(dirname(pidPath), { recursive: true });
2706
+ const info = {
2707
+ pid: process.pid,
2708
+ startedAtMs: Date.now(),
2709
+ hostname: hostname()
2710
+ };
2711
+ writeFileSync2(pidPath, JSON.stringify(info));
2712
+ }
2713
+ function readPidInfo() {
2714
+ if (!existsSync6(pidPath))
2715
+ return null;
2716
+ const raw = readFileSync3(pidPath, "utf-8").trim();
2717
+ const asNumber = Number(raw);
2718
+ if (Number.isFinite(asNumber) && asNumber > 0 && !raw.startsWith("{")) {
2719
+ return { pid: asNumber };
2720
+ }
2721
+ try {
2722
+ const parsed = JSON.parse(raw);
2723
+ if (Number.isFinite(parsed.pid) && parsed.pid > 0)
2724
+ return parsed;
2725
+ } catch {}
2726
+ return null;
2727
+ }
2728
+ function readPid() {
2729
+ return readPidInfo()?.pid ?? null;
2730
+ }
2731
+ function removePid() {
2732
+ try {
2733
+ unlinkSync(pidPath);
2734
+ } catch {}
2735
+ }
2736
+ function isRunning(pid) {
2737
+ try {
2738
+ process.kill(pid, 0);
2739
+ return true;
2740
+ } catch {
2741
+ return false;
2742
+ }
2743
+ }
2744
+
2745
+ // src/api.ts
2746
+ var cachedDeviceId;
2673
2747
  function getCloudConfig() {
2674
2748
  const config = loadConfig();
2675
2749
  if (!config?.cloudToken)
@@ -2724,6 +2798,12 @@ async function refreshStoredToken(currentToken, convexUrl) {
2724
2798
  async function sendHeartbeat() {
2725
2799
  try {
2726
2800
  const { token, convexUrl } = getCloudConfig();
2801
+ const pidInfo = readPidInfo();
2802
+ const heartbeatBody = JSON.stringify({
2803
+ deviceId: cachedDeviceId ??= loadOrCreateDeviceId(),
2804
+ hostname: pidInfo?.hostname ?? osHostname(),
2805
+ startedAtMs: pidInfo?.startedAtMs
2806
+ });
2727
2807
  let activeToken = token;
2728
2808
  let res = await requestText(`${convexUrl}/api/cli/heartbeat`, {
2729
2809
  method: "POST",
@@ -2731,7 +2811,8 @@ async function sendHeartbeat() {
2731
2811
  Authorization: `Bearer ${activeToken}`,
2732
2812
  Connection: "close",
2733
2813
  "Content-Type": "application/json"
2734
- }
2814
+ },
2815
+ body: heartbeatBody
2735
2816
  });
2736
2817
  if (res.status === 401) {
2737
2818
  const refreshedToken = await refreshStoredToken(activeToken, convexUrl);
@@ -2744,7 +2825,8 @@ async function sendHeartbeat() {
2744
2825
  Authorization: `Bearer ${activeToken}`,
2745
2826
  Connection: "close",
2746
2827
  "Content-Type": "application/json"
2747
- }
2828
+ },
2829
+ body: heartbeatBody
2748
2830
  });
2749
2831
  }
2750
2832
  if (res.status === 401) {
@@ -2798,52 +2880,6 @@ function requestText(urlString, options) {
2798
2880
  });
2799
2881
  }
2800
2882
 
2801
- // src/pid.ts
2802
- import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
2803
- import { homedir as homedir9, hostname } from "node:os";
2804
- import { dirname, join as join10 } from "node:path";
2805
- var pidPath = join10(homedir9(), ".agendex", "daemon.pid");
2806
- function writePid() {
2807
- mkdirSync2(dirname(pidPath), { recursive: true });
2808
- const info = {
2809
- pid: process.pid,
2810
- startedAtMs: Date.now(),
2811
- hostname: hostname()
2812
- };
2813
- writeFileSync2(pidPath, JSON.stringify(info));
2814
- }
2815
- function readPidInfo() {
2816
- if (!existsSync6(pidPath))
2817
- return null;
2818
- const raw = readFileSync3(pidPath, "utf-8").trim();
2819
- const asNumber = Number(raw);
2820
- if (Number.isFinite(asNumber) && asNumber > 0 && !raw.startsWith("{")) {
2821
- return { pid: asNumber };
2822
- }
2823
- try {
2824
- const parsed = JSON.parse(raw);
2825
- if (Number.isFinite(parsed.pid) && parsed.pid > 0)
2826
- return parsed;
2827
- } catch {}
2828
- return null;
2829
- }
2830
- function readPid() {
2831
- return readPidInfo()?.pid ?? null;
2832
- }
2833
- function removePid() {
2834
- try {
2835
- unlinkSync(pidPath);
2836
- } catch {}
2837
- }
2838
- function isRunning(pid) {
2839
- try {
2840
- process.kill(pid, 0);
2841
- return true;
2842
- } catch {
2843
- return false;
2844
- }
2845
- }
2846
-
2847
2883
  // src/daemon.ts
2848
2884
  var MAX_RESTARTS = 5;
2849
2885
  var RESTART_WINDOW_MS = 60000;
@@ -3029,7 +3065,7 @@ import { join as join11 } from "node:path";
3029
3065
  // package.json
3030
3066
  var package_default = {
3031
3067
  name: "agendex-cli",
3032
- version: "0.5.0",
3068
+ version: "0.6.0",
3033
3069
  description: "Agendex CLI for login, sync, and daemon workflows",
3034
3070
  homepage: "https://github.com/Tyru5/Agendex#readme",
3035
3071
  repository: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agendex-cli",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Agendex CLI for login, sync, and daemon workflows",
5
5
  "homepage": "https://github.com/Tyru5/Agendex#readme",
6
6
  "repository": {