gbos 1.3.3 → 1.3.5
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/package.json +1 -1
- package/src/cli.js +8 -2
- package/src/commands/tasks.js +278 -11
- package/src/lib/api.js +7 -0
- package/src/lib/display.js +1 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ const program = new Command();
|
|
|
6
6
|
const authCommand = require('./commands/auth');
|
|
7
7
|
const connectCommand = require('./commands/connect');
|
|
8
8
|
const logoutCommand = require('./commands/logout');
|
|
9
|
-
const { tasksCommand, nextTaskCommand, continueCommand, fallbackCommand, autoCommand } = require('./commands/tasks');
|
|
9
|
+
const { tasksCommand, nextTaskCommand, continueCommand, fallbackCommand, autoCommand, addTaskCommand } = require('./commands/tasks');
|
|
10
10
|
const config = require('./lib/config');
|
|
11
11
|
const { displayStatus, printBanner } = require('./lib/display');
|
|
12
12
|
|
|
@@ -123,6 +123,12 @@ program
|
|
|
123
123
|
.description('Automatically work through all tasks and poll for new ones')
|
|
124
124
|
.action(autoCommand);
|
|
125
125
|
|
|
126
|
+
program
|
|
127
|
+
.command('add_task')
|
|
128
|
+
.alias('add')
|
|
129
|
+
.description('Create a new task interactively')
|
|
130
|
+
.action(addTaskCommand);
|
|
131
|
+
|
|
126
132
|
program
|
|
127
133
|
.command('logout')
|
|
128
134
|
.description('Log out from GBOS services and clear credentials')
|
|
@@ -139,7 +145,7 @@ program
|
|
|
139
145
|
cmd.outputHelp();
|
|
140
146
|
} else {
|
|
141
147
|
console.log(`Unknown command: ${command}`);
|
|
142
|
-
console.log('Available commands: auth, connect, disconnect, status, tasks, next, continue, fallback, auto, logout, help');
|
|
148
|
+
console.log('Available commands: auth, connect, disconnect, status, tasks, next, continue, fallback, auto, add_task, logout, help');
|
|
143
149
|
}
|
|
144
150
|
} else {
|
|
145
151
|
program.outputHelp();
|
package/src/commands/tasks.js
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
const api = require('../lib/api');
|
|
2
2
|
const config = require('../lib/config');
|
|
3
3
|
const { displayMessageBox, printBanner, printStatusTable, fg, LOGO_LIGHT, LOGO_NAVY, RESET, BOLD, DIM, getTerminalWidth } = require('../lib/display');
|
|
4
|
+
const readline = require('readline');
|
|
5
|
+
|
|
6
|
+
// Colors for prompts
|
|
7
|
+
const CYAN = '\x1b[36m';
|
|
8
|
+
const YELLOW = '\x1b[33m';
|
|
9
|
+
const GREEN = '\x1b[32m';
|
|
10
|
+
|
|
11
|
+
// Create readline interface for interactive prompts
|
|
12
|
+
function createReadlineInterface() {
|
|
13
|
+
return readline.createInterface({
|
|
14
|
+
input: process.stdin,
|
|
15
|
+
output: process.stdout,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Prompt for text input
|
|
20
|
+
async function promptText(rl, question, defaultValue = '') {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const defaultStr = defaultValue ? ` ${DIM}(${defaultValue})${RESET}` : '';
|
|
23
|
+
rl.question(` ${CYAN}?${RESET} ${question}${defaultStr}: `, (answer) => {
|
|
24
|
+
resolve(answer.trim() || defaultValue);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Prompt for yes/no
|
|
30
|
+
async function promptYesNo(rl, question, defaultValue = false) {
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
const defaultStr = defaultValue ? 'Y/n' : 'y/N';
|
|
33
|
+
rl.question(` ${CYAN}?${RESET} ${question} ${DIM}(${defaultStr})${RESET}: `, (answer) => {
|
|
34
|
+
const lower = answer.trim().toLowerCase();
|
|
35
|
+
if (lower === '') resolve(defaultValue);
|
|
36
|
+
else resolve(lower === 'y' || lower === 'yes');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Prompt for selection from list
|
|
42
|
+
async function promptSelect(rl, question, options) {
|
|
43
|
+
console.log(`\n ${CYAN}?${RESET} ${question}`);
|
|
44
|
+
options.forEach((opt, i) => {
|
|
45
|
+
console.log(` ${DIM}${i + 1}.${RESET} ${opt.label || opt}`);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
rl.question(` ${DIM}Enter number (1-${options.length})${RESET}: `, (answer) => {
|
|
50
|
+
const num = parseInt(answer.trim(), 10);
|
|
51
|
+
if (num >= 1 && num <= options.length) {
|
|
52
|
+
resolve(options[num - 1].value || options[num - 1]);
|
|
53
|
+
} else {
|
|
54
|
+
resolve(options[0].value || options[0]);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
4
59
|
|
|
5
60
|
// Format task for display
|
|
6
61
|
function formatTask(task, index) {
|
|
@@ -96,11 +151,6 @@ async function tasksCommand() {
|
|
|
96
151
|
const response = await api.getTasks();
|
|
97
152
|
const tasks = response.data || [];
|
|
98
153
|
|
|
99
|
-
if (tasks.length === 0) {
|
|
100
|
-
console.log(`${DIM}No tasks assigned to this node.${RESET}\n`);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
154
|
// Display tasks in a table
|
|
105
155
|
const termWidth = getTerminalWidth();
|
|
106
156
|
const tableWidth = Math.min(100, termWidth - 4);
|
|
@@ -109,17 +159,42 @@ async function tasksCommand() {
|
|
|
109
159
|
console.log(`${BOLD} Tasks for ${connection.node?.name || 'this node'}${RESET}`);
|
|
110
160
|
console.log(`${fg(...LOGO_NAVY)}${'─'.repeat(tableWidth)}${RESET}\n`);
|
|
111
161
|
|
|
112
|
-
tasks.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
162
|
+
if (tasks.length === 0) {
|
|
163
|
+
console.log(` ${DIM}No tasks assigned to this node.${RESET}\n`);
|
|
164
|
+
} else {
|
|
165
|
+
tasks.forEach((task, index) => {
|
|
166
|
+
const formatted = formatTask(task, index);
|
|
167
|
+
console.log(` ${formatted.statusDisplay} ${BOLD}${formatted.title}${RESET}`);
|
|
168
|
+
console.log(` ${DIM}ID: ${formatted.id} | Priority: ${formatted.priority}${RESET}`);
|
|
169
|
+
if (index < tasks.length - 1) console.log('');
|
|
170
|
+
});
|
|
171
|
+
}
|
|
118
172
|
|
|
119
173
|
console.log(`\n${fg(...LOGO_NAVY)}${'─'.repeat(tableWidth)}${RESET}`);
|
|
120
174
|
console.log(`${DIM} Total: ${tasks.length} task(s)${RESET}\n`);
|
|
121
175
|
|
|
176
|
+
// Show meta info if available
|
|
177
|
+
if (response.meta) {
|
|
178
|
+
if (response.meta.total > tasks.length) {
|
|
179
|
+
console.log(`${DIM} Showing ${tasks.length} of ${response.meta.total} total tasks${RESET}\n`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
122
183
|
} catch (error) {
|
|
184
|
+
if (error.status === 404 || error.message?.includes('not found')) {
|
|
185
|
+
// Fallback: try to get info from next task endpoint
|
|
186
|
+
try {
|
|
187
|
+
const nextResponse = await api.getNextTask();
|
|
188
|
+
console.log(`${DIM}Tasks list endpoint not available yet.${RESET}`);
|
|
189
|
+
if (nextResponse.pending_tasks_count) {
|
|
190
|
+
console.log(`${DIM}Pending tasks in queue: ${nextResponse.pending_tasks_count}${RESET}`);
|
|
191
|
+
}
|
|
192
|
+
console.log(`${DIM}Use "gbos next" or "gbos continue" to get the next task.${RESET}\n`);
|
|
193
|
+
} catch (e) {
|
|
194
|
+
console.log(`${DIM}No tasks available.${RESET}\n`);
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
123
198
|
displayMessageBox('Error', error.message, 'error');
|
|
124
199
|
process.exit(1);
|
|
125
200
|
}
|
|
@@ -344,11 +419,203 @@ async function autoCommand() {
|
|
|
344
419
|
await runLoop();
|
|
345
420
|
}
|
|
346
421
|
|
|
422
|
+
// Add task command - interactive task creation
|
|
423
|
+
async function addTaskCommand() {
|
|
424
|
+
if (!config.isAuthenticated()) {
|
|
425
|
+
displayMessageBox('Not Authenticated', 'Please run "gbos auth" first.', 'warning');
|
|
426
|
+
process.exit(1);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const connection = config.getConnection();
|
|
430
|
+
if (!connection) {
|
|
431
|
+
displayMessageBox('Not Connected', 'Please run "gbos connect" first.', 'warning');
|
|
432
|
+
process.exit(1);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const rl = createReadlineInterface();
|
|
436
|
+
|
|
437
|
+
console.log(`\n${BOLD}Create New Task${RESET}`);
|
|
438
|
+
console.log(`${DIM}Fill in the task details below. Press Enter to use defaults.${RESET}\n`);
|
|
439
|
+
|
|
440
|
+
try {
|
|
441
|
+
// Required fields
|
|
442
|
+
const title = await promptText(rl, 'Task title', '');
|
|
443
|
+
if (!title) {
|
|
444
|
+
console.log(`\n${DIM}Task title is required. Cancelled.${RESET}\n`);
|
|
445
|
+
rl.close();
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const description = await promptText(rl, 'Description (what needs to be done)', '');
|
|
450
|
+
|
|
451
|
+
// Priority selection
|
|
452
|
+
const priority = await promptSelect(rl, 'Priority level:', [
|
|
453
|
+
{ label: 'Low', value: 'low' },
|
|
454
|
+
{ label: 'Normal', value: 'normal' },
|
|
455
|
+
{ label: 'High', value: 'high' },
|
|
456
|
+
{ label: 'Urgent', value: 'urgent' },
|
|
457
|
+
]);
|
|
458
|
+
|
|
459
|
+
// Task type
|
|
460
|
+
const taskType = await promptSelect(rl, 'Task type:', [
|
|
461
|
+
{ label: 'Feature - New functionality', value: 'feature' },
|
|
462
|
+
{ label: 'Bug Fix - Fix an issue', value: 'bug' },
|
|
463
|
+
{ label: 'Refactor - Improve code', value: 'refactor' },
|
|
464
|
+
{ label: 'Documentation - Update docs', value: 'docs' },
|
|
465
|
+
{ label: 'Test - Add/update tests', value: 'test' },
|
|
466
|
+
{ label: 'Other', value: 'other' },
|
|
467
|
+
]);
|
|
468
|
+
|
|
469
|
+
// Prompt/instructions for coding agent
|
|
470
|
+
console.log(`\n ${CYAN}?${RESET} Detailed instructions for the coding agent:`);
|
|
471
|
+
console.log(` ${DIM}(Enter a blank line to finish)${RESET}`);
|
|
472
|
+
|
|
473
|
+
let prompt = '';
|
|
474
|
+
const promptLines = [];
|
|
475
|
+
|
|
476
|
+
const collectPrompt = () => {
|
|
477
|
+
return new Promise((resolve) => {
|
|
478
|
+
const askLine = () => {
|
|
479
|
+
rl.question(' ', (line) => {
|
|
480
|
+
if (line === '') {
|
|
481
|
+
resolve(promptLines.join('\n'));
|
|
482
|
+
} else {
|
|
483
|
+
promptLines.push(line);
|
|
484
|
+
askLine();
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
};
|
|
488
|
+
askLine();
|
|
489
|
+
});
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
prompt = await collectPrompt();
|
|
493
|
+
|
|
494
|
+
// Optional: Add attachments
|
|
495
|
+
const hasAttachments = await promptYesNo(rl, 'Add attachment URLs?', false);
|
|
496
|
+
const attachments = [];
|
|
497
|
+
|
|
498
|
+
if (hasAttachments) {
|
|
499
|
+
console.log(` ${DIM}Enter attachment URLs (blank line to finish):${RESET}`);
|
|
500
|
+
let addingAttachments = true;
|
|
501
|
+
while (addingAttachments) {
|
|
502
|
+
const url = await promptText(rl, 'URL', '');
|
|
503
|
+
if (!url) {
|
|
504
|
+
addingAttachments = false;
|
|
505
|
+
} else {
|
|
506
|
+
const name = await promptText(rl, 'Name for this attachment', `Attachment ${attachments.length + 1}`);
|
|
507
|
+
attachments.push({ url, name });
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Optional: Add metadata
|
|
513
|
+
const hasMetadata = await promptYesNo(rl, 'Add custom metadata (JSON)?', false);
|
|
514
|
+
let metadata = {};
|
|
515
|
+
|
|
516
|
+
if (hasMetadata) {
|
|
517
|
+
const metadataStr = await promptText(rl, 'Enter JSON metadata', '{}');
|
|
518
|
+
try {
|
|
519
|
+
metadata = JSON.parse(metadataStr);
|
|
520
|
+
} catch (e) {
|
|
521
|
+
console.log(` ${YELLOW}Warning: Invalid JSON, using empty metadata${RESET}`);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Due date (optional)
|
|
526
|
+
const hasDueDate = await promptYesNo(rl, 'Set a due date?', false);
|
|
527
|
+
let dueDate = null;
|
|
528
|
+
|
|
529
|
+
if (hasDueDate) {
|
|
530
|
+
const dueDateStr = await promptText(rl, 'Due date (YYYY-MM-DD)', '');
|
|
531
|
+
if (dueDateStr && /^\d{4}-\d{2}-\d{2}$/.test(dueDateStr)) {
|
|
532
|
+
dueDate = dueDateStr;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
rl.close();
|
|
537
|
+
|
|
538
|
+
// Build task data
|
|
539
|
+
const taskData = {
|
|
540
|
+
title,
|
|
541
|
+
description,
|
|
542
|
+
prompt: prompt || description,
|
|
543
|
+
priority,
|
|
544
|
+
task_type: taskType,
|
|
545
|
+
node_id: connection.node?.id,
|
|
546
|
+
application_id: connection.application?.id || connection.node?.application_id,
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
if (attachments.length > 0) {
|
|
550
|
+
taskData.attachments = attachments;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (Object.keys(metadata).length > 0) {
|
|
554
|
+
taskData.metadata = metadata;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (dueDate) {
|
|
558
|
+
taskData.due_date = dueDate;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Show summary
|
|
562
|
+
console.log(`\n${fg(...LOGO_NAVY)}${'─'.repeat(60)}${RESET}`);
|
|
563
|
+
console.log(`${BOLD} Task Summary${RESET}`);
|
|
564
|
+
console.log(`${fg(...LOGO_NAVY)}${'─'.repeat(60)}${RESET}\n`);
|
|
565
|
+
console.log(` ${DIM}Title:${RESET} ${title}`);
|
|
566
|
+
console.log(` ${DIM}Type:${RESET} ${taskType}`);
|
|
567
|
+
console.log(` ${DIM}Priority:${RESET} ${priority}`);
|
|
568
|
+
if (description) console.log(` ${DIM}Description:${RESET} ${description.substring(0, 50)}${description.length > 50 ? '...' : ''}`);
|
|
569
|
+
if (attachments.length > 0) console.log(` ${DIM}Attachments:${RESET} ${attachments.length} file(s)`);
|
|
570
|
+
if (dueDate) console.log(` ${DIM}Due date:${RESET} ${dueDate}`);
|
|
571
|
+
console.log('');
|
|
572
|
+
|
|
573
|
+
// Confirm and create
|
|
574
|
+
const rl2 = createReadlineInterface();
|
|
575
|
+
const confirm = await promptYesNo(rl2, 'Create this task?', true);
|
|
576
|
+
rl2.close();
|
|
577
|
+
|
|
578
|
+
if (!confirm) {
|
|
579
|
+
console.log(`\n${DIM}Task creation cancelled.${RESET}\n`);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// Create task via API
|
|
584
|
+
console.log(`\n${DIM}Creating task...${RESET}`);
|
|
585
|
+
|
|
586
|
+
try {
|
|
587
|
+
const response = await api.createTask(taskData);
|
|
588
|
+
const task = response.data;
|
|
589
|
+
|
|
590
|
+
console.log(`\n${GREEN}✓${RESET} ${BOLD}Task created successfully!${RESET}`);
|
|
591
|
+
console.log(` ${DIM}Task ID:${RESET} ${task.id || 'N/A'}`);
|
|
592
|
+
console.log(` ${DIM}Status:${RESET} ${task.status || 'pending'}\n`);
|
|
593
|
+
|
|
594
|
+
} catch (error) {
|
|
595
|
+
if (error.status === 404 || error.message?.includes('not found')) {
|
|
596
|
+
console.log(`\n${YELLOW}Note:${RESET} The create task endpoint is not implemented yet.`);
|
|
597
|
+
console.log(`${DIM}Required API: POST /api/v1/cli/tasks${RESET}`);
|
|
598
|
+
console.log(`\n${DIM}Request body that would be sent:${RESET}`);
|
|
599
|
+
console.log(JSON.stringify(taskData, null, 2));
|
|
600
|
+
console.log('');
|
|
601
|
+
} else {
|
|
602
|
+
throw error;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
} catch (error) {
|
|
607
|
+
rl.close();
|
|
608
|
+
displayMessageBox('Error', error.message, 'error');
|
|
609
|
+
process.exit(1);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
347
613
|
module.exports = {
|
|
348
614
|
tasksCommand,
|
|
349
615
|
nextTaskCommand,
|
|
350
616
|
continueCommand,
|
|
351
617
|
fallbackCommand,
|
|
352
618
|
autoCommand,
|
|
619
|
+
addTaskCommand,
|
|
353
620
|
generateAgentPrompt,
|
|
354
621
|
};
|
package/src/lib/api.js
CHANGED
|
@@ -176,6 +176,13 @@ class GbosApiClient {
|
|
|
176
176
|
});
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
async createTask(taskData) {
|
|
180
|
+
return this.request('/cli/tasks', {
|
|
181
|
+
method: 'POST',
|
|
182
|
+
body: taskData,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
179
186
|
// Activity logging
|
|
180
187
|
async logActivity(activity) {
|
|
181
188
|
return this.request('/cli/activity', {
|
package/src/lib/display.js
CHANGED
|
@@ -583,6 +583,7 @@ function displayConnectBanner(data) {
|
|
|
583
583
|
console.log(` ${cmd}continue${RESET} Continue working on current/next task`);
|
|
584
584
|
console.log(` ${cmd}fallback${RESET} Cancel current task and revert to last completed state`);
|
|
585
585
|
console.log(` ${cmd}auto${RESET} Automatically work through all tasks and poll for new ones`);
|
|
586
|
+
console.log(` ${cmd}add_task${RESET} Create a new task interactively`);
|
|
586
587
|
console.log(` ${cmd}logout${RESET} ${dim}[options]${RESET} Log out from GBOS services and clear credentials`);
|
|
587
588
|
console.log(` ${cmd}help${RESET} ${dim}[command]${RESET} Display help for a specific command\n`);
|
|
588
589
|
|