@overlordai/developer-cli 1.0.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.
Files changed (65) hide show
  1. package/dist/auth/api-client.d.ts +15 -0
  2. package/dist/auth/api-client.d.ts.map +1 -0
  3. package/dist/auth/api-client.js +79 -0
  4. package/dist/auth/api-client.js.map +1 -0
  5. package/dist/auth/token-store.d.ts +13 -0
  6. package/dist/auth/token-store.d.ts.map +1 -0
  7. package/dist/auth/token-store.js +52 -0
  8. package/dist/auth/token-store.js.map +1 -0
  9. package/dist/commands/attach.d.ts +3 -0
  10. package/dist/commands/attach.d.ts.map +1 -0
  11. package/dist/commands/attach.js +48 -0
  12. package/dist/commands/attach.js.map +1 -0
  13. package/dist/commands/config.d.ts +11 -0
  14. package/dist/commands/config.d.ts.map +1 -0
  15. package/dist/commands/config.js +100 -0
  16. package/dist/commands/config.js.map +1 -0
  17. package/dist/commands/helpers.d.ts +15 -0
  18. package/dist/commands/helpers.d.ts.map +1 -0
  19. package/dist/commands/helpers.js +41 -0
  20. package/dist/commands/helpers.js.map +1 -0
  21. package/dist/commands/login.d.ts +3 -0
  22. package/dist/commands/login.d.ts.map +1 -0
  23. package/dist/commands/login.js +83 -0
  24. package/dist/commands/login.js.map +1 -0
  25. package/dist/commands/logout.d.ts +3 -0
  26. package/dist/commands/logout.d.ts.map +1 -0
  27. package/dist/commands/logout.js +16 -0
  28. package/dist/commands/logout.js.map +1 -0
  29. package/dist/commands/machine.d.ts +3 -0
  30. package/dist/commands/machine.d.ts.map +1 -0
  31. package/dist/commands/machine.js +81 -0
  32. package/dist/commands/machine.js.map +1 -0
  33. package/dist/commands/notifications.d.ts +3 -0
  34. package/dist/commands/notifications.d.ts.map +1 -0
  35. package/dist/commands/notifications.js +55 -0
  36. package/dist/commands/notifications.js.map +1 -0
  37. package/dist/commands/project.d.ts +3 -0
  38. package/dist/commands/project.d.ts.map +1 -0
  39. package/dist/commands/project.js +61 -0
  40. package/dist/commands/project.js.map +1 -0
  41. package/dist/commands/search.d.ts +3 -0
  42. package/dist/commands/search.d.ts.map +1 -0
  43. package/dist/commands/search.js +58 -0
  44. package/dist/commands/search.js.map +1 -0
  45. package/dist/commands/task.d.ts +3 -0
  46. package/dist/commands/task.d.ts.map +1 -0
  47. package/dist/commands/task.js +347 -0
  48. package/dist/commands/task.js.map +1 -0
  49. package/dist/commands/whoami.d.ts +3 -0
  50. package/dist/commands/whoami.d.ts.map +1 -0
  51. package/dist/commands/whoami.js +32 -0
  52. package/dist/commands/whoami.js.map +1 -0
  53. package/dist/main.d.ts +3 -0
  54. package/dist/main.d.ts.map +1 -0
  55. package/dist/main.js +32 -0
  56. package/dist/main.js.map +1 -0
  57. package/dist/output/formatter.d.ts +18 -0
  58. package/dist/output/formatter.d.ts.map +1 -0
  59. package/dist/output/formatter.js +63 -0
  60. package/dist/output/formatter.js.map +1 -0
  61. package/dist/terminal/pty-client.d.ts +20 -0
  62. package/dist/terminal/pty-client.d.ts.map +1 -0
  63. package/dist/terminal/pty-client.js +133 -0
  64. package/dist/terminal/pty-client.js.map +1 -0
  65. package/package.json +29 -0
