ai-todo-cli 0.4.2 → 0.4.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.js +74 -42
- package/package.json +18 -3
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command } from "commander";
|
|
5
4
|
import { createRequire } from "module";
|
|
5
|
+
import { Command } from "commander";
|
|
6
6
|
|
|
7
7
|
// src/auth.ts
|
|
8
|
-
import { createServer } from "http";
|
|
9
8
|
import { randomUUID } from "crypto";
|
|
9
|
+
import { createServer } from "http";
|
|
10
10
|
import open from "open";
|
|
11
11
|
|
|
12
12
|
// src/config.ts
|
|
@@ -17,7 +17,7 @@ var CONFIG_DIR = join(homedir(), ".config", "ai-todo");
|
|
|
17
17
|
var CREDENTIALS_PATH = join(CONFIG_DIR, "credentials.json");
|
|
18
18
|
|
|
19
19
|
// src/credentials.ts
|
|
20
|
-
import {
|
|
20
|
+
import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
21
21
|
import { dirname } from "path";
|
|
22
22
|
function loadCredentials() {
|
|
23
23
|
try {
|
|
@@ -88,11 +88,13 @@ async function login(tokenDirect) {
|
|
|
88
88
|
"Access-Control-Allow-Origin": new URL(API_BASE_URL).origin
|
|
89
89
|
});
|
|
90
90
|
res.end(JSON.stringify({ success: true }));
|
|
91
|
-
console.log(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
console.log(
|
|
92
|
+
JSON.stringify({
|
|
93
|
+
success: true,
|
|
94
|
+
email: data.email,
|
|
95
|
+
message: "Login successful"
|
|
96
|
+
})
|
|
97
|
+
);
|
|
96
98
|
server.close();
|
|
97
99
|
resolve();
|
|
98
100
|
} catch {
|
|
@@ -113,15 +115,19 @@ async function login(tokenDirect) {
|
|
|
113
115
|
}
|
|
114
116
|
const port = addr.port;
|
|
115
117
|
const authUrl = `${API_BASE_URL}/auth/cli?port=${port}&state=${state}`;
|
|
116
|
-
console.log(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}));
|
|
120
|
-
open(authUrl).catch(() => {
|
|
121
|
-
console.log(JSON.stringify({
|
|
122
|
-
message: "Could not open browser. Please visit this URL manually:",
|
|
118
|
+
console.log(
|
|
119
|
+
JSON.stringify({
|
|
120
|
+
message: "Opening browser for login...",
|
|
123
121
|
url: authUrl
|
|
124
|
-
})
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
open(authUrl).catch(() => {
|
|
125
|
+
console.log(
|
|
126
|
+
JSON.stringify({
|
|
127
|
+
message: "Could not open browser. Please visit this URL manually:",
|
|
128
|
+
url: authUrl
|
|
129
|
+
})
|
|
130
|
+
);
|
|
125
131
|
});
|
|
126
132
|
});
|
|
127
133
|
const timer = setTimeout(() => {
|
|
@@ -133,25 +139,15 @@ async function login(tokenDirect) {
|
|
|
133
139
|
});
|
|
134
140
|
}
|
|
135
141
|
|
|
136
|
-
// src/manifest.ts
|
|
137
|
-
async function fetchManifest() {
|
|
138
|
-
const res = await fetch(`${API_BASE_URL}/api/manifest`);
|
|
139
|
-
if (!res.ok) {
|
|
140
|
-
console.log(JSON.stringify({ error: "Failed to fetch manifest", status: res.status }));
|
|
141
|
-
process.exit(1);
|
|
142
|
-
}
|
|
143
|
-
return res.json();
|
|
144
|
-
}
|
|
145
|
-
|
|
146
142
|
// src/client.ts
|
|
147
|
-
async function apiRequest(method, pathTemplate,
|
|
143
|
+
async function apiRequest(method, pathTemplate, pathParams, queryParams, bodyParams, fixedBody) {
|
|
148
144
|
const creds = loadCredentials();
|
|
149
145
|
if (!creds) {
|
|
150
146
|
console.log(JSON.stringify({ error: "Not logged in. Run: ai-todo login" }));
|
|
151
147
|
process.exit(2);
|
|
152
148
|
}
|
|
153
149
|
let path = pathTemplate;
|
|
154
|
-
for (const [key, value] of Object.entries(
|
|
150
|
+
for (const [key, value] of Object.entries(pathParams)) {
|
|
155
151
|
path = path.replace(`:${key}`, encodeURIComponent(value));
|
|
156
152
|
}
|
|
157
153
|
const url = new URL(path, API_BASE_URL);
|
|
@@ -179,7 +175,12 @@ async function apiRequest(method, pathTemplate, pathParams2, queryParams, bodyPa
|
|
|
179
175
|
}
|
|
180
176
|
const data = await res.json().catch(() => ({}));
|
|
181
177
|
if (!res.ok) {
|
|
182
|
-
console.log(
|
|
178
|
+
console.log(
|
|
179
|
+
JSON.stringify({
|
|
180
|
+
error: data.error ?? "Request failed",
|
|
181
|
+
status: res.status
|
|
182
|
+
})
|
|
183
|
+
);
|
|
183
184
|
process.exit(1);
|
|
184
185
|
}
|
|
185
186
|
return { data, status: res.status };
|
|
@@ -232,16 +233,19 @@ function registerDynamicCommands(program2, operations) {
|
|
|
232
233
|
if (updatedOpts[name] === void 0) {
|
|
233
234
|
const param = op.params.find((p) => p.name === name);
|
|
234
235
|
const aliasList = param?.aliases?.map((a) => `--${a}`).join(", ") ?? "";
|
|
235
|
-
console.log(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
console.log(
|
|
237
|
+
JSON.stringify({
|
|
238
|
+
error: `Missing required option: --${name}`,
|
|
239
|
+
aliases: aliasList ? `Also accepts: ${aliasList}` : void 0
|
|
240
|
+
})
|
|
241
|
+
);
|
|
239
242
|
process.exit(1);
|
|
240
243
|
}
|
|
241
244
|
}
|
|
242
245
|
});
|
|
243
246
|
}
|
|
244
247
|
cmd.action(async (opts) => {
|
|
248
|
+
const pathParams = {};
|
|
245
249
|
const queryParams = {};
|
|
246
250
|
const bodyParams = {};
|
|
247
251
|
for (const param of op.params) {
|
|
@@ -280,7 +284,10 @@ function buildParamDesc(desc, enumValues) {
|
|
|
280
284
|
}
|
|
281
285
|
function levenshtein(a, b) {
|
|
282
286
|
const m = a.length, n = b.length;
|
|
283
|
-
const dp = Array.from(
|
|
287
|
+
const dp = Array.from(
|
|
288
|
+
{ length: m + 1 },
|
|
289
|
+
() => Array(n + 1).fill(0)
|
|
290
|
+
);
|
|
284
291
|
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
285
292
|
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
286
293
|
for (let i = 1; i <= m; i++) {
|
|
@@ -314,12 +321,27 @@ function coerceValue(value, type) {
|
|
|
314
321
|
return value;
|
|
315
322
|
}
|
|
316
323
|
|
|
324
|
+
// src/manifest.ts
|
|
325
|
+
async function fetchManifest() {
|
|
326
|
+
const res = await fetch(`${API_BASE_URL}/api/manifest`);
|
|
327
|
+
if (!res.ok) {
|
|
328
|
+
console.log(
|
|
329
|
+
JSON.stringify({ error: "Failed to fetch manifest", status: res.status })
|
|
330
|
+
);
|
|
331
|
+
process.exit(1);
|
|
332
|
+
}
|
|
333
|
+
return res.json();
|
|
334
|
+
}
|
|
335
|
+
|
|
317
336
|
// src/index.ts
|
|
318
337
|
var require2 = createRequire(import.meta.url);
|
|
319
338
|
var { version } = require2("../package.json");
|
|
320
339
|
var program = new Command();
|
|
321
340
|
program.name("ai-todo").description("CLI for AI agents to interact with ai-todo").version(version);
|
|
322
|
-
program.command("login").description("Authenticate with ai-todo via browser").option(
|
|
341
|
+
program.command("login").description("Authenticate with ai-todo via browser").option(
|
|
342
|
+
"--token <jwt>",
|
|
343
|
+
"Directly provide a JWT token (for headless environments)"
|
|
344
|
+
).action(async (opts) => {
|
|
323
345
|
await login(opts.token);
|
|
324
346
|
});
|
|
325
347
|
program.command("logout").description("Clear stored credentials").action(() => {
|
|
@@ -329,13 +351,17 @@ program.command("logout").description("Clear stored credentials").action(() => {
|
|
|
329
351
|
program.command("whoami").description("Show current authenticated user").action(() => {
|
|
330
352
|
const creds = loadCredentials();
|
|
331
353
|
if (!creds) {
|
|
332
|
-
console.log(
|
|
354
|
+
console.log(
|
|
355
|
+
JSON.stringify({ error: "Not logged in. Run: ai-todo login" })
|
|
356
|
+
);
|
|
333
357
|
process.exit(2);
|
|
334
358
|
}
|
|
335
|
-
console.log(
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
359
|
+
console.log(
|
|
360
|
+
JSON.stringify({
|
|
361
|
+
user_id: creds.user_id,
|
|
362
|
+
email: creds.email
|
|
363
|
+
})
|
|
364
|
+
);
|
|
339
365
|
});
|
|
340
366
|
function setupUnknownCommandHandler(operations) {
|
|
341
367
|
program.on("command:*", (operands) => {
|
|
@@ -371,7 +397,9 @@ async function main() {
|
|
|
371
397
|
} catch {
|
|
372
398
|
const isHelpOrEmpty = !firstArg || ["help", "--help", "-h"].includes(firstArg);
|
|
373
399
|
if (!isHelpOrEmpty) {
|
|
374
|
-
console.log(
|
|
400
|
+
console.log(
|
|
401
|
+
JSON.stringify({ error: "Failed to load commands from server" })
|
|
402
|
+
);
|
|
375
403
|
process.exit(1);
|
|
376
404
|
}
|
|
377
405
|
}
|
|
@@ -379,6 +407,10 @@ async function main() {
|
|
|
379
407
|
await program.parseAsync(process.argv);
|
|
380
408
|
}
|
|
381
409
|
main().catch((err) => {
|
|
382
|
-
console.log(
|
|
410
|
+
console.log(
|
|
411
|
+
JSON.stringify({
|
|
412
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
413
|
+
})
|
|
414
|
+
);
|
|
383
415
|
process.exit(1);
|
|
384
416
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-todo-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "CLI tool for AI agents to interact with ai-todo",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -20,15 +20,24 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "tsup",
|
|
22
22
|
"dev": "tsup --watch",
|
|
23
|
+
"lint": "biome check src/",
|
|
24
|
+
"lint:fix": "biome check --fix src/",
|
|
25
|
+
"format": "biome format --write src/",
|
|
23
26
|
"test": "vitest run",
|
|
24
|
-
"test:watch": "vitest"
|
|
27
|
+
"test:watch": "vitest",
|
|
28
|
+
"test:coverage": "vitest run --coverage",
|
|
29
|
+
"prepare": "husky"
|
|
25
30
|
},
|
|
26
31
|
"dependencies": {
|
|
27
32
|
"commander": "^13.0.0",
|
|
28
33
|
"open": "^10.0.0"
|
|
29
34
|
},
|
|
30
35
|
"devDependencies": {
|
|
36
|
+
"@biomejs/biome": "^2.4.8",
|
|
31
37
|
"@types/node": "^22.0.0",
|
|
38
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
39
|
+
"husky": "^9.1.7",
|
|
40
|
+
"lint-staged": "^16.4.0",
|
|
32
41
|
"tsup": "^8.0.0",
|
|
33
42
|
"typescript": "^5.9.0",
|
|
34
43
|
"vitest": "^4.1.0"
|
|
@@ -36,5 +45,11 @@
|
|
|
36
45
|
"engines": {
|
|
37
46
|
"node": ">=18"
|
|
38
47
|
},
|
|
39
|
-
"license": "MIT"
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"lint-staged": {
|
|
50
|
+
"src/**/*.ts": [
|
|
51
|
+
"biome check --fix",
|
|
52
|
+
"biome format --write"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
40
55
|
}
|