agent-office 0.6.22 → 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 -4
- package/dist/commands/messages.d.ts.map +1 -1
- package/dist/commands/messages.js +18 -13
- 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 +1076 -153
- 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 } 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,396 +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
|
-
.
|
|
146
|
-
|
|
147
|
-
|
|
383
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker1, coworker2, and optional start/end fields')
|
|
384
|
+
.action(async (options, command) => {
|
|
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
|
+
}
|
|
404
|
+
const storage = await getStorage();
|
|
405
|
+
const messages = await listMessagesBetween(storage, data.coworker1, data.coworker2, data.start, data.end);
|
|
406
|
+
console.log(formatWithOptions(messages, opts));
|
|
407
|
+
await storage.close();
|
|
408
|
+
});
|
|
409
|
+
program
|
|
410
|
+
.command('list-messages-to-notify')
|
|
411
|
+
.description('List unread messages older than specified hours that have not been notified')
|
|
412
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker and hours fields')
|
|
413
|
+
.action(async (options, command) => {
|
|
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
|
+
}
|
|
433
|
+
const storage = await getStorage();
|
|
434
|
+
const messages = await listMessagesToNotify(storage, data.coworker, data.hours);
|
|
435
|
+
console.log(formatWithOptions(messages, opts));
|
|
436
|
+
await storage.close();
|
|
437
|
+
});
|
|
438
|
+
program
|
|
439
|
+
.command('mark-messages-as-notified')
|
|
440
|
+
.description('Mark specific messages as notified')
|
|
441
|
+
.requiredOption('--json <json>', 'Full JSON payload with ids array')
|
|
148
442
|
.action(async (options, command) => {
|
|
149
|
-
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
|
+
}
|
|
150
466
|
const storage = await getStorage();
|
|
151
|
-
await
|
|
467
|
+
await markMessagesAsNotified(storage, data.ids);
|
|
468
|
+
console.log(formatWithOptions({ success: true, marked: data.ids.length }, opts));
|
|
152
469
|
await storage.close();
|
|
153
470
|
});
|
|
154
471
|
// Cron commands
|
|
155
472
|
program
|
|
156
473
|
.command('list-crons')
|
|
157
474
|
.description('List all cron jobs for a specific coworker')
|
|
158
|
-
.requiredOption('
|
|
475
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker field')
|
|
159
476
|
.action(async (options, command) => {
|
|
160
|
-
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
|
+
}
|
|
161
492
|
const storage = await getStorage();
|
|
162
|
-
await listCrons(storage,
|
|
493
|
+
const crons = await listCrons(storage, data.coworker);
|
|
494
|
+
console.log(formatWithOptions(crons, opts));
|
|
163
495
|
await storage.close();
|
|
164
496
|
});
|
|
165
497
|
program
|
|
166
498
|
.command('delete-cron')
|
|
167
499
|
.description('Delete a cron job')
|
|
168
|
-
.requiredOption('
|
|
500
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
169
501
|
.action(async (options, command) => {
|
|
170
|
-
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
|
+
}
|
|
171
525
|
const storage = await getStorage();
|
|
172
|
-
await deleteCron(storage,
|
|
526
|
+
await deleteCron(storage, data.id);
|
|
527
|
+
console.log(formatWithOptions({ success: true, message: `Cron job ${data.id} deleted` }, opts));
|
|
173
528
|
await storage.close();
|
|
174
529
|
});
|
|
175
530
|
program
|
|
176
531
|
.command('enable-cron')
|
|
177
532
|
.description('Enable a cron job')
|
|
178
|
-
.requiredOption('
|
|
533
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
179
534
|
.action(async (options, command) => {
|
|
180
|
-
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
|
+
}
|
|
181
558
|
const storage = await getStorage();
|
|
182
|
-
await enableCron(storage,
|
|
559
|
+
await enableCron(storage, data.id);
|
|
560
|
+
console.log(formatWithOptions({ success: true, message: `Cron job ${data.id} enabled` }, opts));
|
|
183
561
|
await storage.close();
|
|
184
562
|
});
|
|
185
563
|
program
|
|
186
564
|
.command('disable-cron')
|
|
187
565
|
.description('Disable a cron job')
|
|
188
|
-
.requiredOption('
|
|
566
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
189
567
|
.action(async (options, command) => {
|
|
190
|
-
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
|
+
}
|
|
191
591
|
const storage = await getStorage();
|
|
192
|
-
await disableCron(storage,
|
|
592
|
+
await disableCron(storage, data.id);
|
|
593
|
+
console.log(formatWithOptions({ success: true, message: `Cron job ${data.id} disabled` }, opts));
|
|
193
594
|
await storage.close();
|
|
194
595
|
});
|
|
195
596
|
program
|
|
196
597
|
.command('cron-history')
|
|
197
598
|
.description('Get cron job execution history')
|
|
198
|
-
.requiredOption('
|
|
199
|
-
.option('-l, --limit <limit>', 'Number of history entries to show', '10')
|
|
599
|
+
.requiredOption('--json <json>', 'Full JSON payload with id and optional limit fields')
|
|
200
600
|
.action(async (options, command) => {
|
|
201
|
-
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;
|
|
202
617
|
const storage = await getStorage();
|
|
203
|
-
await cronHistory(storage,
|
|
618
|
+
const history = await cronHistory(storage, data.id, limit);
|
|
619
|
+
console.log(formatWithOptions(history, opts));
|
|
204
620
|
await storage.close();
|
|
205
621
|
});
|
|
206
622
|
program
|
|
207
623
|
.command('check-cron-jobs')
|
|
208
624
|
.description('Check if there are any active cron jobs for a coworker this minute')
|
|
209
|
-
.requiredOption('
|
|
625
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker field')
|
|
210
626
|
.action(async (options, command) => {
|
|
211
|
-
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
|
+
}
|
|
212
642
|
const storage = await getStorage();
|
|
213
|
-
await checkCronJobs(storage,
|
|
643
|
+
const result = await checkCronJobs(storage, data.coworker);
|
|
644
|
+
console.log(formatWithOptions(result, opts));
|
|
214
645
|
await storage.close();
|
|
215
646
|
});
|
|
216
647
|
program
|
|
217
648
|
.command('list-active-cron-actions')
|
|
218
649
|
.description('List all active cron actions for a specific coworker that should run this minute (for AI execution)')
|
|
219
|
-
.requiredOption('
|
|
650
|
+
.requiredOption('--json <json>', 'Full JSON payload with coworker field')
|
|
220
651
|
.action(async (options, command) => {
|
|
221
|
-
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
|
+
}
|
|
222
667
|
const storage = await getStorage();
|
|
223
|
-
await listActiveCronJobs(storage,
|
|
668
|
+
const jobs = await listActiveCronJobs(storage, data.coworker);
|
|
669
|
+
console.log(formatWithOptions(jobs, opts));
|
|
224
670
|
await storage.close();
|
|
225
671
|
});
|
|
226
672
|
program
|
|
227
673
|
.command('create-cron')
|
|
228
674
|
.description('Create a new cron job directly')
|
|
229
|
-
.requiredOption('
|
|
230
|
-
.requiredOption('-c, --coworker <coworker>', 'Coworker name')
|
|
231
|
-
.requiredOption('-S, --schedule <schedule>', 'Cron schedule expression')
|
|
232
|
-
.requiredOption('-t, --task <task>', 'Task to perform (action to do)')
|
|
233
|
-
.requiredOption('-N, --notify <instructions>', 'Instructions on who to notify when complete (can be names or descriptions)')
|
|
234
|
-
.requiredOption('-z, --timezone <timezone>', 'Timezone')
|
|
675
|
+
.requiredOption('--json <json>', 'Full JSON payload with name, coworker, schedule, task, notify, and timezone fields')
|
|
235
676
|
.action(async (options, command) => {
|
|
236
|
-
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
|
+
}
|
|
237
727
|
const storage = await getStorage();
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
|
|
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));
|
|
241
731
|
await storage.close();
|
|
242
732
|
});
|
|
243
|
-
// Cron request management commands
|
|
733
|
+
// Cron request management commands
|
|
244
734
|
program
|
|
245
735
|
.command('list-cron-requests')
|
|
246
736
|
.description('List all cron job requests')
|
|
247
737
|
.action(async (_args, command) => {
|
|
248
|
-
const
|
|
738
|
+
const opts = command.optsWithGlobals();
|
|
249
739
|
const storage = await getStorage();
|
|
250
|
-
await listCronRequests(storage
|
|
740
|
+
const requests = await listCronRequests(storage);
|
|
741
|
+
console.log(formatWithOptions(requests, opts));
|
|
251
742
|
await storage.close();
|
|
252
743
|
});
|
|
253
744
|
program
|
|
254
745
|
.command('request-cron')
|
|
255
746
|
.description('Create a new cron job request (requires approval)')
|
|
256
|
-
.requiredOption('
|
|
257
|
-
.requiredOption('-c, --coworker <coworker>', 'Coworker name')
|
|
258
|
-
.requiredOption('-S, --schedule <schedule>', 'Cron schedule expression')
|
|
259
|
-
.requiredOption('-t, --task <task>', 'Task to perform (action to do)')
|
|
260
|
-
.requiredOption('-N, --notify <instructions>', 'Instructions on who to notify when complete (can be names or descriptions)')
|
|
261
|
-
.requiredOption('-z, --timezone <timezone>', 'Timezone')
|
|
747
|
+
.requiredOption('--json <json>', 'Full JSON payload with name, coworker, schedule, task, notify, and timezone fields')
|
|
262
748
|
.action(async (options, command) => {
|
|
263
|
-
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
|
+
}
|
|
264
799
|
const storage = await getStorage();
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
|
|
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));
|
|
268
803
|
await storage.close();
|
|
269
804
|
});
|
|
270
805
|
program
|
|
271
806
|
.command('get-cron-request')
|
|
272
807
|
.description('Get details of a cron job request')
|
|
273
|
-
.requiredOption('
|
|
808
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
274
809
|
.action(async (options, command) => {
|
|
275
|
-
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
|
+
}
|
|
276
825
|
const storage = await getStorage();
|
|
277
|
-
await getCronRequest(storage,
|
|
826
|
+
const request = await getCronRequest(storage, data.id);
|
|
827
|
+
console.log(formatWithOptions(request, opts));
|
|
278
828
|
await storage.close();
|
|
279
829
|
});
|
|
280
830
|
program
|
|
281
831
|
.command('approve-cron-request')
|
|
282
832
|
.description('Approve a pending cron job request')
|
|
283
|
-
.requiredOption('
|
|
284
|
-
.requiredOption('-r, --reviewer <name>', 'Name of the reviewer')
|
|
285
|
-
.option('-n, --notes <notes>', 'Optional reviewer notes')
|
|
833
|
+
.requiredOption('--json <json>', 'Full JSON payload with id, reviewer, and optional notes fields')
|
|
286
834
|
.action(async (options, command) => {
|
|
287
|
-
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
|
+
}
|
|
288
862
|
const storage = await getStorage();
|
|
289
|
-
await approveCronRequest(storage,
|
|
863
|
+
const result = await approveCronRequest(storage, data.id, data.reviewer, data.notes);
|
|
864
|
+
console.log(formatWithOptions(result, opts));
|
|
290
865
|
await storage.close();
|
|
291
866
|
});
|
|
292
867
|
program
|
|
293
868
|
.command('reject-cron-request')
|
|
294
869
|
.description('Reject a pending cron job request')
|
|
295
|
-
.requiredOption('
|
|
296
|
-
.requiredOption('-r, --reviewer <name>', 'Name of the reviewer')
|
|
297
|
-
.option('-n, --notes <notes>', 'Optional reviewer notes')
|
|
870
|
+
.requiredOption('--json <json>', 'Full JSON payload with id, reviewer, and optional notes fields')
|
|
298
871
|
.action(async (options, command) => {
|
|
299
|
-
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
|
+
}
|
|
300
899
|
const storage = await getStorage();
|
|
301
|
-
await rejectCronRequest(storage,
|
|
900
|
+
const result = await rejectCronRequest(storage, data.id, data.reviewer, data.notes);
|
|
901
|
+
console.log(formatWithOptions(result, opts));
|
|
302
902
|
await storage.close();
|
|
303
903
|
});
|
|
304
904
|
program
|
|
305
905
|
.command('delete-cron-request')
|
|
306
906
|
.description('Delete a cron job request')
|
|
307
|
-
.requiredOption('
|
|
907
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
308
908
|
.action(async (options, command) => {
|
|
309
|
-
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
|
+
}
|
|
310
932
|
const storage = await getStorage();
|
|
311
|
-
await deleteCronRequest(storage,
|
|
933
|
+
await deleteCronRequest(storage, data.id);
|
|
934
|
+
console.log(formatWithOptions({ success: true, message: `Cron request ${data.id} deleted` }, opts));
|
|
312
935
|
await storage.close();
|
|
313
936
|
});
|
|
314
937
|
// Task board commands
|
|
315
938
|
program
|
|
316
939
|
.command('add-task')
|
|
317
940
|
.description('Create a new task')
|
|
318
|
-
.requiredOption('
|
|
319
|
-
.option('-d, --description <desc>', 'Task description', '')
|
|
320
|
-
.option('-a, --assignee <assignee>', 'Task assignee')
|
|
321
|
-
.requiredOption('-c, --column <column>', 'Initial column (idea, approved idea, working on, blocked, ready for review, done)')
|
|
322
|
-
.option('--dependencies <deps...>', 'Task dependency IDs', [])
|
|
941
|
+
.requiredOption('--json <json>', 'Full JSON payload with title, column, and optional fields')
|
|
323
942
|
.action(async (options, command) => {
|
|
324
|
-
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
|
+
}
|
|
325
976
|
const storage = await getStorage();
|
|
326
|
-
const deps =
|
|
327
|
-
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));
|
|
328
980
|
await storage.close();
|
|
329
981
|
});
|
|
330
982
|
program
|
|
331
983
|
.command('list-tasks')
|
|
332
984
|
.description('List all tasks')
|
|
333
|
-
.option('
|
|
334
|
-
.option('-c, --column <column>', 'Filter by column')
|
|
335
|
-
.option('-s, --search <query>', 'Search in title and description')
|
|
985
|
+
.option('--json <json>', 'Full JSON payload with optional assignee, column, and search fields')
|
|
336
986
|
.action(async (options, command) => {
|
|
337
|
-
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
|
+
}
|
|
338
999
|
const storage = await getStorage();
|
|
339
|
-
await listTasks(storage,
|
|
1000
|
+
const tasks = await listTasks(storage, data.assignee, data.column, data.search);
|
|
1001
|
+
console.log(formatWithOptions(tasks, opts));
|
|
340
1002
|
await storage.close();
|
|
341
1003
|
});
|
|
342
1004
|
program
|
|
343
1005
|
.command('get-task')
|
|
344
1006
|
.description('Get a task by ID')
|
|
345
|
-
.requiredOption('
|
|
1007
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
346
1008
|
.action(async (options, command) => {
|
|
347
|
-
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
|
+
}
|
|
348
1024
|
const storage = await getStorage();
|
|
349
|
-
await getTask(storage,
|
|
1025
|
+
const task = await getTask(storage, data.id);
|
|
1026
|
+
console.log(formatWithOptions(task, opts));
|
|
350
1027
|
await storage.close();
|
|
351
1028
|
});
|
|
352
1029
|
program
|
|
353
1030
|
.command('update-task')
|
|
354
1031
|
.description('Update a task')
|
|
355
|
-
.requiredOption('
|
|
356
|
-
.option('-t, --title <title>', 'New title')
|
|
357
|
-
.option('-d, --description <desc>', 'New description')
|
|
358
|
-
.option('-a, --assignee <assignee>', 'New assignee')
|
|
359
|
-
.option('-c, --column <column>', 'New column')
|
|
360
|
-
.option('--dependencies <deps...>', 'New dependency IDs')
|
|
1032
|
+
.requiredOption('--json <json>', 'Full JSON payload with id and optional fields')
|
|
361
1033
|
.action(async (options, command) => {
|
|
362
|
-
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
|
+
}
|
|
363
1064
|
const storage = await getStorage();
|
|
364
|
-
const deps =
|
|
365
|
-
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));
|
|
366
1068
|
await storage.close();
|
|
367
1069
|
});
|
|
368
1070
|
program
|
|
369
1071
|
.command('delete-task')
|
|
370
1072
|
.description('Delete a task')
|
|
371
|
-
.requiredOption('
|
|
1073
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
372
1074
|
.action(async (options, command) => {
|
|
373
|
-
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
|
+
}
|
|
374
1098
|
const storage = await getStorage();
|
|
375
|
-
await deleteTask(storage,
|
|
1099
|
+
await deleteTask(storage, data.id);
|
|
1100
|
+
console.log(formatWithOptions({ success: true, message: `Task ${data.id} deleted` }, opts));
|
|
376
1101
|
await storage.close();
|
|
377
1102
|
});
|
|
378
1103
|
program
|
|
379
1104
|
.command('assign-task')
|
|
380
1105
|
.description('Assign a task to someone')
|
|
381
|
-
.requiredOption('
|
|
382
|
-
.requiredOption('-a, --assignee <assignee>', 'Assignee name')
|
|
1106
|
+
.requiredOption('--json <json>', 'Full JSON payload with id and assignee fields')
|
|
383
1107
|
.action(async (options, command) => {
|
|
384
|
-
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
|
+
}
|
|
385
1135
|
const storage = await getStorage();
|
|
386
|
-
await assignTask(storage,
|
|
1136
|
+
const task = await assignTask(storage, data.id, data.assignee);
|
|
1137
|
+
console.log(formatWithOptions(task, opts));
|
|
387
1138
|
await storage.close();
|
|
388
1139
|
});
|
|
389
1140
|
program
|
|
390
1141
|
.command('unassign-task')
|
|
391
1142
|
.description('Remove assignment from a task')
|
|
392
|
-
.requiredOption('
|
|
1143
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
393
1144
|
.action(async (options, command) => {
|
|
394
|
-
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
|
+
}
|
|
395
1168
|
const storage = await getStorage();
|
|
396
|
-
await unassignTask(storage,
|
|
1169
|
+
const task = await unassignTask(storage, data.id);
|
|
1170
|
+
console.log(formatWithOptions(task, opts));
|
|
397
1171
|
await storage.close();
|
|
398
1172
|
});
|
|
399
1173
|
program
|
|
400
1174
|
.command('move-task')
|
|
401
1175
|
.description('Move a task to a different column')
|
|
402
|
-
.requiredOption('
|
|
403
|
-
.requiredOption('-c, --column <column>', 'Target column')
|
|
1176
|
+
.requiredOption('--json <json>', 'Full JSON payload with id and column fields')
|
|
404
1177
|
.action(async (options, command) => {
|
|
405
|
-
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
|
+
}
|
|
406
1205
|
const storage = await getStorage();
|
|
407
|
-
await moveTask(storage,
|
|
1206
|
+
const task = await moveTask(storage, data.id, data.column);
|
|
1207
|
+
console.log(formatWithOptions(task, opts));
|
|
408
1208
|
await storage.close();
|
|
409
1209
|
});
|
|
410
1210
|
program
|
|
411
1211
|
.command('task-stats')
|
|
412
1212
|
.description('Show task statistics by column')
|
|
413
1213
|
.action(async (_args, command) => {
|
|
414
|
-
const
|
|
1214
|
+
const opts = command.optsWithGlobals();
|
|
415
1215
|
const storage = await getStorage();
|
|
416
|
-
await taskStats(storage
|
|
1216
|
+
const stats = await taskStats(storage);
|
|
1217
|
+
console.log(formatWithOptions(stats, opts));
|
|
417
1218
|
await storage.close();
|
|
418
1219
|
});
|
|
419
1220
|
program
|
|
420
1221
|
.command('task-history')
|
|
421
1222
|
.description('Show column transition history for a task with durations')
|
|
422
|
-
.requiredOption('
|
|
1223
|
+
.requiredOption('--json <json>', 'Full JSON payload with id field')
|
|
423
1224
|
.action(async (options, command) => {
|
|
424
|
-
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
|
+
}
|
|
425
1240
|
const storage = await getStorage();
|
|
426
|
-
await getTaskHistory(storage,
|
|
1241
|
+
const history = await getTaskHistory(storage, data.id);
|
|
1242
|
+
console.log(formatWithOptions(history, opts));
|
|
427
1243
|
await storage.close();
|
|
428
1244
|
});
|
|
429
1245
|
program
|
|
430
1246
|
.command('list-task-columns')
|
|
431
1247
|
.description('List all valid task board columns')
|
|
432
1248
|
.action(async (_args, command) => {
|
|
433
|
-
const
|
|
434
|
-
|
|
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();
|
|
435
1358
|
});
|
|
436
1359
|
program.parse();
|
|
437
1360
|
//# sourceMappingURL=index.js.map
|