@devpad/cli 1.0.1

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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,531 @@
1
+ #!/usr/bin/env bun
2
+ import { Command } from "commander";
3
+ import { ApiClient, getTool } from "@devpad/api";
4
+ import chalk from "chalk";
5
+ import ora from "ora";
6
+ import { Table } from "console-table-printer";
7
+ // Helper to get API client
8
+ function getApiClient() {
9
+ const apiKey = process.env.DEVPAD_API_KEY || Bun.env.DEVPAD_API_KEY;
10
+ const baseUrl = process.env.DEVPAD_BASE_URL || "https://devpad.tools/api/v0";
11
+ if (!apiKey) {
12
+ console.error(chalk.red("Error: DEVPAD_API_KEY environment variable is required"));
13
+ console.error(chalk.yellow("Get your API key from https://devpad.tools/account"));
14
+ process.exit(1);
15
+ }
16
+ return new ApiClient({
17
+ api_key: apiKey,
18
+ base_url: baseUrl,
19
+ });
20
+ }
21
+ // Helper to handle errors
22
+ function handleError(error) {
23
+ const message = error instanceof Error ? error.message : String(error);
24
+ console.error(chalk.red(`Error: ${message}`));
25
+ process.exit(1);
26
+ }
27
+ // Helper to format output
28
+ function formatOutput(data, format = "json") {
29
+ if (format === "json") {
30
+ console.log(JSON.stringify(data, null, 2));
31
+ }
32
+ else if (format === "table" && Array.isArray(data)) {
33
+ const table = new Table();
34
+ data.forEach(item => table.addRow(item));
35
+ table.printTable();
36
+ }
37
+ else {
38
+ console.log(data);
39
+ }
40
+ }
41
+ const program = new Command();
42
+ program.name("devpad").description("CLI for devpad project and task management").version("0.1.0");
43
+ // Projects command group
44
+ const projects = program.command("projects").description("Manage projects");
45
+ projects
46
+ .command("list")
47
+ .description("List all projects")
48
+ .option("--private", "Include private projects", true)
49
+ .option("-f, --format <format>", "Output format (json|table)", "json")
50
+ .action(async (options) => {
51
+ const spinner = ora("Fetching projects...").start();
52
+ try {
53
+ const tool = getTool("devpad_projects_list");
54
+ if (!tool)
55
+ throw new Error("Tool not found");
56
+ const client = getApiClient();
57
+ const result = await tool.execute(client, { private: options.private });
58
+ spinner.succeed("Projects fetched");
59
+ formatOutput(result, options.format);
60
+ }
61
+ catch (error) {
62
+ spinner.fail("Failed to fetch projects");
63
+ handleError(error);
64
+ }
65
+ });
66
+ projects
67
+ .command("get <idOrName>")
68
+ .description("Get a project by ID or name")
69
+ .option("-f, --format <format>", "Output format (json|table)", "json")
70
+ .action(async (idOrName, options) => {
71
+ const spinner = ora("Fetching project...").start();
72
+ try {
73
+ const tool = getTool("devpad_projects_get");
74
+ if (!tool)
75
+ throw new Error("Tool not found");
76
+ const client = getApiClient();
77
+ // Try ID first, then name
78
+ const input = idOrName.includes("-") ? { id: idOrName } : { name: idOrName };
79
+ const result = await tool.execute(client, input);
80
+ spinner.succeed("Project fetched");
81
+ formatOutput(result, options.format);
82
+ }
83
+ catch (error) {
84
+ spinner.fail("Failed to fetch project");
85
+ handleError(error);
86
+ }
87
+ });
88
+ projects
89
+ .command("create")
90
+ .description("Create a new project")
91
+ .requiredOption("-n, --name <name>", "Project name")
92
+ .option("-d, --description <description>", "Project description")
93
+ .option("--private", "Make project private", false)
94
+ .action(async (options) => {
95
+ const spinner = ora("Creating project...").start();
96
+ try {
97
+ const tool = getTool("devpad_projects_upsert");
98
+ if (!tool)
99
+ throw new Error("Tool not found");
100
+ const client = getApiClient();
101
+ const result = await tool.execute(client, {
102
+ name: options.name,
103
+ description: options.description,
104
+ private: options.private,
105
+ });
106
+ spinner.succeed(`Project "${result.name}" created`);
107
+ console.log(chalk.green(`ID: ${result.id}`));
108
+ }
109
+ catch (error) {
110
+ spinner.fail("Failed to create project");
111
+ handleError(error);
112
+ }
113
+ });
114
+ projects
115
+ .command("delete <id>")
116
+ .description("Delete a project")
117
+ .option("-y, --yes", "Skip confirmation", false)
118
+ .action(async (id, options) => {
119
+ if (!options.yes) {
120
+ console.log(chalk.yellow("Are you sure you want to delete this project? Use --yes to confirm"));
121
+ return;
122
+ }
123
+ const spinner = ora("Deleting project...").start();
124
+ try {
125
+ const tool = getTool("devpad_projects_delete");
126
+ if (!tool)
127
+ throw new Error("Tool not found");
128
+ const client = getApiClient();
129
+ await tool.execute(client, { id });
130
+ spinner.succeed("Project deleted");
131
+ }
132
+ catch (error) {
133
+ spinner.fail("Failed to delete project");
134
+ handleError(error);
135
+ }
136
+ });
137
+ projects
138
+ .command("history <id>")
139
+ .description("Get project history")
140
+ .option("-f, --format <format>", "Output format (json|table)", "json")
141
+ .action(async (id, options) => {
142
+ const spinner = ora("Fetching project history...").start();
143
+ try {
144
+ const tool = getTool("devpad_projects_history");
145
+ if (!tool)
146
+ throw new Error("Tool not found");
147
+ const client = getApiClient();
148
+ const result = await tool.execute(client, { project_id: id });
149
+ spinner.succeed("Project history fetched");
150
+ formatOutput(result, options.format);
151
+ }
152
+ catch (error) {
153
+ spinner.fail("Failed to fetch project history");
154
+ handleError(error);
155
+ }
156
+ });
157
+ // Tasks command group
158
+ const tasks = program.command("tasks").description("Manage tasks");
159
+ tasks
160
+ .command("list")
161
+ .description("List tasks")
162
+ .option("-p, --project <id>", "Filter by project ID")
163
+ .option("-t, --tag <id>", "Filter by tag ID")
164
+ .option("-f, --format <format>", "Output format (json|table)", "json")
165
+ .action(async (options) => {
166
+ const spinner = ora("Fetching tasks...").start();
167
+ try {
168
+ const tool = getTool("devpad_tasks_list");
169
+ if (!tool)
170
+ throw new Error("Tool not found");
171
+ const client = getApiClient();
172
+ const result = await tool.execute(client, {
173
+ project_id: options.project,
174
+ tag_id: options.tag,
175
+ });
176
+ spinner.succeed("Tasks fetched");
177
+ formatOutput(result, options.format);
178
+ }
179
+ catch (error) {
180
+ spinner.fail("Failed to fetch tasks");
181
+ handleError(error);
182
+ }
183
+ });
184
+ tasks
185
+ .command("get <id>")
186
+ .description("Get a task by ID")
187
+ .option("-f, --format <format>", "Output format (json|table)", "json")
188
+ .action(async (id, options) => {
189
+ const spinner = ora("Fetching task...").start();
190
+ try {
191
+ const tool = getTool("devpad_tasks_get");
192
+ if (!tool)
193
+ throw new Error("Tool not found");
194
+ const client = getApiClient();
195
+ const result = await tool.execute(client, { id });
196
+ spinner.succeed("Task fetched");
197
+ formatOutput(result, options.format);
198
+ }
199
+ catch (error) {
200
+ spinner.fail("Failed to fetch task");
201
+ handleError(error);
202
+ }
203
+ });
204
+ tasks
205
+ .command("create")
206
+ .description("Create a new task")
207
+ .requiredOption("-t, --title <title>", "Task title")
208
+ .requiredOption("-p, --project <id>", "Project ID")
209
+ .option("-s, --summary <summary>", "Task summary")
210
+ .option("--priority <priority>", "Task priority (low|medium|high)", "medium")
211
+ .option("--status <status>", "Task status (todo|in_progress|done)", "todo")
212
+ .action(async (options) => {
213
+ const spinner = ora("Creating task...").start();
214
+ try {
215
+ const tool = getTool("devpad_tasks_upsert");
216
+ if (!tool)
217
+ throw new Error("Tool not found");
218
+ const client = getApiClient();
219
+ const result = await tool.execute(client, {
220
+ title: options.title,
221
+ project_id: options.project,
222
+ summary: options.summary,
223
+ priority: options.priority.toUpperCase(),
224
+ progress: options.status === "done" ? "DONE" : options.status === "in_progress" ? "IN_PROGRESS" : "TODO",
225
+ });
226
+ spinner.succeed(`Task "${result.title}" created`);
227
+ console.log(chalk.green(`ID: ${result.id}`));
228
+ }
229
+ catch (error) {
230
+ spinner.fail("Failed to create task");
231
+ handleError(error);
232
+ }
233
+ });
234
+ tasks
235
+ .command("done <id>")
236
+ .description("Mark a task as done")
237
+ .action(async (id) => {
238
+ const spinner = ora("Marking task as done...").start();
239
+ try {
240
+ const tool = getTool("devpad_tasks_upsert");
241
+ if (!tool)
242
+ throw new Error("Tool not found");
243
+ const client = getApiClient();
244
+ const result = await tool.execute(client, {
245
+ id,
246
+ progress: "DONE",
247
+ });
248
+ spinner.succeed(`Task "${result.title}" marked as done`);
249
+ }
250
+ catch (error) {
251
+ spinner.fail("Failed to update task");
252
+ handleError(error);
253
+ }
254
+ });
255
+ tasks
256
+ .command("todo <id>")
257
+ .description("Mark a task as todo")
258
+ .action(async (id) => {
259
+ const spinner = ora("Marking task as todo...").start();
260
+ try {
261
+ const tool = getTool("devpad_tasks_upsert");
262
+ if (!tool)
263
+ throw new Error("Tool not found");
264
+ const client = getApiClient();
265
+ const result = await tool.execute(client, {
266
+ id,
267
+ progress: "TODO",
268
+ });
269
+ spinner.succeed(`Task "${result.title}" marked as todo`);
270
+ }
271
+ catch (error) {
272
+ spinner.fail("Failed to update task");
273
+ handleError(error);
274
+ }
275
+ });
276
+ tasks
277
+ .command("delete <id>")
278
+ .description("Delete a task")
279
+ .option("-y, --yes", "Skip confirmation", false)
280
+ .action(async (id, options) => {
281
+ if (!options.yes) {
282
+ console.log(chalk.yellow("Are you sure you want to delete this task? Use --yes to confirm"));
283
+ return;
284
+ }
285
+ const spinner = ora("Deleting task...").start();
286
+ try {
287
+ const tool = getTool("devpad_tasks_delete");
288
+ if (!tool)
289
+ throw new Error("Tool not found");
290
+ const client = getApiClient();
291
+ await tool.execute(client, { id });
292
+ spinner.succeed("Task deleted");
293
+ }
294
+ catch (error) {
295
+ spinner.fail("Failed to delete task");
296
+ handleError(error);
297
+ }
298
+ });
299
+ tasks
300
+ .command("history <id>")
301
+ .description("Get task history")
302
+ .option("-f, --format <format>", "Output format (json|table)", "json")
303
+ .action(async (id, options) => {
304
+ const spinner = ora("Fetching task history...").start();
305
+ try {
306
+ const tool = getTool("devpad_tasks_history");
307
+ if (!tool)
308
+ throw new Error("Tool not found");
309
+ const client = getApiClient();
310
+ const result = await tool.execute(client, { task_id: id });
311
+ spinner.succeed("Task history fetched");
312
+ formatOutput(result, options.format);
313
+ }
314
+ catch (error) {
315
+ spinner.fail("Failed to fetch task history");
316
+ handleError(error);
317
+ }
318
+ });
319
+ // Milestones command group
320
+ const milestones = program.command("milestones").description("Manage milestones");
321
+ milestones
322
+ .command("list")
323
+ .description("List milestones")
324
+ .option("-p, --project <id>", "Filter by project ID")
325
+ .option("-f, --format <format>", "Output format (json|table)", "json")
326
+ .action(async (options) => {
327
+ const spinner = ora("Fetching milestones...").start();
328
+ try {
329
+ const tool = getTool("devpad_milestones_list");
330
+ if (!tool)
331
+ throw new Error("Tool not found");
332
+ const client = getApiClient();
333
+ const result = await tool.execute(client, {
334
+ project_id: options.project,
335
+ });
336
+ spinner.succeed("Milestones fetched");
337
+ formatOutput(result, options.format);
338
+ }
339
+ catch (error) {
340
+ spinner.fail("Failed to fetch milestones");
341
+ handleError(error);
342
+ }
343
+ });
344
+ milestones
345
+ .command("create")
346
+ .description("Create a new milestone")
347
+ .requiredOption("-n, --name <name>", "Milestone name")
348
+ .requiredOption("-p, --project <id>", "Project ID")
349
+ .option("-d, --description <description>", "Milestone description")
350
+ .option("--target-time <time>", "Target completion time")
351
+ .option("--target-version <version>", "Target version")
352
+ .action(async (options) => {
353
+ const spinner = ora("Creating milestone...").start();
354
+ try {
355
+ const tool = getTool("devpad_milestones_upsert");
356
+ if (!tool)
357
+ throw new Error("Tool not found");
358
+ const client = getApiClient();
359
+ const result = await tool.execute(client, {
360
+ name: options.name,
361
+ project_id: options.project,
362
+ description: options.description,
363
+ target_time: options.targetTime,
364
+ target_version: options.targetVersion,
365
+ });
366
+ spinner.succeed(`Milestone "${result.name}" created`);
367
+ console.log(chalk.green(`ID: ${result.id}`));
368
+ }
369
+ catch (error) {
370
+ spinner.fail("Failed to create milestone");
371
+ handleError(error);
372
+ }
373
+ });
374
+ // Goals command group
375
+ const goals = program.command("goals").description("Manage goals");
376
+ goals
377
+ .command("list")
378
+ .description("List goals")
379
+ .option("-f, --format <format>", "Output format (json|table)", "json")
380
+ .action(async (options) => {
381
+ const spinner = ora("Fetching goals...").start();
382
+ try {
383
+ const tool = getTool("devpad_goals_list");
384
+ if (!tool)
385
+ throw new Error("Tool not found");
386
+ const client = getApiClient();
387
+ const result = await tool.execute(client, {});
388
+ spinner.succeed("Goals fetched");
389
+ formatOutput(result, options.format);
390
+ }
391
+ catch (error) {
392
+ spinner.fail("Failed to fetch goals");
393
+ handleError(error);
394
+ }
395
+ });
396
+ goals
397
+ .command("create")
398
+ .description("Create a new goal")
399
+ .requiredOption("-n, --name <name>", "Goal name")
400
+ .requiredOption("-m, --milestone <id>", "Milestone ID")
401
+ .option("-d, --description <description>", "Goal description")
402
+ .option("--target-time <time>", "Target completion time")
403
+ .action(async (options) => {
404
+ const spinner = ora("Creating goal...").start();
405
+ try {
406
+ const tool = getTool("devpad_goals_upsert");
407
+ if (!tool)
408
+ throw new Error("Tool not found");
409
+ const client = getApiClient();
410
+ const result = await tool.execute(client, {
411
+ name: options.name,
412
+ milestone_id: options.milestone,
413
+ description: options.description,
414
+ target_time: options.targetTime,
415
+ });
416
+ spinner.succeed(`Goal "${result.name}" created`);
417
+ console.log(chalk.green(`ID: ${result.id}`));
418
+ }
419
+ catch (error) {
420
+ spinner.fail("Failed to create goal");
421
+ handleError(error);
422
+ }
423
+ });
424
+ // Tags command group
425
+ const tags = program.command("tags").description("Manage tags");
426
+ tags.command("list")
427
+ .description("List tags")
428
+ .option("-f, --format <format>", "Output format (json|table)", "json")
429
+ .action(async (options) => {
430
+ const spinner = ora("Fetching tags...").start();
431
+ try {
432
+ const tool = getTool("devpad_tags_list");
433
+ if (!tool)
434
+ throw new Error("Tool not found");
435
+ const client = getApiClient();
436
+ const result = await tool.execute(client, {});
437
+ spinner.succeed("Tags fetched");
438
+ formatOutput(result, options.format);
439
+ }
440
+ catch (error) {
441
+ spinner.fail("Failed to fetch tags");
442
+ handleError(error);
443
+ }
444
+ });
445
+ // GitHub command group
446
+ const github = program.command("github").description("GitHub integration");
447
+ github
448
+ .command("repos")
449
+ .description("List GitHub repositories")
450
+ .option("-f, --format <format>", "Output format (json|table)", "json")
451
+ .action(async (options) => {
452
+ const spinner = ora("Fetching GitHub repositories...").start();
453
+ try {
454
+ const tool = getTool("devpad_github_repos");
455
+ if (!tool)
456
+ throw new Error("Tool not found");
457
+ const client = getApiClient();
458
+ const result = await tool.execute(client, {});
459
+ spinner.succeed("Repositories fetched");
460
+ formatOutput(result, options.format);
461
+ }
462
+ catch (error) {
463
+ spinner.fail("Failed to fetch repositories");
464
+ handleError(error);
465
+ }
466
+ });
467
+ github
468
+ .command("branches <owner> <repo>")
469
+ .description("List branches for a GitHub repository")
470
+ .option("-f, --format <format>", "Output format (json|table)", "json")
471
+ .action(async (owner, repo, options) => {
472
+ const spinner = ora("Fetching branches...").start();
473
+ try {
474
+ const tool = getTool("devpad_github_branches");
475
+ if (!tool)
476
+ throw new Error("Tool not found");
477
+ const client = getApiClient();
478
+ const result = await tool.execute(client, { owner, repo });
479
+ spinner.succeed("Branches fetched");
480
+ formatOutput(result, options.format);
481
+ }
482
+ catch (error) {
483
+ spinner.fail("Failed to fetch branches");
484
+ handleError(error);
485
+ }
486
+ });
487
+ // User command group
488
+ const user = program.command("user").description("User preferences and history");
489
+ user.command("history")
490
+ .description("Get user activity history")
491
+ .option("-f, --format <format>", "Output format (json|table)", "json")
492
+ .action(async (options) => {
493
+ const spinner = ora("Fetching user history...").start();
494
+ try {
495
+ const tool = getTool("devpad_user_history");
496
+ if (!tool)
497
+ throw new Error("Tool not found");
498
+ const client = getApiClient();
499
+ const result = await tool.execute(client, {});
500
+ spinner.succeed("User history fetched");
501
+ formatOutput(result, options.format);
502
+ }
503
+ catch (error) {
504
+ spinner.fail("Failed to fetch user history");
505
+ handleError(error);
506
+ }
507
+ });
508
+ user.command("preferences")
509
+ .description("Update user preferences")
510
+ .requiredOption("-u, --user-id <id>", "User ID")
511
+ .requiredOption("-v, --view <view>", "Task view preference (list|grid)")
512
+ .action(async (options) => {
513
+ const spinner = ora("Updating preferences...").start();
514
+ try {
515
+ const tool = getTool("devpad_user_preferences");
516
+ if (!tool)
517
+ throw new Error("Tool not found");
518
+ const client = getApiClient();
519
+ await tool.execute(client, {
520
+ id: options.userId,
521
+ task_view: options.view,
522
+ });
523
+ spinner.succeed("Preferences updated");
524
+ }
525
+ catch (error) {
526
+ spinner.fail("Failed to update preferences");
527
+ handleError(error);
528
+ }
529
+ });
530
+ // Parse and execute
531
+ program.parse(process.argv);
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@devpad/cli",
3
+ "version": "1.0.1",
4
+ "description": "Command line interface for devpad project management",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "devpad": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "bunx tsc",
16
+ "test": "bun test",
17
+ "prepublishOnly": "bun run build"
18
+ },
19
+ "keywords": [
20
+ "devpad",
21
+ "cli",
22
+ "command-line",
23
+ "project-management",
24
+ "task-management",
25
+ "todo"
26
+ ],
27
+ "author": {
28
+ "name": "f0rbit",
29
+ "url": "https://github.com/f0rbit"
30
+ },
31
+ "license": "MIT",
32
+ "homepage": "https://devpad.tools",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/f0rbit/devpad.git",
36
+ "directory": "packages/cli"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/f0rbit/devpad/issues"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public",
43
+ "registry": "https://registry.npmjs.org/"
44
+ },
45
+ "dependencies": {
46
+ "@devpad/api": "^1.0.1",
47
+ "@devpad/schema": "workspace:*",
48
+ "commander": "^12.0.0",
49
+ "chalk": "^5.3.0",
50
+ "ora": "^8.0.1",
51
+ "console-table-printer": "^2.12.1",
52
+ "zod": "^3.22.4"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^20.11.24",
56
+ "bun-types": "latest",
57
+ "typescript": "^5.9.2"
58
+ },
59
+ "engines": {
60
+ "node": ">=18.0.0"
61
+ }
62
+ }