agendex-cli 0.3.2 → 0.5.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 +32 -8
- package/dist/cli.js +175 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,15 +14,39 @@ bun install -g agendex-cli
|
|
|
14
14
|
## Commands
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
agendex login
|
|
18
|
-
agendex login --url
|
|
19
|
-
agendex
|
|
20
|
-
agendex
|
|
21
|
-
agendex
|
|
22
|
-
agendex
|
|
23
|
-
agendex
|
|
24
|
-
agendex
|
|
17
|
+
agendex login # Authenticate via browser OAuth (agendex.dev)
|
|
18
|
+
agendex login --url <url> # Login to a self-hosted instance
|
|
19
|
+
agendex logout # Clear stored cloud token
|
|
20
|
+
agendex configure # Select which agents/adapters to index
|
|
21
|
+
agendex start # Start daemon (backgrounds itself)
|
|
22
|
+
agendex stop # Stop the running daemon
|
|
23
|
+
agendex sync # One-shot scan + sync to cloud
|
|
24
|
+
agendex status # Show config state, daemon status, uptime & hostname
|
|
25
|
+
agendex help # Show help message
|
|
26
|
+
agendex --version / -v # Print CLI version
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Status Output
|
|
30
|
+
|
|
31
|
+
`agendex status` prints a rich overview:
|
|
32
|
+
|
|
33
|
+
- Config version, local/cloud token state, Convex URL
|
|
34
|
+
- Enabled adapters
|
|
35
|
+
- Daemon running state with PID
|
|
36
|
+
- **Uptime** — how long the daemon has been running
|
|
37
|
+
- **Hostname** — machine the daemon is running on
|
|
38
|
+
- CLI version
|
|
39
|
+
|
|
40
|
+
## Auto-Update Check
|
|
41
|
+
|
|
42
|
+
Before running `start`, `configure`, or `sync`, the CLI checks for a newer published version. If an update is required the command is blocked and you are prompted to upgrade:
|
|
43
|
+
|
|
25
44
|
```
|
|
45
|
+
[agendex] update required: v0.1.0 → v0.2.0
|
|
46
|
+
[agendex] run: npm i -g agendex-cli
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The check is skipped for `stop`, `status`, `login`, `logout`, and `help`.
|
|
26
50
|
|
|
27
51
|
## Supported Runtime
|
|
28
52
|
|
package/dist/cli.js
CHANGED
|
@@ -2800,19 +2800,35 @@ function requestText(urlString, options) {
|
|
|
2800
2800
|
|
|
2801
2801
|
// src/pid.ts
|
|
2802
2802
|
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2803
|
-
import { homedir as homedir9 } from "node:os";
|
|
2803
|
+
import { homedir as homedir9, hostname } from "node:os";
|
|
2804
2804
|
import { dirname, join as join10 } from "node:path";
|
|
2805
2805
|
var pidPath = join10(homedir9(), ".agendex", "daemon.pid");
|
|
2806
2806
|
function writePid() {
|
|
2807
2807
|
mkdirSync2(dirname(pidPath), { recursive: true });
|
|
2808
|
-
|
|
2808
|
+
const info = {
|
|
2809
|
+
pid: process.pid,
|
|
2810
|
+
startedAtMs: Date.now(),
|
|
2811
|
+
hostname: hostname()
|
|
2812
|
+
};
|
|
2813
|
+
writeFileSync2(pidPath, JSON.stringify(info));
|
|
2809
2814
|
}
|
|
2810
|
-
function
|
|
2815
|
+
function readPidInfo() {
|
|
2811
2816
|
if (!existsSync6(pidPath))
|
|
2812
2817
|
return null;
|
|
2813
2818
|
const raw = readFileSync3(pidPath, "utf-8").trim();
|
|
2814
|
-
const
|
|
2815
|
-
|
|
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;
|
|
2816
2832
|
}
|
|
2817
2833
|
function removePid() {
|
|
2818
2834
|
try {
|
|
@@ -3006,11 +3022,132 @@ async function syncAll() {
|
|
|
3006
3022
|
console.log(`[agendex] Sync complete: ${synced} synced, ${failed} failed`);
|
|
3007
3023
|
}
|
|
3008
3024
|
|
|
3025
|
+
// src/version.ts
|
|
3026
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
3027
|
+
import { tmpdir } from "node:os";
|
|
3028
|
+
import { join as join11 } from "node:path";
|
|
3029
|
+
// package.json
|
|
3030
|
+
var package_default = {
|
|
3031
|
+
name: "agendex-cli",
|
|
3032
|
+
version: "0.5.0",
|
|
3033
|
+
description: "Agendex CLI for login, sync, and daemon workflows",
|
|
3034
|
+
homepage: "https://github.com/Tyru5/Agendex#readme",
|
|
3035
|
+
repository: {
|
|
3036
|
+
type: "git",
|
|
3037
|
+
url: "git+https://github.com/Tyru5/Agendex.git",
|
|
3038
|
+
directory: "packages/cli"
|
|
3039
|
+
},
|
|
3040
|
+
bugs: {
|
|
3041
|
+
url: "https://github.com/Tyru5/Agendex/issues"
|
|
3042
|
+
},
|
|
3043
|
+
type: "module",
|
|
3044
|
+
license: "AGPL-3.0-only",
|
|
3045
|
+
bin: {
|
|
3046
|
+
agendex: "./dist/cli.js"
|
|
3047
|
+
},
|
|
3048
|
+
files: [
|
|
3049
|
+
"dist",
|
|
3050
|
+
"README.md",
|
|
3051
|
+
"LICENSE"
|
|
3052
|
+
],
|
|
3053
|
+
publishConfig: {
|
|
3054
|
+
access: "public"
|
|
3055
|
+
},
|
|
3056
|
+
engines: {
|
|
3057
|
+
node: ">=20"
|
|
3058
|
+
},
|
|
3059
|
+
scripts: {
|
|
3060
|
+
build: "node ./scripts/build-release.mjs --dist-only",
|
|
3061
|
+
"build:release": "node ./scripts/build-release.mjs",
|
|
3062
|
+
prepack: "node ./scripts/build-release.mjs --dist-only"
|
|
3063
|
+
},
|
|
3064
|
+
dependencies: {
|
|
3065
|
+
"better-sqlite3": "^12.6.2"
|
|
3066
|
+
},
|
|
3067
|
+
devDependencies: {
|
|
3068
|
+
"@agendex/shared": "workspace:*",
|
|
3069
|
+
"@types/bun": "^1.3.9"
|
|
3070
|
+
}
|
|
3071
|
+
};
|
|
3072
|
+
|
|
3073
|
+
// src/version.ts
|
|
3074
|
+
var CLI_VERSION = package_default.version;
|
|
3075
|
+
var CACHE_FILE = join11(tmpdir(), ".agendex-update-cache.json");
|
|
3076
|
+
var CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
3077
|
+
function readCache() {
|
|
3078
|
+
try {
|
|
3079
|
+
if (!existsSync7(CACHE_FILE))
|
|
3080
|
+
return null;
|
|
3081
|
+
const { result, ts } = JSON.parse(readFileSync4(CACHE_FILE, "utf8"));
|
|
3082
|
+
if (Date.now() - ts > CACHE_TTL_MS)
|
|
3083
|
+
return null;
|
|
3084
|
+
return result;
|
|
3085
|
+
} catch {
|
|
3086
|
+
return null;
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
function writeCache(result) {
|
|
3090
|
+
try {
|
|
3091
|
+
writeFileSync3(CACHE_FILE, JSON.stringify({ result, ts: Date.now() }));
|
|
3092
|
+
} catch {}
|
|
3093
|
+
}
|
|
3094
|
+
async function checkForUpdate() {
|
|
3095
|
+
const current = CLI_VERSION;
|
|
3096
|
+
const cached = readCache();
|
|
3097
|
+
if (cached)
|
|
3098
|
+
return { ...cached, current };
|
|
3099
|
+
try {
|
|
3100
|
+
const controller = new AbortController;
|
|
3101
|
+
const timeout = setTimeout(() => controller.abort(), 3000);
|
|
3102
|
+
const res = await fetch("https://registry.npmjs.org/agendex-cli/latest", {
|
|
3103
|
+
signal: controller.signal
|
|
3104
|
+
});
|
|
3105
|
+
clearTimeout(timeout);
|
|
3106
|
+
if (!res.ok) {
|
|
3107
|
+
return { updateAvailable: false, current, latest: current };
|
|
3108
|
+
}
|
|
3109
|
+
const data = await res.json();
|
|
3110
|
+
const latest = data.version;
|
|
3111
|
+
const result = { updateAvailable: isNewer(latest, current), current, latest };
|
|
3112
|
+
writeCache(result);
|
|
3113
|
+
return result;
|
|
3114
|
+
} catch {
|
|
3115
|
+
return { updateAvailable: false, current, latest: current };
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
function isNewer(latest, current) {
|
|
3119
|
+
const l = latest.split(".").map(Number);
|
|
3120
|
+
const c = current.split(".").map(Number);
|
|
3121
|
+
for (let i = 0;i < Math.max(l.length, c.length); i++) {
|
|
3122
|
+
const lv = l[i] ?? 0;
|
|
3123
|
+
const cv = c[i] ?? 0;
|
|
3124
|
+
if (lv > cv)
|
|
3125
|
+
return true;
|
|
3126
|
+
if (lv < cv)
|
|
3127
|
+
return false;
|
|
3128
|
+
}
|
|
3129
|
+
return false;
|
|
3130
|
+
}
|
|
3131
|
+
|
|
3009
3132
|
// src/cli.ts
|
|
3010
3133
|
var args = process.argv.slice(2);
|
|
3011
3134
|
var command = args[0] ?? "start";
|
|
3012
3135
|
var cliEntry = resolve5(process.argv[1] ?? fileURLToPath2(import.meta.url));
|
|
3013
3136
|
async function main() {
|
|
3137
|
+
const isInternal = args.includes("--daemon") || args.includes("--worker");
|
|
3138
|
+
if (command === "--version" || command === "-v") {
|
|
3139
|
+
writeStdout(CLI_VERSION);
|
|
3140
|
+
return 0;
|
|
3141
|
+
}
|
|
3142
|
+
const isPassthrough = ["stop", "status", "login", "logout", "help", "--help", "-h"].includes(command);
|
|
3143
|
+
if (!isInternal && !isPassthrough) {
|
|
3144
|
+
const { updateAvailable, current, latest } = await checkForUpdate();
|
|
3145
|
+
if (updateAvailable) {
|
|
3146
|
+
writeStderr(`[agendex] update required: v${current} → v${latest}`);
|
|
3147
|
+
writeStderr(`[agendex] run: npm i -g agendex-cli`);
|
|
3148
|
+
return 1;
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3014
3151
|
switch (command) {
|
|
3015
3152
|
case "start": {
|
|
3016
3153
|
if (args.includes("--daemon")) {
|
|
@@ -3079,7 +3216,8 @@ async function main() {
|
|
|
3079
3216
|
}
|
|
3080
3217
|
case "status": {
|
|
3081
3218
|
const config = loadConfig();
|
|
3082
|
-
const
|
|
3219
|
+
const pidInfo = readPidInfo();
|
|
3220
|
+
const pid = pidInfo?.pid ?? null;
|
|
3083
3221
|
const running = pid ? isRunning(pid) : false;
|
|
3084
3222
|
writeStdout(`[agendex] Config version: ${config?.configVersion ?? "none"}`);
|
|
3085
3223
|
writeStdout(`[agendex] Local token: ${config?.token ? "set" : "not set"}`);
|
|
@@ -3087,6 +3225,21 @@ async function main() {
|
|
|
3087
3225
|
writeStdout(`[agendex] Convex URL: ${config?.convexUrl ?? "not set"}`);
|
|
3088
3226
|
writeStdout(`[agendex] Enabled adapters: ${config?.enabledAdapters.join(", ") || "none"}`);
|
|
3089
3227
|
writeStdout(`[agendex] Daemon: ${running ? `running (PID ${pid})` : "not running"}`);
|
|
3228
|
+
if (running && pidInfo?.startedAtMs) {
|
|
3229
|
+
writeStdout(`[agendex] Uptime: ${formatDuration(Date.now() - pidInfo.startedAtMs)}`);
|
|
3230
|
+
} else if (running) {
|
|
3231
|
+
writeStdout(`[agendex] Uptime: unknown (restart daemon to populate)`);
|
|
3232
|
+
} else {
|
|
3233
|
+
writeStdout(`[agendex] Uptime: n/a`);
|
|
3234
|
+
}
|
|
3235
|
+
if (running && pidInfo?.hostname) {
|
|
3236
|
+
writeStdout(`[agendex] Hostname: ${pidInfo.hostname}`);
|
|
3237
|
+
} else if (running) {
|
|
3238
|
+
writeStdout(`[agendex] Hostname: unknown (restart daemon to populate)`);
|
|
3239
|
+
} else {
|
|
3240
|
+
writeStdout(`[agendex] Hostname: n/a`);
|
|
3241
|
+
}
|
|
3242
|
+
writeStdout(`[agendex] CLI version: ${CLI_VERSION}`);
|
|
3090
3243
|
return 0;
|
|
3091
3244
|
}
|
|
3092
3245
|
case "help":
|
|
@@ -3106,6 +3259,8 @@ Usage:
|
|
|
3106
3259
|
agendex sync One-shot scan + sync to cloud
|
|
3107
3260
|
agendex status Show current config state + daemon status
|
|
3108
3261
|
agendex help Show this help message
|
|
3262
|
+
agendex --version Print CLI version
|
|
3263
|
+
agendex -v Print CLI version
|
|
3109
3264
|
`.trim());
|
|
3110
3265
|
return 0;
|
|
3111
3266
|
}
|
|
@@ -3146,3 +3301,17 @@ function writeStderr(message) {
|
|
|
3146
3301
|
writeSync(process.stderr.fd, `${message}
|
|
3147
3302
|
`);
|
|
3148
3303
|
}
|
|
3304
|
+
function formatDuration(ms) {
|
|
3305
|
+
const totalSeconds = Math.max(0, Math.floor(ms / 1000));
|
|
3306
|
+
const days = Math.floor(totalSeconds / 86400);
|
|
3307
|
+
const hours = Math.floor(totalSeconds % 86400 / 3600);
|
|
3308
|
+
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
3309
|
+
const seconds = totalSeconds % 60;
|
|
3310
|
+
if (days > 0)
|
|
3311
|
+
return `${days}d ${hours}h ${minutes}m ${seconds}s`;
|
|
3312
|
+
if (hours > 0)
|
|
3313
|
+
return `${hours}h ${minutes}m ${seconds}s`;
|
|
3314
|
+
if (minutes > 0)
|
|
3315
|
+
return `${minutes}m ${seconds}s`;
|
|
3316
|
+
return `${seconds}s`;
|
|
3317
|
+
}
|