agendex-cli 0.8.5 → 0.9.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 (3) hide show
  1. package/README.md +29 -2
  2. package/dist/cli.js +77 -31
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -28,6 +28,33 @@ agendex help # Show help message
28
28
  agendex --version / -v # Print CLI version
29
29
  ```
30
30
 
31
+ ## Dev vs prod (config directory)
32
+
33
+ By default the CLI uses **`~/.agendex/`** for all on-disk state:
34
+
35
+ - `config.json` — local token, cloud token, Convex URL, device id, enabled adapters
36
+ - `daemon.pid` — supervisor PID and metadata
37
+ - `sync-cache.json` — hashes used to skip unchanged plans on sync
38
+
39
+ To use a **separate dev environment** (so local cloud / dev login does not overwrite prod credentials), use either:
40
+
41
+ - **`--dev`** on any command (recommended), or
42
+ - **`AGENDEX_DEV=1`** in the environment
43
+
44
+ That switches the directory to **`~/.agendex-dev/`** with the same filenames inside it.
45
+
46
+ `--dev` takes precedence when set programmatically; otherwise `AGENDEX_DEV=1` is read. When you start the daemon with `agendex start --dev`, the background supervisor and worker inherit `AGENDEX_DEV=1` so they stay on the dev config.
47
+
48
+ Examples:
49
+
50
+ ```bash
51
+ agendex --dev login
52
+ agendex --dev status
53
+ AGENDEX_DEV=1 agendex sync
54
+ ```
55
+
56
+ In dev mode the default OAuth site (when you do not pass `--url` and do not set `AGENDEX_SITE_URL`) points at the local EE app URL used for development.
57
+
31
58
  ## Daemon Cleanup
32
59
 
33
60
  `agendex cleanup` manages registered daemon devices in the cloud.
@@ -76,6 +103,6 @@ For self-hosted deployments, pass your site URL explicitly:
76
103
  agendex login --url https://agendex.yourdomain.com
77
104
  ```
78
105
 
79
- This opens your deployment's OAuth flow and stores the returned `cloudToken` and `convexUrl` in `~/.agendex/config.json`.
106
+ This opens your deployment's OAuth flow and stores the returned `cloudToken` and `convexUrl` in your active config directory (`~/.agendex/config.json` for prod, `~/.agendex-dev/config.json` when using `--dev` or `AGENDEX_DEV=1`).
80
107
 
