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.
Files changed (2) hide show
  1. package/dist/index.js +74 -42
  2. 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 { readFileSync, writeFileSync, mkdirSync, unlinkSync } from "fs";
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(JSON.stringify({
92
- success: true,
93
- email: data.email,
94
- message: "Login successful"
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(JSON.stringify({
117
- message: "Opening browser for login...",
118
- url: authUrl
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, pathParams2, queryParams, bodyParams, fixedBody) {
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(pathParams2)) {
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(JSON.stringify({ error: data.error ?? "Request failed", status: res.status }));
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(JSON.stringify({
236
- error: `Missing required option: --${name}`,
237
- aliases: aliasList ? `Also accepts: ${aliasList}` : void 0
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({ length: m + 1 }, () => Array(n + 1).fill(0));
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("--token <jwt>", "Directly provide a JWT token (for headless environments)").action(async (opts) => {
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(JSON.stringify({ error: "Not logged in. Run: ai-todo login" }));
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(JSON.stringify({
336
- user_id: creds.user_id,
337
- email: creds.email
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(JSON.stringify({ error: "Failed to load commands from server" }));
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(JSON.stringify({ error: err instanceof Error ? err.message : "Unknown error" }));
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.2",
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
  }