@duvoai/cli 1.30.0 → 1.32.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/bin/duvo.js CHANGED
@@ -3,9 +3,6 @@ var __defProp = Object.defineProperty;
3
3
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
4
4
 
5
5
  // src/bin/create-program.ts
6
- import { readFileSync as readFileSync8 } from "node:fs";
7
- import { dirname as dirname3, join as join3 } from "node:path";
8
- import { fileURLToPath as fileURLToPath2 } from "node:url";
9
6
  import { Command, Option as Option2 } from "commander";
10
7
 
11
8
  // src/api/agent-folder-schemas.ts
@@ -2676,6 +2673,34 @@ var BUILD_STATUS = {
2676
2673
  LIVE: "live",
2677
2674
  HISTORIC: "historic"
2678
2675
  };
2676
+ var CASE_PRIORITY = {
2677
+ NONE: "none",
2678
+ MEDIUM: "medium",
2679
+ HIGH: "high"
2680
+ };
2681
+ var CASE_PRIORITY_VALUES = {
2682
+ none: 0,
2683
+ medium: 10,
2684
+ high: 50
2685
+ };
2686
+ var DEFAULT_CASE_PRIORITY = CASE_PRIORITY.NONE;
2687
+ var DEFAULT_CASE_PRIORITY_VALUE = CASE_PRIORITY_VALUES.none;
2688
+ function casePriorityToValue(priority) {
2689
+ return CASE_PRIORITY_VALUES[priority];
2690
+ }
2691
+ __name(casePriorityToValue, "casePriorityToValue");
2692
+ __name2(casePriorityToValue, "casePriorityToValue");
2693
+ function casePriorityFromValue(value) {
2694
+ if (value >= CASE_PRIORITY_VALUES.high) {
2695
+ return CASE_PRIORITY.HIGH;
2696
+ }
2697
+ if (value >= CASE_PRIORITY_VALUES.medium) {
2698
+ return CASE_PRIORITY.MEDIUM;
2699
+ }
2700
+ return CASE_PRIORITY.NONE;
2701
+ }
2702
+ __name(casePriorityFromValue, "casePriorityFromValue");
2703
+ __name2(casePriorityFromValue, "casePriorityFromValue");
2679
2704
  var INGESTION_BODY_LIMIT_BYTES = 5 * 1024 * 1024;
2680
2705
  var CLARITY_WEBHOOK_BODY_LIMIT_BYTES = 25 * 1024 * 1024;
2681
2706
  var SENSITIVE_FIELD_KEYWORDS = [
@@ -3580,7 +3605,7 @@ var legacyClarityProcessDetailSchema = legacyClarityProcessDetailApiSchema.exten
3580
3605
  analysis: legacyClarityAnalysisSchema.nullable()
3581
3606
  });
3582
3607
  var createClarityProcessSchema = z15.object({
3583
- name: z15.string().min(1).max(255).optional()
3608
+ name: z15.string().min(1).max(255).optional().describe("Optional process name; server default applies when omitted")
3584
3609
  });
