agent-office 0.6.23 → 0.7.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/AGENTS.md +0 -0
- package/CONTEXT.md +77 -0
- package/README.md +87 -6
- package/dist/commands/cron-requests.d.ts +5 -5
- package/dist/commands/cron-requests.d.ts.map +1 -1
- package/dist/commands/cron-requests.js +9 -14
- package/dist/commands/cron-requests.js.map +1 -1
- package/dist/commands/crons.d.ts +9 -9
- package/dist/commands/crons.d.ts.map +1 -1
- package/dist/commands/crons.js +17 -27
- package/dist/commands/crons.js.map +1 -1
- package/dist/commands/messages.d.ts +6 -6
- package/dist/commands/messages.d.ts.map +1 -1
- package/dist/commands/messages.js +11 -18
- package/dist/commands/messages.js.map +1 -1
- package/dist/commands/sessions.d.ts +5 -5
- package/dist/commands/sessions.d.ts.map +1 -1
- package/dist/commands/sessions.js +10 -16
- package/dist/commands/sessions.js.map +1 -1
- package/dist/commands/task-columns.d.ts +1 -1
- package/dist/commands/task-columns.d.ts.map +1 -1
- package/dist/commands/task-columns.js +2 -4
- package/dist/commands/task-columns.js.map +1 -1
- package/dist/commands/tasks.d.ts +10 -10
- package/dist/commands/tasks.d.ts.map +1 -1
- package/dist/commands/tasks.js +20 -31
- package/dist/commands/tasks.js.map +1 -1
- package/dist/contracts/commands.d.ts +38 -0
- package/dist/contracts/commands.d.ts.map +1 -0
- package/dist/contracts/commands.js +469 -0
- package/dist/contracts/commands.js.map +1 -0
- package/dist/index.js +1062 -160
- package/dist/index.js.map +1 -1
- package/dist/lib/input.d.ts +7 -0
- package/dist/lib/input.d.ts.map +1 -0
- package/dist/lib/input.js +94 -0
- package/dist/lib/input.js.map +1 -0
- package/dist/lib/mcp.d.ts +36 -0
- package/dist/lib/mcp.d.ts.map +1 -0
- package/dist/lib/mcp.js +150 -0
- package/dist/lib/mcp.js.map +1 -0
- package/dist/lib/output.d.ts +9 -1
- package/dist/lib/output.d.ts.map +1 -1
- package/dist/lib/output.js +59 -4
- package/dist/lib/output.js.map +1 -1
- package/dist/lib/schema.d.ts +35 -0
- package/dist/lib/schema.d.ts.map +1 -0
- package/dist/lib/schema.js +441 -0
- package/dist/lib/schema.js.map +1 -0
- package/dist/lib/validation.d.ts +15 -0
- package/dist/lib/validation.d.ts.map +1 -0
- package/dist/lib/validation.js +140 -0
- package/dist/lib/validation.js.map +1 -0
- package/package.json +5 -2
- package/skills/SKILL-create-coworker.md +51 -0
- package/skills/SKILL-cron-jobs.md +106 -0
- package/skills/SKILL-send-message.md +56 -0
- package/skills/SKILL-task-management.md +86 -0
package/dist/index.js
CHANGED
|
@@ -1,26 +1,77 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command, Option } from 'commander';
|
|
3
|
-
import { readFileSync } from 'fs';
|
|
3
|
+
import { readFileSync, readdirSync } from 'fs';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import { dirname, join } from 'path';
|
|
6
6
|
import { listCoworkers, getCoworkerInfo, updateCoworker, createSession, deleteCoworker } from './commands/sessions.js';
|
|
7
|
-
import { sendMessage, checkUnreadMail, getUnreadMail, listMessagesBetween, listMessagesToNotify, markMessagesAsNotified } from './commands/messages.js';
|
|
7
|
+
import { sendMessage, checkUnreadMail, getUnreadMail, listMessagesBetween, listMessagesToNotify, markMessagesAsNotified, } from './commands/messages.js';
|
|
8
8
|
import { listCrons, deleteCron, enableCron, disableCron, cronHistory, requestCron, createCron, checkCronJobs, listActiveCronJobs, } from './commands/crons.js';
|
|
9
9
|
import { listCronRequests, getCronRequest, approveCronRequest, rejectCronRequest, deleteCronRequest, } from './commands/cron-requests.js';
|
|
10
10
|
import { addTask, listTasks, getTask, updateTask, deleteTask, assignTask, unassignTask, moveTask, taskStats, getTaskHistory, } from './commands/tasks.js';
|
|
11
11
|
import { listTaskColumns } from './commands/task-columns.js';
|
|
12
12
|
import { createSqliteStorage, createPostgresqlStorage } from './db/index.js';
|
|
13
|
+
import { formatOutput } from './lib/output.js';
|
|
14
|
+
import { getSchema, getMutatingCommands } from './lib/schema.js';
|
|
15
|
+
import { MCPServer } from './lib/mcp.js';
|
|
13
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
14
17
|
const __dirname = dirname(__filename);
|
|
15
18
|
const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
|
|
16
19
|
// Global storage instance
|
|
17
20
|
let storage = null;
|
|
21
|
+
let isDryRun = false;
|
|
18
22
|
async function getStorage() {
|
|
19
23
|
if (!storage) {
|
|
20
24
|
throw new Error('Storage not initialized. Use --sqlite <path> or --postgresql <url> option.');
|
|
21
25
|
}
|
|
22
26
|
return storage;
|
|
23
27
|
}
|
|
28
|
+
function getOutputFormat(opts) {
|
|
29
|
+
// Check explicit --output flag first
|
|
30
|
+
const outputFormat = opts.output?.toLowerCase();
|
|
31
|
+
if (outputFormat === 'json')
|
|
32
|
+
return 'json';
|
|
33
|
+
if (outputFormat === 'ndjson')
|
|
34
|
+
return 'ndjson';
|
|
35
|
+
if (outputFormat === 'toon')
|
|
36
|
+
return 'toon';
|
|
37
|
+
if (outputFormat === 'auto')
|
|
38
|
+
return 'auto';
|
|
39
|
+
// Check environment variable as fallback
|
|
40
|
+
const envFormat = process.env.AGENT_OFFICE_OUTPUT_FORMAT?.toLowerCase();
|
|
41
|
+
if (envFormat === 'json')
|
|
42
|
+
return 'json';
|
|
43
|
+
if (envFormat === 'ndjson')
|
|
44
|
+
return 'ndjson';
|
|
45
|
+
if (envFormat === 'toon')
|
|
46
|
+
return 'toon';
|
|
47
|
+
if (envFormat === 'auto')
|
|
48
|
+
return 'auto';
|
|
49
|
+
return 'auto';
|
|
50
|
+
}
|
|
51
|
+
function getFields(opts) {
|
|
52
|
+
if (!opts.fields)
|
|
53
|
+
return undefined;
|
|
54
|
+
return opts.fields
|
|
55
|
+
.split(',')
|
|
56
|
+
.map(f => f.trim())
|
|
57
|
+
.filter(f => f.length > 0);
|
|
58
|
+
}
|
|
59
|
+
function formatWithOptions(data, opts) {
|
|
60
|
+
const format = getOutputFormat(opts);
|
|
61
|
+
const fields = getFields(opts);
|
|
62
|
+
return formatOutput(data, { format, fields });
|
|
63
|
+
}
|
|
64
|
+
// Helper to check if dry-run should be applied
|
|
65
|
+
function shouldExecute(commandName) {
|
|
66
|
+
if (!isDryRun)
|
|
67
|
+
return true;
|
|
68
|
+
const mutatingCommands = getMutatingCommands();
|
|
69
|
+
if (mutatingCommands.includes(commandName)) {
|
|
70
|
+
console.log(`[DRY-RUN] Would execute: ${commandName}`);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
24
75
|
const program = new Command();
|
|
25
76
|
program
|
|
26
77
|
.name('agent-office')
|
|
@@ -28,7 +79,9 @@ program
|
|
|
28
79
|
.version(packageJson.version)
|
|
29
80
|
.addOption(new Option('--sqlite <path>', 'SQLite database file path').env('AGENT_OFFICE_SQLITE'))
|
|
30
81
|
.addOption(new Option('--postgresql <url>', 'PostgreSQL connection URL').env('AGENT_OFFICE_POSTGRESQL'))
|
|
31
|
-
.addOption(new Option('--
|
|
82
|
+
.addOption(new Option('--output <format>', 'Output format (json, ndjson, toon, auto)').env('AGENT_OFFICE_OUTPUT_FORMAT'))
|
|
83
|
+
.addOption(new Option('--fields <fields>', 'Comma-separated list of fields to include in output'))
|
|
84
|
+
.addOption(new Option('--dry-run', 'Validate commands without executing mutating operations'))
|
|
32
85
|
.hook('preAction', async (thisCommand) => {
|
|
33
86
|
const opts = thisCommand.opts();
|
|
34
87
|
if (opts.sqlite && opts.postgresql) {
|
|
@@ -42,417 +95,1266 @@ program
|
|
|
42
95
|
storage = createPostgresqlStorage(opts.postgresql);
|
|
43
96
|
await storage.runMigrations();
|
|
44
97
|
}
|
|
98
|
+
isDryRun = opts.dryRun || false;
|
|
99
|
+
});
|
|
100
|
+
// Schema introspection commands
|
|
101
|
+
program
|
|
102
|
+
.command('schema')
|
|
103
|
+
.description('Show schema for a specific command or all commands')
|
|
104
|
+
.argument('[command]', 'Command name to show schema for (omit for all commands)')
|
|
105
|
+
.action(async (commandName, _cmd) => {
|
|
106
|
+
const opts = program.opts();
|
|
107
|
+
const schema = getSchema(commandName);
|
|
108
|
+
if (commandName && !schema) {
|
|
109
|
+
console.log(formatWithOptions({ error: `Unknown command: ${commandName}` }, opts));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
console.log(formatWithOptions(schema, opts));
|
|
113
|
+
});
|
|
114
|
+
program
|
|
115
|
+
.command('describe')
|
|
116
|
+
.description('Describe available commands (alias for schema)')
|
|
117
|
+
.argument('[command]', 'Command name to describe (omit for all commands)')
|
|
118
|
+
.action(async (commandName, _cmd) => {
|
|
119
|
+
const opts = program.opts();
|
|
120
|
+
const schema = getSchema(commandName);
|
|
121
|
+
if (commandName && !schema) {
|
|
122
|
+
console.log(formatWithOptions({ error: `Unknown command: ${commandName}` }, opts));
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
console.log(formatWithOptions(schema, opts));
|
|
45
126
|
});
|
|
46
127
|
// Session/Coworker commands
|
|
47
128
|
program
|
|
48
129
|
.command('list-coworkers')
|
|
49
130
|
.description('List all coworkers (sessions)')
|
|
50
131
|
.action(async (_args, command) => {
|
|
51
|
-
const
|
|
132
|
+
const opts = command.optsWithGlobals();
|
|
52
133
|
const storage = await getStorage();
|
|
53
|
-
await listCoworkers(storage
|
|
134
|
+
const coworkers = await listCoworkers(storage);
|
|
135
|
+
console.log(formatWithOptions(coworkers, opts));
|
|
54
136
|
await storage.close();
|
|
55
137
|
});
|
|
56
138
|
program
|
|
57
139
|
.command('create-coworker')
|
|
58
140
|
.description('Create a new coworker (session)')
|
|
59
|
-
.requiredOption('
|
|
60
|
-
.requiredOption('-t, --coworker-type <type>', 'Coworker type (e.g., assistant, developer, manager)')
|
|
141
|
+
.requiredOption('--json <json>', 'Full JSON payload with name and coworkerType')
|
|
61
142
|
.action(async (options, command) => {
|
|
62
|
-
const
|
|
143
|
+
const opts = command.optsWithGlobals();
|
|
144
|
+
// Parse JSON input
|
|
145
|
+
let data;
|
|
146
|
+
try {
|
|
147
|
+
data = JSON.parse(options.json);
|
|
148
|
+
}
|
|
149
|
+
catch (e) {
|
|
150
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
// Validate required fields
|
|
154
|
+
if (!data.name) {
|
|
155
|
+
console.log(formatWithOptions({ error: 'Missing required field: name' }, opts));
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
if (!data.coworkerType) {
|
|
159
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworkerType' }, opts));
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
if (!shouldExecute('create-coworker')) {
|
|
163
|
+
console.log(formatWithOptions({
|
|
164
|
+
dryRun: true,
|
|
165
|
+
command: 'create-coworker',
|
|
166
|
+
params: { name: data.name, coworkerType: data.coworkerType },
|
|
167
|
+
}, opts));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
63
170
|
const storage = await getStorage();
|
|
64
|
-
await createSession(storage,
|
|
171
|
+
const session = await createSession(storage, data.name, data.coworkerType);
|
|
172
|
+
console.log(formatWithOptions(session, opts));
|
|
65
173
|
await storage.close();
|
|
66
174
|
});
|
|
67
175
|
program
|
|
68
176
|
.command('delete-coworker')
|
|
69
177
|
.description('Delete a coworker (session)')
|
|
70
|
-
.requiredOption('
|
|
178
|
+
.requiredOption('--json <json>', 'Full JSON payload with name field')
|
|
71
179
|
.action(async (options, command) => {
|
|
72
|
-
const
|
|
180
|
+
const opts = command.optsWithGlobals();
|
|
181
|
+
// Parse JSON input
|
|
182
|
+
let data;
|
|
183
|
+
try {
|
|
184
|
+
data = JSON.parse(options.json);
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
// Validate required fields
|
|
191
|
+
if (!data.name) {
|
|
192
|
+
console.log(formatWithOptions({ error: 'Missing required field: name' }, opts));
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
if (!shouldExecute('delete-coworker')) {
|
|
196
|
+
console.log(formatWithOptions({
|
|
197
|
+
dryRun: true,
|
|
198
|
+
command: 'delete-coworker',
|
|
199
|
+
params: { name: data.name },
|
|
200
|
+
}, opts));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
73
203
|
const storage = await getStorage();
|
|
74
|
-
await deleteCoworker(storage,
|
|
204
|
+
await deleteCoworker(storage, data.name);
|
|
205
|
+
console.log(formatWithOptions({ success: true, message: `Coworker ${data.name} deleted` }, opts));
|
|
75
206
|
await storage.close();
|
|
76
207
|
});
|
|
77
208
|
program
|
|
78
209
|
.command('update-coworker')
|
|
79
210
|
.description("Update a coworker's information (status, description, philosophy, visual description)")
|
|
80
|
-
.requiredOption('
|
|
81
|
-
.option('-t, --coworker-type <type>', 'Set the coworker type')
|
|
82
|
-
.option('-s, --status <status>', 'Set the status (omit to clear)')
|
|
83
|
-
.option('-d, --description <description>', 'Set the description (omit to clear)')
|
|
84
|
-
.option('-p, --philosophy <philosophy>', 'Set the philosophy (omit to clear)')
|
|
85
|
-
.option('-v, --visual-description <visual>', 'Set the visual description (omit to clear)')
|
|
211
|
+
.requiredOption('--json <json>', 'Full JSON payload with name and optional fields')
|
|
86
212
|
.action(async (options, command) => {
|
|
87
|
-
const
|
|
213
|
+
const opts = command.optsWithGlobals();
|
|
214
|
+
// Parse JSON input
|
|
215
|
+
let data;
|
|
216
|
+
try {
|
|
217
|
+
data = JSON.parse(options.json);
|
|
218
|
+
}
|
|
219
|
+
catch (e) {
|
|
220
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
// Validate required fields
|
|
224
|
+
if (!data.name) {
|
|
225
|
+
console.log(formatWithOptions({ error: 'Missing required field: name' }, opts));
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
if (!shouldExecute('update-coworker')) {
|
|
229
|
+
console.log(formatWithOptions({
|
|
230
|
+
dryRun: true,
|
|
231
|
+
command: 'update-coworker',
|
|
232
|
+
params: {
|
|
233
|
+
name: data.name,
|
|
234
|
+
coworkerType: data.coworkerType,
|
|
235
|
+
status: data.status,
|
|
236
|
+
description: data.description,
|
|
237
|
+
philosophy: data.philosophy,
|
|
238
|
+
visualDescription: data.visualDescription,
|
|
239
|
+
},
|
|
240
|
+
}, opts));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
88
243
|
const storage = await getStorage();
|
|
89
|
-
await updateCoworker(storage,
|
|
90
|
-
coworkerType:
|
|
91
|
-
status:
|
|
92
|
-
description:
|
|
93
|
-
philosophy:
|
|
94
|
-
visualDescription:
|
|
95
|
-
}
|
|
244
|
+
await updateCoworker(storage, data.name, {
|
|
245
|
+
coworkerType: data.coworkerType ?? null,
|
|
246
|
+
status: data.status ?? null,
|
|
247
|
+
description: data.description ?? null,
|
|
248
|
+
philosophy: data.philosophy ?? null,
|
|
249
|
+
visualDescription: data.visualDescription ?? null,
|
|
250
|
+
});
|
|
251
|
+
const coworker = await getCoworkerInfo(storage, data.name);
|
|
252
|
+
console.log(formatWithOptions(coworker, opts));
|
|
96
253
|
await storage.close();
|
|
97
254
|
});
|
|
98
255
|
program
|
|
99
256
|
.command('get-coworker-info')
|
|
100
257
|
.description('Get coworker information (name, description, philosophy)')
|
|
101
|
-
.requiredOption('
|
|
258
|
+
.requiredOption('--json <json>', 'Full JSON payload with name field')
|
|
102
259
|
.action(async (options, command) => {
|
|
103
|
-
const
|
|
260
|
+
const opts = command.optsWithGlobals();
|
|
261
|
+
// Parse JSON input
|
|
262
|
+
let data;
|
|
263
|
+
try {
|
|
264
|
+
data = JSON.parse(options.json);
|
|
265
|
+
}
|
|
266
|
+
catch (e) {
|
|
267
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
// Validate required fields
|
|
271
|
+
if (!data.name) {
|
|
272
|
+
console.log(formatWithOptions({ error: 'Missing required field: name' }, opts));
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
104
275
|
const storage = await getStorage();
|
|
105
|
-
await getCoworkerInfo(storage,
|
|
276
|
+
const coworker = await getCoworkerInfo(storage, data.name);
|
|
277
|
+
console.log(formatWithOptions(coworker, opts));
|
|
106
278
|
await storage.close();
|
|
107
279
|
});
|
|
108
280
|
// Message commands
|
|
109
281
|
program
|
|
110
282
|
.command('send-message')
|
|
111
283
|
.description('Send a message to one or more recipients')
|
|
112
|
-
.requiredOption('
|
|
113
|
-
.requiredOption('-t, --to <recipients...>', 'Recipient names')
|
|
114
|
-
.requiredOption('-b, --body <body>', 'Message body')
|
|
284
|
+
.requiredOption('--json <json>', 'Full JSON payload with from, to, and body fields')
|
|
115
285
|
.action(async (options, command) => {
|
|
116
|
-
const
|
|
286
|
+
const opts = command.optsWithGlobals();
|
|
287
|
+
// Parse JSON input
|
|
288
|
+
let data;
|
|
289
|
+
try {
|
|
290
|
+
data = JSON.parse(options.json);
|
|
291
|
+
}
|
|
292
|
+
catch (e) {
|
|
293
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
// Validate required fields
|
|
297
|
+
if (!data.from) {
|
|
298
|
+
console.log(formatWithOptions({ error: 'Missing required field: from' }, opts));
|
|
299
|
+
process.exit(1);
|
|
300
|
+
}
|
|
301
|
+
if (!data.to || !Array.isArray(data.to) || data.to.length === 0) {
|
|
302
|
+
console.log(formatWithOptions({ error: 'Missing required field: to (must be array)' }, opts));
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
if (!data.body) {
|
|
306
|
+
console.log(formatWithOptions({ error: 'Missing required field: body' }, opts));
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
309
|
+
if (!shouldExecute('send-message')) {
|
|
310
|
+
console.log(formatWithOptions({
|
|
311
|
+
dryRun: true,
|
|
312
|
+
command: 'send-message',
|
|
313
|
+
params: { from: data.from, to: data.to, body: data.body },
|
|
314
|
+
}, opts));
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
117
317
|
const storage = await getStorage();
|
|
118
|
-
await sendMessage(storage,
|
|
318
|
+
await sendMessage(storage, data.from, data.to, data.body);
|
|
319
|
+
console.log(formatWithOptions({ success: true, message: 'Message sent' }, opts));
|
|
119
320
|
await storage.close();
|
|
120
321
|
});
|
|
121
322
|
program
|
|
122
323
|
.command('check-unread-messages')
|
|
123
324
|
.description('Check if there are unread messages for a coworker')
|
|
124
|
-
.requiredOption('
|
|
325
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker field')
|
|
125
326
|
.action(async (options, command) => {
|
|
126
|
-
const
|
|
327
|
+
const opts = command.optsWithGlobals();
|
|
328
|
+
// Parse JSON input
|
|
329
|
+
let data;
|
|
330
|
+
try {
|
|
331
|
+
data = JSON.parse(options.json);
|
|
332
|
+
}
|
|
333
|
+
catch (e) {
|
|
334
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
// Validate required fields
|
|
338
|
+
if (!data.coworker) {
|
|
339
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworker' }, opts));
|
|
340
|
+
process.exit(1);
|
|
341
|
+
}
|
|
127
342
|
const storage = await getStorage();
|
|
128
|
-
await checkUnreadMail(storage,
|
|
343
|
+
const result = await checkUnreadMail(storage, data.coworker);
|
|
344
|
+
console.log(formatWithOptions(result, opts));
|
|
129
345
|
await storage.close();
|
|
130
346
|
});
|
|
131
347
|
program
|
|
132
348
|
.command('get-unread-messages')
|
|
133
349
|
.description('Get all unread messages for a coworker and mark as read')
|
|
134
|
-
.requiredOption('
|
|
350
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker field')
|
|
135
351
|
.action(async (options, command) => {
|
|
136
|
-
const
|
|
352
|
+
const opts = command.optsWithGlobals();
|
|
353
|
+
// Parse JSON input
|
|
354
|
+
let data;
|
|
355
|
+
try {
|
|
356
|
+
data = JSON.parse(options.json);
|
|
357
|
+
}
|
|
358
|
+
catch (e) {
|
|
359
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
360
|
+
process.exit(1);
|
|
361
|
+
}
|
|
362
|
+
// Validate required fields
|
|
363
|
+
if (!data.coworker) {
|
|
364
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworker' }, opts));
|
|
365
|
+
process.exit(1);
|
|
366
|
+
}
|
|
367
|
+
if (!shouldExecute('get-unread-messages')) {
|
|
368
|
+
console.log(formatWithOptions({
|
|
369
|
+
dryRun: true,
|
|
370
|
+
command: 'get-unread-messages',
|
|
371
|
+
params: { coworker: data.coworker },
|
|
372
|
+
}, opts));
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
137
375
|
const storage = await getStorage();
|
|
138
|
-
await getUnreadMail(storage,
|
|
376
|
+
const messages = await getUnreadMail(storage, data.coworker);
|
|
377
|
+
console.log(formatWithOptions(messages, opts));
|
|
139
378
|
await storage.close();
|
|
140
379
|
});
|
|
141
380
|
program
|
|
142
381
|
.command('list-messages-between')
|
|
143
382
|
.description('Show all messages between two coworkers')
|
|
144
|
-
.requiredOption('--
|
|
145
|
-
.requiredOption('--coworker2 <name>', 'Second coworker name')
|
|
146
|
-
.option('--start <isoTime>', 'Start time (ISO 8601 format)')
|
|
147
|
-
.option('--end <isoTime>', 'End time (ISO 8601 format)')
|
|
383
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker1, coworker2, and optional start/end fields')
|
|
148
384
|
.action(async (options, command) => {
|
|
149
|
-
const
|
|
385
|
+
const opts = command.optsWithGlobals();
|
|
386
|
+
// Parse JSON input
|
|
387
|
+
let data;
|
|
388
|
+
try {
|
|
389
|
+
data = JSON.parse(options.json);
|
|
390
|
+
}
|
|
391
|
+
catch (e) {
|
|
392
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
393
|
+
process.exit(1);
|
|
394
|
+
}
|
|
395
|
+
// Validate required fields
|
|
396
|
+
if (!data.coworker1) {
|
|
397
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworker1' }, opts));
|
|
398
|
+
process.exit(1);
|
|
399
|
+
}
|
|
400
|
+
if (!data.coworker2) {
|
|
401
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworker2' }, opts));
|
|
402
|
+
process.exit(1);
|
|
403
|
+
}
|
|
150
404
|
const storage = await getStorage();
|
|
151
|
-
await listMessagesBetween(storage,
|
|
405
|
+
const messages = await listMessagesBetween(storage, data.coworker1, data.coworker2, data.start, data.end);
|
|
406
|
+
console.log(formatWithOptions(messages, opts));
|
|
152
407
|
await storage.close();
|
|
153
408
|
});
|
|
154
409
|
program
|
|
155
410
|
.command('list-messages-to-notify')
|
|
156
411
|
.description('List unread messages older than specified hours that have not been notified')
|
|
157
|
-
.requiredOption('
|
|
158
|
-
.requiredOption('-H, --hours <hours>', 'Hours threshold for message age', parseFloat)
|
|
412
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker and hours fields')
|
|
159
413
|
.action(async (options, command) => {
|
|
160
|
-
const
|
|
414
|
+
const opts = command.optsWithGlobals();
|
|
415
|
+
// Parse JSON input
|
|
416
|
+
let data;
|
|
417
|
+
try {
|
|
418
|
+
data = JSON.parse(options.json);
|
|
419
|
+
}
|
|
420
|
+
catch (e) {
|
|
421
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
422
|
+
process.exit(1);
|
|
423
|
+
}
|
|
424
|
+
// Validate required fields
|
|
425
|
+
if (!data.coworker) {
|
|
426
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworker' }, opts));
|
|
427
|
+
process.exit(1);
|
|
428
|
+
}
|
|
429
|
+
if (data.hours === undefined || data.hours === null) {
|
|
430
|
+
console.log(formatWithOptions({ error: 'Missing required field: hours' }, opts));
|
|
431
|
+
process.exit(1);
|
|
432
|
+
}
|
|
161
433
|
const storage = await getStorage();
|
|
162
|
-
await listMessagesToNotify(storage,
|
|
434
|
+
const messages = await listMessagesToNotify(storage, data.coworker, data.hours);
|
|
435
|
+
console.log(formatWithOptions(messages, opts));
|
|
163
436
|
await storage.close();
|
|
164
437
|
});
|
|
165
438
|
program
|
|
166
439
|
.command('mark-messages-as-notified')
|
|
167
440
|
.description('Mark specific messages as notified')
|
|
168
|
-
.requiredOption('
|
|
441
|
+
.requiredOption('--json <json>', 'Full JSON payload with ids array')
|
|
169
442
|
.action(async (options, command) => {
|
|
170
|
-
const
|
|
443
|
+
const opts = command.optsWithGlobals();
|
|
444
|
+
// Parse JSON input
|
|
445
|
+
let data;
|
|
446
|
+
try {
|
|
447
|
+
data = JSON.parse(options.json);
|
|
448
|
+
}
|
|
449
|
+
catch (e) {
|
|
450
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
451
|
+
process.exit(1);
|
|
452
|
+
}
|
|
453
|
+
// Validate required fields
|
|
454
|
+
if (!data.ids || !Array.isArray(data.ids) || data.ids.length === 0) {
|
|
455
|
+
console.log(formatWithOptions({ error: 'Missing required field: ids (must be array of numbers)' }, opts));
|
|
456
|
+
process.exit(1);
|
|
457
|
+
}
|
|
458
|
+
if (!shouldExecute('mark-messages-as-notified')) {
|
|
459
|
+
console.log(formatWithOptions({
|
|
460
|
+
dryRun: true,
|
|
461
|
+
command: 'mark-messages-as-notified',
|
|
462
|
+
params: { ids: data.ids },
|
|
463
|
+
}, opts));
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
171
466
|
const storage = await getStorage();
|
|
172
|
-
await markMessagesAsNotified(storage,
|
|
467
|
+
await markMessagesAsNotified(storage, data.ids);
|
|
468
|
+
console.log(formatWithOptions({ success: true, marked: data.ids.length }, opts));
|
|
173
469
|
await storage.close();
|
|
174
470
|
});
|
|
175
471
|
// Cron commands
|
|
176
472
|
program
|
|
177
473
|
.command('list-crons')
|
|
178
474
|
.description('List all cron jobs for a specific coworker')
|
|
179
|
-
.requiredOption('
|
|
475
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker field')
|
|
180
476
|
.action(async (options, command) => {
|
|
181
|
-
const
|
|
477
|
+
const opts = command.optsWithGlobals();
|
|
478
|
+
// Parse JSON input
|
|
479
|
+
let data;
|
|
480
|
+
try {
|
|
481
|
+
data = JSON.parse(options.json);
|
|
482
|
+
}
|
|
483
|
+
catch (e) {
|
|
484
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
485
|
+
process.exit(1);
|
|
486
|
+
}
|
|
487
|
+
// Validate required fields
|
|
488
|
+
if (!data.coworker) {
|
|
489
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworker' }, opts));
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
182
492
|
const storage = await getStorage();
|
|
183
|
-
await listCrons(storage,
|
|
493
|
+
const crons = await listCrons(storage, data.coworker);
|
|
494
|
+
console.log(formatWithOptions(crons, opts));
|
|
184
495
|
await storage.close();
|
|
185
496
|
});
|
|
186
497
|
program
|
|
187
498
|
.command('delete-cron')
|
|
188
499
|
.description('Delete a cron job')
|
|
189
|
-
.requiredOption('
|
|
500
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
190
501
|
.action(async (options, command) => {
|
|
191
|
-
const
|
|
502
|
+
const opts = command.optsWithGlobals();
|
|
503
|
+
// Parse JSON input
|
|
504
|
+
let data;
|
|
505
|
+
try {
|
|
506
|
+
data = JSON.parse(options.json);
|
|
507
|
+
}
|
|
508
|
+
catch (e) {
|
|
509
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
510
|
+
process.exit(1);
|
|
511
|
+
}
|
|
512
|
+
// Validate required fields
|
|
513
|
+
if (data.id === undefined || data.id === null) {
|
|
514
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
515
|
+
process.exit(1);
|
|
516
|
+
}
|
|
517
|
+
if (!shouldExecute('delete-cron')) {
|
|
518
|
+
console.log(formatWithOptions({
|
|
519
|
+
dryRun: true,
|
|
520
|
+
command: 'delete-cron',
|
|
521
|
+
params: { id: data.id },
|
|
522
|
+
}, opts));
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
192
525
|
const storage = await getStorage();
|
|
193
|
-
await deleteCron(storage,
|
|
526
|
+
await deleteCron(storage, data.id);
|
|
527
|
+
console.log(formatWithOptions({ success: true, message: `Cron job ${data.id} deleted` }, opts));
|
|
194
528
|
await storage.close();
|
|
195
529
|
});
|
|
196
530
|
program
|
|
197
531
|
.command('enable-cron')
|
|
198
532
|
.description('Enable a cron job')
|
|
199
|
-
.requiredOption('
|
|
533
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
200
534
|
.action(async (options, command) => {
|
|
201
|
-
const
|
|
535
|
+
const opts = command.optsWithGlobals();
|
|
536
|
+
// Parse JSON input
|
|
537
|
+
let data;
|
|
538
|
+
try {
|
|
539
|
+
data = JSON.parse(options.json);
|
|
540
|
+
}
|
|
541
|
+
catch (e) {
|
|
542
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
543
|
+
process.exit(1);
|
|
544
|
+
}
|
|
545
|
+
// Validate required fields
|
|
546
|
+
if (data.id === undefined || data.id === null) {
|
|
547
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
548
|
+
process.exit(1);
|
|
549
|
+
}
|
|
550
|
+
if (!shouldExecute('enable-cron')) {
|
|
551
|
+
console.log(formatWithOptions({
|
|
552
|
+
dryRun: true,
|
|
553
|
+
command: 'enable-cron',
|
|
554
|
+
params: { id: data.id },
|
|
555
|
+
}, opts));
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
202
558
|
const storage = await getStorage();
|
|
203
|
-
await enableCron(storage,
|
|
559
|
+
await enableCron(storage, data.id);
|
|
560
|
+
console.log(formatWithOptions({ success: true, message: `Cron job ${data.id} enabled` }, opts));
|
|
204
561
|
await storage.close();
|
|
205
562
|
});
|
|
206
563
|
program
|
|
207
564
|
.command('disable-cron')
|
|
208
565
|
.description('Disable a cron job')
|
|
209
|
-
.requiredOption('
|
|
566
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
210
567
|
.action(async (options, command) => {
|
|
211
|
-
const
|
|
568
|
+
const opts = command.optsWithGlobals();
|
|
569
|
+
// Parse JSON input
|
|
570
|
+
let data;
|
|
571
|
+
try {
|
|
572
|
+
data = JSON.parse(options.json);
|
|
573
|
+
}
|
|
574
|
+
catch (e) {
|
|
575
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
576
|
+
process.exit(1);
|
|
577
|
+
}
|
|
578
|
+
// Validate required fields
|
|
579
|
+
if (data.id === undefined || data.id === null) {
|
|
580
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
581
|
+
process.exit(1);
|
|
582
|
+
}
|
|
583
|
+
if (!shouldExecute('disable-cron')) {
|
|
584
|
+
console.log(formatWithOptions({
|
|
585
|
+
dryRun: true,
|
|
586
|
+
command: 'disable-cron',
|
|
587
|
+
params: { id: data.id },
|
|
588
|
+
}, opts));
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
212
591
|
const storage = await getStorage();
|
|
213
|
-
await disableCron(storage,
|
|
592
|
+
await disableCron(storage, data.id);
|
|
593
|
+
console.log(formatWithOptions({ success: true, message: `Cron job ${data.id} disabled` }, opts));
|
|
214
594
|
await storage.close();
|
|
215
595
|
});
|
|
216
596
|
program
|
|
217
597
|
.command('cron-history')
|
|
218
598
|
.description('Get cron job execution history')
|
|
219
|
-
.requiredOption('
|
|
220
|
-
.option('-l, --limit <limit>', 'Number of history entries to show', '10')
|
|
599
|
+
.requiredOption('--json <json>', 'Full JSON payload with id and optional limit fields')
|
|
221
600
|
.action(async (options, command) => {
|
|
222
|
-
const
|
|
601
|
+
const opts = command.optsWithGlobals();
|
|
602
|
+
// Parse JSON input
|
|
603
|
+
let data;
|
|
604
|
+
try {
|
|
605
|
+
data = JSON.parse(options.json);
|
|
606
|
+
}
|
|
607
|
+
catch (e) {
|
|
608
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
609
|
+
process.exit(1);
|
|
610
|
+
}
|
|
611
|
+
// Validate required fields
|
|
612
|
+
if (data.id === undefined || data.id === null) {
|
|
613
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
614
|
+
process.exit(1);
|
|
615
|
+
}
|
|
616
|
+
const limit = data.limit ?? 10;
|
|
223
617
|
const storage = await getStorage();
|
|
224
|
-
await cronHistory(storage,
|
|
618
|
+
const history = await cronHistory(storage, data.id, limit);
|
|
619
|
+
console.log(formatWithOptions(history, opts));
|
|
225
620
|
await storage.close();
|
|
226
621
|
});
|
|
227
622
|
program
|
|
228
623
|
.command('check-cron-jobs')
|
|
229
624
|
.description('Check if there are any active cron jobs for a coworker this minute')
|
|
230
|
-
.requiredOption('
|
|
625
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker field')
|
|
231
626
|
.action(async (options, command) => {
|
|
232
|
-
const
|
|
627
|
+
const opts = command.optsWithGlobals();
|
|
628
|
+
// Parse JSON input
|
|
629
|
+
let data;
|
|
630
|
+
try {
|
|
631
|
+
data = JSON.parse(options.json);
|
|
632
|
+
}
|
|
633
|
+
catch (e) {
|
|
634
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
635
|
+
process.exit(1);
|
|
636
|
+
}
|
|
637
|
+
// Validate required fields
|
|
638
|
+
if (!data.coworker) {
|
|
639
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworker' }, opts));
|
|
640
|
+
process.exit(1);
|
|
641
|
+
}
|
|
233
642
|
const storage = await getStorage();
|
|
234
|
-
await checkCronJobs(storage,
|
|
643
|
+
const result = await checkCronJobs(storage, data.coworker);
|
|
644
|
+
console.log(formatWithOptions(result, opts));
|
|
235
645
|
await storage.close();
|
|
236
646
|
});
|
|
237
647
|
program
|
|
238
648
|
.command('list-active-cron-actions')
|
|
239
649
|
.description('List all active cron actions for a specific coworker that should run this minute (for AI execution)')
|
|
240
|
-
.requiredOption('
|
|
650
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker field')
|
|
241
651
|
.action(async (options, command) => {
|
|
242
|
-
const
|
|
652
|
+
const opts = command.optsWithGlobals();
|
|
653
|
+
// Parse JSON input
|
|
654
|
+
let data;
|
|
655
|
+
try {
|
|
656
|
+
data = JSON.parse(options.json);
|
|
657
|
+
}
|
|
658
|
+
catch (e) {
|
|
659
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
660
|
+
process.exit(1);
|
|
661
|
+
}
|
|
662
|
+
// Validate required fields
|
|
663
|
+
if (!data.coworker) {
|
|
664
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworker' }, opts));
|
|
665
|
+
process.exit(1);
|
|
666
|
+
}
|
|
243
667
|
const storage = await getStorage();
|
|
244
|
-
await listActiveCronJobs(storage,
|
|
668
|
+
const jobs = await listActiveCronJobs(storage, data.coworker);
|
|
669
|
+
console.log(formatWithOptions(jobs, opts));
|
|
245
670
|
await storage.close();
|
|
246
671
|
});
|
|
247
672
|
program
|
|
248
673
|
.command('create-cron')
|
|
249
674
|
.description('Create a new cron job directly')
|
|
250
|
-
.requiredOption('
|
|
251
|
-
.requiredOption('-c, --coworker <coworker>', 'Coworker name')
|
|
252
|
-
.requiredOption('-S, --schedule <schedule>', 'Cron schedule expression')
|
|
253
|
-
.requiredOption('-t, --task <task>', 'Task to perform (action to do)')
|
|
254
|
-
.requiredOption('-N, --notify <instructions>', 'Instructions on who to notify when complete (can be names or descriptions)')
|
|
255
|
-
.requiredOption('-z, --timezone <timezone>', 'Timezone')
|
|
675
|
+
.requiredOption('--json <json>', 'Full JSON payload with name, coworker, schedule, task, notify, and timezone fields')
|
|
256
676
|
.action(async (options, command) => {
|
|
257
|
-
const
|
|
677
|
+
const opts = command.optsWithGlobals();
|
|
678
|
+
// Parse JSON input
|
|
679
|
+
let data;
|
|
680
|
+
try {
|
|
681
|
+
data = JSON.parse(options.json);
|
|
682
|
+
}
|
|
683
|
+
catch (e) {
|
|
684
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
685
|
+
process.exit(1);
|
|
686
|
+
}
|
|
687
|
+
// Validate required fields
|
|
688
|
+
if (!data.name) {
|
|
689
|
+
console.log(formatWithOptions({ error: 'Missing required field: name' }, opts));
|
|
690
|
+
process.exit(1);
|
|
691
|
+
}
|
|
692
|
+
if (!data.coworker) {
|
|
693
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworker' }, opts));
|
|
694
|
+
process.exit(1);
|
|
695
|
+
}
|
|
696
|
+
if (!data.schedule) {
|
|
697
|
+
console.log(formatWithOptions({ error: 'Missing required field: schedule' }, opts));
|
|
698
|
+
process.exit(1);
|
|
699
|
+
}
|
|
700
|
+
if (!data.task) {
|
|
701
|
+
console.log(formatWithOptions({ error: 'Missing required field: task' }, opts));
|
|
702
|
+
process.exit(1);
|
|
703
|
+
}
|
|
704
|
+
if (!data.notify) {
|
|
705
|
+
console.log(formatWithOptions({ error: 'Missing required field: notify' }, opts));
|
|
706
|
+
process.exit(1);
|
|
707
|
+
}
|
|
708
|
+
if (!data.timezone) {
|
|
709
|
+
console.log(formatWithOptions({ error: 'Missing required field: timezone' }, opts));
|
|
710
|
+
process.exit(1);
|
|
711
|
+
}
|
|
712
|
+
if (!shouldExecute('create-cron')) {
|
|
713
|
+
console.log(formatWithOptions({
|
|
714
|
+
dryRun: true,
|
|
715
|
+
command: 'create-cron',
|
|
716
|
+
params: {
|
|
717
|
+
name: data.name,
|
|
718
|
+
coworker: data.coworker,
|
|
719
|
+
schedule: data.schedule,
|
|
720
|
+
task: data.task,
|
|
721
|
+
notify: data.notify,
|
|
722
|
+
timezone: data.timezone,
|
|
723
|
+
},
|
|
724
|
+
}, opts));
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
258
727
|
const storage = await getStorage();
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
728
|
+
const message = `Action To Do:\n${data.task}\n\nWho To Notify When Complete:\n${data.notify}`;
|
|
729
|
+
const cron = await createCron(storage, data.name, data.coworker, data.schedule, message, data.timezone);
|
|
730
|
+
console.log(formatWithOptions(cron, opts));
|
|
262
731
|
await storage.close();
|
|
263
732
|
});
|
|
264
|
-
// Cron request management commands
|
|
733
|
+
// Cron request management commands
|
|
265
734
|
program
|
|
266
735
|
.command('list-cron-requests')
|
|
267
736
|
.description('List all cron job requests')
|
|
268
737
|
.action(async (_args, command) => {
|
|
269
|
-
const
|
|
738
|
+
const opts = command.optsWithGlobals();
|
|
270
739
|
const storage = await getStorage();
|
|
271
|
-
await listCronRequests(storage
|
|
740
|
+
const requests = await listCronRequests(storage);
|
|
741
|
+
console.log(formatWithOptions(requests, opts));
|
|
272
742
|
await storage.close();
|
|
273
743
|
});
|
|
274
744
|
program
|
|
275
745
|
.command('request-cron')
|
|
276
746
|
.description('Create a new cron job request (requires approval)')
|
|
277
|
-
.requiredOption('
|
|
278
|
-
.requiredOption('-c, --coworker <coworker>', 'Coworker name')
|
|
279
|
-
.requiredOption('-S, --schedule <schedule>', 'Cron schedule expression')
|
|
280
|
-
.requiredOption('-t, --task <task>', 'Task to perform (action to do)')
|
|
281
|
-
.requiredOption('-N, --notify <instructions>', 'Instructions on who to notify when complete (can be names or descriptions)')
|
|
282
|
-
.requiredOption('-z, --timezone <timezone>', 'Timezone')
|
|
747
|
+
.requiredOption('--json <json>', 'Full JSON payload with name, coworker, schedule, task, notify, and timezone fields')
|
|
283
748
|
.action(async (options, command) => {
|
|
284
|
-
const
|
|
749
|
+
const opts = command.optsWithGlobals();
|
|
750
|
+
// Parse JSON input
|
|
751
|
+
let data;
|
|
752
|
+
try {
|
|
753
|
+
data = JSON.parse(options.json);
|
|
754
|
+
}
|
|
755
|
+
catch (e) {
|
|
756
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
757
|
+
process.exit(1);
|
|
758
|
+
}
|
|
759
|
+
// Validate required fields
|
|
760
|
+
if (!data.name) {
|
|
761
|
+
console.log(formatWithOptions({ error: 'Missing required field: name' }, opts));
|
|
762
|
+
process.exit(1);
|
|
763
|
+
}
|
|
764
|
+
if (!data.coworker) {
|
|
765
|
+
console.log(formatWithOptions({ error: 'Missing required field: coworker' }, opts));
|
|
766
|
+
process.exit(1);
|
|
767
|
+
}
|
|
768
|
+
if (!data.schedule) {
|
|
769
|
+
console.log(formatWithOptions({ error: 'Missing required field: schedule' }, opts));
|
|
770
|
+
process.exit(1);
|
|
771
|
+
}
|
|
772
|
+
if (!data.task) {
|
|
773
|
+
console.log(formatWithOptions({ error: 'Missing required field: task' }, opts));
|
|
774
|
+
process.exit(1);
|
|
775
|
+
}
|
|
776
|
+
if (!data.notify) {
|
|
777
|
+
console.log(formatWithOptions({ error: 'Missing required field: notify' }, opts));
|
|
778
|
+
process.exit(1);
|
|
779
|
+
}
|
|
780
|
+
if (!data.timezone) {
|
|
781
|
+
console.log(formatWithOptions({ error: 'Missing required field: timezone' }, opts));
|
|
782
|
+
process.exit(1);
|
|
783
|
+
}
|
|
784
|
+
if (!shouldExecute('request-cron')) {
|
|
785
|
+
console.log(formatWithOptions({
|
|
786
|
+
dryRun: true,
|
|
787
|
+
command: 'request-cron',
|
|
788
|
+
params: {
|
|
789
|
+
name: data.name,
|
|
790
|
+
coworker: data.coworker,
|
|
791
|
+
schedule: data.schedule,
|
|
792
|
+
task: data.task,
|
|
793
|
+
notify: data.notify,
|
|
794
|
+
timezone: data.timezone,
|
|
795
|
+
},
|
|
796
|
+
}, opts));
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
285
799
|
const storage = await getStorage();
|
|
286
|
-
|
|
287
|
-
const
|
|
288
|
-
|
|
800
|
+
const message = `Action To Do:\n${data.task}\n\nWho To Notify When Complete:\n${data.notify}`;
|
|
801
|
+
const request = await requestCron(storage, data.name, data.coworker, data.schedule, message, data.timezone);
|
|
802
|
+
console.log(formatWithOptions(request, opts));
|
|
289
803
|
await storage.close();
|
|
290
804
|
});
|
|
291
805
|
program
|
|
292
806
|
.command('get-cron-request')
|
|
293
807
|
.description('Get details of a cron job request')
|
|
294
|
-
.requiredOption('
|
|
808
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
295
809
|
.action(async (options, command) => {
|
|
296
|
-
const
|
|
810
|
+
const opts = command.optsWithGlobals();
|
|
811
|
+
// Parse JSON input
|
|
812
|
+
let data;
|
|
813
|
+
try {
|
|
814
|
+
data = JSON.parse(options.json);
|
|
815
|
+
}
|
|
816
|
+
catch (e) {
|
|
817
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
818
|
+
process.exit(1);
|
|
819
|
+
}
|
|
820
|
+
// Validate required fields
|
|
821
|
+
if (data.id === undefined || data.id === null) {
|
|
822
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
823
|
+
process.exit(1);
|
|
824
|
+
}
|
|
297
825
|
const storage = await getStorage();
|
|
298
|
-
await getCronRequest(storage,
|
|
826
|
+
const request = await getCronRequest(storage, data.id);
|
|
827
|
+
console.log(formatWithOptions(request, opts));
|
|
299
828
|
await storage.close();
|
|
300
829
|
});
|
|
301
830
|
program
|
|
302
831
|
.command('approve-cron-request')
|
|
303
832
|
.description('Approve a pending cron job request')
|
|
304
|
-
.requiredOption('
|
|
305
|
-
.requiredOption('-r, --reviewer <name>', 'Name of the reviewer')
|
|
306
|
-
.option('-n, --notes <notes>', 'Optional reviewer notes')
|
|
833
|
+
.requiredOption('--json <json>', 'Full JSON payload with id, reviewer, and optional notes fields')
|
|
307
834
|
.action(async (options, command) => {
|
|
308
|
-
const
|
|
835
|
+
const opts = command.optsWithGlobals();
|
|
836
|
+
// Parse JSON input
|
|
837
|
+
let data;
|
|
838
|
+
try {
|
|
839
|
+
data = JSON.parse(options.json);
|
|
840
|
+
}
|
|
841
|
+
catch (e) {
|
|
842
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
843
|
+
process.exit(1);
|
|
844
|
+
}
|
|
845
|
+
// Validate required fields
|
|
846
|
+
if (data.id === undefined || data.id === null) {
|
|
847
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
848
|
+
process.exit(1);
|
|
849
|
+
}
|
|
850
|
+
if (!data.reviewer) {
|
|
851
|
+
console.log(formatWithOptions({ error: 'Missing required field: reviewer' }, opts));
|
|
852
|
+
process.exit(1);
|
|
853
|
+
}
|
|
854
|
+
if (!shouldExecute('approve-cron-request')) {
|
|
855
|
+
console.log(formatWithOptions({
|
|
856
|
+
dryRun: true,
|
|
857
|
+
command: 'approve-cron-request',
|
|
858
|
+
params: { id: data.id, reviewer: data.reviewer, notes: data.notes },
|
|
859
|
+
}, opts));
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
309
862
|
const storage = await getStorage();
|
|
310
|
-
await approveCronRequest(storage,
|
|
863
|
+
const result = await approveCronRequest(storage, data.id, data.reviewer, data.notes);
|
|
864
|
+
console.log(formatWithOptions(result, opts));
|
|
311
865
|
await storage.close();
|
|
312
866
|
});
|
|
313
867
|
program
|
|
314
868
|
.command('reject-cron-request')
|
|
315
869
|
.description('Reject a pending cron job request')
|
|
316
|
-
.requiredOption('
|
|
317
|
-
.requiredOption('-r, --reviewer <name>', 'Name of the reviewer')
|
|
318
|
-
.option('-n, --notes <notes>', 'Optional reviewer notes')
|
|
870
|
+
.requiredOption('--json <json>', 'Full JSON payload with id, reviewer, and optional notes fields')
|
|
319
871
|
.action(async (options, command) => {
|
|
320
|
-
const
|
|
872
|
+
const opts = command.optsWithGlobals();
|
|
873
|
+
// Parse JSON input
|
|
874
|
+
let data;
|
|
875
|
+
try {
|
|
876
|
+
data = JSON.parse(options.json);
|
|
877
|
+
}
|
|
878
|
+
catch (e) {
|
|
879
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
880
|
+
process.exit(1);
|
|
881
|
+
}
|
|
882
|
+
// Validate required fields
|
|
883
|
+
if (data.id === undefined || data.id === null) {
|
|
884
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
885
|
+
process.exit(1);
|
|
886
|
+
}
|
|
887
|
+
if (!data.reviewer) {
|
|
888
|
+
console.log(formatWithOptions({ error: 'Missing required field: reviewer' }, opts));
|
|
889
|
+
process.exit(1);
|
|
890
|
+
}
|
|
891
|
+
if (!shouldExecute('reject-cron-request')) {
|
|
892
|
+
console.log(formatWithOptions({
|
|
893
|
+
dryRun: true,
|
|
894
|
+
command: 'reject-cron-request',
|
|
895
|
+
params: { id: data.id, reviewer: data.reviewer, notes: data.notes },
|
|
896
|
+
}, opts));
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
321
899
|
const storage = await getStorage();
|
|
322
|
-
await rejectCronRequest(storage,
|
|
900
|
+
const result = await rejectCronRequest(storage, data.id, data.reviewer, data.notes);
|
|
901
|
+
console.log(formatWithOptions(result, opts));
|
|
323
902
|
await storage.close();
|
|
324
903
|
});
|
|
325
904
|
program
|
|
326
905
|
.command('delete-cron-request')
|
|
327
906
|
.description('Delete a cron job request')
|
|
328
|
-
.requiredOption('
|
|
907
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
329
908
|
.action(async (options, command) => {
|
|
330
|
-
const
|
|
909
|
+
const opts = command.optsWithGlobals();
|
|
910
|
+
// Parse JSON input
|
|
911
|
+
let data;
|
|
912
|
+
try {
|
|
913
|
+
data = JSON.parse(options.json);
|
|
914
|
+
}
|
|
915
|
+
catch (e) {
|
|
916
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
917
|
+
process.exit(1);
|
|
918
|
+
}
|
|
919
|
+
// Validate required fields
|
|
920
|
+
if (data.id === undefined || data.id === null) {
|
|
921
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
922
|
+
process.exit(1);
|
|
923
|
+
}
|
|
924
|
+
if (!shouldExecute('delete-cron-request')) {
|
|
925
|
+
console.log(formatWithOptions({
|
|
926
|
+
dryRun: true,
|
|
927
|
+
command: 'delete-cron-request',
|
|
928
|
+
params: { id: data.id },
|
|
929
|
+
}, opts));
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
331
932
|
const storage = await getStorage();
|
|
332
|
-
await deleteCronRequest(storage,
|
|
933
|
+
await deleteCronRequest(storage, data.id);
|
|
934
|
+
console.log(formatWithOptions({ success: true, message: `Cron request ${data.id} deleted` }, opts));
|
|
333
935
|
await storage.close();
|
|
334
936
|
});
|
|
335
937
|
// Task board commands
|
|
336
938
|
program
|
|
337
939
|
.command('add-task')
|
|
338
940
|
.description('Create a new task')
|
|
339
|
-
.requiredOption('
|
|
340
|
-
.option('-d, --description <desc>', 'Task description', '')
|
|
341
|
-
.option('-a, --assignee <assignee>', 'Task assignee')
|
|
342
|
-
.requiredOption('-c, --column <column>', 'Initial column (idea, approved idea, working on, blocked, ready for review, done)')
|
|
343
|
-
.option('--dependencies <deps...>', 'Task dependency IDs', [])
|
|
941
|
+
.requiredOption('--json <json>', 'Full JSON payload with title, column, and optional fields')
|
|
344
942
|
.action(async (options, command) => {
|
|
345
|
-
const
|
|
943
|
+
const opts = command.optsWithGlobals();
|
|
944
|
+
// Parse JSON input
|
|
945
|
+
let data;
|
|
946
|
+
try {
|
|
947
|
+
data = JSON.parse(options.json);
|
|
948
|
+
}
|
|
949
|
+
catch (e) {
|
|
950
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
951
|
+
process.exit(1);
|
|
952
|
+
}
|
|
953
|
+
// Validate required fields
|
|
954
|
+
if (!data.title) {
|
|
955
|
+
console.log(formatWithOptions({ error: 'Missing required field: title' }, opts));
|
|
956
|
+
process.exit(1);
|
|
957
|
+
}
|
|
958
|
+
if (!data.column) {
|
|
959
|
+
console.log(formatWithOptions({ error: 'Missing required field: column' }, opts));
|
|
960
|
+
process.exit(1);
|
|
961
|
+
}
|
|
962
|
+
if (!shouldExecute('add-task')) {
|
|
963
|
+
console.log(formatWithOptions({
|
|
964
|
+
dryRun: true,
|
|
965
|
+
command: 'add-task',
|
|
966
|
+
params: {
|
|
967
|
+
title: data.title,
|
|
968
|
+
description: data.description,
|
|
969
|
+
assignee: data.assignee,
|
|
970
|
+
column: data.column,
|
|
971
|
+
dependencies: data.dependencies,
|
|
972
|
+
},
|
|
973
|
+
}, opts));
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
346
976
|
const storage = await getStorage();
|
|
347
|
-
const deps =
|
|
348
|
-
await addTask(storage,
|
|
977
|
+
const deps = data.dependencies || [];
|
|
978
|
+
const task = await addTask(storage, data.title, data.description || '', data.assignee || null, data.column, deps);
|
|
979
|
+
console.log(formatWithOptions(task, opts));
|
|
349
980
|
await storage.close();
|
|
350
981
|
});
|
|
351
982
|
program
|
|
352
983
|
.command('list-tasks')
|
|
353
984
|
.description('List all tasks')
|
|
354
|
-
.option('
|
|
355
|
-
.option('-c, --column <column>', 'Filter by column')
|
|
356
|
-
.option('-s, --search <query>', 'Search in title and description')
|
|
985
|
+
.option('--json <json>', 'Full JSON payload with optional assignee, column, and search fields')
|
|
357
986
|
.action(async (options, command) => {
|
|
358
|
-
const
|
|
987
|
+
const opts = command.optsWithGlobals();
|
|
988
|
+
// Parse JSON input if provided
|
|
989
|
+
let data = {};
|
|
990
|
+
if (options.json) {
|
|
991
|
+
try {
|
|
992
|
+
data = JSON.parse(options.json);
|
|
993
|
+
}
|
|
994
|
+
catch (e) {
|
|
995
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
996
|
+
process.exit(1);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
359
999
|
const storage = await getStorage();
|
|
360
|
-
await listTasks(storage,
|
|
1000
|
+
const tasks = await listTasks(storage, data.assignee, data.column, data.search);
|
|
1001
|
+
console.log(formatWithOptions(tasks, opts));
|
|
361
1002
|
await storage.close();
|
|
362
1003
|
});
|
|
363
1004
|
program
|
|
364
1005
|
.command('get-task')
|
|
365
1006
|
.description('Get a task by ID')
|
|
366
|
-
.requiredOption('
|
|
1007
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
367
1008
|
.action(async (options, command) => {
|
|
368
|
-
const
|
|
1009
|
+
const opts = command.optsWithGlobals();
|
|
1010
|
+
// Parse JSON input
|
|
1011
|
+
let data;
|
|
1012
|
+
try {
|
|
1013
|
+
data = JSON.parse(options.json);
|
|
1014
|
+
}
|
|
1015
|
+
catch (e) {
|
|
1016
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
1017
|
+
process.exit(1);
|
|
1018
|
+
}
|
|
1019
|
+
// Validate required fields
|
|
1020
|
+
if (data.id === undefined || data.id === null) {
|
|
1021
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
1022
|
+
process.exit(1);
|
|
1023
|
+
}
|
|
369
1024
|
const storage = await getStorage();
|
|
370
|
-
await getTask(storage,
|
|
1025
|
+
const task = await getTask(storage, data.id);
|
|
1026
|
+
console.log(formatWithOptions(task, opts));
|
|
371
1027
|
await storage.close();
|
|
372
1028
|
});
|
|
373
1029
|
program
|
|
374
1030
|
.command('update-task')
|
|
375
1031
|
.description('Update a task')
|
|
376
|
-
.requiredOption('
|
|
377
|
-
.option('-t, --title <title>', 'New title')
|
|
378
|
-
.option('-d, --description <desc>', 'New description')
|
|
379
|
-
.option('-a, --assignee <assignee>', 'New assignee')
|
|
380
|
-
.option('-c, --column <column>', 'New column')
|
|
381
|
-
.option('--dependencies <deps...>', 'New dependency IDs')
|
|
1032
|
+
.requiredOption('--json <json>', 'Full JSON payload with id and optional fields')
|
|
382
1033
|
.action(async (options, command) => {
|
|
383
|
-
const
|
|
1034
|
+
const opts = command.optsWithGlobals();
|
|
1035
|
+
// Parse JSON input
|
|
1036
|
+
let data;
|
|
1037
|
+
try {
|
|
1038
|
+
data = JSON.parse(options.json);
|
|
1039
|
+
}
|
|
1040
|
+
catch (e) {
|
|
1041
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
1042
|
+
process.exit(1);
|
|
1043
|
+
}
|
|
1044
|
+
// Validate required fields
|
|
1045
|
+
if (data.id === undefined || data.id === null) {
|
|
1046
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
1047
|
+
process.exit(1);
|
|
1048
|
+
}
|
|
1049
|
+
if (!shouldExecute('update-task')) {
|
|
1050
|
+
console.log(formatWithOptions({
|
|
1051
|
+
dryRun: true,
|
|
1052
|
+
command: 'update-task',
|
|
1053
|
+
params: {
|
|
1054
|
+
id: data.id,
|
|
1055
|
+
title: data.title,
|
|
1056
|
+
description: data.description,
|
|
1057
|
+
assignee: data.assignee,
|
|
1058
|
+
column: data.column,
|
|
1059
|
+
dependencies: data.dependencies,
|
|
1060
|
+
},
|
|
1061
|
+
}, opts));
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
384
1064
|
const storage = await getStorage();
|
|
385
|
-
const deps =
|
|
386
|
-
await updateTask(storage,
|
|
1065
|
+
const deps = data.dependencies;
|
|
1066
|
+
const task = await updateTask(storage, data.id, data.title, data.description, data.assignee, data.column, deps);
|
|
1067
|
+
console.log(formatWithOptions(task, opts));
|
|
387
1068
|
await storage.close();
|
|
388
1069
|
});
|
|
389
1070
|
program
|
|
390
1071
|
.command('delete-task')
|
|
391
1072
|
.description('Delete a task')
|
|
392
|
-
.requiredOption('
|
|
1073
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
393
1074
|
.action(async (options, command) => {
|
|
394
|
-
const
|
|
1075
|
+
const opts = command.optsWithGlobals();
|
|
1076
|
+
// Parse JSON input
|
|
1077
|
+
let data;
|
|
1078
|
+
try {
|
|
1079
|
+
data = JSON.parse(options.json);
|
|
1080
|
+
}
|
|
1081
|
+
catch (e) {
|
|
1082
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
1083
|
+
process.exit(1);
|
|
1084
|
+
}
|
|
1085
|
+
// Validate required fields
|
|
1086
|
+
if (data.id === undefined || data.id === null) {
|
|
1087
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
1088
|
+
process.exit(1);
|
|
1089
|
+
}
|
|
1090
|
+
if (!shouldExecute('delete-task')) {
|
|
1091
|
+
console.log(formatWithOptions({
|
|
1092
|
+
dryRun: true,
|
|
1093
|
+
command: 'delete-task',
|
|
1094
|
+
params: { id: data.id },
|
|
1095
|
+
}, opts));
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
395
1098
|
const storage = await getStorage();
|
|
396
|
-
await deleteTask(storage,
|
|
1099
|
+
await deleteTask(storage, data.id);
|
|
1100
|
+
console.log(formatWithOptions({ success: true, message: `Task ${data.id} deleted` }, opts));
|
|
397
1101
|
await storage.close();
|
|
398
1102
|
});
|
|
399
1103
|
program
|
|
400
1104
|
.command('assign-task')
|
|
401
1105
|
.description('Assign a task to someone')
|
|
402
|
-
.requiredOption('
|
|
403
|
-
.requiredOption('-a, --assignee <assignee>', 'Assignee name')
|
|
1106
|
+
.requiredOption('--json <json>', 'Full JSON payload with id and assignee fields')
|
|
404
1107
|
.action(async (options, command) => {
|
|
405
|
-
const
|
|
1108
|
+
const opts = command.optsWithGlobals();
|
|
1109
|
+
// Parse JSON input
|
|
1110
|
+
let data;
|
|
1111
|
+
try {
|
|
1112
|
+
data = JSON.parse(options.json);
|
|
1113
|
+
}
|
|
1114
|
+
catch (e) {
|
|
1115
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
1116
|
+
process.exit(1);
|
|
1117
|
+
}
|
|
1118
|
+
// Validate required fields
|
|
1119
|
+
if (data.id === undefined || data.id === null) {
|
|
1120
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
1121
|
+
process.exit(1);
|
|
1122
|
+
}
|
|
1123
|
+
if (!data.assignee) {
|
|
1124
|
+
console.log(formatWithOptions({ error: 'Missing required field: assignee' }, opts));
|
|
1125
|
+
process.exit(1);
|
|
1126
|
+
}
|
|
1127
|
+
if (!shouldExecute('assign-task')) {
|
|
1128
|
+
console.log(formatWithOptions({
|
|
1129
|
+
dryRun: true,
|
|
1130
|
+
command: 'assign-task',
|
|
1131
|
+
params: { id: data.id, assignee: data.assignee },
|
|
1132
|
+
}, opts));
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
406
1135
|
const storage = await getStorage();
|
|
407
|
-
await assignTask(storage,
|
|
1136
|
+
const task = await assignTask(storage, data.id, data.assignee);
|
|
1137
|
+
console.log(formatWithOptions(task, opts));
|
|
408
1138
|
await storage.close();
|
|
409
1139
|
});
|
|
410
1140
|
program
|
|
411
1141
|
.command('unassign-task')
|
|
412
1142
|
.description('Remove assignment from a task')
|
|
413
|
-
.requiredOption('
|
|
1143
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
414
1144
|
.action(async (options, command) => {
|
|
415
|
-
const
|
|
1145
|
+
const opts = command.optsWithGlobals();
|
|
1146
|
+
// Parse JSON input
|
|
1147
|
+
let data;
|
|
1148
|
+
try {
|
|
1149
|
+
data = JSON.parse(options.json);
|
|
1150
|
+
}
|
|
1151
|
+
catch (e) {
|
|
1152
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
1153
|
+
process.exit(1);
|
|
1154
|
+
}
|
|
1155
|
+
// Validate required fields
|
|
1156
|
+
if (data.id === undefined || data.id === null) {
|
|
1157
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
1158
|
+
process.exit(1);
|
|
1159
|
+
}
|
|
1160
|
+
if (!shouldExecute('unassign-task')) {
|
|
1161
|
+
console.log(formatWithOptions({
|
|
1162
|
+
dryRun: true,
|
|
1163
|
+
command: 'unassign-task',
|
|
1164
|
+
params: { id: data.id },
|
|
1165
|
+
}, opts));
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
416
1168
|
const storage = await getStorage();
|
|
417
|
-
await unassignTask(storage,
|
|
1169
|
+
const task = await unassignTask(storage, data.id);
|
|
1170
|
+
console.log(formatWithOptions(task, opts));
|
|
418
1171
|
await storage.close();
|
|
419
1172
|
});
|
|
420
1173
|
program
|
|
421
1174
|
.command('move-task')
|
|
422
1175
|
.description('Move a task to a different column')
|
|
423
|
-
.requiredOption('
|
|
424
|
-
.requiredOption('-c, --column <column>', 'Target column')
|
|
1176
|
+
.requiredOption('--json <json>', 'Full JSON payload with id and column fields')
|
|
425
1177
|
.action(async (options, command) => {
|
|
426
|
-
const
|
|
1178
|
+
const opts = command.optsWithGlobals();
|
|
1179
|
+
// Parse JSON input
|
|
1180
|
+
let data;
|
|
1181
|
+
try {
|
|
1182
|
+
data = JSON.parse(options.json);
|
|
1183
|
+
}
|
|
1184
|
+
catch (e) {
|
|
1185
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
1186
|
+
process.exit(1);
|
|
1187
|
+
}
|
|
1188
|
+
// Validate required fields
|
|
1189
|
+
if (data.id === undefined || data.id === null) {
|
|
1190
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
1191
|
+
process.exit(1);
|
|
1192
|
+
}
|
|
1193
|
+
if (!data.column) {
|
|
1194
|
+
console.log(formatWithOptions({ error: 'Missing required field: column' }, opts));
|
|
1195
|
+
process.exit(1);
|
|
1196
|
+
}
|
|
1197
|
+
if (!shouldExecute('move-task')) {
|
|
1198
|
+
console.log(formatWithOptions({
|
|
1199
|
+
dryRun: true,
|
|
1200
|
+
command: 'move-task',
|
|
1201
|
+
params: { id: data.id, column: data.column },
|
|
1202
|
+
}, opts));
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
427
1205
|
const storage = await getStorage();
|
|
428
|
-
await moveTask(storage,
|
|
1206
|
+
const task = await moveTask(storage, data.id, data.column);
|
|
1207
|
+
console.log(formatWithOptions(task, opts));
|
|
429
1208
|
await storage.close();
|
|
430
1209
|
});
|
|
431
1210
|
program
|
|
432
1211
|
.command('task-stats')
|
|
433
1212
|
.description('Show task statistics by column')
|
|
434
1213
|
.action(async (_args, command) => {
|
|
435
|
-
const
|
|
1214
|
+
const opts = command.optsWithGlobals();
|
|
436
1215
|
const storage = await getStorage();
|
|
437
|
-
await taskStats(storage
|
|
1216
|
+
const stats = await taskStats(storage);
|
|
1217
|
+
console.log(formatWithOptions(stats, opts));
|
|
438
1218
|
await storage.close();
|
|
439
1219
|
});
|
|
440
1220
|
program
|
|
441
1221
|
.command('task-history')
|
|
442
1222
|
.description('Show column transition history for a task with durations')
|
|
443
|
-
.requiredOption('
|
|
1223
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
444
1224
|
.action(async (options, command) => {
|
|
445
|
-
const
|
|
1225
|
+
const opts = command.optsWithGlobals();
|
|
1226
|
+
// Parse JSON input
|
|
1227
|
+
let data;
|
|
1228
|
+
try {
|
|
1229
|
+
data = JSON.parse(options.json);
|
|
1230
|
+
}
|
|
1231
|
+
catch (e) {
|
|
1232
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
1233
|
+
process.exit(1);
|
|
1234
|
+
}
|
|
1235
|
+
// Validate required fields
|
|
1236
|
+
if (data.id === undefined || data.id === null) {
|
|
1237
|
+
console.log(formatWithOptions({ error: 'Missing required field: id' }, opts));
|
|
1238
|
+
process.exit(1);
|
|
1239
|
+
}
|
|
446
1240
|
const storage = await getStorage();
|
|
447
|
-
await getTaskHistory(storage,
|
|
1241
|
+
const history = await getTaskHistory(storage, data.id);
|
|
1242
|
+
console.log(formatWithOptions(history, opts));
|
|
448
1243
|
await storage.close();
|
|
449
1244
|
});
|
|
450
1245
|
program
|
|
451
1246
|
.command('list-task-columns')
|
|
452
1247
|
.description('List all valid task board columns')
|
|
453
1248
|
.action(async (_args, command) => {
|
|
454
|
-
const
|
|
455
|
-
|
|
1249
|
+
const opts = command.optsWithGlobals();
|
|
1250
|
+
const columns = listTaskColumns();
|
|
1251
|
+
console.log(formatWithOptions(columns, opts));
|
|
1252
|
+
});
|
|
1253
|
+
// Skill and context commands
|
|
1254
|
+
function listSkills() {
|
|
1255
|
+
try {
|
|
1256
|
+
const skillsDir = join(__dirname, '../skills');
|
|
1257
|
+
return readdirSync(skillsDir)
|
|
1258
|
+
.filter(f => f.startsWith('SKILL-') && f.endsWith('.md'))
|
|
1259
|
+
.map(f => f.replace('SKILL-', '').replace('.md', ''));
|
|
1260
|
+
}
|
|
1261
|
+
catch {
|
|
1262
|
+
return [];
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
function getSkillContent(skillName) {
|
|
1266
|
+
try {
|
|
1267
|
+
const skillPath = join(__dirname, `../skills/SKILL-${skillName}.md`);
|
|
1268
|
+
return readFileSync(skillPath, 'utf-8');
|
|
1269
|
+
}
|
|
1270
|
+
catch {
|
|
1271
|
+
return null;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
function getContextDoc() {
|
|
1275
|
+
try {
|
|
1276
|
+
const contextPath = join(__dirname, '../CONTEXT.md');
|
|
1277
|
+
return readFileSync(contextPath, 'utf-8');
|
|
1278
|
+
}
|
|
1279
|
+
catch {
|
|
1280
|
+
return null;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
function getAgentsDoc() {
|
|
1284
|
+
try {
|
|
1285
|
+
const agentsPath = join(__dirname, '../AGENTS.md');
|
|
1286
|
+
return readFileSync(agentsPath, 'utf-8');
|
|
1287
|
+
}
|
|
1288
|
+
catch {
|
|
1289
|
+
return null;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
program
|
|
1293
|
+
.command('list-skills')
|
|
1294
|
+
.description('List available agent skills')
|
|
1295
|
+
.action(async (_args, command) => {
|
|
1296
|
+
const opts = command.optsWithGlobals();
|
|
1297
|
+
const skills = listSkills();
|
|
1298
|
+
console.log(formatWithOptions(skills, opts));
|
|
1299
|
+
});
|
|
1300
|
+
program
|
|
1301
|
+
.command('get-skill')
|
|
1302
|
+
.description('Get the content of a specific agent skill')
|
|
1303
|
+
.requiredOption('--json <json>', 'Full JSON payload with name field')
|
|
1304
|
+
.action(async (options, command) => {
|
|
1305
|
+
const opts = command.optsWithGlobals();
|
|
1306
|
+
// Parse JSON input
|
|
1307
|
+
let data;
|
|
1308
|
+
try {
|
|
1309
|
+
data = JSON.parse(options.json);
|
|
1310
|
+
}
|
|
1311
|
+
catch (e) {
|
|
1312
|
+
console.log(formatWithOptions({ error: 'Invalid JSON in --json' }, opts));
|
|
1313
|
+
process.exit(1);
|
|
1314
|
+
}
|
|
1315
|
+
// Validate required fields
|
|
1316
|
+
if (!data.name) {
|
|
1317
|
+
console.log(formatWithOptions({ error: 'Missing required field: name' }, opts));
|
|
1318
|
+
process.exit(1);
|
|
1319
|
+
}
|
|
1320
|
+
const content = getSkillContent(data.name);
|
|
1321
|
+
if (!content) {
|
|
1322
|
+
console.log(formatWithOptions({ error: `Skill not found: ${data.name}` }, opts));
|
|
1323
|
+
process.exit(1);
|
|
1324
|
+
}
|
|
1325
|
+
console.log(content); // Output raw markdown content
|
|
1326
|
+
});
|
|
1327
|
+
program
|
|
1328
|
+
.command('context')
|
|
1329
|
+
.description('Show context window discipline guidelines')
|
|
1330
|
+
.action(async (_args, command) => {
|
|
1331
|
+
const opts = command.optsWithGlobals();
|
|
1332
|
+
const content = getContextDoc();
|
|
1333
|
+
if (!content) {
|
|
1334
|
+
console.log(formatWithOptions({ error: 'CONTEXT.md not found' }, opts));
|
|
1335
|
+
process.exit(1);
|
|
1336
|
+
}
|
|
1337
|
+
console.log(content); // Output raw markdown content
|
|
1338
|
+
});
|
|
1339
|
+
program
|
|
1340
|
+
.command('agents')
|
|
1341
|
+
.description('Show agent security guidelines')
|
|
1342
|
+
.action(async (_args, command) => {
|
|
1343
|
+
const opts = command.optsWithGlobals();
|
|
1344
|
+
const content = getAgentsDoc();
|
|
1345
|
+
if (!content) {
|
|
1346
|
+
console.log(formatWithOptions({ error: 'AGENTS.md not found' }, opts));
|
|
1347
|
+
process.exit(1);
|
|
1348
|
+
}
|
|
1349
|
+
console.log(content); // Output raw markdown content
|
|
1350
|
+
});
|
|
1351
|
+
// MCP Server command
|
|
1352
|
+
program
|
|
1353
|
+
.command('mcp')
|
|
1354
|
+
.description('Run as an MCP (Model Context Protocol) server')
|
|
1355
|
+
.action(async () => {
|
|
1356
|
+
const server = new MCPServer();
|
|
1357
|
+
await server.processStdio();
|
|
456
1358
|
});
|
|
457
1359
|
program.parse();
|
|
458
1360
|
//# sourceMappingURL=index.js.map
|