@dosu/cli 0.25.0 → 0.27.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.
Files changed (2) hide show
  1. package/bin/dosu.js +141 -29
  2. package/package.json +2 -2
package/bin/dosu.js CHANGED
@@ -4577,7 +4577,7 @@ var init_dist4 = __esm(() => {
4577
4577
  function getVersionString() {
4578
4578
  return `v${VERSION}`;
4579
4579
  }
4580
- var VERSION = "0.25.0", INSTALL_CHANNEL = "npm";
4580
+ var VERSION = "0.27.0", INSTALL_CHANNEL = "npm";
4581
4581
 
4582
4582
  // src/debug/logger.ts
4583
4583
  import {
@@ -13657,7 +13657,7 @@ var init_flow3 = __esm(() => {
13657
13657
  // src/cli/cli.ts
13658
13658
  init_commander();
13659
13659
  init_client();
13660
- import { readFileSync as readFileSync13, unlinkSync as unlinkSync2 } from "node:fs";
13660
+ import { readFileSync as readFileSync14, unlinkSync as unlinkSync2 } from "node:fs";
13661
13661
 
13662
13662
  // src/commands/analytics.ts
13663
13663
  init_commander();
@@ -15258,9 +15258,30 @@ init_dist();
15258
15258
  init_commander();
15259
15259
  init_trpc();
15260
15260
  var import_picocolors18 = __toESM(require_picocolors(), 1);
15261
+ import { readFileSync as readFileSync12 } from "node:fs";
15261
15262
  function requireConfig9() {
15262
15263
  return requireLoginConfig();
15263
15264
  }
15265
+ function isNotFound(err) {
15266
+ return isTRPCClientError(err) && err.data?.code === "NOT_FOUND";
15267
+ }
15268
+ async function resolveChange(client, id) {
15269
+ try {
15270
+ return await client.review.getChange.query({ id });
15271
+ } catch (err) {
15272
+ if (isNotFound(err))
15273
+ return null;
15274
+ throw err;
15275
+ }
15276
+ }
15277
+ async function requireDraft(client, id) {
15278
+ const draft = await client.messages.getMessage.query(id);
15279
+ if (!draft) {
15280
+ console.error(import_picocolors18.default.red(`No review item found for '${id}'. Run 'dosu review list' to see pending items.`));
15281
+ process.exit(1);
15282
+ }
15283
+ return draft;
15284
+ }
15264
15285
  function humanizeSource(origin, version) {
15265
15286
  switch (origin) {
15266
15287
  case "manual_update":
@@ -15304,6 +15325,14 @@ function printChangePreview(change) {
15304
15325
  console.log();
15305
15326
  console.log(colorizeDiff(change.diff));
15306
15327
  }
15328
+ function printDraftPreview(draft) {
15329
+ printInfo([
15330
+ ["Title", draft.title ?? "(untitled)"],
15331
+ ["Source", "Draft reply"]
15332
+ ]);
15333
+ console.log();
15334
+ console.log(draft.body ?? "");
15335
+ }
15307
15336
  async function getKnowledgeStoreId2(client, spaceId) {
15308
15337
  const store = await client.knowledgeStore.getBySpaceId.query({ space_id: spaceId });
15309
15338
  if (!store) {
@@ -15313,8 +15342,8 @@ async function getKnowledgeStoreId2(client, spaceId) {
15313
15342
  return store.id;
15314
15343
  }
15315
15344
  function reviewCommand() {
15316
- const cmd = new Command("review").description("Document review workflow");
15317
- cmd.command("list").description("List pending document review items").option("--json", "Output as JSON").action(async (opts) => {
15345
+ const cmd = new Command("review").description("Review workflow (doc changes and draft replies)");
15346
+ cmd.command("list").description("List pending review items (doc changes and draft replies)").option("--json", "Output as JSON").action(async (opts) => {
15318
15347
  const cfg = requireConfig9();
15319
15348
  if (!cfg.space_id) {
15320
15349
  console.error(import_picocolors18.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
@@ -15322,7 +15351,10 @@ function reviewCommand() {
15322
15351
  }
15323
15352
  const client = createTypedClient(cfg);
15324
15353
  const ksId = await getKnowledgeStoreId2(client, cfg.space_id);
15325
- const items = await client.review.listPending.query({ knowledgeStoreId: ksId });
15354
+ const items = await client.review.listPending.query({
15355
+ knowledgeStoreId: ksId,
15356
+ deploymentId: cfg.deployment_id
15357
+ });
15326
15358
  if (opts.json) {
15327
15359
  printResult(items, opts);
15328
15360
  return;
@@ -15331,7 +15363,14 @@ function reviewCommand() {
15331
15363
  console.log(import_picocolors18.default.dim("No pending review items."));
15332
15364
  return;
15333
15365
  }
15334
- printTable(["ID", "Kind", "Title", "Source", "Status", "Created"], items.map((i2) => [
15366
+ printTable(["ID", "Kind", "Title", "Source", "Status", "Created"], items.map((i2) => i2.kind === "draft_message" ? [
15367
+ i2.id.slice(0, 8),
15368
+ i2.kind,
15369
+ truncate(i2.title || "(untitled)", 40),
15370
+ "Draft reply",
15371
+ "draft",
15372
+ formatDate(i2.createdAt)
15373
+ ] : [
15335
15374
  i2.id.slice(0, 8),
15336
15375
  i2.kind,
15337
15376
  truncate(i2.title ?? "(untitled)", 40),
@@ -15340,18 +15379,21 @@ function reviewCommand() {
15340
15379
  formatDate(i2.createdAt)
15341
15380
  ]), { rawData: items });
15342
15381
  });
15343
- cmd.command("diff").description("Show the server-rendered diff for a pending document version").argument("<page-version-id>", "Page version ID (from `dosu review list`)").option("--json", "Output as JSON").action(async (id, opts) => {
15382
+ cmd.command("diff").description("Show a pending review item (doc-change diff or draft reply body)").argument("<id>", "Review item ID (from `dosu review list`)").option("--json", "Output as JSON").action(async (id, opts) => {
15344
15383
  const cfg = requireConfig9();
15345
15384
  const client = createTypedClient(cfg);
15346
- let change;
15347
- try {
15348
- change = await client.review.getChange.query({ id });
15349
- } catch (err) {
15350
- if (isTRPCClientError(err) && err.data?.code === "NOT_FOUND") {
15351
- console.error(import_picocolors18.default.red(`No review item found for '${id}'. Run 'dosu review list' to see pending items.`));
15352
- process.exit(1);
15385
+ const change = await resolveChange(client, id);
15386
+ if (!change) {
15387
+ const draft = await requireDraft(client, id);
15388
+ if (opts.json) {
15389
+ printResult({ id, kind: "draft_message", title: draft.title, body: draft.body }, opts);
15390
+ return;
15353
15391
  }
15354
- throw err;
15392
+ console.log(import_picocolors18.default.bold(draft.title ?? "(untitled)"));
15393
+ console.log(import_picocolors18.default.dim("Draft reply"));
15394
+ console.log("");
15395
+ console.log(draft.body ?? "");
15396
+ return;
15355
15397
  }
15356
15398
  if (opts.json) {
15357
15399
  printResult(change, opts);
@@ -15363,6 +15405,55 @@ function reviewCommand() {
15363
15405
  console.log("");
15364
15406
  console.log(change.diff);
15365
15407
  });
15408
+ cmd.command("edit").description("Edit a pending review item in place (doc body/title, or draft reply body)").argument("<id>", "Review item ID (from `dosu review list`)").option("--title <title>", "New title").option("--body <markdown>", "New body (markdown)").option("--body-file <path>", "Read body from file").option("--json", "Output as JSON").action(async (id, opts) => {
15409
+ const cfg = requireConfig9();
15410
+ const client = createTypedClient(cfg);
15411
+ if (opts.body !== undefined && opts.bodyFile !== undefined) {
15412
+ console.error(import_picocolors18.default.red("Pass only one of --body or --body-file."));
15413
+ process.exit(1);
15414
+ }
15415
+ let body = opts.body;
15416
+ if (opts.bodyFile) {
15417
+ try {
15418
+ body = readFileSync12(opts.bodyFile, "utf-8");
15419
+ } catch (err) {
15420
+ console.error(import_picocolors18.default.red(`Failed to read --body-file: ${err.message}`));
15421
+ process.exit(1);
15422
+ }
15423
+ }
15424
+ if (body === undefined && opts.title === undefined) {
15425
+ console.error(import_picocolors18.default.red("Nothing to edit. Pass --title and/or --body/--body-file."));
15426
+ process.exit(1);
15427
+ }
15428
+ const change = await resolveChange(client, id);
15429
+ if (!change) {
15430
+ if (opts.title !== undefined) {
15431
+ console.error(import_picocolors18.default.red("Draft replies support --body only (no --title)."));
15432
+ process.exit(1);
15433
+ }
15434
+ await requireDraft(client, id);
15435
+ await client.messages.saveDraft.mutate({ messageId: id, body });
15436
+ } else {
15437
+ try {
15438
+ await client.page.updateReview.mutate({
15439
+ page_version_id: id,
15440
+ title: opts.title,
15441
+ body
15442
+ });
15443
+ } catch (err) {
15444
+ if (isNotFound(err)) {
15445
+ console.error(import_picocolors18.default.red(`No pending review item found for '${id}'. Run 'dosu review list' to see editable items.`));
15446
+ process.exit(1);
15447
+ }
15448
+ throw err;
15449
+ }
15450
+ }
15451
+ if (opts.json) {
15452
+ printResult({ success: true, id }, opts);
15453
+ return;
15454
+ }
15455
+ console.log(import_picocolors18.default.green(`Review edited: ${id.slice(0, 8)}`));
15456
+ });
15366
15457
  cmd.command("context").description("Get review context for a thread").argument("<thread-id>", "Thread ID").option("--json", "Output as JSON").action(async (threadId, opts) => {
15367
15458
  const cfg = requireConfig9();
15368
15459
  const client = createTypedClient(cfg);
@@ -15389,16 +15480,22 @@ function reviewCommand() {
15389
15480
  { name: "reject", action: "decline", verb: "Reject" }
15390
15481
  ];
15391
15482
  for (const { name, action, verb } of gated) {
15392
- cmd.command(name).description(`${verb} a document version (shows the diff, requires --confirm)`).argument("<id>", "Review item ID (from `dosu review list`)").option("--confirm", "Apply without the interactive prompt").option("--json", "Output as JSON").action(async (id, opts) => {
15483
+ cmd.command(name).description(`${verb} a review item (doc change or draft reply; shows a preview, requires --confirm)`).argument("<id>", "Review item ID (from `dosu review list`)").option("--confirm", "Apply without the interactive prompt").option("--json", "Output as JSON").action(async (id, opts) => {
15393
15484
  const cfg = requireConfig9();
15394
15485
  const client = createTypedClient(cfg);
15395
- const change = await client.review.getChange.query({ id });
15396
- if (!opts.json)
15397
- printChangePreview(change);
15486
+ const change = await resolveChange(client, id);
15487
+ const draft = change ? null : await requireDraft(client, id);
15488
+ const noun = change ? "change" : "draft reply";
15489
+ if (!opts.json) {
15490
+ if (change)
15491
+ printChangePreview(change);
15492
+ else
15493
+ printDraftPreview(draft);
15494
+ }
15398
15495
  let proceed = opts.confirm === true;
15399
15496
  if (!proceed && !opts.json && process.stdin?.isTTY) {
15400
15497
  const answer = await confirm({
15401
- message: `${verb} this change?`,
15498
+ message: `${verb} this ${noun}?`,
15402
15499
  initialValue: false
15403
15500
  });
15404
15501
  if (isCancel(answer)) {
@@ -15409,16 +15506,25 @@ function reviewCommand() {
15409
15506
  }
15410
15507
  if (!proceed) {
15411
15508
  if (opts.json) {
15412
- printResult({ ...change, applied: false, confirmRequired: true }, opts);
15509
+ const preview = change ?? {
15510
+ id,
15511
+ kind: "draft_message",
15512
+ title: draft?.title,
15513
+ body: draft?.body
15514
+ };
15515
+ printResult({ ...preview, applied: false, confirmRequired: true }, opts);
15413
15516
  } else {
15414
15517
  console.log(import_picocolors18.default.dim("Aborted. Re-run with --confirm to apply."));
15415
15518
  }
15416
15519
  return;
15417
15520
  }
15418
- await client.page.updatePublicationStatus.mutate({
15419
- page_version_id: id,
15420
- action
15421
- });
15521
+ if (change) {
15522
+ await client.page.updatePublicationStatus.mutate({ page_version_id: id, action });
15523
+ } else if (action === "accept") {
15524
+ await client.messages.publishMessage.mutate({ postId: id });
15525
+ } else {
15526
+ await client.messages.deleteMessage.mutate(id);
15527
+ }
15422
15528
  if (opts.json) {
15423
15529
  printResult({ success: true, id, action }, opts);
15424
15530
  return;
@@ -15426,9 +15532,15 @@ function reviewCommand() {
15426
15532
  console.log(import_picocolors18.default.green(`Review ${name}: ${id.slice(0, 8)}`));
15427
15533
  });
15428
15534
  }
15429
- cmd.command("revert").description("Revert to pending review").argument("<id>", "Review item ID (from `dosu review list`)").option("--json", "Output as JSON").action(async (id, opts) => {
15535
+ cmd.command("revert").description("Revert a doc change to pending review (not supported for draft replies)").argument("<id>", "Review item ID (from `dosu review list`)").option("--json", "Output as JSON").action(async (id, opts) => {
15430
15536
  const cfg = requireConfig9();
15431
15537
  const client = createTypedClient(cfg);
15538
+ const change = await resolveChange(client, id);
15539
+ if (!change) {
15540
+ await requireDraft(client, id);
15541
+ console.error(import_picocolors18.default.red("Revert is not supported for draft replies. A rejected draft is regenerated on the next agent run."));
15542
+ process.exit(1);
15543
+ }
15432
15544
  await client.page.updatePublicationStatus.mutate({
15433
15545
  page_version_id: id,
15434
15546
  action: "revert_to_pending"
@@ -15810,7 +15922,7 @@ init_skill_update_check();
15810
15922
  init_config();
15811
15923
  init_logger();
15812
15924
  var import_picocolors23 = __toESM(require_picocolors(), 1);
15813
- import { existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "node:fs";
15925
+ import { existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "node:fs";
15814
15926
  import { join as join25 } from "node:path";
15815
15927
  var CACHE_FILENAME2 = "update-check.json";
15816
15928
  var CHECK_INTERVAL_MS2 = 24 * 60 * 60 * 1000;
@@ -15841,7 +15953,7 @@ function readCache() {
15841
15953
  const path3 = getCachePath2();
15842
15954
  if (!existsSync14(path3))
15843
15955
  return null;
15844
- const data = JSON.parse(readFileSync12(path3, "utf-8"));
15956
+ const data = JSON.parse(readFileSync13(path3, "utf-8"));
15845
15957
  if (typeof data.lastCheck === "number" && typeof data.latestVersion === "string") {
15846
15958
  return data;
15847
15959
  }
@@ -16177,7 +16289,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
16177
16289
  if (opts.tail !== undefined) {
16178
16290
  const n2 = typeof opts.tail === "string" ? parseInt(opts.tail, 10) || 50 : 50;
16179
16291
  try {
16180
- const content = readFileSync13(logPath, "utf-8");
16292
+ const content = readFileSync14(logPath, "utf-8");
16181
16293
  const lines = content.split(`
16182
16294
  `);
16183
16295
  console.log(lines.slice(-n2).join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.25.0",
3
+ "version": "0.27.0",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Manage MCP servers for AI tools",
6
6
  "license": "MIT",
@@ -37,7 +37,7 @@
37
37
  "devDependencies": {
38
38
  "@biomejs/biome": "^2.5.0",
39
39
  "@clack/prompts": "^1.6.0",
40
- "@dosu/api-types": "0.0.33",
40
+ "@dosu/api-types": "0.0.36",
41
41
  "@semantic-release/changelog": "^6.0.3",
42
42
  "@semantic-release/exec": "^7.1.0",
43
43
  "@semantic-release/git": "^10.0.1",