@nookplot/cli 0.3.28 → 0.4.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/dist/commands/attest.d.ts +11 -0
- package/dist/commands/attest.js +162 -0
- package/dist/commands/attest.js.map +1 -0
- package/dist/commands/bounties.d.ts +10 -3
- package/dist/commands/bounties.js +290 -23
- package/dist/commands/bounties.js.map +1 -1
- package/dist/commands/bundles.d.ts +16 -0
- package/dist/commands/bundles.js +365 -0
- package/dist/commands/bundles.js.map +1 -0
- package/dist/commands/cliques.d.ts +16 -0
- package/dist/commands/cliques.js +401 -0
- package/dist/commands/cliques.js.map +1 -0
- package/dist/commands/online.js +66 -0
- package/dist/commands/online.js.map +1 -1
- package/dist/commands/projects.js +669 -0
- package/dist/commands/projects.js.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/http.d.ts +1 -1
- package/dist/utils/http.js.map +1 -1
- package/package.json +1 -1
|
@@ -170,6 +170,272 @@ export function registerProjectsCommand(program) {
|
|
|
170
170
|
process.exit(1);
|
|
171
171
|
}
|
|
172
172
|
});
|
|
173
|
+
// ── Wave 1: Task / Milestone / Broadcast subcommands ──
|
|
174
|
+
cmd
|
|
175
|
+
.command("tasks <projectId>")
|
|
176
|
+
.description("List tasks for a project")
|
|
177
|
+
.option("--status <s>", "Filter by status (open, in_progress, completed)")
|
|
178
|
+
.option("--priority <p>", "Filter by priority (low, medium, high, critical)")
|
|
179
|
+
.option("--assignee <addr>", "Filter by assignee address")
|
|
180
|
+
.option("--milestone <mid>", "Filter by milestone ID")
|
|
181
|
+
.action(async (projectId, opts) => {
|
|
182
|
+
try {
|
|
183
|
+
await runListTasks(program.opts(), projectId, opts);
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
187
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
cmd
|
|
192
|
+
.command("task-create <projectId>")
|
|
193
|
+
.description("Create a task in a project")
|
|
194
|
+
.requiredOption("--title <title>", "Task title")
|
|
195
|
+
.option("--description <desc>", "Task description")
|
|
196
|
+
.option("--milestone <mid>", "Milestone ID")
|
|
197
|
+
.option("--priority <p>", "Priority: low, medium, high, critical", "medium")
|
|
198
|
+
.action(async (projectId, opts) => {
|
|
199
|
+
try {
|
|
200
|
+
await runCreateTask(program.opts(), projectId, opts);
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
204
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
cmd
|
|
209
|
+
.command("task-update <projectId> <taskId>")
|
|
210
|
+
.description("Update a task (status, priority, etc.)")
|
|
211
|
+
.option("--status <s>", "Set status (open, in_progress, completed)")
|
|
212
|
+
.option("--priority <p>", "Set priority")
|
|
213
|
+
.option("--title <title>", "Set title")
|
|
214
|
+
.action(async (projectId, taskId, opts) => {
|
|
215
|
+
try {
|
|
216
|
+
await runUpdateTask(program.opts(), projectId, taskId, opts);
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
220
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
cmd
|
|
225
|
+
.command("milestones <projectId>")
|
|
226
|
+
.description("List milestones for a project")
|
|
227
|
+
.action(async (projectId) => {
|
|
228
|
+
try {
|
|
229
|
+
await runListMilestones(program.opts(), projectId);
|
|
230
|
+
}
|
|
231
|
+
catch (err) {
|
|
232
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
233
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
cmd
|
|
238
|
+
.command("milestone-create <projectId>")
|
|
239
|
+
.description("Create a milestone")
|
|
240
|
+
.requiredOption("--title <title>", "Milestone title")
|
|
241
|
+
.option("--description <desc>", "Description")
|
|
242
|
+
.option("--due-date <date>", "Due date (ISO 8601)")
|
|
243
|
+
.action(async (projectId, opts) => {
|
|
244
|
+
try {
|
|
245
|
+
await runCreateMilestone(program.opts(), projectId, opts);
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
249
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
cmd
|
|
254
|
+
.command("broadcast <projectId>")
|
|
255
|
+
.description("Post a broadcast/status update in a project")
|
|
256
|
+
.requiredOption("--body <text>", "Broadcast message (supports @0xAddress mentions)")
|
|
257
|
+
.option("--type <type>", "Broadcast type (update, announcement, question)", "update")
|
|
258
|
+
.action(async (projectId, opts) => {
|
|
259
|
+
try {
|
|
260
|
+
await runBroadcast(program.opts(), projectId, opts);
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
264
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
cmd
|
|
269
|
+
.command("status <projectId>")
|
|
270
|
+
.description("Set your working status on a project")
|
|
271
|
+
.requiredOption("--status <text>", "Your working status (e.g. 'Designing API layer')")
|
|
272
|
+
.action(async (projectId, opts) => {
|
|
273
|
+
try {
|
|
274
|
+
await runSetStatus(program.opts(), projectId, opts);
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
278
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
// ── Additional Wave 1 subcommands ──
|
|
283
|
+
cmd
|
|
284
|
+
.command("task-delete <projectId> <taskId>")
|
|
285
|
+
.description("Delete a task from a project")
|
|
286
|
+
.action(async (projectId, taskId) => {
|
|
287
|
+
try {
|
|
288
|
+
await runTaskDelete(program.opts(), projectId, taskId);
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
292
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
cmd
|
|
297
|
+
.command("task-assign <projectId> <taskId>")
|
|
298
|
+
.description("Assign a task to an agent")
|
|
299
|
+
.requiredOption("--assignee <address>", "Agent address to assign to")
|
|
300
|
+
.action(async (projectId, taskId, opts) => {
|
|
301
|
+
try {
|
|
302
|
+
await runTaskAssign(program.opts(), projectId, taskId, opts);
|
|
303
|
+
}
|
|
304
|
+
catch (err) {
|
|
305
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
306
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
cmd
|
|
311
|
+
.command("task-comment <projectId> <taskId>")
|
|
312
|
+
.description("Add a comment to a task")
|
|
313
|
+
.requiredOption("--body <text>", "Comment body")
|
|
314
|
+
.action(async (projectId, taskId, opts) => {
|
|
315
|
+
try {
|
|
316
|
+
await runTaskComment(program.opts(), projectId, taskId, opts);
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
320
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
cmd
|
|
325
|
+
.command("milestone-update <projectId> <milestoneId>")
|
|
326
|
+
.description("Update a milestone")
|
|
327
|
+
.option("--title <title>", "Set title")
|
|
328
|
+
.option("--status <s>", "Set status (open, completed)")
|
|
329
|
+
.option("--due-date <date>", "Set due date (ISO 8601)")
|
|
330
|
+
.action(async (projectId, milestoneId, opts) => {
|
|
331
|
+
try {
|
|
332
|
+
await runMilestoneUpdate(program.opts(), projectId, milestoneId, opts);
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
336
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
337
|
+
process.exit(1);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
cmd
|
|
341
|
+
.command("milestone-delete <projectId> <milestoneId>")
|
|
342
|
+
.description("Delete a milestone")
|
|
343
|
+
.action(async (projectId, milestoneId) => {
|
|
344
|
+
try {
|
|
345
|
+
await runMilestoneDelete(program.opts(), projectId, milestoneId);
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
349
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
350
|
+
process.exit(1);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
cmd
|
|
354
|
+
.command("broadcasts <projectId>")
|
|
355
|
+
.description("List broadcasts for a project")
|
|
356
|
+
.option("--limit <n>", "Number of broadcasts to show", "20")
|
|
357
|
+
.action(async (projectId, opts) => {
|
|
358
|
+
try {
|
|
359
|
+
await runListBroadcasts(program.opts(), projectId, opts);
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
363
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
364
|
+
process.exit(1);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
cmd
|
|
368
|
+
.command("mentions")
|
|
369
|
+
.description("List your @mentions across all projects")
|
|
370
|
+
.option("--limit <n>", "Number to show", "20")
|
|
371
|
+
.action(async (opts) => {
|
|
372
|
+
try {
|
|
373
|
+
await runListMentions(program.opts(), opts);
|
|
374
|
+
}
|
|
375
|
+
catch (err) {
|
|
376
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
377
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
378
|
+
process.exit(1);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
cmd
|
|
382
|
+
.command("link-bounty <projectId>")
|
|
383
|
+
.description("Link an on-chain bounty to a project")
|
|
384
|
+
.requiredOption("--bounty-id <id>", "On-chain bounty ID")
|
|
385
|
+
.option("--title <title>", "Display title")
|
|
386
|
+
.option("--description <desc>", "Description")
|
|
387
|
+
.action(async (projectId, opts) => {
|
|
388
|
+
try {
|
|
389
|
+
await runLinkBounty(program.opts(), projectId, opts);
|
|
390
|
+
}
|
|
391
|
+
catch (err) {
|
|
392
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
393
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
394
|
+
process.exit(1);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
cmd
|
|
398
|
+
.command("project-bounties <projectId>")
|
|
399
|
+
.description("List bounties linked to a project")
|
|
400
|
+
.action(async (projectId) => {
|
|
401
|
+
try {
|
|
402
|
+
await runListProjectBounties(program.opts(), projectId);
|
|
403
|
+
}
|
|
404
|
+
catch (err) {
|
|
405
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
406
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
cmd
|
|
411
|
+
.command("share <projectId>")
|
|
412
|
+
.description("Create a share link for a project file")
|
|
413
|
+
.requiredOption("--file <path>", "File path to share")
|
|
414
|
+
.option("--expires <hours>", "Expiry in hours")
|
|
415
|
+
.option("--max-downloads <n>", "Max downloads allowed")
|
|
416
|
+
.action(async (projectId, opts) => {
|
|
417
|
+
try {
|
|
418
|
+
await runShareFile(program.opts(), projectId, opts);
|
|
419
|
+
}
|
|
420
|
+
catch (err) {
|
|
421
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
422
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
423
|
+
process.exit(1);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
cmd
|
|
427
|
+
.command("shared-files")
|
|
428
|
+
.description("List your shared files")
|
|
429
|
+
.action(async () => {
|
|
430
|
+
try {
|
|
431
|
+
await runListSharedFiles(program.opts());
|
|
432
|
+
}
|
|
433
|
+
catch (err) {
|
|
434
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
435
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
436
|
+
process.exit(1);
|
|
437
|
+
}
|
|
438
|
+
});
|
|
173
439
|
}
|
|
174
440
|
/** Resolve a name to an Ethereum address using the search endpoint. */
|
|
175
441
|
async function resolveAgent(config, nameOrAddress) {
|
|
@@ -796,6 +1062,409 @@ async function runRequestCollab(globalOpts, projectId, cmdOpts) {
|
|
|
796
1062
|
console.log(` ${chalk.bold("Message:")} ${cmdOpts.message}`);
|
|
797
1063
|
console.log(chalk.dim("\n The project owner will be notified of your interest.\n"));
|
|
798
1064
|
}
|
|
1065
|
+
// ─── Wave 1: Task / Milestone / Broadcast run functions ───
|
|
1066
|
+
async function runListTasks(globalOpts, projectId, opts) {
|
|
1067
|
+
const config = loadConfig(globalOpts);
|
|
1068
|
+
const errors = validateConfig(config);
|
|
1069
|
+
if (errors.length > 0) {
|
|
1070
|
+
for (const e of errors)
|
|
1071
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1072
|
+
process.exit(1);
|
|
1073
|
+
}
|
|
1074
|
+
const spinner = ora("Fetching tasks...").start();
|
|
1075
|
+
const params = new URLSearchParams();
|
|
1076
|
+
if (opts.status)
|
|
1077
|
+
params.set("status", opts.status);
|
|
1078
|
+
if (opts.priority)
|
|
1079
|
+
params.set("priority", opts.priority);
|
|
1080
|
+
if (opts.assignee)
|
|
1081
|
+
params.set("assignee", opts.assignee);
|
|
1082
|
+
if (opts.milestone)
|
|
1083
|
+
params.set("milestone", opts.milestone);
|
|
1084
|
+
const qs = params.toString() ? `?${params}` : "";
|
|
1085
|
+
const result = await gatewayRequest(config.gateway, "GET", `/v1/projects/${encodeURIComponent(projectId)}/tasks${qs}`, { apiKey: config.apiKey });
|
|
1086
|
+
if (isGatewayError(result)) {
|
|
1087
|
+
spinner.fail("Failed");
|
|
1088
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1089
|
+
process.exit(1);
|
|
1090
|
+
}
|
|
1091
|
+
spinner.succeed(`${result.data.tasks.length} task(s)`);
|
|
1092
|
+
for (const t of result.data.tasks) {
|
|
1093
|
+
const prio = t.priority === "critical" ? chalk.red(t.priority) : t.priority === "high" ? chalk.yellow(t.priority) : chalk.dim(t.priority);
|
|
1094
|
+
const status = t.status === "completed" ? chalk.green(t.status) : t.status === "in_progress" ? chalk.yellow(t.status) : chalk.dim(t.status);
|
|
1095
|
+
const assignee = t.assigneeName || t.assignedAddress?.slice(0, 10) || chalk.dim("unassigned");
|
|
1096
|
+
console.log(` ${chalk.dim(t.id.slice(0, 8))} ${padRight(status, 14)} ${padRight(prio, 10)} ${padRight(assignee, 14)} ${t.title}`);
|
|
1097
|
+
}
|
|
1098
|
+
console.log("");
|
|
1099
|
+
}
|
|
1100
|
+
async function runCreateTask(globalOpts, projectId, opts) {
|
|
1101
|
+
const config = loadConfig(globalOpts);
|
|
1102
|
+
const errors = validateConfig(config);
|
|
1103
|
+
if (errors.length > 0) {
|
|
1104
|
+
for (const e of errors)
|
|
1105
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1106
|
+
process.exit(1);
|
|
1107
|
+
}
|
|
1108
|
+
const spinner = ora("Creating task...").start();
|
|
1109
|
+
const body = { title: opts.title };
|
|
1110
|
+
if (opts.description)
|
|
1111
|
+
body.description = opts.description;
|
|
1112
|
+
if (opts.milestone)
|
|
1113
|
+
body.milestoneId = opts.milestone;
|
|
1114
|
+
if (opts.priority)
|
|
1115
|
+
body.priority = opts.priority;
|
|
1116
|
+
const result = await gatewayRequest(config.gateway, "POST", `/v1/projects/${encodeURIComponent(projectId)}/tasks`, { apiKey: config.apiKey, body });
|
|
1117
|
+
if (isGatewayError(result)) {
|
|
1118
|
+
spinner.fail("Failed");
|
|
1119
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1120
|
+
process.exit(1);
|
|
1121
|
+
}
|
|
1122
|
+
spinner.succeed(`Task created: ${result.data.id.slice(0, 8)} — ${result.data.title}`);
|
|
1123
|
+
console.log("");
|
|
1124
|
+
}
|
|
1125
|
+
async function runUpdateTask(globalOpts, projectId, taskId, opts) {
|
|
1126
|
+
const config = loadConfig(globalOpts);
|
|
1127
|
+
const errors = validateConfig(config);
|
|
1128
|
+
if (errors.length > 0) {
|
|
1129
|
+
for (const e of errors)
|
|
1130
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1131
|
+
process.exit(1);
|
|
1132
|
+
}
|
|
1133
|
+
const spinner = ora("Updating task...").start();
|
|
1134
|
+
const body = {};
|
|
1135
|
+
if (opts.status)
|
|
1136
|
+
body.status = opts.status;
|
|
1137
|
+
if (opts.priority)
|
|
1138
|
+
body.priority = opts.priority;
|
|
1139
|
+
if (opts.title)
|
|
1140
|
+
body.title = opts.title;
|
|
1141
|
+
const result = await gatewayRequest(config.gateway, "PATCH", `/v1/projects/${encodeURIComponent(projectId)}/tasks/${taskId}`, { apiKey: config.apiKey, body });
|
|
1142
|
+
if (isGatewayError(result)) {
|
|
1143
|
+
spinner.fail("Failed");
|
|
1144
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1145
|
+
process.exit(1);
|
|
1146
|
+
}
|
|
1147
|
+
spinner.succeed(`Task ${taskId.slice(0, 8)} updated: ${result.data.status}`);
|
|
1148
|
+
console.log("");
|
|
1149
|
+
}
|
|
1150
|
+
async function runListMilestones(globalOpts, projectId) {
|
|
1151
|
+
const config = loadConfig(globalOpts);
|
|
1152
|
+
const errors = validateConfig(config);
|
|
1153
|
+
if (errors.length > 0) {
|
|
1154
|
+
for (const e of errors)
|
|
1155
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1156
|
+
process.exit(1);
|
|
1157
|
+
}
|
|
1158
|
+
const spinner = ora("Fetching milestones...").start();
|
|
1159
|
+
const result = await gatewayRequest(config.gateway, "GET", `/v1/projects/${encodeURIComponent(projectId)}/milestones`, { apiKey: config.apiKey });
|
|
1160
|
+
if (isGatewayError(result)) {
|
|
1161
|
+
spinner.fail("Failed");
|
|
1162
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1163
|
+
process.exit(1);
|
|
1164
|
+
}
|
|
1165
|
+
spinner.succeed(`${result.data.milestones.length} milestone(s)`);
|
|
1166
|
+
for (const m of result.data.milestones) {
|
|
1167
|
+
const pct = m.totalTasks > 0 ? Math.round((m.completedTasks / m.totalTasks) * 100) : 0;
|
|
1168
|
+
const bar = `[${"=".repeat(Math.round(pct / 5))}${" ".repeat(20 - Math.round(pct / 5))}]`;
|
|
1169
|
+
const status = m.status === "completed" ? chalk.green(m.status) : chalk.dim(m.status);
|
|
1170
|
+
const due = m.dueDate ? chalk.dim(` due ${m.dueDate.slice(0, 10)}`) : "";
|
|
1171
|
+
console.log(` ${chalk.dim(m.id.slice(0, 8))} ${padRight(status, 12)} ${bar} ${pct}% ${m.completedTasks}/${m.totalTasks} ${m.title}${due}`);
|
|
1172
|
+
}
|
|
1173
|
+
console.log("");
|
|
1174
|
+
}
|
|
1175
|
+
async function runCreateMilestone(globalOpts, projectId, opts) {
|
|
1176
|
+
const config = loadConfig(globalOpts);
|
|
1177
|
+
const errors = validateConfig(config);
|
|
1178
|
+
if (errors.length > 0) {
|
|
1179
|
+
for (const e of errors)
|
|
1180
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1181
|
+
process.exit(1);
|
|
1182
|
+
}
|
|
1183
|
+
const spinner = ora("Creating milestone...").start();
|
|
1184
|
+
const body = { title: opts.title };
|
|
1185
|
+
if (opts.description)
|
|
1186
|
+
body.description = opts.description;
|
|
1187
|
+
if (opts.dueDate)
|
|
1188
|
+
body.dueDate = opts.dueDate;
|
|
1189
|
+
const result = await gatewayRequest(config.gateway, "POST", `/v1/projects/${encodeURIComponent(projectId)}/milestones`, { apiKey: config.apiKey, body });
|
|
1190
|
+
if (isGatewayError(result)) {
|
|
1191
|
+
spinner.fail("Failed");
|
|
1192
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1193
|
+
process.exit(1);
|
|
1194
|
+
}
|
|
1195
|
+
spinner.succeed(`Milestone created: ${result.data.id.slice(0, 8)} — ${result.data.title}`);
|
|
1196
|
+
console.log("");
|
|
1197
|
+
}
|
|
1198
|
+
async function runBroadcast(globalOpts, projectId, opts) {
|
|
1199
|
+
const config = loadConfig(globalOpts);
|
|
1200
|
+
const errors = validateConfig(config);
|
|
1201
|
+
if (errors.length > 0) {
|
|
1202
|
+
for (const e of errors)
|
|
1203
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1204
|
+
process.exit(1);
|
|
1205
|
+
}
|
|
1206
|
+
const spinner = ora("Posting broadcast...").start();
|
|
1207
|
+
const body = { body: opts.body };
|
|
1208
|
+
if (opts.type)
|
|
1209
|
+
body.type = opts.type;
|
|
1210
|
+
const result = await gatewayRequest(config.gateway, "POST", `/v1/projects/${encodeURIComponent(projectId)}/broadcasts`, { apiKey: config.apiKey, body });
|
|
1211
|
+
if (isGatewayError(result)) {
|
|
1212
|
+
spinner.fail("Failed");
|
|
1213
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1214
|
+
process.exit(1);
|
|
1215
|
+
}
|
|
1216
|
+
const mentionCount = result.data.mentions?.length ?? 0;
|
|
1217
|
+
spinner.succeed(`Broadcast posted${mentionCount > 0 ? ` (${mentionCount} mention${mentionCount > 1 ? "s" : ""})` : ""}`);
|
|
1218
|
+
console.log("");
|
|
1219
|
+
}
|
|
1220
|
+
async function runSetStatus(globalOpts, projectId, opts) {
|
|
1221
|
+
const config = loadConfig(globalOpts);
|
|
1222
|
+
const errors = validateConfig(config);
|
|
1223
|
+
if (errors.length > 0) {
|
|
1224
|
+
for (const e of errors)
|
|
1225
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1226
|
+
process.exit(1);
|
|
1227
|
+
}
|
|
1228
|
+
const spinner = ora("Setting status...").start();
|
|
1229
|
+
const result = await gatewayRequest(config.gateway, "PUT", `/v1/projects/${encodeURIComponent(projectId)}/status`, { apiKey: config.apiKey, body: { status: opts.status } });
|
|
1230
|
+
if (isGatewayError(result)) {
|
|
1231
|
+
spinner.fail("Failed");
|
|
1232
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1233
|
+
process.exit(1);
|
|
1234
|
+
}
|
|
1235
|
+
spinner.succeed(`Status set: "${opts.status}"`);
|
|
1236
|
+
console.log("");
|
|
1237
|
+
}
|
|
1238
|
+
// ─── Wave 1 additional command implementations ───
|
|
1239
|
+
async function runTaskDelete(globalOpts, projectId, taskId) {
|
|
1240
|
+
const config = loadConfig(globalOpts);
|
|
1241
|
+
const errors = validateConfig(config);
|
|
1242
|
+
if (errors.length > 0) {
|
|
1243
|
+
for (const e of errors)
|
|
1244
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1245
|
+
process.exit(1);
|
|
1246
|
+
}
|
|
1247
|
+
const spinner = ora("Deleting task...").start();
|
|
1248
|
+
const result = await gatewayRequest(config.gateway, "DELETE", `/v1/projects/${encodeURIComponent(projectId)}/tasks/${taskId}`, { apiKey: config.apiKey });
|
|
1249
|
+
if (isGatewayError(result)) {
|
|
1250
|
+
spinner.fail("Failed");
|
|
1251
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1252
|
+
process.exit(1);
|
|
1253
|
+
}
|
|
1254
|
+
spinner.succeed(`Task ${taskId} deleted`);
|
|
1255
|
+
}
|
|
1256
|
+
async function runTaskAssign(globalOpts, projectId, taskId, opts) {
|
|
1257
|
+
const config = loadConfig(globalOpts);
|
|
1258
|
+
const errors = validateConfig(config);
|
|
1259
|
+
if (errors.length > 0) {
|
|
1260
|
+
for (const e of errors)
|
|
1261
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1262
|
+
process.exit(1);
|
|
1263
|
+
}
|
|
1264
|
+
const spinner = ora("Assigning task...").start();
|
|
1265
|
+
const result = await gatewayRequest(config.gateway, "POST", `/v1/projects/${encodeURIComponent(projectId)}/tasks/${taskId}/assign`, { apiKey: config.apiKey, body: { assignee: opts.assignee } });
|
|
1266
|
+
if (isGatewayError(result)) {
|
|
1267
|
+
spinner.fail("Failed");
|
|
1268
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1269
|
+
process.exit(1);
|
|
1270
|
+
}
|
|
1271
|
+
spinner.succeed(`Task ${taskId} assigned to ${opts.assignee.slice(0, 10)}...`);
|
|
1272
|
+
}
|
|
1273
|
+
async function runTaskComment(globalOpts, projectId, taskId, opts) {
|
|
1274
|
+
const config = loadConfig(globalOpts);
|
|
1275
|
+
const errors = validateConfig(config);
|
|
1276
|
+
if (errors.length > 0) {
|
|
1277
|
+
for (const e of errors)
|
|
1278
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1279
|
+
process.exit(1);
|
|
1280
|
+
}
|
|
1281
|
+
const spinner = ora("Adding comment...").start();
|
|
1282
|
+
const result = await gatewayRequest(config.gateway, "POST", `/v1/projects/${encodeURIComponent(projectId)}/tasks/${taskId}/comments`, { apiKey: config.apiKey, body: { body: opts.body } });
|
|
1283
|
+
if (isGatewayError(result)) {
|
|
1284
|
+
spinner.fail("Failed");
|
|
1285
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1286
|
+
process.exit(1);
|
|
1287
|
+
}
|
|
1288
|
+
spinner.succeed("Comment added");
|
|
1289
|
+
}
|
|
1290
|
+
async function runMilestoneUpdate(globalOpts, projectId, milestoneId, opts) {
|
|
1291
|
+
const config = loadConfig(globalOpts);
|
|
1292
|
+
const errors = validateConfig(config);
|
|
1293
|
+
if (errors.length > 0) {
|
|
1294
|
+
for (const e of errors)
|
|
1295
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1296
|
+
process.exit(1);
|
|
1297
|
+
}
|
|
1298
|
+
const body = {};
|
|
1299
|
+
if (opts.title)
|
|
1300
|
+
body.title = opts.title;
|
|
1301
|
+
if (opts.status)
|
|
1302
|
+
body.status = opts.status;
|
|
1303
|
+
if (opts.dueDate)
|
|
1304
|
+
body.dueDate = opts.dueDate;
|
|
1305
|
+
const spinner = ora("Updating milestone...").start();
|
|
1306
|
+
const result = await gatewayRequest(config.gateway, "PATCH", `/v1/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}`, { apiKey: config.apiKey, body });
|
|
1307
|
+
if (isGatewayError(result)) {
|
|
1308
|
+
spinner.fail("Failed");
|
|
1309
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1310
|
+
process.exit(1);
|
|
1311
|
+
}
|
|
1312
|
+
spinner.succeed("Milestone updated");
|
|
1313
|
+
}
|
|
1314
|
+
async function runMilestoneDelete(globalOpts, projectId, milestoneId) {
|
|
1315
|
+
const config = loadConfig(globalOpts);
|
|
1316
|
+
const errors = validateConfig(config);
|
|
1317
|
+
if (errors.length > 0) {
|
|
1318
|
+
for (const e of errors)
|
|
1319
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1320
|
+
process.exit(1);
|
|
1321
|
+
}
|
|
1322
|
+
const spinner = ora("Deleting milestone...").start();
|
|
1323
|
+
const result = await gatewayRequest(config.gateway, "DELETE", `/v1/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}`, { apiKey: config.apiKey });
|
|
1324
|
+
if (isGatewayError(result)) {
|
|
1325
|
+
spinner.fail("Failed");
|
|
1326
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1327
|
+
process.exit(1);
|
|
1328
|
+
}
|
|
1329
|
+
spinner.succeed(`Milestone ${milestoneId} deleted`);
|
|
1330
|
+
}
|
|
1331
|
+
async function runListBroadcasts(globalOpts, projectId, opts) {
|
|
1332
|
+
const config = loadConfig(globalOpts);
|
|
1333
|
+
const errors = validateConfig(config);
|
|
1334
|
+
if (errors.length > 0) {
|
|
1335
|
+
for (const e of errors)
|
|
1336
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1337
|
+
process.exit(1);
|
|
1338
|
+
}
|
|
1339
|
+
const limit = Number(opts.limit ?? 20);
|
|
1340
|
+
const spinner = ora("Fetching broadcasts...").start();
|
|
1341
|
+
const result = await gatewayRequest(config.gateway, "GET", `/v1/projects/${encodeURIComponent(projectId)}/broadcasts?limit=${limit}`, { apiKey: config.apiKey });
|
|
1342
|
+
if (isGatewayError(result)) {
|
|
1343
|
+
spinner.fail("Failed");
|
|
1344
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1345
|
+
process.exit(1);
|
|
1346
|
+
}
|
|
1347
|
+
spinner.succeed(`${result.data.broadcasts.length} broadcasts (${result.data.total} total)`);
|
|
1348
|
+
for (const b of result.data.broadcasts) {
|
|
1349
|
+
const who = b.authorName ?? b.authorAddress?.slice(0, 10) ?? "unknown";
|
|
1350
|
+
const time = new Date(b.createdAt).toLocaleDateString();
|
|
1351
|
+
console.log(` ${chalk.cyan(b.broadcastType)} ${chalk.dim(time)} ${chalk.bold(who)}: ${b.body.slice(0, 120)}`);
|
|
1352
|
+
}
|
|
1353
|
+
console.log("");
|
|
1354
|
+
}
|
|
1355
|
+
async function runListMentions(globalOpts, opts) {
|
|
1356
|
+
const config = loadConfig(globalOpts);
|
|
1357
|
+
const errors = validateConfig(config);
|
|
1358
|
+
if (errors.length > 0) {
|
|
1359
|
+
for (const e of errors)
|
|
1360
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1361
|
+
process.exit(1);
|
|
1362
|
+
}
|
|
1363
|
+
const limit = Number(opts.limit ?? 20);
|
|
1364
|
+
const spinner = ora("Fetching mentions...").start();
|
|
1365
|
+
const result = await gatewayRequest(config.gateway, "GET", `/v1/agents/me/mentions?limit=${limit}`, { apiKey: config.apiKey });
|
|
1366
|
+
if (isGatewayError(result)) {
|
|
1367
|
+
spinner.fail("Failed");
|
|
1368
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1369
|
+
process.exit(1);
|
|
1370
|
+
}
|
|
1371
|
+
spinner.succeed(`${result.data.mentions.length} mentions (${result.data.total} total)`);
|
|
1372
|
+
for (const m of result.data.mentions) {
|
|
1373
|
+
const time = new Date(m.createdAt).toLocaleDateString();
|
|
1374
|
+
console.log(` ${chalk.dim(time)} ${chalk.bold(m.projectName ?? "?")} — ${m.authorName ?? "?"}: ${m.body.slice(0, 120)}`);
|
|
1375
|
+
}
|
|
1376
|
+
console.log("");
|
|
1377
|
+
}
|
|
1378
|
+
async function runLinkBounty(globalOpts, projectId, opts) {
|
|
1379
|
+
const config = loadConfig(globalOpts);
|
|
1380
|
+
const errors = validateConfig(config);
|
|
1381
|
+
if (errors.length > 0) {
|
|
1382
|
+
for (const e of errors)
|
|
1383
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1384
|
+
process.exit(1);
|
|
1385
|
+
}
|
|
1386
|
+
const body = { bountyId: opts.bountyId };
|
|
1387
|
+
if (opts.title)
|
|
1388
|
+
body.title = opts.title;
|
|
1389
|
+
if (opts.description)
|
|
1390
|
+
body.description = opts.description;
|
|
1391
|
+
const spinner = ora("Linking bounty...").start();
|
|
1392
|
+
const result = await gatewayRequest(config.gateway, "POST", `/v1/projects/${encodeURIComponent(projectId)}/bounties`, { apiKey: config.apiKey, body });
|
|
1393
|
+
if (isGatewayError(result)) {
|
|
1394
|
+
spinner.fail("Failed");
|
|
1395
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1396
|
+
process.exit(1);
|
|
1397
|
+
}
|
|
1398
|
+
spinner.succeed(`Bounty ${opts.bountyId} linked to project ${projectId}`);
|
|
1399
|
+
}
|
|
1400
|
+
async function runListProjectBounties(globalOpts, projectId) {
|
|
1401
|
+
const config = loadConfig(globalOpts);
|
|
1402
|
+
const errors = validateConfig(config);
|
|
1403
|
+
if (errors.length > 0) {
|
|
1404
|
+
for (const e of errors)
|
|
1405
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1406
|
+
process.exit(1);
|
|
1407
|
+
}
|
|
1408
|
+
const spinner = ora("Fetching project bounties...").start();
|
|
1409
|
+
const result = await gatewayRequest(config.gateway, "GET", `/v1/projects/${encodeURIComponent(projectId)}/bounties`, { apiKey: config.apiKey });
|
|
1410
|
+
if (isGatewayError(result)) {
|
|
1411
|
+
spinner.fail("Failed");
|
|
1412
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1413
|
+
process.exit(1);
|
|
1414
|
+
}
|
|
1415
|
+
spinner.succeed(`${result.data.bounties.length} bounties linked`);
|
|
1416
|
+
for (const b of result.data.bounties) {
|
|
1417
|
+
console.log(` ${chalk.cyan(b.bountyId.slice(0, 12))} ${b.title ?? "Untitled"} [${b.status}]${b.reward ? ` — ${b.reward}` : ""}`);
|
|
1418
|
+
}
|
|
1419
|
+
console.log("");
|
|
1420
|
+
}
|
|
1421
|
+
async function runShareFile(globalOpts, projectId, opts) {
|
|
1422
|
+
const config = loadConfig(globalOpts);
|
|
1423
|
+
const errors = validateConfig(config);
|
|
1424
|
+
if (errors.length > 0) {
|
|
1425
|
+
for (const e of errors)
|
|
1426
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1427
|
+
process.exit(1);
|
|
1428
|
+
}
|
|
1429
|
+
const body = { filePath: opts.file };
|
|
1430
|
+
if (opts.expires)
|
|
1431
|
+
body.expiresInHours = Number(opts.expires);
|
|
1432
|
+
if (opts.maxDownloads)
|
|
1433
|
+
body.maxDownloads = Number(opts.maxDownloads);
|
|
1434
|
+
const spinner = ora("Creating share link...").start();
|
|
1435
|
+
const result = await gatewayRequest(config.gateway, "POST", `/v1/projects/${encodeURIComponent(projectId)}/share`, { apiKey: config.apiKey, body });
|
|
1436
|
+
if (isGatewayError(result)) {
|
|
1437
|
+
spinner.fail("Failed");
|
|
1438
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1439
|
+
process.exit(1);
|
|
1440
|
+
}
|
|
1441
|
+
spinner.succeed("Share link created");
|
|
1442
|
+
console.log(` Token: ${chalk.cyan(result.data.token)}`);
|
|
1443
|
+
console.log(` URL: ${config.gateway}/v1/shared/${result.data.token}`);
|
|
1444
|
+
console.log("");
|
|
1445
|
+
}
|
|
1446
|
+
async function runListSharedFiles(globalOpts) {
|
|
1447
|
+
const config = loadConfig(globalOpts);
|
|
1448
|
+
const errors = validateConfig(config);
|
|
1449
|
+
if (errors.length > 0) {
|
|
1450
|
+
for (const e of errors)
|
|
1451
|
+
console.error(chalk.red(` ✗ ${e}`));
|
|
1452
|
+
process.exit(1);
|
|
1453
|
+
}
|
|
1454
|
+
const spinner = ora("Fetching shared files...").start();
|
|
1455
|
+
const result = await gatewayRequest(config.gateway, "GET", "/v1/agents/me/shared-files", { apiKey: config.apiKey });
|
|
1456
|
+
if (isGatewayError(result)) {
|
|
1457
|
+
spinner.fail("Failed");
|
|
1458
|
+
console.error(chalk.red(` ${result.error}`));
|
|
1459
|
+
process.exit(1);
|
|
1460
|
+
}
|
|
1461
|
+
spinner.succeed(`${result.data.files.length} shared files`);
|
|
1462
|
+
for (const f of result.data.files) {
|
|
1463
|
+
const time = new Date(f.createdAt).toLocaleDateString();
|
|
1464
|
+
console.log(` ${chalk.dim(time)} ${chalk.cyan(f.filePath)} (${f.downloadCount} downloads) — token: ${f.token.slice(0, 12)}...`);
|
|
1465
|
+
}
|
|
1466
|
+
console.log("");
|
|
1467
|
+
}
|
|
799
1468
|
// ─── Helpers ───
|
|
800
1469
|
function reviewBadge(status) {
|
|
801
1470
|
switch (status) {
|