cognary-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.
- package/README.md +88 -0
- package/bin/cognary-cli.js +3 -0
- package/package.json +25 -0
- package/src/api.js +105 -0
- package/src/commands/tasks.js +339 -0
- package/src/config.js +25 -0
- package/src/index.js +20 -0
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Cognary CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for Cognary Tasks.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd cognary-cli
|
|
9
|
+
npm install
|
|
10
|
+
npm link # Optional: makes 'cognary-cli' available globally
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Authentication
|
|
14
|
+
|
|
15
|
+
The CLI requires an API key to authenticate with the Cognary Tasks API. You can provide it in two ways:
|
|
16
|
+
|
|
17
|
+
1. **Environment variable** (recommended):
|
|
18
|
+
```bash
|
|
19
|
+
export COGNARY_API_KEY=nts_your_api_key_here
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
2. **Command line option**:
|
|
23
|
+
```bash
|
|
24
|
+
cognary-cli --api-key nts_your_api_key_here tasks list
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Configuration
|
|
28
|
+
|
|
29
|
+
You can also configure the API URL:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Environment variable
|
|
33
|
+
export COGNARY_API_URL=https://your-api-url.com
|
|
34
|
+
|
|
35
|
+
# Or command line option
|
|
36
|
+
cognary-cli --api-url https://your-api-url.com tasks list
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Commands
|
|
40
|
+
|
|
41
|
+
### List Tasks
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cognary-cli tasks list
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Options:
|
|
48
|
+
- `-l, --limit <number>` - Number of tasks to return (default: 20)
|
|
49
|
+
- `-p, --page <number>` - Page number (default: 1)
|
|
50
|
+
- `-s, --status <status>` - Filter by status: active, completed, all (default: all)
|
|
51
|
+
- `-c, --category <category>` - Filter by category
|
|
52
|
+
- `--priority <priority>` - Filter by priority: High, Medium, Low
|
|
53
|
+
- `--search <query>` - Search tasks
|
|
54
|
+
- `--sort <field>` - Sort by: createdAt, updatedAt, dueDate, priority, title
|
|
55
|
+
- `--order <order>` - Sort order: asc, desc (default: desc)
|
|
56
|
+
- `--json` - Output as JSON
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
```bash
|
|
60
|
+
# List all tasks
|
|
61
|
+
cognary-cli tasks list
|
|
62
|
+
|
|
63
|
+
# List only active tasks
|
|
64
|
+
cognary-cli tasks list --status active
|
|
65
|
+
|
|
66
|
+
# Search for tasks containing "meeting"
|
|
67
|
+
cognary-cli tasks list --search meeting
|
|
68
|
+
|
|
69
|
+
# List high priority tasks sorted by due date
|
|
70
|
+
cognary-cli tasks list --priority High --sort dueDate --order asc
|
|
71
|
+
|
|
72
|
+
# Output as JSON
|
|
73
|
+
cognary-cli tasks list --json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Get a Single Task
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
cognary-cli tasks get <task-id>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Options:
|
|
83
|
+
- `--json` - Output as JSON
|
|
84
|
+
|
|
85
|
+
Example:
|
|
86
|
+
```bash
|
|
87
|
+
cognary-cli tasks get abc123-def456-ghi789
|
|
88
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cognary-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI for Cognary AI Tasks, Notes and Leads",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"cognary-cli": "./bin/cognary-cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node bin/cognary-cli.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"cognary",
|
|
15
|
+
"tasks",
|
|
16
|
+
"cli"
|
|
17
|
+
],
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"chalk": "^5.3.0",
|
|
22
|
+
"commander": "^12.1.0",
|
|
23
|
+
"dotenv": "^16.4.5"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/api.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API client for Cognary Tasks
|
|
3
|
+
*/
|
|
4
|
+
export class CognaryApi {
|
|
5
|
+
constructor(apiUrl, apiKey) {
|
|
6
|
+
this.apiUrl = apiUrl;
|
|
7
|
+
this.apiKey = apiKey;
|
|
8
|
+
this.baseEndpoint = '/api/v1/public';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async request(endpoint, options = {}) {
|
|
12
|
+
const url = `${this.apiUrl}${this.baseEndpoint}${endpoint}`;
|
|
13
|
+
|
|
14
|
+
const response = await fetch(url, {
|
|
15
|
+
...options,
|
|
16
|
+
headers: {
|
|
17
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
...options.headers,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
25
|
+
const error = new Error(errorBody.message || `API request failed with status ${response.status}`);
|
|
26
|
+
error.status = response.status;
|
|
27
|
+
error.code = errorBody.error;
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return response.json();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* List tasks with optional filters
|
|
36
|
+
*/
|
|
37
|
+
async listTasks(options = {}) {
|
|
38
|
+
const params = new URLSearchParams();
|
|
39
|
+
|
|
40
|
+
if (options.page) params.set('page', options.page);
|
|
41
|
+
if (options.limit) params.set('limit', options.limit);
|
|
42
|
+
if (options.status) params.set('status', options.status);
|
|
43
|
+
if (options.category) params.set('category', options.category);
|
|
44
|
+
if (options.priority) params.set('priority', options.priority);
|
|
45
|
+
if (options.search) params.set('search', options.search);
|
|
46
|
+
if (options.sort) params.set('sort', options.sort);
|
|
47
|
+
if (options.order) params.set('order', options.order);
|
|
48
|
+
if (options.completedLimit) params.set('completed_limit', options.completedLimit);
|
|
49
|
+
|
|
50
|
+
const queryString = params.toString();
|
|
51
|
+
const endpoint = `/tasks${queryString ? `?${queryString}` : ''}`;
|
|
52
|
+
|
|
53
|
+
return this.request(endpoint);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get a single task by ID
|
|
58
|
+
*/
|
|
59
|
+
async getTask(taskId) {
|
|
60
|
+
return this.request(`/tasks/${taskId}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create a new task
|
|
65
|
+
*/
|
|
66
|
+
async createTask({ title, notes, category, priority, dueDate }) {
|
|
67
|
+
const body = { title };
|
|
68
|
+
if (notes) body.notes = notes;
|
|
69
|
+
if (category) body.category = category;
|
|
70
|
+
if (priority) body.priority = priority;
|
|
71
|
+
if (dueDate) body.dueDate = dueDate;
|
|
72
|
+
|
|
73
|
+
return this.request('/tasks', {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
body: JSON.stringify(body),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Update an existing task
|
|
81
|
+
*/
|
|
82
|
+
async updateTask(taskId, fields) {
|
|
83
|
+
const body = {};
|
|
84
|
+
if (fields.title !== undefined) body.title = fields.title;
|
|
85
|
+
if (fields.notes !== undefined) body.notes = fields.notes;
|
|
86
|
+
if (fields.category !== undefined) body.category = fields.category;
|
|
87
|
+
if (fields.priority !== undefined) body.priority = fields.priority;
|
|
88
|
+
if (fields.dueDate !== undefined) body.dueDate = fields.dueDate;
|
|
89
|
+
if (fields.isCompleted !== undefined) body.isCompleted = fields.isCompleted;
|
|
90
|
+
|
|
91
|
+
return this.request(`/tasks/${taskId}`, {
|
|
92
|
+
method: 'PATCH',
|
|
93
|
+
body: JSON.stringify(body),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Delete a task
|
|
99
|
+
*/
|
|
100
|
+
async deleteTask(taskId) {
|
|
101
|
+
return this.request(`/tasks/${taskId}`, {
|
|
102
|
+
method: 'DELETE',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { getConfig } from '../config.js';
|
|
4
|
+
import { CognaryApi } from '../api.js';
|
|
5
|
+
|
|
6
|
+
export const tasksCommand = new Command('tasks')
|
|
7
|
+
.description('Manage tasks');
|
|
8
|
+
|
|
9
|
+
// List tasks command
|
|
10
|
+
tasksCommand
|
|
11
|
+
.command('list')
|
|
12
|
+
.description('List tasks')
|
|
13
|
+
.option('-l, --limit <number>', 'Number of tasks to return', '20')
|
|
14
|
+
.option('-p, --page <number>', 'Page number', '1')
|
|
15
|
+
.option('-s, --status <status>', 'Filter by status (active, completed, all)', 'all')
|
|
16
|
+
.option('-c, --category <category>', 'Filter by category')
|
|
17
|
+
.option('--priority <priority>', 'Filter by priority (High, Medium, Low)')
|
|
18
|
+
.option('--search <query>', 'Search tasks')
|
|
19
|
+
.option('--sort <field>', 'Sort by field (createdAt, updatedAt, dueDate, priority, title)', 'createdAt')
|
|
20
|
+
.option('--order <order>', 'Sort order (asc, desc)', 'desc')
|
|
21
|
+
.option('--active-only', 'Show only active tasks')
|
|
22
|
+
.option('--completed-limit <number>', 'Limit number of completed tasks returned')
|
|
23
|
+
.option('--json', 'Output as JSON')
|
|
24
|
+
.action(async (options, cmd) => {
|
|
25
|
+
try {
|
|
26
|
+
const config = getConfig(cmd);
|
|
27
|
+
const api = new CognaryApi(config.apiUrl, config.apiKey);
|
|
28
|
+
|
|
29
|
+
const status = options.activeOnly ? 'active' : options.status;
|
|
30
|
+
|
|
31
|
+
const result = await api.listTasks({
|
|
32
|
+
limit: parseInt(options.limit, 10),
|
|
33
|
+
page: parseInt(options.page, 10),
|
|
34
|
+
status,
|
|
35
|
+
completedLimit: options.completedLimit ? parseInt(options.completedLimit, 10) : undefined,
|
|
36
|
+
category: options.category,
|
|
37
|
+
priority: options.priority,
|
|
38
|
+
search: options.search,
|
|
39
|
+
sort: options.sort,
|
|
40
|
+
order: options.order,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (options.json) {
|
|
44
|
+
console.log(JSON.stringify(result, null, 2));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Display tasks in a readable format
|
|
49
|
+
const { data: tasks, pagination } = result;
|
|
50
|
+
|
|
51
|
+
if (tasks.length === 0) {
|
|
52
|
+
console.log(chalk.yellow('No tasks found.'));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log(chalk.bold(`\nTasks (${pagination.total} total)\n`));
|
|
57
|
+
|
|
58
|
+
for (const task of tasks) {
|
|
59
|
+
const status = task.isCompleted
|
|
60
|
+
? chalk.green('✓')
|
|
61
|
+
: chalk.gray('○');
|
|
62
|
+
|
|
63
|
+
const priority = formatPriority(task.priority);
|
|
64
|
+
const dueDate = task.dueDate
|
|
65
|
+
? chalk.cyan(new Date(task.dueDate).toLocaleDateString())
|
|
66
|
+
: chalk.gray('No due date');
|
|
67
|
+
|
|
68
|
+
console.log(`${status} ${chalk.bold(task.title)}`);
|
|
69
|
+
console.log(` ${chalk.gray('ID:')} ${task.id}`);
|
|
70
|
+
console.log(` ${chalk.gray('Category:')} ${task.category} | ${chalk.gray('Priority:')} ${priority} | ${chalk.gray('Due:')} ${dueDate}`);
|
|
71
|
+
|
|
72
|
+
if (task.notes) {
|
|
73
|
+
const truncatedNotes = task.notes.length > 100
|
|
74
|
+
? task.notes.substring(0, 100) + '...'
|
|
75
|
+
: task.notes;
|
|
76
|
+
console.log(` ${chalk.gray('Notes:')} ${truncatedNotes}`);
|
|
77
|
+
}
|
|
78
|
+
console.log('');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Pagination info
|
|
82
|
+
console.log(chalk.gray(`Page ${pagination.page} of ${pagination.totalPages} (${pagination.limit} per page)`));
|
|
83
|
+
|
|
84
|
+
if (pagination.hasMore) {
|
|
85
|
+
console.log(chalk.gray(`Use --page ${pagination.page + 1} to see more`));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
} catch (error) {
|
|
89
|
+
handleError(error);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Get single task command
|
|
94
|
+
tasksCommand
|
|
95
|
+
.command('get <id>')
|
|
96
|
+
.description('Get a task by ID')
|
|
97
|
+
.option('--json', 'Output as JSON')
|
|
98
|
+
.action(async (id, options, cmd) => {
|
|
99
|
+
try {
|
|
100
|
+
const config = getConfig(cmd);
|
|
101
|
+
const api = new CognaryApi(config.apiUrl, config.apiKey);
|
|
102
|
+
|
|
103
|
+
const result = await api.getTask(id);
|
|
104
|
+
|
|
105
|
+
if (options.json) {
|
|
106
|
+
console.log(JSON.stringify(result, null, 2));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const task = result.data;
|
|
111
|
+
const status = task.isCompleted
|
|
112
|
+
? chalk.green('✓ Completed')
|
|
113
|
+
: chalk.yellow('○ Active');
|
|
114
|
+
|
|
115
|
+
console.log(`\n${chalk.bold(task.title)}`);
|
|
116
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
117
|
+
console.log(`${chalk.gray('ID:')} ${task.id}`);
|
|
118
|
+
console.log(`${chalk.gray('Status:')} ${status}`);
|
|
119
|
+
console.log(`${chalk.gray('Category:')} ${task.category}`);
|
|
120
|
+
console.log(`${chalk.gray('Priority:')} ${formatPriority(task.priority)}`);
|
|
121
|
+
|
|
122
|
+
if (task.dueDate) {
|
|
123
|
+
console.log(`${chalk.gray('Due Date:')} ${new Date(task.dueDate).toLocaleString()}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.log(`${chalk.gray('Created:')} ${new Date(task.createdAt).toLocaleString()}`);
|
|
127
|
+
console.log(`${chalk.gray('Updated:')} ${new Date(task.updatedAt).toLocaleString()}`);
|
|
128
|
+
|
|
129
|
+
if (task.notes) {
|
|
130
|
+
console.log(`\n${chalk.gray('Notes:')}`);
|
|
131
|
+
console.log(task.notes);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (task.labels && task.labels.length > 0) {
|
|
135
|
+
console.log(`\n${chalk.gray('Labels:')} ${task.labels.map(l => l.name).join(', ')}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.log('');
|
|
139
|
+
|
|
140
|
+
} catch (error) {
|
|
141
|
+
handleError(error);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Add task command
|
|
146
|
+
tasksCommand
|
|
147
|
+
.command('add <title>')
|
|
148
|
+
.description('Create a new task')
|
|
149
|
+
.option('-n, --notes <notes>', 'Task notes')
|
|
150
|
+
.option('-c, --category <category>', 'Task category')
|
|
151
|
+
.option('--priority <priority>', 'Task priority (High, Medium, Low)')
|
|
152
|
+
.option('--due-date <date>', 'Due date')
|
|
153
|
+
.option('--json', 'Output as JSON')
|
|
154
|
+
.action(async (title, options, cmd) => {
|
|
155
|
+
try {
|
|
156
|
+
const config = getConfig(cmd);
|
|
157
|
+
const api = new CognaryApi(config.apiUrl, config.apiKey);
|
|
158
|
+
|
|
159
|
+
const result = await api.createTask({
|
|
160
|
+
title,
|
|
161
|
+
notes: options.notes,
|
|
162
|
+
category: options.category,
|
|
163
|
+
priority: options.priority,
|
|
164
|
+
dueDate: options.dueDate,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (options.json) {
|
|
168
|
+
console.log(JSON.stringify(result, null, 2));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const task = result.data;
|
|
173
|
+
console.log(chalk.green(`\n✓ Task created successfully!\n`));
|
|
174
|
+
console.log(`${chalk.bold(task.title)}`);
|
|
175
|
+
console.log(` ${chalk.gray('ID:')} ${task.id}`);
|
|
176
|
+
if (task.category) console.log(` ${chalk.gray('Category:')} ${task.category}`);
|
|
177
|
+
if (task.priority) console.log(` ${chalk.gray('Priority:')} ${formatPriority(task.priority)}`);
|
|
178
|
+
if (task.dueDate) console.log(` ${chalk.gray('Due:')} ${chalk.cyan(new Date(task.dueDate).toLocaleDateString())}`);
|
|
179
|
+
if (task.notes) console.log(` ${chalk.gray('Notes:')} ${task.notes}`);
|
|
180
|
+
console.log('');
|
|
181
|
+
|
|
182
|
+
} catch (error) {
|
|
183
|
+
handleError(error);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Update task command
|
|
188
|
+
tasksCommand
|
|
189
|
+
.command('update <id>')
|
|
190
|
+
.description('Update an existing task')
|
|
191
|
+
.option('-t, --title <title>', 'New title')
|
|
192
|
+
.option('-n, --notes <notes>', 'New notes')
|
|
193
|
+
.option('-c, --category <category>', 'New category')
|
|
194
|
+
.option('--priority <priority>', 'New priority (High, Medium, Low)')
|
|
195
|
+
.option('--due-date <date>', 'New due date')
|
|
196
|
+
.option('--json', 'Output as JSON')
|
|
197
|
+
.action(async (id, options, cmd) => {
|
|
198
|
+
try {
|
|
199
|
+
const config = getConfig(cmd);
|
|
200
|
+
const api = new CognaryApi(config.apiUrl, config.apiKey);
|
|
201
|
+
|
|
202
|
+
const result = await api.updateTask(id, {
|
|
203
|
+
title: options.title,
|
|
204
|
+
notes: options.notes,
|
|
205
|
+
category: options.category,
|
|
206
|
+
priority: options.priority,
|
|
207
|
+
dueDate: options.dueDate,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
if (options.json) {
|
|
211
|
+
console.log(JSON.stringify(result, null, 2));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const task = result.data;
|
|
216
|
+
console.log(chalk.green(`\n✓ Task updated successfully!\n`));
|
|
217
|
+
console.log(`${chalk.bold(task.title)}`);
|
|
218
|
+
console.log(` ${chalk.gray('ID:')} ${task.id}`);
|
|
219
|
+
if (task.category) console.log(` ${chalk.gray('Category:')} ${task.category}`);
|
|
220
|
+
if (task.priority) console.log(` ${chalk.gray('Priority:')} ${formatPriority(task.priority)}`);
|
|
221
|
+
if (task.dueDate) console.log(` ${chalk.gray('Due:')} ${chalk.cyan(new Date(task.dueDate).toLocaleDateString())}`);
|
|
222
|
+
console.log('');
|
|
223
|
+
|
|
224
|
+
} catch (error) {
|
|
225
|
+
handleError(error);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Delete task command
|
|
230
|
+
tasksCommand
|
|
231
|
+
.command('delete <id>')
|
|
232
|
+
.description('Delete a task')
|
|
233
|
+
.option('--json', 'Output as JSON')
|
|
234
|
+
.action(async (id, options, cmd) => {
|
|
235
|
+
try {
|
|
236
|
+
const config = getConfig(cmd);
|
|
237
|
+
const api = new CognaryApi(config.apiUrl, config.apiKey);
|
|
238
|
+
|
|
239
|
+
const result = await api.deleteTask(id);
|
|
240
|
+
|
|
241
|
+
if (options.json) {
|
|
242
|
+
console.log(JSON.stringify(result, null, 2));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log(chalk.green(`\n✓ Task ${id} deleted successfully!\n`));
|
|
247
|
+
|
|
248
|
+
} catch (error) {
|
|
249
|
+
handleError(error);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Complete task command
|
|
254
|
+
tasksCommand
|
|
255
|
+
.command('complete <id>')
|
|
256
|
+
.description('Mark a task as completed')
|
|
257
|
+
.option('--json', 'Output as JSON')
|
|
258
|
+
.action(async (id, options, cmd) => {
|
|
259
|
+
try {
|
|
260
|
+
const config = getConfig(cmd);
|
|
261
|
+
const api = new CognaryApi(config.apiUrl, config.apiKey);
|
|
262
|
+
|
|
263
|
+
const result = await api.updateTask(id, { isCompleted: true });
|
|
264
|
+
|
|
265
|
+
if (options.json) {
|
|
266
|
+
console.log(JSON.stringify(result, null, 2));
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const task = result.data;
|
|
271
|
+
console.log(chalk.green(`\n✓ Task marked as completed!\n`));
|
|
272
|
+
console.log(`${chalk.green('✓')} ${chalk.bold(task.title)}`);
|
|
273
|
+
console.log(` ${chalk.gray('ID:')} ${task.id}`);
|
|
274
|
+
console.log('');
|
|
275
|
+
|
|
276
|
+
} catch (error) {
|
|
277
|
+
handleError(error);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// Uncomplete task command
|
|
282
|
+
tasksCommand
|
|
283
|
+
.command('uncomplete <id>')
|
|
284
|
+
.description('Mark a task as active')
|
|
285
|
+
.option('--json', 'Output as JSON')
|
|
286
|
+
.action(async (id, options, cmd) => {
|
|
287
|
+
try {
|
|
288
|
+
const config = getConfig(cmd);
|
|
289
|
+
const api = new CognaryApi(config.apiUrl, config.apiKey);
|
|
290
|
+
|
|
291
|
+
const result = await api.updateTask(id, { isCompleted: false });
|
|
292
|
+
|
|
293
|
+
if (options.json) {
|
|
294
|
+
console.log(JSON.stringify(result, null, 2));
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const task = result.data;
|
|
299
|
+
console.log(chalk.green(`\n✓ Task marked as active!\n`));
|
|
300
|
+
console.log(`${chalk.yellow('○')} ${chalk.bold(task.title)}`);
|
|
301
|
+
console.log(` ${chalk.gray('ID:')} ${task.id}`);
|
|
302
|
+
console.log('');
|
|
303
|
+
|
|
304
|
+
} catch (error) {
|
|
305
|
+
handleError(error);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
function formatPriority(priority) {
|
|
310
|
+
if (!priority) return chalk.gray('None');
|
|
311
|
+
|
|
312
|
+
switch (priority) {
|
|
313
|
+
case 'High':
|
|
314
|
+
return chalk.red('High');
|
|
315
|
+
case 'Medium':
|
|
316
|
+
return chalk.yellow('Medium');
|
|
317
|
+
case 'Low':
|
|
318
|
+
return chalk.blue('Low');
|
|
319
|
+
default:
|
|
320
|
+
return priority;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function handleError(error) {
|
|
325
|
+
if (error.status === 401) {
|
|
326
|
+
console.error(chalk.red('Error: Authentication failed. Please check your API key.'));
|
|
327
|
+
} else if (error.status === 403) {
|
|
328
|
+
console.error(chalk.red('Error: Access denied. Your API key may not have the required permissions.'));
|
|
329
|
+
} else if (error.status === 404) {
|
|
330
|
+
console.error(chalk.red('Error: Resource not found.'));
|
|
331
|
+
} else if (error.status === 429) {
|
|
332
|
+
console.error(chalk.red('Error: Rate limit exceeded. Please try again later.'));
|
|
333
|
+
} else if (error.code === 'ECONNREFUSED') {
|
|
334
|
+
console.error(chalk.red('Error: Could not connect to the API. Is the server running?'));
|
|
335
|
+
} else {
|
|
336
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
337
|
+
}
|
|
338
|
+
process.exit(1);
|
|
339
|
+
}
|
package/src/config.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get configuration from command options or environment variables
|
|
3
|
+
*/
|
|
4
|
+
export function getConfig(cmd) {
|
|
5
|
+
// Walk up the command chain to find the root program options
|
|
6
|
+
let root = cmd;
|
|
7
|
+
while (root.parent) {
|
|
8
|
+
root = root.parent;
|
|
9
|
+
}
|
|
10
|
+
const opts = root.opts();
|
|
11
|
+
|
|
12
|
+
const apiKey = opts.apiKey || process.env.COGNARY_API_KEY;
|
|
13
|
+
const apiUrl = opts.apiUrl || process.env.COGNARY_API_URL || 'https://tasks.cognary.ai';
|
|
14
|
+
|
|
15
|
+
if (!apiKey) {
|
|
16
|
+
console.error('Error: API key is required.');
|
|
17
|
+
console.error('Provide it via --api-key option or set COGNARY_API_KEY environment variable.');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
apiKey,
|
|
23
|
+
apiUrl: apiUrl.replace(/\/$/, ''), // Remove trailing slash
|
|
24
|
+
};
|
|
25
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import dotenv from 'dotenv';
|
|
3
|
+
import { tasksCommand } from './commands/tasks.js';
|
|
4
|
+
|
|
5
|
+
// Load environment variables from .env file
|
|
6
|
+
dotenv.config();
|
|
7
|
+
|
|
8
|
+
const program = new Command();
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name('cognary-cli')
|
|
12
|
+
.description('CLI for Cognary Tasks')
|
|
13
|
+
.version('1.0.0')
|
|
14
|
+
.option('-k, --api-key <key>', 'API key for authentication (or set COGNARY_API_KEY env var)')
|
|
15
|
+
.option('-u, --api-url <url>', 'API base URL (or set COGNARY_API_URL env var)');
|
|
16
|
+
|
|
17
|
+
// Add commands
|
|
18
|
+
program.addCommand(tasksCommand);
|
|
19
|
+
|
|
20
|
+
program.parse();
|