@dosu/cli 0.57.1 → 0.58.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 +139 -10
  2. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -1083,7 +1083,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
1083
1083
  function getVersionString() {
1084
1084
  return `v${VERSION}`;
1085
1085
  }
1086
- var VERSION = "0.57.1", INSTALL_CHANNEL = "npm";
1086
+ var VERSION = "0.58.0", INSTALL_CHANNEL = "npm";
1087
1087
 
1088
1088
  // src/debug/logger.ts
1089
1089
  import {
@@ -6786,7 +6786,7 @@ var init_dist4 = __esm(() => {
6786
6786
  });
6787
6787
 
6788
6788
  // src/client/contract.ts
6789
- var CLI_CONTRACT_HASH = "d7c6f0f0e8d0";
6789
+ var CLI_CONTRACT_HASH = "a6e002dff58e";
6790
6790
 
6791
6791
  // src/client/trpc.ts
6792
6792
  function createTypedClient(config) {
@@ -6869,8 +6869,11 @@ function messageLimit(value) {
6869
6869
  }
6870
6870
  return parsed;
6871
6871
  }
6872
+ function isUuid(value) {
6873
+ return UUID_RE.test(value);
6874
+ }
6872
6875
  function uuid(value) {
6873
- if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) {
6876
+ if (!isUuid(value)) {
6874
6877
  throw new InvalidArgumentError("must be a UUID");
6875
6878
  }
6876
6879
  return value;
@@ -6913,8 +6916,10 @@ function boundedText(maximum) {
6913
6916
  return trimmed;
6914
6917
  };
6915
6918
  }
6919
+ var UUID_RE;
6916
6920
  var init_arguments = __esm(() => {
6917
6921
  init_commander();
6922
+ UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
6918
6923
  });
6919
6924
 
6920
6925
  // src/commands/auth.ts
@@ -11170,6 +11175,25 @@ async function listAccessibleDeployments(client, activeOrgId) {
11170
11175
  const deployments = await Promise.all(orgs.map((org) => client.workspaces.listForOrg.query(org.org_id)));
11171
11176
  return deployments.flat();
11172
11177
  }
11178
+ async function resolveDeploymentId(client, activeOrgId, id) {
11179
+ const needle = id.trim();
11180
+ if (isUuid(needle))
11181
+ return needle;
11182
+ const prefix = needle.toLowerCase();
11183
+ const matches = (await listAccessibleDeployments(client, activeOrgId)).filter((d) => d.provider_slug === MCP_PROVIDER_SLUG && prefix.length > 0 && d.deployment_id.toLowerCase().startsWith(prefix));
11184
+ if (matches.length === 1)
11185
+ return matches[0].deployment_id;
11186
+ if (matches.length === 0) {
11187
+ console.error(import_picocolors15.default.red(`Deployment not found: ${id}`));
11188
+ console.error(import_picocolors15.default.dim("Expected a full deployment ID (UUID). Run 'dosu deployments list --json' to see full IDs."));
11189
+ process.exit(1);
11190
+ }
11191
+ console.error(import_picocolors15.default.red(`Ambiguous deployment ID prefix: ${id} matches ${matches.length}:`));
11192
+ for (const d of matches) {
11193
+ console.error(import_picocolors15.default.dim(` ${d.deployment_id} ${d.name}`));
11194
+ }
11195
+ process.exit(1);
11196
+ }
11173
11197
  function deploymentsCommand() {
11174
11198
  const cmd = new Command("deployments").description("Manage deployments");
11175
11199
  cmd.command("list").description("List all deployments").option("--json", "Output as JSON").action(async (opts) => {
@@ -11223,9 +11247,10 @@ ${import_picocolors15.default.dim(`Current: ${cfg.active_account?.target?.deploy
11223
11247
  ["Created", formatDate(deployment.created_at)]
11224
11248
  ], { rawData: deployment });
11225
11249
  });
11226
- cmd.command("switch").description("Switch to a different deployment").argument("<id>", "Deployment ID").option("--json", "Output as JSON").action(async (id, opts) => {
11250
+ cmd.command("switch").description("Switch to a different deployment").argument("<id>", "Deployment ID (full UUID, or a unique prefix as shown by 'list')").option("--json", "Output as JSON").action(async (rawId, opts) => {
11227
11251
  const cfg = requireConfig4();
11228
11252
  const client = createTypedClient(cfg);
11253
+ const id = await resolveDeploymentId(client, cfg.active_account?.target?.org_id, rawId);
11229
11254
  const deployment = await client.workspaces.get.query(id);
11230
11255
  if (!deployment) {
11231
11256
  console.error(import_picocolors15.default.red(`Deployment not found: ${id}`));
@@ -11258,6 +11283,7 @@ var init_deployments = __esm(() => {
11258
11283
  init_client();
11259
11284
  init_trpc();
11260
11285
  init_config();
11286
+ init_arguments();
11261
11287
  init_auth();
11262
11288
  init_output();
11263
11289
  import_picocolors15 = __toESM(require_picocolors(), 1);
@@ -13716,7 +13742,7 @@ var init_sync = __esm(() => {
13716
13742
  });
13717
13743
 
13718
13744
  // src/telemetry/debug-id.ts
13719
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "ca9e58ba-ed30-6875-6475-6e2164756e21";
13745
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "102e2621-b1fd-c662-6475-6e2164756e21";
13720
13746
 
13721
13747
  // src/telemetry/telemetry.ts
13722
13748
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -59352,6 +59378,95 @@ var init_org = __esm(() => {
59352
59378
  import_picocolors24 = __toESM(require_picocolors(), 1);
59353
59379
  });
59354
59380
 
59381
+ // src/commands/time-range.ts
59382
+ function utcDay(year, month, day) {
59383
+ const [y, m, d] = [Number(year), Number(month), Number(day)];
59384
+ const ms = Date.UTC(y, m - 1, d);
59385
+ const check = new Date(ms);
59386
+ const exists = check.getUTCFullYear() === y && check.getUTCMonth() === m - 1 && check.getUTCDate() === d;
59387
+ return exists ? ms : undefined;
59388
+ }
59389
+ function offsetMs(offset) {
59390
+ if (!offset || offset.toUpperCase() === "Z")
59391
+ return 0;
59392
+ const sign = offset.startsWith("-") ? -1 : 1;
59393
+ const digits = offset.slice(1).replace(":", "");
59394
+ const hours = Number(digits.slice(0, 2));
59395
+ const minutes = Number(digits.slice(2) || "0");
59396
+ if (hours > 23 || minutes > 59)
59397
+ return;
59398
+ return sign * (hours * HOUR_MS + minutes * 60 * 1000);
59399
+ }
59400
+ function parseIsoDatetime(text) {
59401
+ const match = ISO_DATETIME.exec(text);
59402
+ if (!match)
59403
+ return;
59404
+ const [, year, month, day, hour, minute, second = "0", fraction = "", offset] = match;
59405
+ const dayMs = utcDay(year, month, day);
59406
+ const offsetValue = offsetMs(offset);
59407
+ const [h, mi, s] = [Number(hour), Number(minute), Number(second)];
59408
+ if (dayMs === undefined || offsetValue === undefined || h > 23 || mi > 59 || s > 59) {
59409
+ return;
59410
+ }
59411
+ const ms = Number(fraction.padEnd(3, "0").slice(0, 3));
59412
+ return dayMs + h * HOUR_MS + mi * 60 * 1000 + s * 1000 + ms - offsetValue;
59413
+ }
59414
+ function parseTimeBound(value, opts) {
59415
+ const text = value.trim();
59416
+ let ms;
59417
+ const relative = RELATIVE_BOUND.exec(text);
59418
+ const dateOnly = DATE_ONLY.exec(text);
59419
+ if (relative) {
59420
+ ms = opts.now.getTime() - Number(relative[1]) * RELATIVE_UNIT_MS[relative[2]];
59421
+ } else if (dateOnly) {
59422
+ const day = utcDay(dateOnly[1], dateOnly[2], dateOnly[3]);
59423
+ ms = day === undefined ? undefined : day + (opts.endOfDay ? 24 * HOUR_MS : 0);
59424
+ } else {
59425
+ ms = parseIsoDatetime(text);
59426
+ }
59427
+ const date = ms === undefined ? undefined : new Date(ms);
59428
+ if (!date || Number.isNaN(date.getTime()))
59429
+ throw new InvalidArgumentError(INVALID_BOUND);
59430
+ return date;
59431
+ }
59432
+ function timeBound(value) {
59433
+ parseTimeBound(value, { endOfDay: false, now: new Date });
59434
+ return value.trim();
59435
+ }
59436
+ function resolveTimeRange(since, until, now = new Date) {
59437
+ const range = {
59438
+ since: since ? parseTimeBound(since, { endOfDay: false, now }) : undefined,
59439
+ until: until ? parseTimeBound(until, { endOfDay: true, now }) : undefined
59440
+ };
59441
+ if (range.since && range.until && range.since >= range.until) {
59442
+ throw new InvalidArgumentError("--since must be earlier than --until");
59443
+ }
59444
+ return range;
59445
+ }
59446
+ function describeTimeRange(range) {
59447
+ const fmt = (d) => `${d.toISOString().slice(0, 16)}Z`;
59448
+ const parts = [];
59449
+ if (range.since)
59450
+ parts.push(`since ${fmt(range.since)}`);
59451
+ if (range.until)
59452
+ parts.push(`before ${fmt(range.until)}`);
59453
+ return parts.join(" and ");
59454
+ }
59455
+ var RELATIVE_BOUND, DATE_ONLY, ISO_DATETIME, HOUR_MS, RELATIVE_UNIT_MS, INVALID_BOUND;
59456
+ var init_time_range = __esm(() => {
59457
+ init_commander();
59458
+ RELATIVE_BOUND = /^(\d+)([hdw])$/;
59459
+ DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
59460
+ ISO_DATETIME = /^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(Z|[+-]\d{2}(?::?\d{2})?)?$/i;
59461
+ HOUR_MS = 60 * 60 * 1000;
59462
+ RELATIVE_UNIT_MS = {
59463
+ h: HOUR_MS,
59464
+ d: 24 * HOUR_MS,
59465
+ w: 7 * 24 * HOUR_MS
59466
+ };
59467
+ INVALID_BOUND = 'must be a duration like "24h", "7d", or "2w", a UTC date like "2026-09-01", ' + 'or an ISO-8601 datetime like "2026-09-01T14:00:00Z"';
59468
+ });
59469
+
59355
59470
  // src/commands/review.ts
59356
59471
  import { readFileSync as readFileSync18 } from "node:fs";
59357
59472
  function requireConfig10() {
@@ -59452,7 +59567,16 @@ async function getKnowledgeStoreId2(client, spaceId) {
59452
59567
  }
59453
59568
  function reviewCommand() {
59454
59569
  const cmd = new Command("review").description("Review workflow (doc changes and draft replies)");
59455
- cmd.command("list").description("List pending review items (doc changes and draft replies)").option("--json", "Output as JSON").action(async (opts) => {
59570
+ cmd.command("list").description("List pending review items (doc changes and draft replies)").addOption(new Option("--since <when>", "Only items created at or after <when>: a duration back from now (24h, 7d, 2w), " + "a UTC date (2026-09-01), or an ISO-8601 datetime").argParser(timeBound)).addOption(new Option("--until <when>", "Only items created before <when> (same forms; a date includes that whole day)").argParser(timeBound)).option("--json", "Output as JSON").action(async (opts) => {
59571
+ let range;
59572
+ try {
59573
+ range = resolveTimeRange(opts.since, opts.until);
59574
+ } catch (err) {
59575
+ console.error(import_picocolors25.default.red(`${err.message}.`));
59576
+ process.exit(1);
59577
+ }
59578
+ const rangeLabel = describeTimeRange(range);
59579
+ const inRange = rangeLabel ? ` ${rangeLabel}` : "";
59456
59580
  const cfg = requireConfig10();
59457
59581
  if (!cfg.active_account?.target?.space_id) {
59458
59582
  console.error(import_picocolors25.default.red("Missing space config. Run 'dosu setup' to reconfigure."));
@@ -59462,7 +59586,9 @@ function reviewCommand() {
59462
59586
  const ksId = await getKnowledgeStoreId2(client, cfg.active_account?.target?.space_id);
59463
59587
  const result = await client.review.listPending.query({
59464
59588
  knowledgeStoreId: ksId,
59465
- deploymentId: cfg.active_account?.target?.deployment_id
59589
+ deploymentId: cfg.active_account?.target?.deployment_id,
59590
+ ...range.since && { since: range.since.toISOString() },
59591
+ ...range.until && { until: range.until.toISOString() }
59466
59592
  });
59467
59593
  const { items, truncated, total } = result;
59468
59594
  if (opts.json) {
@@ -59470,9 +59596,11 @@ function reviewCommand() {
59470
59596
  return;
59471
59597
  }
59472
59598
  if (!items || items.length === 0) {
59473
- console.log(import_picocolors25.default.dim("No pending review items."));
59599
+ console.log(import_picocolors25.default.dim(`No pending review items${inRange}.`));
59474
59600
  return;
59475
59601
  }
59602
+ if (rangeLabel)
59603
+ console.log(import_picocolors25.default.dim(`Pending review items created ${rangeLabel}:`));
59476
59604
  printTable(["ID", "Kind", "Title", "Source", "Status", "Created"], items.map((i) => i.kind === "draft_message" ? [
59477
59605
  i.id,
59478
59606
  i.kind,
@@ -59489,7 +59617,7 @@ function reviewCommand() {
59489
59617
  formatDate(i.createdAt)
59490
59618
  ]), { rawData: items });
59491
59619
  if (truncated) {
59492
- console.log(import_picocolors25.default.dim(`Showing ${items.length} of ${total}+ pending items (list truncated).`));
59620
+ console.log(import_picocolors25.default.dim(`Showing ${items.length} of ${total}+ pending items${inRange} (list truncated).`));
59493
59621
  }
59494
59622
  });
59495
59623
  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) => {
@@ -59667,6 +59795,7 @@ var init_review = __esm(() => {
59667
59795
  init_auth();
59668
59796
  init_confirmation();
59669
59797
  init_output();
59798
+ init_time_range();
59670
59799
  import_picocolors25 = __toESM(require_picocolors(), 1);
59671
59800
  });
59672
59801
 
@@ -66813,4 +66942,4 @@ main().catch((err) => {
66813
66942
  process.exit(1);
66814
66943
  });
66815
66944
 
66816
- //# debugId=ca9e58ba-ed30-6875-6475-6e2164756e21
66945
+ //# debugId=102e2621-b1fd-c662-6475-6e2164756e21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.57.1",
3
+ "version": "0.58.0",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Manage MCP servers for AI tools",
6
6
  "license": "MIT",