agendex-cli 0.8.4 → 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.
- package/README.md +29 -2
- package/dist/cli.js +165 -37
- 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`
|
|
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
|
|
2257
|
-
|
|
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
|
-
|
|
2260
|
-
|
|
2269
|
+
const dir = getConfigDir();
|
|
2270
|
+
if (!existsSync3(dir))
|
|
2271
|
+
mkdirSync(dir, { recursive: true });
|
|
2261
2272
|
}
|
|
2262
2273
|
function readStoredConfig() {
|
|
2263
|
-
|
|
2274
|
+
const cfgPath = getConfigPath();
|
|
2275
|
+
if (!existsSync3(cfgPath))
|
|
2264
2276
|
return null;
|
|
2265
2277
|
try {
|
|
2266
|
-
const raw = JSON.parse(readFileSync3(
|
|
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(
|
|
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 ${
|
|
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
|
-
|
|
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
|
-
|
|
2516
|
+
const userPlansDir = getUserPlansDir();
|
|
2517
|
+
if (!existsSync4(userPlansDir))
|
|
2500
2518
|
return;
|
|
2501
|
-
const files = await walkDir(
|
|
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 {
|
|
2675
|
+
import { hostname } from "node:os";
|
|
2658
2676
|
import { dirname, join as join10 } from "node:path";
|
|
2659
|
-
|
|
2677
|
+
function getPidPath() {
|
|
2678
|
+
return join10(getConfigDir(), "daemon.pid");
|
|
2679
|
+
}
|
|
2660
2680
|
function writePid() {
|
|
2661
|
-
|
|
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(
|
|
2688
|
+
writeFileSync2(path, JSON.stringify(info));
|
|
2668
2689
|
}
|
|
2669
2690
|
function readPidInfo() {
|
|
2670
|
-
|
|
2691
|
+
const path = getPidPath();
|
|
2692
|
+
if (!existsSync6(path))
|
|
2671
2693
|
return null;
|
|
2672
|
-
const raw = readFileSync4(
|
|
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(
|
|
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 {
|
|
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
|
|
2942
|
+
return isDevMode() ? DEV_SITE_URL : PROD_SITE_URL;
|
|
2918
2943
|
}
|
|
2919
2944
|
async function login(siteUrlOverride) {
|
|
2920
2945
|
const { port, result } = await startCallbackServer();
|
|
@@ -3104,6 +3129,56 @@ function spawnBrowser(command, args, options = {}) {
|
|
|
3104
3129
|
import { spawn as spawn2 } from "node:child_process";
|
|
3105
3130
|
import { resolve as resolve4 } from "node:path";
|
|
3106
3131
|
import { fileURLToPath } from "node:url";
|
|
3132
|
+
|
|
3133
|
+
// src/sync-cache.ts
|
|
3134
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
3135
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
|
|
3136
|
+
import { join as join11 } from "node:path";
|
|
3137
|
+
function getCachePath() {
|
|
3138
|
+
return join11(getConfigDir(), "sync-cache.json");
|
|
3139
|
+
}
|
|
3140
|
+
function loadSyncCache() {
|
|
3141
|
+
const cachePath = getCachePath();
|
|
3142
|
+
if (!existsSync7(cachePath))
|
|
3143
|
+
return {};
|
|
3144
|
+
try {
|
|
3145
|
+
const raw = JSON.parse(readFileSync5(cachePath, "utf-8"));
|
|
3146
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
3147
|
+
return {};
|
|
3148
|
+
return raw;
|
|
3149
|
+
} catch {
|
|
3150
|
+
return {};
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
function saveSyncCache(cache, options) {
|
|
3154
|
+
const dir = getConfigDir();
|
|
3155
|
+
if (!existsSync7(dir))
|
|
3156
|
+
mkdirSync3(dir, { recursive: true });
|
|
3157
|
+
const cachePath = getCachePath();
|
|
3158
|
+
if (options?.replace) {
|
|
3159
|
+
writeFileSync3(cachePath, JSON.stringify(cache));
|
|
3160
|
+
return;
|
|
3161
|
+
}
|
|
3162
|
+
const existing = loadSyncCache();
|
|
3163
|
+
writeFileSync3(cachePath, JSON.stringify({ ...existing, ...cache }));
|
|
3164
|
+
}
|
|
3165
|
+
function computePayloadHash(payload) {
|
|
3166
|
+
const canonical = JSON.stringify([
|
|
3167
|
+
payload.localPlanId,
|
|
3168
|
+
payload.agent,
|
|
3169
|
+
payload.title,
|
|
3170
|
+
payload.content,
|
|
3171
|
+
payload.format,
|
|
3172
|
+
payload.filePath ?? null,
|
|
3173
|
+
payload.workspace ?? null,
|
|
3174
|
+
payload.metadata ?? null,
|
|
3175
|
+
payload.createdAt ?? null,
|
|
3176
|
+
payload.updatedAt ?? null
|
|
3177
|
+
]);
|
|
3178
|
+
return createHash2("sha256").update(canonical).digest("hex").slice(0, 20);
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3181
|
+
// src/daemon.ts
|
|
3107
3182
|
var MAX_RESTARTS = 5;
|
|
3108
3183
|
var RESTART_WINDOW_MS = 60000;
|
|
3109
3184
|
var RESTART_DELAY_MS = 5000;
|
|
@@ -3127,6 +3202,7 @@ async function runWorker() {
|
|
|
3127
3202
|
setActiveAdapters(adapters);
|
|
3128
3203
|
console.log(`[agendex] daemon starting with ${config.enabledAdapters.length} adapters`);
|
|
3129
3204
|
sendHeartbeat();
|
|
3205
|
+
const syncCache = loadSyncCache();
|
|
3130
3206
|
const syncQueue = [];
|
|
3131
3207
|
let syncing = false;
|
|
3132
3208
|
async function tryRefreshToken() {
|
|
@@ -3167,6 +3243,7 @@ async function runWorker() {
|
|
|
3167
3243
|
console.error(`[agendex] sync failed for "${payload.title}": ${result.error}`);
|
|
3168
3244
|
} else {
|
|
3169
3245
|
syncedCount++;
|
|
3246
|
+
syncCache[payload.localPlanId] = computePayloadHash(payload);
|
|
3170
3247
|
}
|
|
3171
3248
|
}
|
|
3172
3249
|
} catch (err) {
|
|
@@ -3176,6 +3253,7 @@ async function runWorker() {
|
|
|
3176
3253
|
syncing = false;
|
|
3177
3254
|
}
|
|
3178
3255
|
if (syncedCount > 0 || failedCount > 0) {
|
|
3256
|
+
saveSyncCache(syncCache);
|
|
3179
3257
|
console.log(`[agendex] sync complete: ${syncedCount} synced, ${failedCount} failed`);
|
|
3180
3258
|
}
|
|
3181
3259
|
if (syncQueue.length > 0)
|
|
@@ -3185,10 +3263,23 @@ async function runWorker() {
|
|
|
3185
3263
|
console.log(`[agendex] initial scan...`);
|
|
3186
3264
|
await scan();
|
|
3187
3265
|
const plans = getAll();
|
|
3188
|
-
|
|
3266
|
+
let initialSkipped = 0;
|
|
3189
3267
|
for (const plan of plans) {
|
|
3190
|
-
|
|
3268
|
+
const payload = planToPayload(plan);
|
|
3269
|
+
const hash = computePayloadHash(payload);
|
|
3270
|
+
if (syncCache[plan.id] === hash) {
|
|
3271
|
+
initialSkipped++;
|
|
3272
|
+
continue;
|
|
3273
|
+
}
|
|
3274
|
+
syncQueue.push(payload);
|
|
3191
3275
|
}
|
|
3276
|
+
const activePlanIds = new Set(plans.map((plan) => plan.id));
|
|
3277
|
+
for (const id of Object.keys(syncCache)) {
|
|
3278
|
+
if (!activePlanIds.has(id))
|
|
3279
|
+
delete syncCache[id];
|
|
3280
|
+
}
|
|
3281
|
+
saveSyncCache(syncCache, { replace: true });
|
|
3282
|
+
console.log(`[agendex] syncing ${syncQueue.length} plans (${initialSkipped} unchanged)...`);
|
|
3192
3283
|
await processSyncQueue();
|
|
3193
3284
|
setInterval(() => void sendHeartbeat(), CLI_DAEMON_HEARTBEAT_INTERVAL_MS);
|
|
3194
3285
|
startWatching((changedPlans) => {
|
|
@@ -3249,7 +3340,7 @@ async function startSupervisor() {
|
|
|
3249
3340
|
}
|
|
3250
3341
|
|
|
3251
3342
|
// src/sync.ts
|
|
3252
|
-
async function syncAll() {
|
|
3343
|
+
async function syncAll(force = false) {
|
|
3253
3344
|
const config = await loadOrInitConfig();
|
|
3254
3345
|
const adapters = resolveAdapters(config.enabledAdapters);
|
|
3255
3346
|
setActiveAdapters(adapters);
|
|
@@ -3257,9 +3348,13 @@ async function syncAll() {
|
|
|
3257
3348
|
await scan();
|
|
3258
3349
|
const plans = getAll();
|
|
3259
3350
|
console.log(`[agendex] Found ${plans.length} plans. Syncing to cloud...`);
|
|
3351
|
+
const cache = force ? {} : loadSyncCache();
|
|
3352
|
+
const activePlanIds = new Set;
|
|
3260
3353
|
let synced = 0;
|
|
3354
|
+
let skipped = 0;
|
|
3261
3355
|
let failed = 0;
|
|
3262
3356
|
for (const plan of plans) {
|
|
3357
|
+
activePlanIds.add(plan.id);
|
|
3263
3358
|
const payload = {
|
|
3264
3359
|
localPlanId: plan.id,
|
|
3265
3360
|
agent: plan.agent,
|
|
@@ -3268,27 +3363,40 @@ async function syncAll() {
|
|
|
3268
3363
|
format: plan.format,
|
|
3269
3364
|
filePath: plan.filePath,
|
|
3270
3365
|
workspace: plan.workspace,
|
|
3271
|
-
metadata: plan.metadata
|
|
3366
|
+
metadata: plan.metadata,
|
|
3367
|
+
createdAt: plan.createdAt.getTime(),
|
|
3368
|
+
updatedAt: plan.updatedAt.getTime()
|
|
3272
3369
|
};
|
|
3370
|
+
const hash = computePayloadHash(payload);
|
|
3371
|
+
if (!force && cache[plan.id] === hash) {
|
|
3372
|
+
skipped++;
|
|
3373
|
+
continue;
|
|
3374
|
+
}
|
|
3273
3375
|
const result = await syncPlan(payload);
|
|
3274
3376
|
if (result.ok) {
|
|
3275
3377
|
synced++;
|
|
3378
|
+
cache[plan.id] = hash;
|
|
3276
3379
|
} else {
|
|
3277
3380
|
failed++;
|
|
3278
3381
|
console.error(`[agendex] Failed to sync "${plan.title}": ${result.error}`);
|
|
3279
3382
|
}
|
|
3280
3383
|
}
|
|
3281
|
-
|
|
3384
|
+
for (const id of Object.keys(cache)) {
|
|
3385
|
+
if (!activePlanIds.has(id))
|
|
3386
|
+
delete cache[id];
|
|
3387
|
+
}
|
|
3388
|
+
saveSyncCache(cache, { replace: true });
|
|
3389
|
+
console.log(`[agendex] Sync complete: ${synced} synced, ${skipped} unchanged, ${failed} failed`);
|
|
3282
3390
|
}
|
|
3283
3391
|
|
|
3284
3392
|
// src/version.ts
|
|
3285
|
-
import { existsSync as
|
|
3393
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
3286
3394
|
import { tmpdir } from "node:os";
|
|
3287
|
-
import { join as
|
|
3395
|
+
import { join as join12 } from "node:path";
|
|
3288
3396
|
// package.json
|
|
3289
3397
|
var package_default = {
|
|
3290
3398
|
name: "agendex-cli",
|
|
3291
|
-
version: "0.
|
|
3399
|
+
version: "0.9.0",
|
|
3292
3400
|
description: "Agendex CLI for login, sync, and daemon workflows",
|
|
3293
3401
|
homepage: "https://github.com/Tyru5/Agendex#readme",
|
|
3294
3402
|
repository: {
|
|
@@ -3332,14 +3440,14 @@ var package_default = {
|
|
|
3332
3440
|
|
|
3333
3441
|
// src/version.ts
|
|
3334
3442
|
var CLI_VERSION = package_default.version;
|
|
3335
|
-
var CACHE_FILE = process.env.AGENDEX_UPDATE_CACHE_FILE ??
|
|
3443
|
+
var CACHE_FILE = process.env.AGENDEX_UPDATE_CACHE_FILE ?? join12(tmpdir(), ".agendex-update-cache.json");
|
|
3336
3444
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
3337
3445
|
var UPDATE_URL = process.env.AGENDEX_UPDATE_URL ?? "https://registry.npmjs.org/agendex-cli/latest";
|
|
3338
3446
|
function readCache(current) {
|
|
3339
3447
|
try {
|
|
3340
|
-
if (!
|
|
3448
|
+
if (!existsSync8(CACHE_FILE))
|
|
3341
3449
|
return null;
|
|
3342
|
-
const { result, ts } = JSON.parse(
|
|
3450
|
+
const { result, ts } = JSON.parse(readFileSync6(CACHE_FILE, "utf8"));
|
|
3343
3451
|
if (Date.now() - ts > CACHE_TTL_MS)
|
|
3344
3452
|
return null;
|
|
3345
3453
|
return normalizeResult(result, current);
|
|
@@ -3349,7 +3457,7 @@ function readCache(current) {
|
|
|
3349
3457
|
}
|
|
3350
3458
|
function writeCache(result) {
|
|
3351
3459
|
try {
|
|
3352
|
-
|
|
3460
|
+
writeFileSync4(CACHE_FILE, JSON.stringify({ result, ts: Date.now() }));
|
|
3353
3461
|
} catch {}
|
|
3354
3462
|
}
|
|
3355
3463
|
async function checkForUpdate() {
|
|
@@ -3400,7 +3508,18 @@ function isNewer(latest, current) {
|
|
|
3400
3508
|
|
|
3401
3509
|
// src/cli.ts
|
|
3402
3510
|
var args = process.argv.slice(2);
|
|
3403
|
-
var
|
|
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";
|
|
3404
3523
|
var cliEntry = resolve5(process.argv[1] ?? fileURLToPath2(import.meta.url));
|
|
3405
3524
|
async function main() {
|
|
3406
3525
|
const isInternal = args.includes("--daemon") || args.includes("--worker");
|
|
@@ -3443,9 +3562,13 @@ async function main() {
|
|
|
3443
3562
|
}
|
|
3444
3563
|
if (existingPid)
|
|
3445
3564
|
removePid();
|
|
3446
|
-
const
|
|
3565
|
+
const daemonArgs = [cliEntry, "start", "--daemon"];
|
|
3566
|
+
if (devFlag)
|
|
3567
|
+
daemonArgs.push("--dev");
|
|
3568
|
+
const child = spawn3(process.execPath, daemonArgs, {
|
|
3447
3569
|
detached: true,
|
|
3448
|
-
stdio: "ignore"
|
|
3570
|
+
stdio: "ignore",
|
|
3571
|
+
env: { ...process.env, ...devFlag ? { AGENDEX_DEV: "1" } : {} }
|
|
3449
3572
|
});
|
|
3450
3573
|
child.unref();
|
|
3451
3574
|
await new Promise((r) => setTimeout(r, 500));
|
|
@@ -3489,7 +3612,8 @@ async function main() {
|
|
|
3489
3612
|
return 0;
|
|
3490
3613
|
}
|
|
3491
3614
|
case "sync": {
|
|
3492
|
-
|
|
3615
|
+
const force = args.includes("--force");
|
|
3616
|
+
await syncAll(force);
|
|
3493
3617
|
return 0;
|
|
3494
3618
|
}
|
|
3495
3619
|
case "cleanup": {
|
|
@@ -3622,13 +3746,17 @@ Usage:
|
|
|
3622
3746
|
agendex login --url <url> Login to a self-hosted instance
|
|
3623
3747
|
agendex logout Clear stored cloud token
|
|
3624
3748
|
agendex configure Select which agents/adapters to index
|
|
3625
|
-
agendex sync One-shot scan + sync to cloud
|
|
3749
|
+
agendex sync One-shot scan + sync to cloud (skips unchanged plans)
|
|
3750
|
+
agendex sync --force Re-sync all plans, ignoring cache
|
|
3626
3751
|
agendex cleanup Interactively remove cloud daemons
|
|
3627
3752
|
agendex cleanup --stale Auto-remove all stale daemons
|
|
3628
3753
|
agendex status Show current config state + daemon status
|
|
3629
3754
|
agendex help Show this help message
|
|
3630
3755
|
agendex --version Print CLI version
|
|
3631
3756
|
agendex -v Print CLI version
|
|
3757
|
+
|
|
3758
|
+
Flags:
|
|
3759
|
+
--dev Use dev environment (~/.agendex-dev/ config dir)
|
|
3632
3760
|
`.trim());
|
|
3633
3761
|
return 0;
|
|
3634
3762
|
}
|