3585
3610
  var createClarityProcessResponseSchema = z15.object({
3586
3611
  id: z15.guid(),
@@ -3672,12 +3697,27 @@ var portfolioIntelligenceStatusSchema = z15.enum(
3672
3697
  PORTFOLIO_INTELLIGENCE_STATUSES
3673
3698
  );
3674
3699
  var EXECUTION_MODES = ["human-led", "hybrid", "agent-led"];
3700
+ var BENEFIT_BASES = ["evidenced", "estimate"];
3701
+ var operatingModelBenefitSchema = z15.object({
3702
+ statement: z15.string().min(1),
3703
+ basis: z15.enum(BENEFIT_BASES),
3704
+ assumption: z15.string().nullable(),
3705
+ dataToFirmUp: z15.string().nullable()
3706
+ }).refine(
3707
+ (benefit) => benefit.basis !== "estimate" || Boolean(benefit.assumption && benefit.assumption.trim().length > 0),
3708
+ {
3709
+ message: "Estimate benefits require a stated assumption",
3710
+ path: ["assumption"]
3711
+ }
3712
+ );
3675
3713
  var operatingModelValueStreamSchema = z15.object({
3676
3714
  name: z15.string().min(1),
3677
3715
  description: z15.string().min(1),
3678
3716
  currentPainPoints: z15.array(z15.string()),
3679
3717
  targetOutcome: z15.string().min(1),
3680
- kpis: z15.array(z15.string())
3718
+ kpis: z15.array(z15.string()),
3719
+ gap: z15.string().nullable().default(null),
3720
+ benefits: z15.array(operatingModelBenefitSchema).min(1).nullable().default(null)
3681
3721
  });
3682
3722
  var operatingModelOrgElementSchema = z15.object({
3683
3723
  element: z15.string().min(1),
@@ -3717,8 +3757,11 @@ var operatingModelTransformationPrioritySchema = z15.object({
3717
3757
  impact: z15.enum(PRIORITY_RATING_LEVELS),
3718
3758
  effort: z15.enum(PRIORITY_RATING_LEVELS),
3719
3759
  readiness: z15.enum(PRIORITY_RATING_LEVELS),
3760
+ // Displayed as "Evidence" in the UI; JSON key kept for stored-analysis
3761
+ // back-compat.
3720
3762
  confidence: z15.enum(PRIORITY_RATING_LEVELS),
3721
- quickWin: z15.boolean()
3763
+ quickWin: z15.boolean(),
3764
+ whyThisApproach: z15.string().nullable().default(null)
3722
3765
  });
3723
3766
  var ERP_GAP_DIMENSIONS = [
3724
3767
  "processes",
@@ -3793,6 +3836,11 @@ var operatingModelAnalysisSchema = z15.object({
3793
3836
  erpTransformationInsights: operatingModelErpInsightsSchema.nullable().default(null),
3794
3837
  objectionsAndChangeManagement: operatingModelObjectionsSchema.nullable().default(null),
3795
3838
  businessCase: z15.string().nullable(),
3839
+ transformationGoal: z15.object({
3840
+ objective: z15.string().min(1),
3841
+ targetEndState: z15.string().min(1),
3842
+ expectedBenefits: z15.array(operatingModelBenefitSchema).min(1)
3843
+ }).nullable().default(null),
3796
3844
  generatedAt: z15.string()
3797
3845
  });
3798
3846
  var portfolioProcessLinkSchema = z15.object({
@@ -6601,7 +6649,7 @@ var backgroundJobNotificationSchema = z25.object({
6601
6649
  jobType: backgroundJobTypeSchema,
6602
6650
  outcome: z25.enum(BACKGROUND_JOB_OUTCOMES),
6603
6651
  sourceId: z25.guid(),
6604
- processId: z25.string().nullable()
6652
+ processId: z25.string().nullable().default(null)
6605
6653
  });
6606
6654
  var RECONNECT_BROKEN_REASONS = [
6607
6655
  "oauth_grant_revoked",
@@ -6632,6 +6680,20 @@ var notificationSchema = z25.discriminatedUnion("type", [
6632
6680
  connectionBrokenNotificationSchema,
6633
6681
  scheduleIssueNotificationSchema
6634
6682
  ]);
6683
+ var fallbackNotificationSchema = z25.object({
6684
+ ...notificationBaseShape,
6685
+ type: z25.string(),
6686
+ fallback: z25.literal(true)
6687
+ });
6688
+ var notificationWireSchema = z25.union([
6689
+ notificationSchema,
6690
+ fallbackNotificationSchema
6691
+ ]);
6692
+ function isFallbackNotification(n) {
6693
+ return "fallback" in n && n.fallback === true;
6694
+ }
6695
+ __name(isFallbackNotification, "isFallbackNotification");
6696
+ __name2(isFallbackNotification, "isFallbackNotification");
6635
6697
  var NOTIFICATION_LIST_DEFAULT_LIMIT = 30;
6636
6698
  var NOTIFICATION_LIST_MAX_LIMIT = 100;
6637
6699
  var notificationListQuerySchema = z25.object({
@@ -6642,7 +6704,7 @@ var notificationListQuerySchema = z25.object({
6642
6704
  cursor: z25.string().optional()
6643
6705
  });
6644
6706
  var notificationListResponseSchema = z25.object({
6645
- items: z25.array(notificationSchema),
6707
+ items: z25.array(notificationWireSchema),
6646
6708
  nextCursor: z25.string().nullable()
6647
6709
  });
6648
6710
  var notificationUnreadCountResponseSchema = z25.object({
@@ -6669,8 +6731,14 @@ var agentNotificationSettingsResponseSchema = z25.object({
6669
6731
  });
6670
6732
  var notificationsRoomPayloadSchema = z26.object({ userId: z26.guid() });
6671
6733
  var notificationsEventPayloadSchema = z26.discriminatedUnion("type", [
6672
- z26.object({ type: z26.literal("created"), notification: notificationSchema }),
6673
- z26.object({ type: z26.literal("updated"), notification: notificationSchema }),
6734
+ z26.object({
6735
+ type: z26.literal("created"),
6736
+ notification: notificationWireSchema
6737
+ }),
6738
+ z26.object({
6739
+ type: z26.literal("updated"),
6740
+ notification: notificationWireSchema
6741
+ }),
6674
6742
  z26.object({ type: z26.literal("deleted"), notificationId: z26.guid() }),
6675
6743
  z26.object({ type: z26.literal("bulk_read") }),
6676
6744
  z26.object({ type: z26.literal("bulk_deleted") }),
@@ -9706,12 +9774,19 @@ var humanRequestContextSchema = z59.discriminatedUnion("kind", [
9706
9774
  caseTitle: z59.string()
9707
9775
  })
9708
9776
  ]);
9777
+ var casePrioritySchema = z60.enum([
9778
+ CASE_PRIORITY.NONE,
9779
+ CASE_PRIORITY.MEDIUM,
9780
+ CASE_PRIORITY.HIGH
9781
+ ]);
9709
9782
  var caseQueueItemSchema = z60.object({
9710
9783
  id: z60.guid(),
9711
9784
  queue_id: z60.guid(),
9712
9785
  title: z60.string(),
9713
9786
  data: z60.string(),
9714
9787
  status: z60.enum(["pending", "completed", "failed"]),
9788
+ /** Case priority level. `none` = default (no priority). */
9789
+ priority: casePrioritySchema,
9715
9790
  /**
9716
9791
  * Derived display bucket combining the settlement status with ownership,
9717
9792
  * open HITL tokens, and scheduling. See CASE_DISPLAY_STATUS in
@@ -9806,6 +9881,9 @@ var caseCreateInputSchema = z60.object({
9806
9881
  })
9807
9882
  ).max(50).optional().describe(
9808
9883
  "Optional labels to assign to the case at creation. Labels are created on the queue if they don't already exist."
9884
+ ),
9885
+ priority: casePrioritySchema.optional().describe(
9886
+ "Case priority. `medium` or `high` raise the case above the default in the queue; omit (or `none`) for normal priority. Only set this when the AOP or the user explicitly instructs prioritization \u2014 do not infer it on your own."
9809
9887
  )
9810
9888
  });
9811
9889
  var caseCreateRequestSchema = z60.object({
@@ -9929,6 +10007,10 @@ var caseBulkStatusUpdateResponseSchema = z60.object({
9929
10007
  skippedCount: z60.number(),
9930
10008
  interruptedRunIds: z60.array(z60.guid())
9931
10009
  });
10010
+ var caseBulkPriorityUpdateResponseSchema = z60.object({
10011
+ updatedCount: z60.number(),
10012
+ skippedCount: z60.number()
10013
+ });
9932
10014
  var deleteQueueResponseSchema = z60.object({
9933
10015
  success: z60.boolean(),
9934
10016
  deleted_case_count: z60.number(),
@@ -10017,7 +10099,9 @@ var exportCasesResponseSchema = z60.object({
10017
10099
  cases: z60.array(
10018
10100
  z60.object({
10019
10101
  title: z60.string(),
10020
- data: z60.string().optional()
10102
+ data: z60.string().optional(),
10103
+ /** Priority level; omitted for default (`none`) priority cases. */
10104
+ priority: casePrioritySchema.optional()
10021
10105
  })
10022
10106
  )
10023
10107
  });
@@ -11409,6 +11493,7 @@ function canonicalizeSopInput(config) {
11409
11493
  }
11410
11494
  __name(canonicalizeSopInput, "canonicalizeSopInput");
11411
11495
  __name2(canonicalizeSopInput, "canonicalizeSopInput");
11496
+ var casePriorityFilterSchema = casePrioritySchema;
11412
11497
  var caseFilterStatusSchema = z81.enum([
11413
11498
  "pending",
11414
11499
  "claimed",
@@ -11419,6 +11504,7 @@ var caseFilterStatusSchema = z81.enum([
11419
11504
  ]);
11420
11505
  var casesFiltersSchema = z81.object({
11421
11506
  status: z81.array(caseFilterStatusSchema).optional(),
11507
+ priority: z81.array(casePriorityFilterSchema).optional(),
11422
11508
  created_at_from: z81.string().optional(),
11423
11509
  updated_at_from: z81.string().optional(),
11424
11510
  labels: z81.record(z81.string(), z81.array(z81.string())).optional()
@@ -11504,6 +11590,9 @@ function getFilterValuesByCategoryKey(filters, categoryKey) {
11504
11590
  if (categoryKey === "status") {
11505
11591
  return filters.status ?? [];
11506
11592
  }
11593
+ if (categoryKey === "priority") {
11594
+ return filters.priority ?? [];
11595
+ }
11507
11596
  if (categoryKey === "created_at_from") {
11508
11597
  return filters.created_at_from ? [filters.created_at_from] : [];
11509
11598
  }
@@ -11530,6 +11619,17 @@ function setFilterValuesByCategoryKey(filters, categoryKey, values) {
11530
11619
  }
11531
11620
  return { ...filters, status: parsed.data };
11532
11621
  }
11622
+ if (categoryKey === "priority") {
11623
+ if (values.length === 0) {
11624
+ const { priority: _, ...rest } = filters;
11625
+ return rest;
11626
+ }
11627
+ const parsed = z81.array(casePriorityFilterSchema).safeParse(values);
11628
+ if (!parsed.success) {
11629
+ return filters;
11630
+ }
11631
+ return { ...filters, priority: parsed.data };
11632
+ }
11533
11633
  if (categoryKey === "created_at_from") {
11534
11634
  if (values.length === 0 || !values[0]) {
11535
11635
  const { created_at_from: _, ...rest } = filters;
@@ -11568,7 +11668,7 @@ function removeFilterByCategoryKey(filters, categoryKey) {
11568
11668
  __name(removeFilterByCategoryKey, "removeFilterByCategoryKey");
11569
11669
  __name2(removeFilterByCategoryKey, "removeFilterByCategoryKey");
11570
11670
  function isCasesFiltersEmpty(filters) {
11571
- return !filters.status?.length && !filters.created_at_from && !filters.updated_at_from && (!filters.labels || Object.keys(filters.labels).length === 0);
11671
+ return !filters.status?.length && !filters.priority?.length && !filters.created_at_from && !filters.updated_at_from && (!filters.labels || Object.keys(filters.labels).length === 0);
11572
11672
  }
11573
11673
  __name(isCasesFiltersEmpty, "isCasesFiltersEmpty");
11574
11674
  __name2(isCasesFiltersEmpty, "isCasesFiltersEmpty");
@@ -11577,6 +11677,9 @@ function countCasesFilters(filters) {
11577
11677
  if (filters.status?.length) {
11578
11678
  count += 1;
11579
11679
  }
11680
+ if (filters.priority?.length) {
11681
+ count += 1;
11682
+ }
11580
11683
  if (filters.created_at_from) {
11581
11684
  count += 1;
11582
11685
  }
@@ -12288,6 +12391,7 @@ var green = /* @__PURE__ */ __name((text3) => wrap(ANSI.green, text3), "green");
12288
12391
  var red = /* @__PURE__ */ __name((text3) => wrap(ANSI.red, text3), "red");
12289
12392
  var cyan = /* @__PURE__ */ __name((text3) => wrap(ANSI.cyan, text3), "cyan");
12290
12393
  var bold = /* @__PURE__ */ __name((text3) => wrap(ANSI.bold, text3), "bold");
12394
+ var dim = /* @__PURE__ */ __name((text3) => wrap(ANSI.dim, text3), "dim");
12291
12395
  var yellow = /* @__PURE__ */ __name((text3) => wrap(ANSI.yellow, text3), "yellow");
12292
12396
 
12293
12397
  // src/output/deprecation-notice.ts
@@ -17353,6 +17457,62 @@ function registerCasesBulkReprocess(cases) {
17353
17457
  }
17354
17458
  __name(registerCasesBulkReprocess, "registerCasesBulkReprocess");
17355
17459
 
17460
+ // src/commands/cases/bulk-update-priority.ts
17461
+ function registerCasesBulkUpdatePriority(cases) {
17462
+ cases.command("bulk-update-priority").description(
17463
+ "Set the priority of multiple cases (1-100). Due postponed cases are picked up first; otherwise higher priority is picked up first. Use 'none' to clear."
17464
+ ).requiredOption("--queue <id>", "ID of the queue the cases belong to").requiredOption("--ids <list>", "comma-separated case IDs (1-100)").requiredOption(
17465
+ "--priority <level>",
17466
+ `priority level (${casePrioritySchema.options.join(", ")})`
17467
+ ).option("-y, --yes", "skip confirmation prompt").option("--json", "output raw JSON from the API").action(/* @__PURE__ */ __name(async function bulkUpdatePriorityAction(options) {
17468
+ const caseIds = parseCaseIds(options.ids);
17469
+ const priority = parsePriority(options.priority);
17470
+ const { apiKey, apiBaseUrl } = await requireAuthenticatedConfig(this);
17471
+ await confirmDestructive({
17472
+ message: `Set the priority of ${caseIds.length} case(s) in queue "${options.queue}" to "${priority}"?`,
17473
+ skip: Boolean(options.yes)
17474
+ });
17475
+ const raw = await httpRequest({
17476
+ method: "POST",
17477
+ path: `/v2/queues/${encodeURIComponent(options.queue)}/cases/bulk-update-priority`,
17478
+ apiKey,
17479
+ apiBaseUrl,
17480
+ body: { case_ids: caseIds, priority }
17481
+ });
17482
+ if (options.json) {
17483
+ printJson(raw);
17484
+ return;
17485
+ }
17486
+ const parsed = caseBulkPriorityUpdateResponseSchema.safeParse(raw);
17487
+ if (!parsed.success) {
17488
+ throw new CliError(
17489
+ `Unexpected response from the API: ${parsed.error.message}`
17490
+ );
17491
+ }
17492
+ const result = parsed.data;
17493
+ console.log(green("Bulk priority update complete."));
17494
+ console.log();
17495
+ console.log(
17496
+ renderKeyValue([
17497
+ { label: "Updated", value: String(result.updatedCount) },
17498
+ { label: "Skipped", value: String(result.skippedCount) }
17499
+ ])
17500
+ );
17501
+ }, "bulkUpdatePriorityAction"));
17502
+ }
17503
+ __name(registerCasesBulkUpdatePriority, "registerCasesBulkUpdatePriority");
17504
+ function parsePriority(raw) {
17505
+ if (!casePrioritySchema.options.includes(
17506
+ raw
17507
+ )) {
17508
+ throw new CliError(
17509
+ `Invalid --priority value "${raw}". Allowed: ${casePrioritySchema.options.join(", ")}.`
17510
+ );
17511
+ }
17512
+ return raw;
17513
+ }
17514
+ __name(parsePriority, "parsePriority");
17515
+
17356
17516
  // src/commands/cases/bulk-update-status.ts
17357
17517
  var CASE_TERMINAL_STATUSES = ["completed", "failed"];
17358
17518
  function registerCasesBulkUpdateStatus(cases) {
@@ -17511,6 +17671,9 @@ function registerCasesCreate(cases) {
17511
17671
  cases.command("create").description(
17512
17672
  "Create one or more cases in a queue. Provide --title for one case or --from-file with a JSON array for many."
17513
17673
  ).requiredOption("--queue <id>", "ID of the queue to create cases in").option("--title <text>", "case title (max 500 chars)").option("--data <text>", "free-form data passed to the assignment on claim").option(
17674
+ "--priority <level>",
17675
+ `case priority (${casePrioritySchema.options.join(", ")}); only set when instructed`
17676
+ ).option(
17514
17677
  "--label <key=value>",
17515
17678
  "label to assign to the case (omit key for a simple tag, repeat for multiple)",
17516
17679
  collectLabel,
@@ -17555,9 +17718,9 @@ function collectLabel(value, previous) {
17555
17718
  __name(collectLabel, "collectLabel");
17556
17719
  async function buildRequestBody(options) {
17557
17720
  if (options.fromFile !== void 0) {
17558
- if (options.title !== void 0 || options.data !== void 0 || (options.label?.length ?? 0) > 0) {
17721
+ if (options.title !== void 0 || options.data !== void 0 || options.priority !== void 0 || (options.label?.length ?? 0) > 0) {
17559
17722
  throw new CliError(
17560
- "--from-file cannot be combined with --title, --data, or --label."
17723
+ "--from-file cannot be combined with --title, --data, --priority, or --label."
17561
17724
  );
17562
17725
  }
17563
17726
  return readCasesFromFile(options.fromFile);
@@ -17573,9 +17736,22 @@ async function buildRequestBody(options) {
17573
17736
  if (labels) {
17574
17737
  single.labels = labels;
17575
17738
  }
17739
+ if (options.priority !== void 0) {
17740
+ single.priority = parsePriority2(options.priority, "--priority");
17741
+ }
17576
17742
  return { case: single };
17577
17743
  }
17578
17744
  __name(buildRequestBody, "buildRequestBody");
17745
+ function parsePriority2(raw, location) {
17746
+ const parsed = casePrioritySchema.safeParse(raw);
17747
+ if (!parsed.success) {
17748
+ throw new CliError(
17749
+ `Invalid ${location} value "${raw}". Allowed: ${casePrioritySchema.options.join(", ")}.`
17750
+ );
17751
+ }
17752
+ return parsed.data;
17753
+ }
17754
+ __name(parsePriority2, "parsePriority");
17579
17755
  async function readCasesFromFile(path) {
17580
17756
  let raw;
17581
17757
  try {
@@ -17635,6 +17811,12 @@ function coerceCase(value, location) {
17635
17811
  (l, i) => coerceLabel(l, `${location}.labels[${i}]`)
17636
17812
  );
17637
17813
  }
17814
+ if (obj.priority !== void 0) {
17815
+ if (typeof obj.priority !== "string") {
17816
+ throw new CliError(`${location}.priority must be a string when present.`);
17817
+ }
17818
+ out.priority = parsePriority2(obj.priority, `${location}.priority`);
17819
+ }
17638
17820
  return out;
17639
17821
  }
17640
17822
  __name(coerceCase, "coerceCase");
@@ -17972,12 +18154,16 @@ var TABLE_COLUMNS18 = [
17972
18154
  { header: "ID", cell: /* @__PURE__ */ __name((row) => row.id, "cell") },
17973
18155
  { header: "TITLE", cell: /* @__PURE__ */ __name((row) => row.title, "cell"), maxWidth: 50 },
17974
18156
  { header: "STATUS", cell: /* @__PURE__ */ __name((row) => row.display_status, "cell") },
18157
+ { header: "PRIORITY", cell: /* @__PURE__ */ __name((row) => row.priority, "cell") },
17975
18158
  { header: "CREATED", cell: /* @__PURE__ */ __name((row) => row.created_at ?? "", "cell") }
17976
18159
  ];
17977
18160
  function registerCasesList(cases) {
17978
18161
  cases.command("list", { isDefault: true }).description("List cases in a queue").requiredOption("--queue <id>", "ID of the queue to list cases for").option("--limit <n>", `page size (${MIN_LIMIT3}-${MAX_LIMIT3})`).option("--offset <n>", "number of cases to skip").option(
17979
18162
  "--status <statuses>",
17980
18163
  `comma-separated case statuses (${caseFilterStatusSchema.options.join(", ")})`
18164
+ ).option(
18165
+ "--priority <levels>",
18166
+ `comma-separated priority levels (${casePriorityFilterSchema.options.join(", ")})`
17981
18167
  ).option("--search <text>", "full-text search across title and data").option(
17982
18168
  "--created-at-from <iso>",
17983
18169
  "include cases created on or after this ISO-8601 timestamp"
@@ -17995,6 +18181,7 @@ function registerCasesList(cases) {
17995
18181
  });
17996
18182
  const offset = parseOffset(options.offset);
17997
18183
  const statuses = parseStatuses(options.status);
18184
+ const priorities = parsePriorities(options.priority);
17998
18185
  const sortBy = parseSortBy(options.sortBy);
17999
18186
  const sortOrder = parseSortOrder(options.sortOrder);
18000
18187
  const { apiKey, apiBaseUrl } = await requireAuthenticatedConfig(this);
@@ -18004,6 +18191,9 @@ function registerCasesList(cases) {
18004
18191
  if (statuses) {
18005
18192
  searchParams.append("status", statuses.join(","));
18006
18193
  }
18194
+ if (priorities) {
18195
+ searchParams.append("priority", priorities.join(","));
18196
+ }
18007
18197
  if (options.search !== void 0) {
18008
18198
  searchParams.append("search", options.search);
18009
18199
  }
@@ -18069,6 +18259,26 @@ function parseStatuses(raw) {
18069
18259
  return parts;
18070
18260
  }
18071
18261
  __name(parseStatuses, "parseStatuses");
18262
+ function parsePriorities(raw) {
18263
+ if (raw === void 0) {
18264
+ return void 0;
18265
+ }
18266
+ const parts = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
18267
+ if (parts.length === 0) {
18268
+ throw new CliError(
18269
+ `Invalid --priority value "${raw}". Allowed: ${casePriorityFilterSchema.options.join(", ")}.`
18270
+ );
18271
+ }
18272
+ const allowed = new Set(casePriorityFilterSchema.options);
18273
+ const invalid = parts.filter((p) => !allowed.has(p));
18274
+ if (invalid.length > 0) {
18275
+ throw new CliError(
18276
+ `Invalid --priority value(s): ${invalid.join(", ")}. Allowed: ${casePriorityFilterSchema.options.join(", ")}.`
18277
+ );
18278
+ }
18279
+ return parts;
18280
+ }
18281
+ __name(parsePriorities, "parsePriorities");
18072
18282
  function parseSortBy(raw) {
18073
18283
  if (raw === void 0) {
18074
18284
  return void 0;
@@ -18246,6 +18456,7 @@ function registerCases(program) {
18246
18456
  registerCasesBulkDelete(cases);
18247
18457
  registerCasesBulkReprocess(cases);
18248
18458
  registerCasesBulkUpdateStatus(cases);
18459
+ registerCasesBulkUpdatePriority(cases);
18249
18460
  registerCasesRuns(cases);
18250
18461
  registerCasesLabels(cases);
18251
18462
  }
@@ -18292,6 +18503,16 @@ var createClarityInviteLinkResponseSchema = z93.object({
18292
18503
  })
18293
18504
  })
18294
18505
  });
18506
+ var createClarityProcessResponseSchema2 = z93.object({
18507
+ id: z93.guid(),
18508
+ name: z93.string(),
18509
+ status: clarityProcessStatusSchema,
18510
+ version: z93.union([z93.literal(1), z93.literal(2)]),
18511
+ createdAt: z93.string()
18512
+ });
18513
+ var getClarityCaptureResponseSchema = z93.object({
18514
+ capture: clarityCaptureSchema
18515
+ });
18295
18516
  var createArtifactImportUploadUrlResponseSchema = z93.object({
18296
18517
  signed_url: z93.url(),
18297
18518
  capture_id: z93.guid(),
@@ -18861,6 +19082,44 @@ function registerClarityCreateInviteLink(clarity) {
18861
19082
  }
18862
19083
  __name(registerClarityCreateInviteLink, "registerClarityCreateInviteLink");
18863
19084
 
19085
+ // src/commands/clarity/create-process.ts
19086
+ function registerClarityCreateProcess(clarity) {
19087
+ clarity.command("create").description("Create a new Clarity v2 process for the current team").option("--name <name>", "process name").option("--json", "output raw JSON from the API").action(/* @__PURE__ */ __name(async function action(options) {
19088
+ const config = await requireAuthenticatedConfig(this);
19089
+ const teamId = await resolveRequiredTeamId(config, {
19090
+ override: getTeamFlag(this)
19091
+ });
19092
+ const raw = await httpRequest({
19093
+ method: "POST",
19094
+ path: buildTeamPath(teamId, "/clarity/processes"),
19095
+ apiKey: config.apiKey,
19096
+ apiBaseUrl: config.apiBaseUrl,
19097
+ body: options.name === void 0 ? {} : { name: options.name }
19098
+ });
19099
+ const parsed = createClarityProcessResponseSchema2.safeParse(raw);
19100
+ if (!parsed.success) {
19101
+ throw new CliError(
19102
+ `Unexpected response from the API: ${parsed.error.message}`
19103
+ );
19104
+ }
19105
+ if (options.json) {
19106
+ printJson(raw);
19107
+ return;
19108
+ }
19109
+ const process2 = parsed.data;
19110
+ console.log(
19111
+ renderKeyValue([
19112
+ { label: "ID", value: process2.id },
19113
+ { label: "Name", value: process2.name },
19114
+ { label: "Status", value: process2.status },
19115
+ { label: "Version", value: String(process2.version) },
19116
+ { label: "Created", value: process2.createdAt }
19117
+ ])
19118
+ );
19119
+ }, "action"));
19120
+ }
19121
+ __name(registerClarityCreateProcess, "registerClarityCreateProcess");
19122
+
18864
19123
  // src/commands/clarity/doctor.ts
18865
19124
  import { z as z96 } from "zod";
18866
19125
 
@@ -19846,6 +20105,17 @@ async function getClarityV2Process(config, processId) {
19846
20105
  return parseResponse(clarityV2ProcessReadModelSchema, raw);
19847
20106
  }
19848
20107
  __name(getClarityV2Process, "getClarityV2Process");
20108
+ async function getClarityCapture(config, processId, captureId) {
20109
+ const raw = await getClarityJson(config, {
20110
+ method: "GET",
20111
+ path: `/v2/clarity-v2/processes/${encodeURIComponent(
20112
+ processId
20113
+ )}/captures/${encodeURIComponent(captureId)}`,
20114
+ resource: "Clarity capture"
20115
+ });
20116
+ return parseResponse(getClarityCaptureResponseSchema, raw).capture;
20117
+ }
20118
+ __name(getClarityCapture, "getClarityCapture");
19849
20119
  async function getLegacyClarityProcess(config, processId) {
19850
20120
  const raw = await getClarityJson(config, {
19851
20121
  method: "GET",
@@ -20021,6 +20291,19 @@ var CLARITY_READ_TOOLS = [
20021
20291
  endpoints: [{ method: "GET", path: "/v2/clarity-v2/processes/:processId" }],
20022
20292
  description: "Read the v2 process model: process metadata, captures, and lightweight current/proposal version lists."
20023
20293
  },
20294
+ {
20295
+ name: "getClarityCapture",
20296
+ scope: "v2",
20297
+ read_only: true,
20298
+ commands: ["duvo clarity capture"],
20299
+ endpoints: [
20300
+ {
20301
+ method: "GET",
20302
+ path: "/v2/clarity-v2/processes/:processId/captures/:captureId"
20303
+ }
20304
+ ],
20305
+ description: "Read one Clarity v2 capture including full transcript and video transcript."
20306
+ },
20024
20307
  {
20025
20308
  name: "getLegacyClarityProcess",
20026
20309
  scope: "v1 fallback",
@@ -20240,6 +20523,16 @@ var CLARITY_READ_TOOLS = [
20240
20523
  }
20241
20524
  ];
20242
20525
  var CLARITY_WRITE_TOOLS = [
20526
+ {
20527
+ name: "createClarityProcess",
20528
+ scope: "v1+v2",
20529
+ read_only: false,
20530
+ commands: ["duvo clarity create"],
20531
+ endpoints: [
20532
+ { method: "POST", path: "/v2/teams/:teamId/clarity/processes" }
20533
+ ],
20534
+ description: "Create a new Clarity v2 process for the current team (manager+)."
20535
+ },
20243
20536
  {
20244
20537
  name: "sendClarityArtifactChatMessage",
20245
20538
  scope: "v2",
@@ -23277,6 +23570,7 @@ function registerClarity(program) {
23277
23570
  registerClarityStopTransformationProposal(clarity);
23278
23571
  registerClarityCreateInviteLink(clarity);
23279
23572
  registerClarityImportArtifact(clarity);
23573
+ registerClarityCreateProcess(clarity);
23280
23574
  }
23281
23575
  __name(registerClarity, "registerClarity");
23282
23576
  function registerList2(clarity) {
@@ -23455,6 +23749,21 @@ function registerCapture(clarity) {
23455
23749
  "include capture transcripts and media URLs in JSON output"
23456
23750
  ).option("--json", "output JSON").action(/* @__PURE__ */ __name(async function captureAction(processId, captureId, options) {
23457
23751
  const config = await requireAuthenticatedConfig(this);
23752
+ if (options.includeTranscripts) {
23753
+ try {
23754
+ const capture2 = await getClarityCapture(config, processId, captureId);
23755
+ if (options.json) {
23756
+ printJson({ capture: buildCaptureOutput(capture2, options) });
23757
+ return;
23758
+ }
23759
+ console.log(renderCapturesTable([capture2]));
23760
+ return;
23761
+ } catch (error) {
23762
+ if (!isLegacyV2ReadError(error)) {
23763
+ throw error;
23764
+ }
23765
+ }
23766
+ }
23458
23767
  const { captures } = await loadProcessWithCaptures(config, processId);
23459
23768
  const capture = captures.find((item) => item.id === captureId);
23460
23769
  if (!capture) {
@@ -31710,6 +32019,357 @@ function registerTeams(program) {
31710
32019
  }
31711
32020
  __name(registerTeams, "registerTeams");
31712
32021
 
32022
+ // src/version/fetch-latest-binary-version.ts
32023
+ var CLI_RELEASES_BASE_URL = "https://storage.googleapis.com/duvo-cli-releases";
32024
+ var LATEST_POINTER_TIMEOUT_MS = 5e3;
32025
+ async function fetchLatestBinaryVersion() {
32026
+ const response = await fetch(`${CLI_RELEASES_BASE_URL}/latest`, {
32027
+ signal: AbortSignal.timeout(LATEST_POINTER_TIMEOUT_MS)
32028
+ });
32029
+ if (!response.ok) {
32030
+ throw new Error(`releases bucket responded with ${response.status}`);
32031
+ }
32032
+ const version2 = (await response.text()).trim().replace(/^v/, "");
32033
+ if (!/^\d+\.\d+\.\d+$/.test(version2)) {
32034
+ throw new Error(`releases bucket returned an invalid version: ${version2}`);
32035
+ }
32036
+ return version2;
32037
+ }
32038
+ __name(fetchLatestBinaryVersion, "fetchLatestBinaryVersion");
32039
+
32040
+ // src/version/fetch-latest-npm-version.ts
32041
+ var REGISTRY_TIMEOUT_MS = 5e3;
32042
+ async function fetchLatestNpmVersion(packageName, timeoutMs = REGISTRY_TIMEOUT_MS) {
32043
+ const response = await fetch(
32044
+ `https://registry.npmjs.org/-/package/${packageName}/dist-tags`,
32045
+ {
32046
+ signal: AbortSignal.timeout(timeoutMs),
32047
+ headers: { accept: "application/json" }
32048
+ }
32049
+ );
32050
+ if (!response.ok) {
32051
+ throw new Error(`npm registry responded with ${response.status}`);
32052
+ }
32053
+ const body = await response.json();
32054
+ if (body === null || typeof body !== "object" || typeof body.latest !== "string") {
32055
+ throw new Error("npm registry response is missing the latest dist-tag");
32056
+ }
32057
+ return body.latest;
32058
+ }
32059
+ __name(fetchLatestNpmVersion, "fetchLatestNpmVersion");
32060
+
32061
+ // src/version/is-newer-version.ts
32062
+ function isSafeNumericIdentifier(value) {
32063
+ return Number(value) <= Number.MAX_SAFE_INTEGER;
32064
+ }
32065
+ __name(isSafeNumericIdentifier, "isSafeNumericIdentifier");
32066
+ function parseVersion(version2) {
32067
+ const match = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?$/.exec(
32068
+ version2.trim()
32069
+ );
32070
+ if (!match) {
32071
+ return null;
32072
+ }
32073
+ const prerelease = match[4] ? match[4].split(".") : [];
32074
+ const numericIdentifiers = [
32075
+ match[1],
32076
+ match[2],
32077
+ match[3],
32078
+ ...prerelease.filter((identifier) => /^\d+$/.test(identifier))
32079
+ ];
32080
+ if (!numericIdentifiers.every(isSafeNumericIdentifier)) {
32081
+ return null;
32082
+ }
32083
+ return {
32084
+ core: [Number(match[1]), Number(match[2]), Number(match[3])],
32085
+ prerelease
32086
+ };
32087
+ }
32088
+ __name(parseVersion, "parseVersion");
32089
+ function comparePrereleaseIdentifiers(a, b) {
32090
+ const aIsNumeric = /^\d+$/.test(a);
32091
+ const bIsNumeric = /^\d+$/.test(b);
32092
+ if (aIsNumeric && bIsNumeric) {
32093
+ return Math.sign(Number(a) - Number(b));
32094
+ }
32095
+ if (aIsNumeric !== bIsNumeric) {
32096
+ return aIsNumeric ? -1 : 1;
32097
+ }
32098
+ if (a === b) {
32099
+ return 0;
32100
+ }
32101
+ return a < b ? -1 : 1;
32102
+ }
32103
+ __name(comparePrereleaseIdentifiers, "comparePrereleaseIdentifiers");
32104
+ function compareVersions(a, b) {
32105
+ for (let index = 0; index < 3; index += 1) {
32106
+ if (a.core[index] !== b.core[index]) {
32107
+ return Math.sign(a.core[index] - b.core[index]);
32108
+ }
32109
+ }
32110
+ if (a.prerelease.length === 0 || b.prerelease.length === 0) {
32111
+ return Math.sign(b.prerelease.length - a.prerelease.length);
32112
+ }
32113
+ const sharedLength = Math.min(a.prerelease.length, b.prerelease.length);
32114
+ for (let index = 0; index < sharedLength; index += 1) {
32115
+ const result = comparePrereleaseIdentifiers(
32116
+ a.prerelease[index],
32117
+ b.prerelease[index]
32118
+ );
32119
+ if (result !== 0) {
32120
+ return result;
32121
+ }
32122
+ }
32123
+ return Math.sign(a.prerelease.length - b.prerelease.length);
32124
+ }
32125
+ __name(compareVersions, "compareVersions");
32126
+ function isNewerVersion(candidate, current) {
32127
+ const parsedCandidate = parseVersion(candidate);
32128
+ const parsedCurrent = parseVersion(current);
32129
+ if (!parsedCandidate || !parsedCurrent) {
32130
+ return false;
32131
+ }
32132
+ return compareVersions(parsedCandidate, parsedCurrent) > 0;
32133
+ }
32134
+ __name(isNewerVersion, "isNewerVersion");
32135
+
32136
+ // src/version/is-standalone-binary.ts
32137
+ function isStandaloneBinary(moduleUrl = import.meta.url) {
32138
+ return moduleUrl.includes("$bunfs") || moduleUrl.includes("~BUN");
32139
+ }
32140
+ __name(isStandaloneBinary, "isStandaloneBinary");
32141
+
32142
+ // src/version/package-meta.ts
32143
+ import { createRequire } from "node:module";
32144
+ function getPackageMeta() {
32145
+ if (true) {
32146
+ return { name: "@duvoai/cli", version: "1.32.0" };
32147
+ }
32148
+ const require2 = createRequire(import.meta.url);
32149
+ const raw = require2("../../package.json");
32150
+ if (typeof raw !== "object" || raw === null || !("name" in raw) || !("version" in raw) || typeof raw.name !== "string" || typeof raw.version !== "string") {
32151
+ throw new Error("package.json is missing name or version");
32152
+ }
32153
+ const typed = raw;
32154
+ return { name: typed.name, version: typed.version };
32155
+ }
32156
+ __name(getPackageMeta, "getPackageMeta");
32157
+
32158
+ // src/commands/update/self-update-binary.ts
32159
+ import { createHash as createHash2 } from "node:crypto";
32160
+ import { rename, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
32161
+ import { dirname as dirname3 } from "node:path";
32162
+ var DOWNLOAD_TIMEOUT_MS = 12e4;
32163
+ var EXECUTABLE_MODE = 493;
32164
+ var BINARY_ASSETS = {
32165
+ "linux-x64": "duvo-linux-x64",
32166
+ "linux-arm64": "duvo-linux-arm64",
32167
+ "darwin-x64": "duvo-darwin-x64",
32168
+ "darwin-arm64": "duvo-darwin-arm64"
32169
+ };
32170
+ function resolveBinaryAsset(platform2 = process.platform, arch = process.arch) {
32171
+ const asset = BINARY_ASSETS[`${platform2}-${arch}`];
32172
+ if (!asset) {
32173
+ throw new CliError(
32174
+ `no prebuilt duvo binary for ${platform2}-${arch} (supported: ${Object.keys(BINARY_ASSETS).join(", ")})`
32175
+ );
32176
+ }
32177
+ return asset;
32178
+ }
32179
+ __name(resolveBinaryAsset, "resolveBinaryAsset");
32180
+ async function selfUpdateBinary({
32181
+ version: version2,
32182
+ asset,
32183
+ execPath = process.execPath,
32184
+ fetchImpl = fetch
32185
+ }) {
32186
+ const url = `${CLI_RELEASES_BASE_URL}/v${version2}/${asset}`;
32187
+ const [binaryResponse, checksumResponse] = await Promise.all([
32188
+ fetchImpl(url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS) }),
32189
+ fetchImpl(`${url}.sha256`, {
32190
+ signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
32191
+ })
32192
+ ]);
32193
+ if (!binaryResponse.ok) {
32194
+ throw new CliError(
32195
+ `failed to download ${url} (HTTP ${binaryResponse.status})`
32196
+ );
32197
+ }
32198
+ if (!checksumResponse.ok) {
32199
+ throw new CliError(
32200
+ `failed to download ${url}.sha256 (HTTP ${checksumResponse.status})`
32201
+ );
32202
+ }
32203
+ const bytes = Buffer.from(await binaryResponse.arrayBuffer());
32204
+ const expected = (await checksumResponse.text()).trim().split(/\s+/)[0];
32205
+ const actual = createHash2("sha256").update(bytes).digest("hex");
32206
+ if (expected !== actual) {
32207
+ throw new CliError(
32208
+ `checksum mismatch for ${asset} (expected ${expected}, got ${actual}) \u2014 not installing`
32209
+ );
32210
+ }
32211
+ const stagedPath = `${execPath}.update-${process.pid}`;
32212
+ try {
32213
+ await writeFile4(stagedPath, bytes, { mode: EXECUTABLE_MODE });
32214
+ await rename(stagedPath, execPath);
32215
+ } catch (error) {
32216
+ await rm2(stagedPath, { force: true });
32217
+ if (isPermissionError(error)) {
32218
+ throw new CliError(
32219
+ `cannot write to ${dirname3(execPath)} \u2014 re-run the installer, which handles sudo:
32220
+ curl -fsSL https://duvo.ai/install-cli.sh | sh`
32221
+ );
32222
+ }
32223
+ throw error;
32224
+ }
32225
+ }
32226
+ __name(selfUpdateBinary, "selfUpdateBinary");
32227
+ function isPermissionError(error) {
32228
+ if (!(error instanceof Error) || !("code" in error)) {
32229
+ return false;
32230
+ }
32231
+ const { code } = error;
32232
+ return code === "EACCES" || code === "EPERM" || code === "EROFS";
32233
+ }
32234
+ __name(isPermissionError, "isPermissionError");
32235
+
32236
+ // src/commands/update/self-update-npm.ts
32237
+ import { spawn as spawn2 } from "node:child_process";
32238
+ function selfUpdateNpm(packageName, { quiet = false, spawnImpl = spawn2 } = {}) {
32239
+ return new Promise((resolve, reject) => {
32240
+ const child = spawnImpl("npm", ["install", "-g", `${packageName}@latest`], {
32241
+ stdio: quiet ? ["ignore", "ignore", "inherit"] : "inherit"
32242
+ });
32243
+ child.on("error", (error) => {
32244
+ reject(
32245
+ new CliError(
32246
+ `failed to run npm: ${error.message} \u2014 is npm on your PATH?`
32247
+ )
32248
+ );
32249
+ });
32250
+ child.on("close", (code) => {
32251
+ if (code === 0) {
32252
+ resolve();
32253
+ } else {
32254
+ reject(
32255
+ new CliError(
32256
+ `\`npm install -g ${packageName}@latest\` exited with code ${String(code)}`
32257
+ )
32258
+ );
32259
+ }
32260
+ });
32261
+ });
32262
+ }
32263
+ __name(selfUpdateNpm, "selfUpdateNpm");
32264
+
32265
+ // src/commands/update/index.ts
32266
+ function registerUpdate3(program) {
32267
+ program.command("update").description(
32268
+ "Update the duvo CLI to the latest version. Auto-detects the install method: npm installs run `npm install -g`, standalone binaries (curl installer) self-replace in place."
32269
+ ).option("--check", "check for a newer version without installing it").option("--json", "output raw JSON").action(async (options) => {
32270
+ await runUpdate(options);
32271
+ });
32272
+ }
32273
+ __name(registerUpdate3, "registerUpdate");
32274
+ async function runUpdate(options) {
32275
+ const pkg = getPackageMeta();
32276
+ const installMethod = isStandaloneBinary() ? "binary" : "npm";
32277
+ const latestVersion = await resolveLatestVersion(installMethod, pkg.name);
32278
+ const updateAvailable = isNewerVersion(latestVersion, pkg.version);
32279
+ if (options.check) {
32280
+ printCheckResult(pkg.version, latestVersion, installMethod, options);
32281
+ return;
32282
+ }
32283
+ if (!updateAvailable) {
32284
+ if (options.json) {
32285
+ printJson({
32286
+ currentVersion: pkg.version,
32287
+ latestVersion,
32288
+ installMethod,
32289
+ updated: false
32290
+ });
32291
+ } else {
32292
+ console.log(`Already up to date (v${pkg.version}).`);
32293
+ }
32294
+ return;
32295
+ }
32296
+ if (installMethod === "binary") {
32297
+ await updateStandaloneBinary(pkg.version, latestVersion, options);
32298
+ } else {
32299
+ await updateNpmInstall(pkg.name, pkg.version, latestVersion, options);
32300
+ }
32301
+ }
32302
+ __name(runUpdate, "runUpdate");
32303
+ async function resolveLatestVersion(installMethod, packageName) {
32304
+ try {
32305
+ return installMethod === "binary" ? await fetchLatestBinaryVersion() : await fetchLatestNpmVersion(packageName);
32306
+ } catch (error) {
32307
+ const message = error instanceof Error ? error.message : String(error);
32308
+ throw new CliError(`failed to determine the latest version: ${message}`);
32309
+ }
32310
+ }
32311
+ __name(resolveLatestVersion, "resolveLatestVersion");
32312
+ function printCheckResult(currentVersion, latestVersion, installMethod, options) {
32313
+ const updateAvailable = isNewerVersion(latestVersion, currentVersion);
32314
+ if (options.json) {
32315
+ printJson({
32316
+ currentVersion,
32317
+ latestVersion,
32318
+ installMethod,
32319
+ updateAvailable
32320
+ });
32321
+ return;
32322
+ }
32323
+ console.log(`Current ${currentVersion}`);
32324
+ console.log(`Latest ${latestVersion}`);
32325
+ console.log(
32326
+ `Install ${installMethod === "binary" ? "standalone binary (curl installer)" : "npm"}`
32327
+ );
32328
+ console.log(
32329
+ updateAvailable ? "Update available \u2014 run `duvo update` to install it." : "Already up to date."
32330
+ );
32331
+ }
32332
+ __name(printCheckResult, "printCheckResult");
32333
+ async function updateStandaloneBinary(currentVersion, latestVersion, options) {
32334
+ const asset = resolveBinaryAsset();
32335
+ if (!options.json) {
32336
+ console.log(
32337
+ `Updating duvo ${currentVersion} \u2192 ${latestVersion} (standalone binary)`
32338
+ );
32339
+ console.log(`Downloading ${asset}\u2026`);
32340
+ }
32341
+ await selfUpdateBinary({ version: latestVersion, asset });
32342
+ if (options.json) {
32343
+ printJson({
32344
+ currentVersion,
32345
+ latestVersion,
32346
+ installMethod: "binary",
32347
+ updated: true
32348
+ });
32349
+ } else {
32350
+ console.log(`Updated ${process.execPath} to v${latestVersion}.`);
32351
+ }
32352
+ }
32353
+ __name(updateStandaloneBinary, "updateStandaloneBinary");
32354
+ async function updateNpmInstall(packageName, currentVersion, latestVersion, options) {
32355
+ if (!options.json) {
32356
+ console.log(`Updating duvo ${currentVersion} \u2192 ${latestVersion} (npm)`);
32357
+ console.log(`Running \`npm install -g ${packageName}@latest\`\u2026`);
32358
+ }
32359
+ await selfUpdateNpm(packageName, { quiet: options.json === true });
32360
+ if (options.json) {
32361
+ printJson({
32362
+ currentVersion,
32363
+ latestVersion,
32364
+ installMethod: "npm",
32365
+ updated: true
32366
+ });
32367
+ } else {
32368
+ console.log(`Updated to v${latestVersion}.`);
32369
+ }
32370
+ }
32371
+ __name(updateNpmInstall, "updateNpmInstall");
32372
+
31713
32373
  // src/commands/whoami.ts
31714
32374
  function registerWhoami(program) {
31715
32375
  program.command("whoami").description(
@@ -31759,20 +32419,137 @@ async function resolveActiveTeamId(config, override) {
31759
32419
  }
31760
32420
  __name(resolveActiveTeamId, "resolveActiveTeamId");
31761
32421
 
31762
- // src/bin/create-program.ts
31763
- var version = resolveVersion();
31764
- function resolveVersion() {
31765
- if (true) {
31766
- return "1.30.0";
32422
+ // src/update-check.ts
32423
+ import { readFileSync as readFileSync8 } from "node:fs";
32424
+ import { mkdir as mkdir2, readFile as readFile10, writeFile as writeFile5 } from "node:fs/promises";
32425
+ import { dirname as dirname4 } from "node:path";
32426
+
32427
+ // src/output/notice-box.ts
32428
+ var ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
32429
+ var HORIZONTAL_PADDING = 3;
32430
+ function visibleLength(line) {
32431
+ return line.replace(ANSI_PATTERN, "").length;
32432
+ }
32433
+ __name(visibleLength, "visibleLength");
32434
+ function renderNoticeBox(lines) {
32435
+ const contentWidth = Math.max(...lines.map(visibleLength));
32436
+ const innerWidth = contentWidth + HORIZONTAL_PADDING * 2;
32437
+ const pad2 = " ".repeat(HORIZONTAL_PADDING);
32438
+ const emptyRow = `${yellow("\u2502")}${" ".repeat(innerWidth)}${yellow("\u2502")}`;
32439
+ const body = lines.map((line) => {
32440
+ const fill = " ".repeat(contentWidth - visibleLength(line));
32441
+ return `${yellow("\u2502")}${pad2}${line}${fill}${pad2}${yellow("\u2502")}`;
32442
+ });
32443
+ return [
32444
+ yellow(`\u256D${"\u2500".repeat(innerWidth)}\u256E`),
32445
+ emptyRow,
32446
+ ...body,
32447
+ emptyRow,
32448
+ yellow(`\u2570${"\u2500".repeat(innerWidth)}\u256F`)
32449
+ ].join("\n");
32450
+ }
32451
+ __name(renderNoticeBox, "renderNoticeBox");
32452
+
32453
+ // src/update-check.ts
32454
+ var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
32455
+ var REGISTRY_TIMEOUT_MS2 = 2e3;
32456
+ var DIR_MODE2 = 448;
32457
+ function checkForUpdate() {
32458
+ if (isUpdateCheckDisabled()) {
32459
+ return Promise.resolve();
31767
32460
  }
31768
- const packageJsonPath = join3(
31769
- dirname3(fileURLToPath2(import.meta.url)),
31770
- "../../package.json"
31771
- );
31772
- const { version: v } = JSON.parse(readFileSync8(packageJsonPath, "utf8"));
31773
- return v;
32461
+ return runUpdateCheck().catch(() => {
32462
+ });
32463
+ }
32464
+ __name(checkForUpdate, "checkForUpdate");
32465
+ function getPendingUpdateNotice() {
32466
+ if (isUpdateCheckDisabled()) {
32467
+ return null;
32468
+ }
32469
+ const pkg = getPackageMeta();
32470
+ const cache = readCacheSync();
32471
+ if (cache && isNewerVersion(cache.latestVersion, pkg.version)) {
32472
+ return renderUpdateNotice(pkg, cache.latestVersion);
32473
+ }
32474
+ return null;
32475
+ }
32476
+ __name(getPendingUpdateNotice, "getPendingUpdateNotice");
32477
+ function isUpdateCheckDisabled() {
32478
+ const ci = process.env.CI;
32479
+ return process.env.NO_UPDATE_NOTIFIER !== void 0 || process.env.NODE_ENV === "test" || ci !== void 0 && ci !== "" && ci !== "false" && ci !== "0" || process.argv.includes("--no-update-notifier");
32480
+ }
32481
+ __name(isUpdateCheckDisabled, "isUpdateCheckDisabled");
32482
+ async function runUpdateCheck() {
32483
+ const pkg = getPackageMeta();
32484
+ const cache = await readCache();
32485
+ if (cache && isNewerVersion(cache.latestVersion, pkg.version)) {
32486
+ console.error(`
32487
+ ${renderUpdateNotice(pkg, cache.latestVersion)}
32488
+ `);
32489
+ }
32490
+ const isFresh = cache && Date.now() - cache.lastCheckedAtMs < ONE_DAY_MS;
32491
+ if (isFresh) {
32492
+ return;
32493
+ }
32494
+ await refreshCache(pkg, cache);
32495
+ }
32496
+ __name(runUpdateCheck, "runUpdateCheck");
32497
+ async function refreshCache(pkg, previous) {
32498
+ try {
32499
+ const latestVersion = await fetchLatestNpmVersion(
32500
+ pkg.name,
32501
+ REGISTRY_TIMEOUT_MS2
32502
+ );
32503
+ await writeCache({ lastCheckedAtMs: Date.now(), latestVersion });
32504
+ } catch {
32505
+ await writeCache({
32506
+ lastCheckedAtMs: Date.now(),
32507
+ latestVersion: previous?.latestVersion ?? pkg.version
32508
+ });
32509
+ }
32510
+ }
32511
+ __name(refreshCache, "refreshCache");
32512
+ function renderUpdateNotice(pkg, latestVersion) {
32513
+ const fallbackCommand = isStandaloneBinary() ? "curl -fsSL https://duvo.ai/install-cli.sh | sh" : `npm install -g ${pkg.name}`;
32514
+ return renderNoticeBox([
32515
+ `Update available for ${bold(pkg.name)}: ${dim(pkg.version)} \u2192 ${green(latestVersion)}`,
32516
+ `Run ${cyan("duvo update")} (or \`${fallbackCommand}\`) to update.`
32517
+ ]);
32518
+ }
32519
+ __name(renderUpdateNotice, "renderUpdateNotice");
32520
+ function parseCache(raw) {
32521
+ const parsed = JSON.parse(raw);
32522
+ if (parsed === null || typeof parsed !== "object" || typeof parsed.lastCheckedAtMs !== "number" || typeof parsed.latestVersion !== "string") {
32523
+ return null;
32524
+ }
32525
+ return parsed;
31774
32526
  }
31775
- __name(resolveVersion, "resolveVersion");
32527
+ __name(parseCache, "parseCache");
32528
+ async function readCache() {
32529
+ try {
32530
+ return parseCache(await readFile10(getUpdateCheckCachePath(), "utf8"));
32531
+ } catch {
32532
+ return null;
32533
+ }
32534
+ }
32535
+ __name(readCache, "readCache");
32536
+ function readCacheSync() {
32537
+ try {
32538
+ return parseCache(readFileSync8(getUpdateCheckCachePath(), "utf8"));
32539
+ } catch {
32540
+ return null;
32541
+ }
32542
+ }
32543
+ __name(readCacheSync, "readCacheSync");
32544
+ async function writeCache(cache) {
32545
+ const path = getUpdateCheckCachePath();
32546
+ await mkdir2(dirname4(path), { recursive: true, mode: DIR_MODE2 });
32547
+ await writeFile5(path, JSON.stringify(cache), "utf8");
32548
+ }
32549
+ __name(writeCache, "writeCache");
32550
+
32551
+ // src/bin/create-program.ts
32552
+ var { version } = getPackageMeta();
31776
32553
  function createProgram() {
31777
32554
  const program = new Command();
31778
32555
  program.name("duvo").description("Command-line interface for the Duvo public API").version(version).option(
@@ -31799,6 +32576,11 @@ function createProgram() {
31799
32576
  ""
31800
32577
  ].join("\n")
31801
32578
  );
32579
+ program.addHelpText("afterAll", () => {
32580
+ const notice = getPendingUpdateNotice();
32581
+ return notice ? `
32582
+ ${notice}` : "";
32583
+ });
31802
32584
  registerLogin(program);
31803
32585
  registerLogout(program);
31804
32586
  registerWhoami(program);
@@ -31829,146 +32611,11 @@ function createProgram() {
31829
32611
  registerRevisionLogins(program);
31830
32612
  registerClarity(program);
31831
32613
  registerPulse(program);
32614
+ registerUpdate3(program);
31832
32615
  return program;
31833
32616
  }
31834
32617
  __name(createProgram, "createProgram");
31835
32618
 
31836
- // src/update-check.ts
31837
- import { mkdir as mkdir2, readFile as readFile10, writeFile as writeFile4 } from "node:fs/promises";
31838
- import { createRequire } from "node:module";
31839
- import { dirname as dirname4 } from "node:path";
31840
- var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
31841
- var REGISTRY_TIMEOUT_MS = 2e3;
31842
- var DIR_MODE2 = 448;
31843
- function checkForUpdate() {
31844
- if (isUpdateCheckDisabled()) {
31845
- return Promise.resolve();
31846
- }
31847
- return runUpdateCheck().catch(() => {
31848
- });
31849
- }
31850
- __name(checkForUpdate, "checkForUpdate");
31851
- function isUpdateCheckDisabled() {
31852
- const ci = process.env.CI;
31853
- return process.env.NO_UPDATE_NOTIFIER !== void 0 || process.env.NODE_ENV === "test" || ci !== void 0 && ci !== "" && ci !== "false" && ci !== "0" || process.argv.includes("--no-update-notifier");
31854
- }
31855
- __name(isUpdateCheckDisabled, "isUpdateCheckDisabled");
31856
- async function runUpdateCheck() {
31857
- const pkg = loadPackageMeta();
31858
- const cache = await readCache();
31859
- if (cache && isNewerVersion(cache.latestVersion, pkg.version)) {
31860
- printUpdateNotice(pkg, cache.latestVersion);
31861
- }
31862
- const isFresh = cache && Date.now() - cache.lastCheckedAtMs < ONE_DAY_MS;
31863
- if (isFresh) {
31864
- return;
31865
- }
31866
- await refreshCache(pkg, cache);
31867
- }
31868
- __name(runUpdateCheck, "runUpdateCheck");
31869
- async function refreshCache(pkg, previous) {
31870
- try {
31871
- const latestVersion = await fetchLatestVersion(pkg.name);
31872
- await writeCache({ lastCheckedAtMs: Date.now(), latestVersion });
31873
- } catch {
31874
- await writeCache({
31875
- lastCheckedAtMs: Date.now(),
31876
- latestVersion: previous?.latestVersion ?? pkg.version
31877
- });
31878
- }
31879
- }
31880
- __name(refreshCache, "refreshCache");
31881
- function printUpdateNotice(pkg, latestVersion) {
31882
- const updateCommand = resolveUpdateCommand(pkg.name, isStandaloneBinary());
31883
- console.error(
31884
- `
31885
- Update available for ${pkg.name}: ${pkg.version} \u2192 ${latestVersion}
31886
- Run \`${updateCommand}\` to update.
31887
- `
31888
- );
31889
- }
31890
- __name(printUpdateNotice, "printUpdateNotice");
31891
- function resolveUpdateCommand(packageName, isStandalone) {
31892
- return isStandalone ? "curl -fsSL https://duvo.ai/install-cli.sh | sh" : `npm install -g ${packageName}`;
31893
- }
31894
- __name(resolveUpdateCommand, "resolveUpdateCommand");
31895
- function isStandaloneBinary() {
31896
- return import.meta.url.includes("$bunfs") || import.meta.url.includes("~BUN");
31897
- }
31898
- __name(isStandaloneBinary, "isStandaloneBinary");
31899
- async function fetchLatestVersion(packageName) {
31900
- const response = await fetch(
31901
- `https://registry.npmjs.org/-/package/${packageName}/dist-tags`,
31902
- {
31903
- signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS),
31904
- headers: { accept: "application/json" }
31905
- }
31906
- );
31907
- if (!response.ok) {
31908
- throw new Error(`npm registry responded with ${response.status}`);
31909
- }
31910
- const body = await response.json();
31911
- if (body === null || typeof body !== "object" || typeof body.latest !== "string") {
31912
- throw new Error("npm registry response is missing the latest dist-tag");
31913
- }
31914
- return body.latest;
31915
- }
31916
- __name(fetchLatestVersion, "fetchLatestVersion");
31917
- async function readCache() {
31918
- try {
31919
- const raw = await readFile10(getUpdateCheckCachePath(), "utf8");
31920
- const parsed = JSON.parse(raw);
31921
- if (parsed === null || typeof parsed !== "object" || typeof parsed.lastCheckedAtMs !== "number" || typeof parsed.latestVersion !== "string") {
31922
- return null;
31923
- }
31924
- return parsed;
31925
- } catch {
31926
- return null;
31927
- }
31928
- }
31929
- __name(readCache, "readCache");
31930
- async function writeCache(cache) {
31931
- const path = getUpdateCheckCachePath();
31932
- await mkdir2(dirname4(path), { recursive: true, mode: DIR_MODE2 });
31933
- await writeFile4(path, JSON.stringify(cache), "utf8");
31934
- }
31935
- __name(writeCache, "writeCache");
31936
- function parseVersion(version2) {
31937
- const match = /^v?(\d+)\.(\d+)\.(\d+)/.exec(version2.trim());
31938
- if (!match) {
31939
- return null;
31940
- }
31941
- return [Number(match[1]), Number(match[2]), Number(match[3])];
31942
- }
31943
- __name(parseVersion, "parseVersion");
31944
- function isNewerVersion(candidate, current) {
31945
- const parsedCandidate = parseVersion(candidate);
31946
- const parsedCurrent = parseVersion(current);
31947
- if (!parsedCandidate || !parsedCurrent) {
31948
- return false;
31949
- }
31950
- for (let index = 0; index < 3; index += 1) {
31951
- if (parsedCandidate[index] !== parsedCurrent[index]) {
31952
- return parsedCandidate[index] > parsedCurrent[index];
31953
- }
31954
- }
31955
- return false;
31956
- }
31957
- __name(isNewerVersion, "isNewerVersion");
31958
- function loadPackageMeta() {
31959
- if (true) {
31960
- return { name: "@duvoai/cli", version: "1.30.0" };
31961
- }
31962
- const require2 = createRequire(import.meta.url);
31963
- const raw = require2("../package.json");
31964
- if (typeof raw !== "object" || raw === null || !("name" in raw) || !("version" in raw) || typeof raw.name !== "string" || typeof raw.version !== "string") {
31965
- throw new Error("package.json is missing name or version");
31966
- }
31967
- const typed = raw;
31968
- return { name: typed.name, version: typed.version };
31969
- }
31970
- __name(loadPackageMeta, "loadPackageMeta");
31971
-
31972
32619
  // src/bin/duvo.ts
31973
32620
  void checkForUpdate();
31974
32621
  createProgram().parseAsync(process.argv).catch((error) => {