@@ -0,0 +1,81 @@
1
+ import { Command } from 'commander';
2
+ import { getApiClient } from './helpers.js';
3
+ import { formatter } from '../output/formatter.js';
4
+ import chalk from 'chalk';
5
+ const MACHINE_STATUS_COLORS = {
6
+ 'online': chalk.green,
7
+ 'offline': chalk.red,
8
+ 'draining': chalk.yellow,
9
+ 'maintenance': chalk.gray,
10
+ };
11
+ export const machineCommand = new Command('machine')
12
+ .description('Machine status commands');
13
+ machineCommand
14
+ .command('list')
15
+ .description('List cluster machines')
16
+ .option('--json', 'Output as JSON')
17
+ .action(async (opts) => {
18
+ if (opts.json)
19
+ formatter.setJsonMode(true);
20
+ const client = getApiClient();
21
+ try {
22
+ const res = await client.get('/api/web/machines');
23
+ if (res.status !== 200) {
24
+ formatter.error(`Failed to list machines (status ${res.status}).`);
25
+ process.exitCode = 1;
26
+ return;
27
+ }
28
+ formatter.table(res.data, [
29
+ { key: 'name', label: 'Name', width: 16 },
30
+ {
31
+ key: 'status',
32
+ label: 'Status',
33
+ width: 10,
34
+ color: (v) => {
35
+ const fn = MACHINE_STATUS_COLORS[v.trim()];
36
+ return fn ? fn(v) : v;
37
+ },
38
+ },
39
+ { key: 'cpuUsage', label: 'CPU %', width: 8 },
40
+ { key: 'activeSlots', label: 'Used', width: 6 },
41
+ { key: 'maxSlots', label: 'Total', width: 6 },
42
+ ]);
43
+ }
44
+ catch (err) {
45
+ formatter.error(err instanceof Error ? err.message : String(err));
46
+ process.exitCode = 1;
47
+ }
48
+ });
49
+ machineCommand
50
+ .command('show <id>')
51
+ .description('Show machine details')
52
+ .option('--json', 'Output as JSON')
53
+ .action(async (id, opts) => {
54
+ if (opts.json)
55
+ formatter.setJsonMode(true);
56
+ const client = getApiClient();
57
+ try {
58
+ const res = await client.get(`/api/web/machines/${id}`);
59
+ if (res.status !== 200) {
60
+ formatter.error(`Machine not found (status ${res.status}).`);
61
+ process.exitCode = 1;
62
+ return;
63
+ }
64
+ const machine = res.data;
65
+ formatter.detail({
66
+ Name: machine.name,
67
+ Status: machine.status,
68
+ OS: machine.os,
69
+ IP: machine.ip,
70
+ 'CPU Load': `${machine.cpuUsage}%`,
71
+ 'Slots': `${machine.activeSlots}/${machine.maxSlots}`,
72
+ 'Last Heartbeat': machine.lastHeartbeat,
73
+ 'Current Tasks': machine.currentTasks?.map((t) => `#${t.id}`).join(', ') || '—',
74
+ });
75
+ }
76
+ catch (err) {
77
+ formatter.error(err instanceof Error ? err.message : String(err));
78
+ process.exitCode = 1;
79
+ }
80
+ });
81
+ //# sourceMappingURL=machine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"machine.js","sourceRoot":"","sources":["../../src/commands/machine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,KAAK,MAAM,OAAO,CAAC;AAkB1B,MAAM,qBAAqB,GAA0C;IACnE,QAAQ,EAAE,KAAK,CAAC,KAAK;IACrB,SAAS,EAAE,KAAK,CAAC,GAAG;IACpB,UAAU,EAAE,KAAK,CAAC,MAAM;IACxB,aAAa,EAAE,KAAK,CAAC,IAAI;CAC1B,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC;KACjD,WAAW,CAAC,yBAAyB,CAAC,CAAC;AAE1C,cAAc;KACX,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,uBAAuB,CAAC;KACpC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CAAC,KAAK,EAAE,IAAwB,EAAE,EAAE;IACzC,IAAI,IAAI,CAAC,IAAI;QAAE,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAkB,mBAAmB,CAAC,CAAC;QACnE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,SAAS,CAAC,KAAK,CAAC,mCAAmC,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;YACnE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,IAA4C,EAAE;YAChE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;YACzC;gBACE,GAAG,EAAE,QAAQ;gBACb,KAAK,EAAE,QAAQ;gBACf,KAAK,EAAE,EAAE;gBACT,KAAK,EAAE,CAAC,CAAS,EAAE,EAAE;oBACnB,MAAM,EAAE,GAAG,qBAAqB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;oBAC3C,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACxB,CAAC;aACF;YACD,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE;YAC7C,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE;YAC/C,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE;SAC9C,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,SAAS,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,cAAc;KACX,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,sBAAsB,CAAC;KACnC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,IAAwB,EAAE,EAAE;IACrD,IAAI,IAAI,CAAC,IAAI;QAAE,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAgB,qBAAqB,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,SAAS,CAAC,KAAK,CAAC,6BAA6B,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;YAC7D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC;QACzB,SAAS,CAAC,MAAM,CAAC;YACf,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,UAAU,EAAE,GAAG,OAAO,CAAC,QAAQ,GAAG;YAClC,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,QAAQ,EAAE;YACrD,gBAAgB,EAAE,OAAO,CAAC,aAAa;YACvC,eAAe,EAAE,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG;SAChF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,SAAS,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const notificationsCommand: Command;
3
+ //# sourceMappingURL=notifications.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../src/commands/notifications.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,eAAO,MAAM,oBAAoB,SAgC7B,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { Command } from 'commander';
2
+ import { getApiClient } from './helpers.js';
3
+ import { formatter } from '../output/formatter.js';
4
+ export const notificationsCommand = new Command('notifications')
5
+ .description('View notifications')
6
+ .option('--all', 'Show all notifications (including read)')
7
+ .option('--json', 'Output as JSON')
8
+ .action(async (opts) => {
9
+ if (opts.json)
10
+ formatter.setJsonMode(true);
11
+ const client = getApiClient();
12
+ try {
13
+ const res = await client.get('/api/web/notifications');
14
+ if (res.status !== 200) {
15
+ formatter.error(`Failed to fetch notifications (status ${res.status}).`);
16
+ process.exitCode = 1;
17
+ return;
18
+ }
19
+ const notifications = res.data?.data ?? [];
20
+ const filtered = opts.all ? notifications : notifications.filter((n) => !n.isRead);
21
+ formatter.table(filtered, [
22
+ { key: 'id', label: 'ID', width: 6 },
23
+ { key: 'type', label: 'Type', width: 14 },
24
+ { key: 'title', label: 'Title', width: 30 },
25
+ { key: 'body', label: 'Body', width: 30 },
26
+ { key: 'isRead', label: 'Read', width: 6 },
27
+ { key: 'createdAt', label: 'Time', width: 12 },
28
+ ]);
29
+ }
30
+ catch (err) {
31
+ formatter.error(err instanceof Error ? err.message : String(err));
32
+ process.exitCode = 1;
33
+ }
34
+ });
35
+ notificationsCommand
36
+ .command('read <id>')
37
+ .description('Mark notification as read')
38
+ .action(async (id) => {
39
+ const client = getApiClient();
40
+ try {
41
+ const res = await client.post(`/api/web/notifications/${id}/read`);
42
+ if (res.status === 200) {
43
+ formatter.success(`Notification #${id} marked as read.`);
44
+ }
45
+ else {
46
+ formatter.error(`Failed to mark notification (status ${res.status}).`);
47
+ process.exitCode = 1;
48
+ }
49
+ }
50
+ catch (err) {
51
+ formatter.error(err instanceof Error ? err.message : String(err));
52
+ process.exitCode = 1;
53
+ }
54
+ });
55
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../src/commands/notifications.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const projectCommand: Command;
3
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/commands/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,eAAO,MAAM,cAAc,SACkB,CAAC"}
@@ -0,0 +1,61 @@
1
+ import { Command } from 'commander';
2
+ import { getApiClient } from './helpers.js';
3
+ import { formatter } from '../output/formatter.js';
4
+ export const projectCommand = new Command('project')
5
+ .description('Project management commands');
6
+ projectCommand
7
+ .command('list')
8
+ .description('List projects you belong to')
9
+ .option('--json', 'Output as JSON')
10
+ .action(async (opts) => {
11
+ if (opts.json)
12
+ formatter.setJsonMode(true);
13
+ const client = getApiClient();
14
+ try {
15
+ const res = await client.get('/api/web/projects');
16
+ if (res.status !== 200) {
17
+ formatter.error(`Failed to list projects (status ${res.status}).`);
18
+ process.exitCode = 1;
19
+ return;
20
+ }
21
+ formatter.table(res.data, [
22
+ { key: 'key', label: 'Key', width: 14 },
23
+ { key: 'name', label: 'Name', width: 24 },
24
+ { key: 'description', label: 'Description', width: 40 },
25
+ { key: 'memberCount', label: 'Members', width: 8 },
26
+ ]);
27
+ }
28
+ catch (err) {
29
+ formatter.error(err instanceof Error ? err.message : String(err));
30
+ process.exitCode = 1;
31
+ }
32
+ });
33
+ projectCommand
34
+ .command('show <key>')
35
+ .description('Show project details')
36
+ .option('--json', 'Output as JSON')
37
+ .action(async (key, opts) => {
38
+ if (opts.json)
39
+ formatter.setJsonMode(true);
40
+ const client = getApiClient();
41
+ try {
42
+ const res = await client.get(`/api/web/projects/${key}`);
43
+ if (res.status !== 200) {
44
+ formatter.error(`Project not found (status ${res.status}).`);
45
+ process.exitCode = 1;
46
+ return;
47
+ }
48
+ const project = res.data;
49
+ formatter.detail({
50
+ Key: project.key,
51
+ Name: project.name,
52
+ Description: project.description,
53
+ Members: project.members?.map((m) => `${m.name} (${m.role})`).join(', ') || '—',
54
+ });
55
+ }
56
+ catch (err) {
57
+ formatter.error(err instanceof Error ? err.message : String(err));
58
+ process.exitCode = 1;
59
+ }
60
+ });
61
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/commands/project.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const searchCommand: Command;
3
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,eAAO,MAAM,aAAa,SA6DtB,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { Command } from 'commander';
2
+ import { getApiClient } from './helpers.js';
3
+ import { formatter } from '../output/formatter.js';
4
+ import chalk from 'chalk';
5
+ export const searchCommand = new Command('search')
6
+ .description('Global search across tasks, projects, and machines')
7
+ .argument('<query>', 'Search query')
8
+ .option('--json', 'Output as JSON')
9
+ .action(async (query, opts) => {
10
+ if (opts.json)
11
+ formatter.setJsonMode(true);
12
+ const client = getApiClient();
13
+ try {
14
+ const res = await client.get(`/api/web/search?q=${encodeURIComponent(query)}`);
15
+ if (res.status !== 200) {
16
+ formatter.error(`Search failed (status ${res.status}).`);
17
+ process.exitCode = 1;
18
+ return;
19
+ }
20
+ if (opts.json) {
21
+ formatter.detail(res.data);
22
+ return;
23
+ }
24
+ const { tasks, projects, machines } = res.data;
25
+ if (tasks && tasks.length > 0) {
26
+ console.log(chalk.bold('\n Tasks'));
27
+ formatter.table(tasks, [
28
+ { key: 'id', label: 'ID', width: 6 },
29
+ { key: 'description', label: 'Description', width: 40 },
30
+ { key: 'status', label: 'Status', width: 12 },
31
+ ]);
32
+ }
33
+ if (projects && projects.length > 0) {
34
+ console.log(chalk.bold('\n Projects'));
35
+ formatter.table(projects, [
36
+ { key: 'key', label: 'Key', width: 14 },
37
+ { key: 'name', label: 'Name', width: 30 },
38
+ ]);
39
+ }
40
+ if (machines && machines.length > 0) {
41
+ console.log(chalk.bold('\n Machines'));
42
+ formatter.table(machines, [
43
+ { key: 'id', label: 'ID', width: 10 },
44
+ { key: 'name', label: 'Name', width: 20 },
45
+ { key: 'status', label: 'Status', width: 12 },
46
+ ]);
47
+ }
48
+ const total = (tasks?.length ?? 0) + (projects?.length ?? 0) + (machines?.length ?? 0);
49
+ if (total === 0) {
50
+ formatter.info('No results found.');
51
+ }
52
+ }
53
+ catch (err) {
54
+ formatter.error(err instanceof Error ? err.message : String(err));
55
+ process.exitCode = 1;
56
+ }
57
+ });
58
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const taskCommand: Command;
3
+ //# sourceMappingURL=task.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiCpC,eAAO,MAAM,WAAW,SACkB,CAAC"}
@@ -0,0 +1,347 @@
1
+ import { Command } from 'commander';
2
+ import * as fs from 'node:fs';
3
+ import { getApiClient, getServerUrl, getToken } from './helpers.js';
4
+ import { formatter } from '../output/formatter.js';
5
+ import { PtyClient } from '../terminal/pty-client.js';
6
+ import { ApiClient } from '../auth/api-client.js';
7
+ import chalk from 'chalk';
8
+ const STATUS_COLORS = {
9
+ RUNNING: chalk.green,
10
+ QUEUED: chalk.yellow,
11
+ ASSIGNED: chalk.blue,
12
+ COMPLETED: chalk.cyan,
13
+ FAILED: chalk.red,
14
+ CANCELLED: chalk.dim,
15
+ SUSPENDED: chalk.magenta,
16
+ };
17
+ export const taskCommand = new Command('task')
18
+ .description('Task management commands');
19
+ taskCommand
20
+ .command('create')
21
+ .description('Create a new task')
22
+ .option('-d, --description <text>', 'Task description')
23
+ .option('-f, --file <path>', 'Create from YAML file')
24
+ .option('-p, --project <key>', 'Project key')
25
+ .option('--on <machine>', 'Target machine')
26
+ .option('--json', 'Output as JSON')
27
+ .action(async (opts) => {
28
+ if (opts.json)
29
+ formatter.setJsonMode(true);
30
+ const client = getApiClient();
31
+ let body;
32
+ if (opts.file) {
33
+ const raw = fs.readFileSync(opts.file, 'utf-8');
34
+ // Simple YAML-like parsing — in production, use a proper YAML library
35
+ body = parseSimpleYaml(raw);
36
+ }
37
+ else if (opts.description) {
38
+ body = {
39
+ description: opts.description,
40
+ ...(opts.project && { projectKey: opts.project }),
41
+ ...(opts.on && { machineId: opts.on }),
42
+ };
43
+ }
44
+ else {
45
+ formatter.error('Either -d <description> or -f <file> is required.');
46
+ process.exitCode = 1;
47
+ return;
48
+ }
49
+ if (opts.project && !body['projectKey']) {
50
+ body['projectKey'] = opts.project;
51
+ }
52
+ if (opts.on && !body['machineId']) {
53
+ body['machineId'] = opts.on;
54
+ }
55
+ try {
56
+ const res = await client.post('/api/web/tasks', body);
57
+ if (res.status === 201 || res.status === 200) {
58
+ formatter.success(`Task created: #${res.data.task.id}`);
59
+ }
60
+ else if (res.status === 409) {
61
+ formatter.error('A duplicate or conflicting task already exists. Please check existing tasks before creating a new one.');
62
+ process.exitCode = 1;
63
+ }
64
+ else {
65
+ formatter.error(`Failed to create task (status ${res.status}).`);
66
+ process.exitCode = 1;
67
+ }
68
+ }
69
+ catch (err) {
70
+ formatter.error(err instanceof Error ? err.message : String(err));
71
+ process.exitCode = 1;
72
+ }
73
+ });
74
+ taskCommand
75
+ .command('list')
76
+ .description('List tasks')
77
+ .option('--status <status>', 'Filter by status')
78
+ .option('-p, --project <key>', 'Filter by project')
79
+ .option('--json', 'Output as JSON')
80
+ .action(async (opts) => {
81
+ if (opts.json)
82
+ formatter.setJsonMode(true);
83
+ const client = getApiClient();
84
+ const params = new URLSearchParams();
85
+ if (opts.status)
86
+ params.set('status', opts.status);
87
+ if (opts.project)
88
+ params.set('projectKey', opts.project);
89
+ const qs = params.toString();
90
+ const path = `/api/web/tasks${qs ? `?${qs}` : ''}`;
91
+ try {
92
+ const res = await client.get(path);
93
+ if (res.status !== 200) {
94
+ formatter.error(`Failed to list tasks (status ${res.status}).`);
95
+ process.exitCode = 1;
96
+ return;
97
+ }
98
+ // API returns { data: [...], nextCursor: ... } or a plain array
99
+ const rawData = res.data;
100
+ const tasks = Array.isArray(rawData)
101
+ ? rawData
102
+ : rawData.data ?? [];
103
+ formatter.table(tasks, [
104
+ { key: 'id', label: 'ID', width: 6 },
105
+ {
106
+ key: 'status',
107
+ label: 'Status',
108
+ width: 12,
109
+ color: (v) => {
110
+ const fn = STATUS_COLORS[v.trim()];
111
+ return fn ? fn(v) : v;
112
+ },
113
+ },
114
+ { key: 'projectKey', label: 'Project', width: 14 },
115
+ { key: 'description', label: 'Description', width: 30 },
116
+ { key: 'machineName', label: 'Machine', width: 14 },
117
+ { key: 'createdAt', label: 'Created', width: 12 },
118
+ ]);
119
+ const active = tasks.filter((t) => ['RUNNING', 'QUEUED', 'ASSIGNED', 'SUSPENDED'].includes(t.status)).length;
120
+ const completed = tasks.length - active;
121
+ console.log('');
122
+ console.log(chalk.dim(` ${tasks.length} tasks shown (${active} active, ${completed} completed)`));
123
+ }
124
+ catch (err) {
125
+ formatter.error(err instanceof Error ? err.message : String(err));
126
+ process.exitCode = 1;
127
+ }
128
+ });
129
+ taskCommand
130
+ .command('show <id>')
131
+ .description('Show task details')
132
+ .option('--json', 'Output as JSON')
133
+ .action(async (id, opts) => {
134
+ if (opts.json)
135
+ formatter.setJsonMode(true);
136
+ const client = getApiClient();
137
+ try {
138
+ const res = await client.get(`/api/web/tasks/${id}`);
139
+ if (res.status !== 200) {
140
+ formatter.error(`Task not found (status ${res.status}).`);
141
+ process.exitCode = 1;
142
+ return;
143
+ }
144
+ const task = res.data;
145
+ formatter.detail({
146
+ ID: task.id,
147
+ Status: task.status,
148
+ Project: task.projectKey,
149
+ Description: task.description,
150
+ Machine: task.machineName ?? '—',
151
+ Stage: task.currentStage ?? '—',
152
+ 'MR URL': task.mrUrl ?? '—',
153
+ Created: task.createdAt,
154
+ Updated: task.updatedAt,
155
+ });
156
+ }
157
+ catch (err) {
158
+ formatter.error(err instanceof Error ? err.message : String(err));
159
+ process.exitCode = 1;
160
+ }
161
+ });
162
+ taskCommand
163
+ .command('logs <id>')
164
+ .description('View task logs')
165
+ // Note: --stage filtering is not currently supported by the server API
166
+ .option('--json', 'Output as JSON')
167
+ .action(async (id, opts) => {
168
+ if (opts.json)
169
+ formatter.setJsonMode(true);
170
+ const client = getApiClient();
171
+ try {
172
+ // Check task status first
173
+ const taskRes = await client.get(`/api/web/tasks/${id}`);
174
+ if (taskRes.status !== 200) {
175
+ formatter.error(`Task not found (status ${taskRes.status}).`);
176
+ process.exitCode = 1;
177
+ return;
178
+ }
179
+ const task = taskRes.data;
180
+ const isActive = ['RUNNING', 'QUEUED', 'SUSPENDED'].includes(task.status);
181
+ if (isActive) {
182
+ // Stream logs via PTY watch mode
183
+ formatter.info(`Streaming logs for task #${id} (Ctrl+C to stop)...`);
184
+ const ptyClient = new PtyClient({
185
+ serverUrl: getServerUrl(),
186
+ taskId: id,
187
+ token: getToken(),
188
+ mode: 'watch',
189
+ getChannelToken: async (serverUrl, taskId, token) => {
190
+ const apiClient = new ApiClient(serverUrl, token);
191
+ const res = await apiClient.post(`/api/web/tasks/${taskId}/pty-token`);
192
+ if (res.status !== 200 && res.status !== 201) {
193
+ throw new Error(`Failed to obtain PTY channel token (status ${res.status})`);
194
+ }
195
+ return res.data.channelToken;
196
+ },
197
+ });
198
+ await ptyClient.connect();
199
+ }
200
+ else {
201
+ // Fetch historical logs
202
+ const params = new URLSearchParams({ limit: '100' });
203
+ const logsRes = await client.get(`/api/web/tasks/${id}/logs?${params.toString()}`);
204
+ if (logsRes.status === 200 && logsRes.data.lines) {
205
+ for (const line of logsRes.data.lines) {
206
+ console.log(line);
207
+ }
208
+ }
209
+ else {
210
+ formatter.info('No logs available.');
211
+ }
212
+ }
213
+ }
214
+ catch (err) {
215
+ formatter.error(err instanceof Error ? err.message : String(err));
216
+ process.exitCode = 1;
217
+ }
218
+ });
219
+ taskCommand
220
+ .command('cancel <id>')
221
+ .description('Cancel a running task')
222
+ .action(async (id) => {
223
+ const client = getApiClient();
224
+ try {
225
+ const res = await client.post(`/api/web/tasks/${id}/cancel`);
226
+ if (res.status >= 200 && res.status < 300) {
227
+ formatter.success(`Task #${id} cancelled.`);
228
+ }
229
+ else {
230
+ formatter.error(`Failed to cancel task (status ${res.status}).`);
231
+ process.exitCode = 1;
232
+ }
233
+ }
234
+ catch (err) {
235
+ formatter.error(err instanceof Error ? err.message : String(err));
236
+ process.exitCode = 1;
237
+ }
238
+ });
239
+ taskCommand
240
+ .command('retry <id>')
241
+ .description('Retry a failed task')
242
+ .action(async (id) => {
243
+ const client = getApiClient();
244
+ try {
245
+ const res = await client.post(`/api/web/tasks/${id}/retry`);
246
+ if (res.status >= 200 && res.status < 300) {
247
+ formatter.success(`Task #${id} retry initiated.`);
248
+ }
249
+ else {
250
+ formatter.error(`Failed to retry task (status ${res.status}).`);
251
+ process.exitCode = 1;
252
+ }
253
+ }
254
+ catch (err) {
255
+ formatter.error(err instanceof Error ? err.message : String(err));
256
+ process.exitCode = 1;
257
+ }
258
+ });
259
+ taskCommand
260
+ .command('confirm <id>')
261
+ .description('Confirm a suspended task stage')
262
+ .requiredOption('--stage <index>', 'Stage index to confirm', (val) => parseInt(val, 10))
263
+ .action(async (id, opts) => {
264
+ const client = getApiClient();
265
+ try {
266
+ const res = await client.post(`/api/web/tasks/${id}/confirm-stage`, { stageIndex: opts.stage, result: 'confirmed' });
267
+ if (res.status === 200) {
268
+ formatter.success(`Task #${id} stage ${opts.stage} confirmed.`);
269
+ }
270
+ else {
271
+ formatter.error(`Failed to confirm task stage (status ${res.status}).`);
272
+ process.exitCode = 1;
273
+ }
274
+ }
275
+ catch (err) {
276
+ formatter.error(err instanceof Error ? err.message : String(err));
277
+ process.exitCode = 1;
278
+ }
279
+ });
280
+ taskCommand
281
+ .command('choose <id> <option>')
282
+ .description('Choose an option for a suspended task stage')
283
+ .requiredOption('--stage <index>', 'Stage index to respond to', (val) => parseInt(val, 10))
284
+ .action(async (id, option, opts) => {
285
+ const client = getApiClient();
286
+ try {
287
+ const res = await client.post(`/api/web/tasks/${id}/confirm-stage`, { stageIndex: opts.stage, result: option });
288
+ if (res.status === 200) {
289
+ formatter.success(`Task #${id}: option "${option}" submitted.`);
290
+ }
291
+ else {
292
+ formatter.error(`Failed to submit option (status ${res.status}).`);
293
+ process.exitCode = 1;
294
+ }
295
+ }
296
+ catch (err) {
297
+ formatter.error(err instanceof Error ? err.message : String(err));
298
+ process.exitCode = 1;
299
+ }
300
+ });
301
+ taskCommand
302
+ .command('input <id> <value>')
303
+ .description('Provide input for a suspended task stage')
304
+ .requiredOption('--stage <index>', 'Stage index to respond to', (val) => parseInt(val, 10))
305
+ .action(async (id, value, opts) => {
306
+ const client = getApiClient();
307
+ try {
308
+ const res = await client.post(`/api/web/tasks/${id}/confirm-stage`, { stageIndex: opts.stage, result: value });
309
+ if (res.status === 200) {
310
+ formatter.success(`Task #${id}: input submitted.`);
311
+ }
312
+ else {
313
+ formatter.error(`Failed to submit input (status ${res.status}).`);
314
+ process.exitCode = 1;
315
+ }
316
+ }
317
+ catch (err) {
318
+ formatter.error(err instanceof Error ? err.message : String(err));
319
+ process.exitCode = 1;
320
+ }
321
+ });
322
+ /**
323
+ * Simple YAML-to-object parser for task files.
324
+ * Handles flat key: value pairs. For full YAML support, use the `yaml` package.
325
+ */
326
+ function parseSimpleYaml(content) {
327
+ const result = {};
328
+ for (const line of content.split('\n')) {
329
+ const trimmed = line.trim();
330
+ if (!trimmed || trimmed.startsWith('#'))
331
+ continue;
332
+ const colonIndex = trimmed.indexOf(':');
333
+ if (colonIndex === -1)
334
+ continue;
335
+ const key = trimmed.slice(0, colonIndex).trim();
336
+ let value = trimmed.slice(colonIndex + 1).trim();
337
+ // Strip surrounding quotes
338
+ if (typeof value === 'string' && value.startsWith('"') && value.endsWith('"')) {
339
+ value = value.slice(1, -1);
340
+ }
341
+ // Convert snake_case to camelCase
342
+ const camelKey = key.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
343
+ result[camelKey] = value;
344
+ }
345
+ return result;
346
+ }
347
+ //# sourceMappingURL=task.js.map