81
- The target can also be set via `AGENDEX_SITE_URL` env var. For local development, set `AGENDEX_DEV=1` to use the local dev server.
108
+ The target can also be set via `AGENDEX_SITE_URL` env var. For local development against the default dev app URL, use `agendex login --dev` or set `AGENDEX_DEV=1` (see [Dev vs prod](#dev-vs-prod-config-directory) above).
package/dist/cli.js CHANGED
@@ -2253,17 +2253,29 @@ async function promptForAdapterSelection(options = {}) {
2253
2253
  }
2254
2254
 
2255
2255
  // ../shared/src/config.ts
2256
- var configDir = join7(homedir7(), ".agendex");
2257
- var configPath = join7(configDir, "config.json");
2256
+ var devModeOverride;
2257
+ function setDevMode(dev) {
2258
+ devModeOverride = dev;
2259
+ }
2260
+ function isDevMode() {
2261
+ if (devModeOverride !== undefined)
2262
+ return devModeOverride;
2263
+ return process.env.AGENDEX_DEV === "1";
2264
+ }
2265
+ function getConfigDir() {
2266
+ return join7(homedir7(), isDevMode() ? ".agendex-dev" : ".agendex");
2267
+ }
2258
2268
  function ensureConfigDir() {
2259
- if (!existsSync3(configDir))
2260
- mkdirSync(configDir, { recursive: true });
2269
+ const dir = getConfigDir();
2270
+ if (!existsSync3(dir))
2271
+ mkdirSync(dir, { recursive: true });
2261
2272
  }
2262
2273
  function readStoredConfig() {
2263
- if (!existsSync3(configPath))
2274
+ const cfgPath = getConfigPath();
2275
+ if (!existsSync3(cfgPath))
2264
2276
  return null;
2265
2277
  try {
2266
- const raw = JSON.parse(readFileSync3(configPath, "utf-8"));
2278
+ const raw = JSON.parse(readFileSync3(cfgPath, "utf-8"));
2267
2279
  if (!raw || typeof raw !== "object")
2268
2280
  return null;
2269
2281
  return raw;
@@ -2305,7 +2317,7 @@ function saveConfig(config) {
2305
2317
  deviceId: config.deviceId,
2306
2318
  enabledAdapters: sanitizeEnabledAdapterIds(config.enabledAdapters)
2307
2319
  };
2308
- writeFileSync(configPath, JSON.stringify(payload, null, 2));
2320
+ writeFileSync(getConfigPath(), JSON.stringify(payload, null, 2));
2309
2321
  }
2310
2322
  function generateToken() {
2311
2323
  return randomBytes(32).toString("hex");
@@ -2324,7 +2336,7 @@ function loadOrCreateToken() {
2324
2336
  });
2325
2337
  console.log(`
2326
2338
  [agendex] generated auth token: ${token}`);
2327
- console.log(`[agendex] saved to ${configPath}
2339
+ console.log(`[agendex] saved to ${getConfigPath()}
2328
2340
  `);
2329
2341
  return token;
2330
2342
  }
@@ -2341,6 +2353,9 @@ function loadOrCreateDeviceId() {
2341
2353
  });
2342
2354
  return deviceId;
2343
2355
  }
2356
+ function getConfigPath() {
2357
+ return join7(getConfigDir(), "config.json");
2358
+ }
2344
2359
  async function loadOrInitConfig(options = {}) {
2345
2360
  const configureAdapters = Boolean(options.configureAdapters);
2346
2361
  const existing = loadConfig();
@@ -2389,7 +2404,9 @@ import { existsSync as existsSync4, readdirSync as readdirSync3, statSync } from
2389
2404
  import { lstat, mkdir, readdir as readdir2, readFile as readFile6, stat as stat6, writeFile as writeFile3 } from "node:fs/promises";
2390
2405
  import { homedir as homedir8 } from "node:os";
2391
2406
  import { join as join8, resolve as resolve2, sep as sep2 } from "node:path";
2392
- var USER_PLANS_DIR = join8(homedir8(), ".agendex", "plans");
2407
+ function getUserPlansDir() {
2408
+ return join8(getConfigDir(), "plans");
2409
+ }
2393
2410
  var store = new Map;
2394
2411
  var MAX_DEPTH = 6;
2395
2412
  var DISCOVERY_MAX_DEPTH = 4;
@@ -2496,9 +2513,10 @@ async function walkDir(dir, depth = 0, seen = new Set) {
2496
2513
  return files;
2497
2514
  }
2498
2515
  async function scanUserPlans() {
2499
- if (!existsSync4(USER_PLANS_DIR))
2516
+ const userPlansDir = getUserPlansDir();
2517
+ if (!existsSync4(userPlansDir))
2500
2518
  return;
2501
- const files = await walkDir(USER_PLANS_DIR);
2519
+ const files = await walkDir(userPlansDir);
2502
2520
  for (const file of files) {
2503
2521
  if (!file.endsWith(".md"))
2504
2522
  continue;
@@ -2654,22 +2672,26 @@ import { hostname as osHostname } from "node:os";
2654
2672
 
2655
2673
  // src/pid.ts
2656
2674
  import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
2657
- import { homedir as homedir9, hostname } from "node:os";
2675
+ import { hostname } from "node:os";
2658
2676
  import { dirname, join as join10 } from "node:path";
2659
- var pidPath = join10(homedir9(), ".agendex", "daemon.pid");
2677
+ function getPidPath() {
2678
+ return join10(getConfigDir(), "daemon.pid");
2679
+ }
2660
2680
  function writePid() {
2661
- mkdirSync2(dirname(pidPath), { recursive: true });
2681
+ const path = getPidPath();
2682
+ mkdirSync2(dirname(path), { recursive: true });
2662
2683
  const info = {
2663
2684
  pid: process.pid,
2664
2685
  startedAtMs: Date.now(),
2665
2686
  hostname: hostname()
2666
2687
  };
2667
- writeFileSync2(pidPath, JSON.stringify(info));
2688
+ writeFileSync2(path, JSON.stringify(info));
2668
2689
  }
2669
2690
  function readPidInfo() {
2670
- if (!existsSync6(pidPath))
2691
+ const path = getPidPath();
2692
+ if (!existsSync6(path))
2671
2693
  return null;
2672
- const raw = readFileSync4(pidPath, "utf-8").trim();
2694
+ const raw = readFileSync4(path, "utf-8").trim();
2673
2695
  const asNumber = Number(raw);
2674
2696
  if (Number.isFinite(asNumber) && asNumber > 0 && !raw.startsWith("{")) {
2675
2697
  return { pid: asNumber };
@@ -2686,7 +2708,7 @@ function readPid() {
2686
2708
  }
2687
2709
  function removePid() {
2688
2710
  try {
2689
- unlinkSync(pidPath);
2711
+ unlinkSync(getPidPath());
2690
2712
  } catch {}
2691
2713
  }
2692
2714
  function isRunning(pid) {
@@ -2706,7 +2728,10 @@ function getCloudConfig() {
2706
2728
  throw new Error("Not logged in. Run `agendex login` first.");
2707
2729
  if (!config.convexUrl)
2708
2730
  throw new Error("No Convex URL configured. Run `agendex login` first.");
2709
- return { token: config.cloudToken, convexUrl: config.convexUrl };
2731
+ return {
2732
+ token: config.cloudToken,
2733
+ convexUrl: config.convexUrl
2734
+ };
2710
2735
  }
2711
2736
  async function syncPlan(plan) {
2712
2737
  const { token, convexUrl } = getCloudConfig();
@@ -2914,7 +2939,7 @@ var DEV_SITE_URL = "http://app.agendex.local:5174";
2914
2939
  function getDefaultSiteUrl() {
2915
2940
  if (process.env.AGENDEX_SITE_URL)
2916
2941
  return process.env.AGENDEX_SITE_URL;
2917
- return process.env.AGENDEX_DEV === "1" ? DEV_SITE_URL : PROD_SITE_URL;
2942
+ return isDevMode() ? DEV_SITE_URL : PROD_SITE_URL;
2918
2943
  }
2919
2944
  async function login(siteUrlOverride) {
2920
2945
  const { port, result } = await startCallbackServer();
@@ -3108,14 +3133,16 @@ import { fileURLToPath } from "node:url";
3108
3133
  // src/sync-cache.ts
3109
3134
  import { createHash as createHash2 } from "node:crypto";
3110
3135
  import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
3111
- import { homedir as homedir10 } from "node:os";
3112
3136
  import { join as join11 } from "node:path";
3113
- var CACHE_PATH = join11(homedir10(), ".agendex", "sync-cache.json");
3137
+ function getCachePath() {
3138
+ return join11(getConfigDir(), "sync-cache.json");
3139
+ }
3114
3140
  function loadSyncCache() {
3115
- if (!existsSync7(CACHE_PATH))
3141
+ const cachePath = getCachePath();
3142
+ if (!existsSync7(cachePath))
3116
3143
  return {};
3117
3144
  try {
3118
- const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf-8"));
3145
+ const raw = JSON.parse(readFileSync5(cachePath, "utf-8"));
3119
3146
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
3120
3147
  return {};
3121
3148
  return raw;
@@ -3124,15 +3151,16 @@ function loadSyncCache() {
3124
3151
  }
3125
3152
  }
3126
3153
  function saveSyncCache(cache, options) {
3127
- const dir = join11(homedir10(), ".agendex");
3154
+ const dir = getConfigDir();
3128
3155
  if (!existsSync7(dir))
3129
3156
  mkdirSync3(dir, { recursive: true });
3157
+ const cachePath = getCachePath();
3130
3158
  if (options?.replace) {
3131
- writeFileSync3(CACHE_PATH, JSON.stringify(cache));
3159
+ writeFileSync3(cachePath, JSON.stringify(cache));
3132
3160
  return;
3133
3161
  }
3134
3162
  const existing = loadSyncCache();
3135
- writeFileSync3(CACHE_PATH, JSON.stringify({ ...existing, ...cache }));
3163
+ writeFileSync3(cachePath, JSON.stringify({ ...existing, ...cache }));
3136
3164
  }
3137
3165
  function computePayloadHash(payload) {
3138
3166
  const canonical = JSON.stringify([
@@ -3368,7 +3396,7 @@ import { join as join12 } from "node:path";
3368
3396
  // package.json
3369
3397
  var package_default = {
3370
3398
  name: "agendex-cli",
3371
- version: "0.8.5",
3399
+ version: "0.9.0",
3372
3400
  description: "Agendex CLI for login, sync, and daemon workflows",
3373
3401
  homepage: "https://github.com/Tyru5/Agendex#readme",
3374
3402
  repository: {
@@ -3480,7 +3508,18 @@ function isNewer(latest, current) {
3480
3508
 
3481
3509
  // src/cli.ts
3482
3510
  var args = process.argv.slice(2);
3483
- var command = args[0] ?? "start";
3511
+ var devFlag = args.includes("--dev");
3512
+ if (devFlag)
3513
+ setDevMode(true);
3514
+ function firstCommandToken(argv) {
3515
+ for (const a of argv) {
3516
+ if (a === "--dev")
3517
+ continue;
3518
+ return a;
3519
+ }
3520
+ return;
3521
+ }
3522
+ var command = firstCommandToken(args) ?? "start";
3484
3523
  var cliEntry = resolve5(process.argv[1] ?? fileURLToPath2(import.meta.url));
3485
3524
  async function main() {
3486
3525
  const isInternal = args.includes("--daemon") || args.includes("--worker");
@@ -3523,9 +3562,13 @@ async function main() {
3523
3562
  }
3524
3563
  if (existingPid)
3525
3564
  removePid();
3526
- const child = spawn3(process.execPath, [cliEntry, "start", "--daemon"], {
3565
+ const daemonArgs = [cliEntry, "start", "--daemon"];
3566
+ if (devFlag)
3567
+ daemonArgs.push("--dev");
3568
+ const child = spawn3(process.execPath, daemonArgs, {
3527
3569
  detached: true,
3528
- stdio: "ignore"
3570
+ stdio: "ignore",
3571
+ env: { ...process.env, ...devFlag ? { AGENDEX_DEV: "1" } : {} }
3529
3572
  });
3530
3573
  child.unref();
3531
3574
  await new Promise((r) => setTimeout(r, 500));
@@ -3711,6 +3754,9 @@ Usage:
3711
3754
  agendex help Show this help message
3712
3755
  agendex --version Print CLI version
3713
3756
  agendex -v Print CLI version
3757
+
3758
+ Flags:
3759
+ --dev Use dev environment (~/.agendex-dev/ config dir)
3714
3760
  `.trim());
3715
3761
  return 0;
3716
3762
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agendex-cli",
3
- "version": "0.8.5",
3
+ "version": "0.9.0",
4
4
  "description": "Agendex CLI for login, sync, and daemon workflows",
5
5
  "homepage": "https://github.com/Tyru5/Agendex#readme",
6
6
  "repository": {