@duvoai/cli 1.28.1 → 1.31.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 = [
@@ -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") }),
@@ -8120,10 +8188,18 @@ var adminDreamEditReferenceSchema = z38.object({
8120
8188
  source_refs: z38.array(memorySourceRefSchema),
8121
8189
  created_at: z38.string()
8122
8190
  });
8191
+ var adminDreamTraceEntrySchema = z38.object({
8192
+ type: z38.string().max(128),
8193
+ role: z38.string().max(64).optional(),
8194
+ toolName: z38.string().max(512).optional(),
8195
+ contentPreview: z38.string().max(2e3).optional(),
8196
+ ts: z38.string()
8197
+ });
8123
8198
  var adminDreamingRunDetailSchema = adminDreamingRunSummarySchema.extend({
8124
8199
  input: z38.record(z38.string(), z38.unknown()),
8125
8200
  resolvedInputs: z38.array(adminDreamResolvedInputSchema),
8126
- editReferences: z38.array(adminDreamEditReferenceSchema)
8201
+ editReferences: z38.array(adminDreamEditReferenceSchema),
8202
+ sessionTrace: z38.array(adminDreamTraceEntrySchema)
8127
8203
  });
8128
8204
  var adminDreamingRunDetailResponseSchema = z38.object({
8129
8205
  dream: adminDreamingRunDetailSchema
@@ -9698,12 +9774,19 @@ var humanRequestContextSchema = z59.discriminatedUnion("kind", [
9698
9774
  caseTitle: z59.string()
9699
9775
  })
9700
9776
  ]);
9777
+ var casePrioritySchema = z60.enum([
9778
+ CASE_PRIORITY.NONE,
9779
+ CASE_PRIORITY.MEDIUM,
9780
+ CASE_PRIORITY.HIGH
9781
+ ]);
9701
9782
  var caseQueueItemSchema = z60.object({
9702
9783
  id: z60.guid(),
9703
9784
  queue_id: z60.guid(),
9704
9785
  title: z60.string(),
9705
9786
  data: z60.string(),
9706
9787
  status: z60.enum(["pending", "completed", "failed"]),
9788
+ /** Case priority level. `none` = default (no priority). */
9789
+ priority: casePrioritySchema,
9707
9790
  /**
9708
9791
  * Derived display bucket combining the settlement status with ownership,
9709
9792
  * open HITL tokens, and scheduling. See CASE_DISPLAY_STATUS in
@@ -9798,6 +9881,9 @@ var caseCreateInputSchema = z60.object({
9798
9881
  })
9799
9882
  ).max(50).optional().describe(
9800
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."
9801
9887
  )
9802
9888
  });
9803
9889
  var caseCreateRequestSchema = z60.object({
@@ -9921,6 +10007,10 @@ var caseBulkStatusUpdateResponseSchema = z60.object({
9921
10007
  skippedCount: z60.number(),
9922
10008
  interruptedRunIds: z60.array(z60.guid())
9923
10009
  });
10010
+ var caseBulkPriorityUpdateResponseSchema = z60.object({
10011
+ updatedCount: z60.number(),
10012
+ skippedCount: z60.number()
10013
+ });
9924
10014
  var deleteQueueResponseSchema = z60.object({
9925
10015
  success: z60.boolean(),
9926
10016
  deleted_case_count: z60.number(),
@@ -10009,7 +10099,9 @@ var exportCasesResponseSchema = z60.object({
10009
10099
  cases: z60.array(
10010
10100
  z60.object({
10011
10101
  title: z60.string(),
10012
- data: z60.string().optional()
10102
+ data: z60.string().optional(),
10103
+ /** Priority level; omitted for default (`none`) priority cases. */
10104
+ priority: casePrioritySchema.optional()
10013
10105
  })
10014
10106
  )
10015
10107
  });
@@ -11401,6 +11493,7 @@ function canonicalizeSopInput(config) {
11401
11493
  }
11402
11494
  __name(canonicalizeSopInput, "canonicalizeSopInput");
11403
11495
  __name2(canonicalizeSopInput, "canonicalizeSopInput");
11496
+ var casePriorityFilterSchema = casePrioritySchema;
11404
11497
  var caseFilterStatusSchema = z81.enum([
11405
11498
  "pending",
11406
11499
  "claimed",
@@ -11411,6 +11504,7 @@ var caseFilterStatusSchema = z81.enum([
11411
11504
  ]);
11412
11505
  var casesFiltersSchema = z81.object({
11413
11506
  status: z81.array(caseFilterStatusSchema).optional(),
11507
+ priority: z81.array(casePriorityFilterSchema).optional(),
11414
11508
  created_at_from: z81.string().optional(),
11415
11509
  updated_at_from: z81.string().optional(),
11416
11510
  labels: z81.record(z81.string(), z81.array(z81.string())).optional()
@@ -11496,6 +11590,9 @@ function getFilterValuesByCategoryKey(filters, categoryKey) {
11496
11590
  if (categoryKey === "status") {
11497
11591
  return filters.status ?? [];
11498
11592
  }
11593
+ if (categoryKey === "priority") {
11594
+ return filters.priority ?? [];
11595
+ }
11499
11596
  if (categoryKey === "created_at_from") {
11500
11597
  return filters.created_at_from ? [filters.created_at_from] : [];
11501
11598
  }
@@ -11522,6 +11619,17 @@ function setFilterValuesByCategoryKey(filters, categoryKey, values) {
11522
11619
  }
11523
11620
  return { ...filters, status: parsed.data };
11524
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
+ }
11525
11633
  if (categoryKey === "created_at_from") {
11526
11634
  if (values.length === 0 || !values[0]) {
11527
11635
  const { created_at_from: _, ...rest } = filters;
@@ -11560,7 +11668,7 @@ function removeFilterByCategoryKey(filters, categoryKey) {
11560
11668
  __name(removeFilterByCategoryKey, "removeFilterByCategoryKey");
11561
11669
  __name2(removeFilterByCategoryKey, "removeFilterByCategoryKey");
11562
11670
  function isCasesFiltersEmpty(filters) {
11563
- 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);
11564
11672
  }
11565
11673
  __name(isCasesFiltersEmpty, "isCasesFiltersEmpty");
11566
11674
  __name2(isCasesFiltersEmpty, "isCasesFiltersEmpty");
@@ -11569,6 +11677,9 @@ function countCasesFilters(filters) {
11569
11677
  if (filters.status?.length) {
11570
11678
  count += 1;
11571
11679
  }
11680
+ if (filters.priority?.length) {
11681
+ count += 1;
11682
+ }
11572
11683
  if (filters.created_at_from) {
11573
11684
  count += 1;
11574
11685
  }
@@ -12280,6 +12391,7 @@ var green = /* @__PURE__ */ __name((text3) => wrap(ANSI.green, text3), "green");
12280
12391
  var red = /* @__PURE__ */ __name((text3) => wrap(ANSI.red, text3), "red");
12281
12392
  var cyan = /* @__PURE__ */ __name((text3) => wrap(ANSI.cyan, text3), "cyan");
12282
12393
  var bold = /* @__PURE__ */ __name((text3) => wrap(ANSI.bold, text3), "bold");
12394
+ var dim = /* @__PURE__ */ __name((text3) => wrap(ANSI.dim, text3), "dim");
12283
12395
  var yellow = /* @__PURE__ */ __name((text3) => wrap(ANSI.yellow, text3), "yellow");
12284
12396
 
12285
12397
  // src/output/deprecation-notice.ts
@@ -17345,6 +17457,62 @@ function registerCasesBulkReprocess(cases) {
17345
17457
  }
17346
17458
  __name(registerCasesBulkReprocess, "registerCasesBulkReprocess");
17347
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
+
17348
17516
  // src/commands/cases/bulk-update-status.ts
17349
17517
  var CASE_TERMINAL_STATUSES = ["completed", "failed"];
17350
17518
  function registerCasesBulkUpdateStatus(cases) {
@@ -17503,6 +17671,9 @@ function registerCasesCreate(cases) {
17503
17671
  cases.command("create").description(
17504
17672
  "Create one or more cases in a queue. Provide --title for one case or --from-file with a JSON array for many."
17505
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(
17506
17677
  "--label <key=value>",
17507
17678
  "label to assign to the case (omit key for a simple tag, repeat for multiple)",
17508
17679
  collectLabel,
@@ -17547,9 +17718,9 @@ function collectLabel(value, previous) {
17547
17718
  __name(collectLabel, "collectLabel");
17548
17719
  async function buildRequestBody(options) {
17549
17720
  if (options.fromFile !== void 0) {
17550
- 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) {
17551
17722
  throw new CliError(
17552
- "--from-file cannot be combined with --title, --data, or --label."
17723
+ "--from-file cannot be combined with --title, --data, --priority, or --label."
17553
17724
  );
17554
17725
  }
17555
17726
  return readCasesFromFile(options.fromFile);
@@ -17565,9 +17736,22 @@ async function buildRequestBody(options) {
17565
17736
  if (labels) {
17566
17737
  single.labels = labels;
17567
17738
  }
17739
+ if (options.priority !== void 0) {
17740
+ single.priority = parsePriority2(options.priority, "--priority");
17741
+ }
17568
17742
  return { case: single };
17569
17743
  }
17570
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");
17571
17755
  async function readCasesFromFile(path) {
17572
17756
  let raw;
17573
17757
  try {
@@ -17627,6 +17811,12 @@ function coerceCase(value, location) {
17627
17811
  (l, i) => coerceLabel(l, `${location}.labels[${i}]`)
17628
17812
  );
17629
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
+ }
17630
17820
  return out;
17631
17821
  }
17632
17822
  __name(coerceCase, "coerceCase");
@@ -17964,12 +18154,16 @@ var TABLE_COLUMNS18 = [
17964
18154
  { header: "ID", cell: /* @__PURE__ */ __name((row) => row.id, "cell") },
17965
18155
  { header: "TITLE", cell: /* @__PURE__ */ __name((row) => row.title, "cell"), maxWidth: 50 },
17966
18156
  { header: "STATUS", cell: /* @__PURE__ */ __name((row) => row.display_status, "cell") },
18157
+ { header: "PRIORITY", cell: /* @__PURE__ */ __name((row) => row.priority, "cell") },
17967
18158
  { header: "CREATED", cell: /* @__PURE__ */ __name((row) => row.created_at ?? "", "cell") }
17968
18159
  ];
17969
18160
  function registerCasesList(cases) {
17970
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(
17971
18162
  "--status <statuses>",
17972
18163
  `comma-separated case statuses (${caseFilterStatusSchema.options.join(", ")})`
18164
+ ).option(
18165
+ "--priority <levels>",
18166
+ `comma-separated priority levels (${casePriorityFilterSchema.options.join(", ")})`
17973
18167
  ).option("--search <text>", "full-text search across title and data").option(
17974
18168
  "--created-at-from <iso>",
17975
18169
  "include cases created on or after this ISO-8601 timestamp"
@@ -17987,6 +18181,7 @@ function registerCasesList(cases) {
17987
18181
  });
17988
18182
  const offset = parseOffset(options.offset);
17989
18183
  const statuses = parseStatuses(options.status);
18184
+ const priorities = parsePriorities(options.priority);
17990
18185
  const sortBy = parseSortBy(options.sortBy);
17991
18186
  const sortOrder = parseSortOrder(options.sortOrder);
17992
18187
  const { apiKey, apiBaseUrl } = await requireAuthenticatedConfig(this);
@@ -17996,6 +18191,9 @@ function registerCasesList(cases) {
17996
18191
  if (statuses) {
17997
18192
  searchParams.append("status", statuses.join(","));
17998
18193
  }
18194
+ if (priorities) {
18195
+ searchParams.append("priority", priorities.join(","));
18196
+ }
17999
18197
  if (options.search !== void 0) {
18000
18198
  searchParams.append("search", options.search);
18001
18199
  }
@@ -18061,6 +18259,26 @@ function parseStatuses(raw) {
18061
18259
  return parts;
18062
18260
  }
18063
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");
18064
18282
  function parseSortBy(raw) {
18065
18283
  if (raw === void 0) {
18066
18284
  return void 0;
@@ -18238,6 +18456,7 @@ function registerCases(program) {
18238
18456
  registerCasesBulkDelete(cases);
18239
18457
  registerCasesBulkReprocess(cases);
18240
18458
  registerCasesBulkUpdateStatus(cases);
18459
+ registerCasesBulkUpdatePriority(cases);
18241
18460
  registerCasesRuns(cases);
18242
18461
  registerCasesLabels(cases);
18243
18462
  }
@@ -31186,15 +31405,128 @@ function registerTeam(program) {
31186
31405
  }
31187
31406
  __name(registerTeam, "registerTeam");
31188
31407
 
31189
- // src/commands/teams/list.ts
31408
+ // src/commands/teams/create-org-team.ts
31190
31409
  import { z as z113 } from "zod";
31191
- var teamApiSchema2 = z113.object({
31192
- id: z113.string(),
31193
- name: z113.string(),
31194
- organization_id: z113.string().nullable()
31410
+ var createOrgTeamResponseSchema = z113.object({
31411
+ id: z113.guid(),
31412
+ name: z113.string()
31413
+ });
31414
+ function registerTeamsCreateOrgTeam(teams) {
31415
+ teams.command("create-org-team <org-id>").description("Create a new team inside an organization you administer").requiredOption("--name <name>", "team name").option("--json", "output raw JSON from the API").action(/* @__PURE__ */ __name(async function createOrgTeamAction(orgId, options) {
31416
+ if (options.name === void 0 || options.name.trim().length === 0) {
31417
+ throw new CliError("--name must not be empty");
31418
+ }
31419
+ const { apiKey, apiBaseUrl } = await requireAuthenticatedConfig(this);
31420
+ const raw = await httpRequest({
31421
+ method: "POST",
31422
+ path: `/v2/organizations/${encodeURIComponent(orgId)}/teams`,
31423
+ apiKey,
31424
+ apiBaseUrl,
31425
+ body: { name: options.name.trim() }
31426
+ });
31427
+ if (options.json) {
31428
+ printJson(raw);
31429
+ return;
31430
+ }
31431
+ const parsed = createOrgTeamResponseSchema.safeParse(raw);
31432
+ if (!parsed.success) {
31433
+ throw new CliError(
31434
+ `Unexpected response from POST /v2/organizations/:orgId/teams: ${parsed.error.message}`
31435
+ );
31436
+ }
31437
+ console.log(green("Team created!"));
31438
+ console.log();
31439
+ console.log(
31440
+ renderKeyValue([
31441
+ { label: "ID", value: parsed.data.id },
31442
+ { label: "Name", value: parsed.data.name }
31443
+ ])
31444
+ );
31445
+ }, "createOrgTeamAction"));
31446
+ }
31447
+ __name(registerTeamsCreateOrgTeam, "registerTeamsCreateOrgTeam");
31448
+
31449
+ // src/commands/teams/invite-org-member.ts
31450
+ var ORG_ROLES2 = Object.values(ORG_ROLE);
31451
+ var DEFAULT_ROLE = ORG_ROLE.MEMBER;
31452
+ function registerTeamsInviteOrgMember(teams) {
31453
+ teams.command("invite-org-member <org-id>").description(
31454
+ "Invite a person to an organization, optionally onto one of its teams"
31455
+ ).requiredOption("--email <email>", "email address of the person to invite").option(
31456
+ "--role <role>",
31457
+ `organization role to grant: ${ORG_ROLES2.join(", ")} (default ${DEFAULT_ROLE})`,
31458
+ DEFAULT_ROLE
31459
+ ).option("--team-id <id>", "assign the invitee to this team in the org").option(
31460
+ "--frontend-url <url>",
31461
+ "base URL used to build the invitation email link (email is skipped if omitted)"
31462
+ ).option("--json", "output raw JSON from the API").action(/* @__PURE__ */ __name(async function inviteOrgMemberAction(orgId, options) {
31463
+ const email = options.email?.trim();
31464
+ if (email === void 0 || email.length === 0) {
31465
+ throw new CliError("--email must not be empty");
31466
+ }
31467
+ const role = options.role ?? DEFAULT_ROLE;
31468
+ if (!ORG_ROLES2.includes(role)) {
31469
+ throw new CliError(
31470
+ `Invalid --role "${role}"; expected one of: ${ORG_ROLES2.join(", ")}`
31471
+ );
31472
+ }
31473
+ const { apiKey, apiBaseUrl } = await requireAuthenticatedConfig(this);
31474
+ const body = { email, role };
31475
+ if (options.teamId !== void 0) {
31476
+ const teamId = options.teamId.trim();
31477
+ if (teamId.length === 0) {
31478
+ throw new CliError("--team-id must not be empty");
31479
+ }
31480
+ body.teamId = teamId;
31481
+ }
31482
+ if (options.frontendUrl !== void 0) {
31483
+ const frontendUrl = options.frontendUrl.trim();
31484
+ if (frontendUrl.length === 0) {
31485
+ throw new CliError("--frontend-url must not be empty");
31486
+ }
31487
+ body.frontendUrl = frontendUrl;
31488
+ }
31489
+ const raw = await httpRequest({
31490
+ method: "POST",
31491
+ path: `/v2/organizations/${encodeURIComponent(orgId)}/members`,
31492
+ apiKey,
31493
+ apiBaseUrl,
31494
+ body
31495
+ });
31496
+ if (options.json) {
31497
+ printJson(raw);
31498
+ return;
31499
+ }
31500
+ const parsed = inviteOrgMemberResponseSchema.safeParse(raw);
31501
+ if (!parsed.success) {
31502
+ throw new CliError(
31503
+ `Unexpected response from POST /v2/organizations/:orgId/members: ${parsed.error.message}`
31504
+ );
31505
+ }
31506
+ console.log(green("Invitation created!"));
31507
+ console.log();
31508
+ console.log(
31509
+ renderKeyValue([
31510
+ { label: "Invitation ID", value: parsed.data.invitationId },
31511
+ { label: "Email", value: email },
31512
+ { label: "Role", value: role },
31513
+ { label: "Team", value: body.teamId ?? "\u2014" },
31514
+ { label: "Email sent", value: parsed.data.emailSent ? "yes" : "no" }
31515
+ ])
31516
+ );
31517
+ }, "inviteOrgMemberAction"));
31518
+ }
31519
+ __name(registerTeamsInviteOrgMember, "registerTeamsInviteOrgMember");
31520
+
31521
+ // src/commands/teams/list.ts
31522
+ import { z as z114 } from "zod";
31523
+ var teamApiSchema2 = z114.object({
31524
+ id: z114.string(),
31525
+ name: z114.string(),
31526
+ organization_id: z114.string().nullable()
31195
31527
  });
31196
- var listMyTeamsResponseSchema3 = z113.object({
31197
- teams: z113.array(teamApiSchema2)
31528
+ var listMyTeamsResponseSchema3 = z114.object({
31529
+ teams: z114.array(teamApiSchema2)
31198
31530
  });
31199
31531
  function registerTeamsList(teams) {
31200
31532
  teams.command("list", { isDefault: true }).description("List every team you can act on").option("--json", "output raw JSON from the API").action(/* @__PURE__ */ __name(async function listAction(options) {
@@ -31237,21 +31569,21 @@ function registerTeamsList(teams) {
31237
31569
  __name(registerTeamsList, "registerTeamsList");
31238
31570
 
31239
31571
  // src/commands/teams/org-insights.ts
31240
- import { z as z114 } from "zod";
31241
- var headlineSchema = z114.object({
31242
- total_runs: z114.number(),
31243
- completed_runs: z114.number(),
31244
- failed_runs: z114.number(),
31245
- success_rate: z114.number().nullable(),
31246
- active_agents: z114.number(),
31247
- active_users: z114.number(),
31248
- start_date: z114.string(),
31249
- end_date: z114.string(),
31250
- truncated: z114.boolean(),
31251
- aggregated_teams: z114.number(),
31252
- total_teams: z114.number()
31253
- });
31254
- var orgInsightsHeadlineResponseSchema = z114.object({
31572
+ import { z as z115 } from "zod";
31573
+ var headlineSchema = z115.object({
31574
+ total_runs: z115.number(),
31575
+ completed_runs: z115.number(),
31576
+ failed_runs: z115.number(),
31577
+ success_rate: z115.number().nullable(),
31578
+ active_agents: z115.number(),
31579
+ active_users: z115.number(),
31580
+ start_date: z115.string(),
31581
+ end_date: z115.string(),
31582
+ truncated: z115.boolean(),
31583
+ aggregated_teams: z115.number(),
31584
+ total_teams: z115.number()
31585
+ });
31586
+ var orgInsightsHeadlineResponseSchema = z115.object({
31255
31587
  headline: headlineSchema
31256
31588
  });
31257
31589
  function formatRate(rate) {
@@ -31319,26 +31651,26 @@ function registerTeamsOrgInsights(teams) {
31319
31651
  __name(registerTeamsOrgInsights, "registerTeamsOrgInsights");
31320
31652
 
31321
31653
  // src/commands/teams/org-metrics.ts
31322
- import { z as z115 } from "zod";
31323
- var teamMetricSchema = z115.object({
31324
- team_id: z115.string(),
31325
- team_name: z115.string(),
31326
- is_deleted: z115.boolean(),
31327
- member_count: z115.number(),
31328
- assignment_count: z115.number(),
31329
- scheduled_job_count: z115.number(),
31330
- total_jobs: z115.number(),
31331
- completed_jobs: z115.number(),
31332
- failed_jobs: z115.number(),
31333
- total_runs: z115.number()
31334
- });
31335
- var orgInsightsMetricsResponseSchema = z115.object({
31336
- teams: z115.array(teamMetricSchema),
31337
- start_date: z115.string(),
31338
- end_date: z115.string(),
31339
- truncated: z115.boolean(),
31340
- total_teams: z115.number(),
31341
- org_member_count: z115.number()
31654
+ import { z as z116 } from "zod";
31655
+ var teamMetricSchema = z116.object({
31656
+ team_id: z116.string(),
31657
+ team_name: z116.string(),
31658
+ is_deleted: z116.boolean(),
31659
+ member_count: z116.number(),
31660
+ assignment_count: z116.number(),
31661
+ scheduled_job_count: z116.number(),
31662
+ total_jobs: z116.number(),
31663
+ completed_jobs: z116.number(),
31664
+ failed_jobs: z116.number(),
31665
+ total_runs: z116.number()
31666
+ });
31667
+ var orgInsightsMetricsResponseSchema = z116.object({
31668
+ teams: z116.array(teamMetricSchema),
31669
+ start_date: z116.string(),
31670
+ end_date: z116.string(),
31671
+ truncated: z116.boolean(),
31672
+ total_teams: z116.number(),
31673
+ org_member_count: z116.number()
31342
31674
  });
31343
31675
  function registerTeamsOrgMetrics(teams) {
31344
31676
  teams.command("org-metrics <org-id>").description("Show per-team run metrics across an organization").option("--start-date <date>", "window start (ISO 8601, default 7d ago)").option("--end-date <date>", "window end (ISO 8601, default now)").option("--json", "output raw JSON from the API").action(/* @__PURE__ */ __name(async function orgMetricsAction(orgId, options) {
@@ -31401,20 +31733,20 @@ ${total_teams} teams${suffix} \xB7 ${org_member_count} org members`
31401
31733
  __name(registerTeamsOrgMetrics, "registerTeamsOrgMetrics");
31402
31734
 
31403
31735
  // src/commands/teams/org-usage.ts
31404
- import { z as z116 } from "zod";
31736
+ import { z as z117 } from "zod";
31405
31737
  var GRANULARITIES = ["day", "week", "month"];
31406
31738
  var DEFAULT_LOOKBACK_MS = 30 * 24 * 60 * 60 * 1e3;
31407
- var bucketSchema = z116.object({
31408
- period: z116.string(),
31409
- total_runs: z116.number(),
31410
- scheduled_runs: z116.number(),
31411
- on_demand_runs: z116.number()
31412
- });
31413
- var usageChartResponseSchema = z116.object({
31414
- buckets: z116.array(bucketSchema),
31415
- granularity: z116.enum(GRANULARITIES),
31416
- truncated: z116.boolean(),
31417
- total_teams: z116.number()
31739
+ var bucketSchema = z117.object({
31740
+ period: z117.string(),
31741
+ total_runs: z117.number(),
31742
+ scheduled_runs: z117.number(),
31743
+ on_demand_runs: z117.number()
31744
+ });
31745
+ var usageChartResponseSchema = z117.object({
31746
+ buckets: z117.array(bucketSchema),
31747
+ granularity: z117.enum(GRANULARITIES),
31748
+ truncated: z117.boolean(),
31749
+ total_teams: z117.number()
31418
31750
  });
31419
31751
  function registerTeamsOrgUsage(teams) {
31420
31752
  teams.command("org-usage <org-id>").description("Show org-wide run volume over time (scheduled vs on-demand)").option("--start-date <date>", "window start (ISO 8601, default 30d ago)").option("--end-date <date>", "window end (ISO 8601, default now)").option(
@@ -31473,17 +31805,17 @@ function registerTeamsOrgUsage(teams) {
31473
31805
  __name(registerTeamsOrgUsage, "registerTeamsOrgUsage");
31474
31806
 
31475
31807
  // src/commands/teams/org.ts
31476
- import { z as z117 } from "zod";
31477
- var orgTeamSchema = z117.object({
31478
- id: z117.string(),
31479
- name: z117.string(),
31480
- userIsMember: z117.boolean(),
31481
- userRole: z117.string().nullable(),
31482
- memberCount: z117.number()
31808
+ import { z as z118 } from "zod";
31809
+ var orgTeamSchema = z118.object({
31810
+ id: z118.string(),
31811
+ name: z118.string(),
31812
+ userIsMember: z118.boolean(),
31813
+ userRole: z118.string().nullable(),
31814
+ memberCount: z118.number()
31483
31815
  });
31484
- var listOrgTeamsResponseSchema = z117.object({
31485
- teams: z117.array(orgTeamSchema),
31486
- total: z117.number()
31816
+ var listOrgTeamsResponseSchema = z118.object({
31817
+ teams: z118.array(orgTeamSchema),
31818
+ total: z118.number()
31487
31819
  });
31488
31820
  function registerTeamsOrg(teams) {
31489
31821
  teams.command("org <org-id>").description("List all teams in an organization you belong to").option("--json", "output raw JSON from the API").action(/* @__PURE__ */ __name(async function orgAction(orgId, options) {
@@ -31525,17 +31857,17 @@ function registerTeamsOrg(teams) {
31525
31857
  __name(registerTeamsOrg, "registerTeamsOrg");
31526
31858
 
31527
31859
  // src/commands/teams/orgs.ts
31528
- import { z as z118 } from "zod";
31529
- var orgMembershipSchema = z118.object({
31530
- organization: z118.object({
31531
- id: z118.string(),
31532
- name: z118.string()
31860
+ import { z as z119 } from "zod";
31861
+ var orgMembershipSchema = z119.object({
31862
+ organization: z119.object({
31863
+ id: z119.string(),
31864
+ name: z119.string()
31533
31865
  }),
31534
- role: z118.string(),
31535
- memberCount: z118.number()
31866
+ role: z119.string(),
31867
+ memberCount: z119.number()
31536
31868
  });
31537
- var listMyOrganizationsResponseSchema = z118.object({
31538
- memberships: z118.array(orgMembershipSchema)
31869
+ var listMyOrganizationsResponseSchema = z119.object({
31870
+ memberships: z119.array(orgMembershipSchema)
31539
31871
  });
31540
31872
  function registerTeamsOrgs(teams) {
31541
31873
  teams.command("orgs").description("List the organizations you belong to and your role in each").option("--json", "output raw JSON from the API").action(/* @__PURE__ */ __name(async function orgsAction(options) {
@@ -31581,141 +31913,448 @@ function registerTeams(program) {
31581
31913
  registerTeamsList(teams);
31582
31914
  registerTeamsOrg(teams);
31583
31915
  registerTeamsOrgs(teams);
31916
+ registerTeamsCreateOrgTeam(teams);
31917
+ registerTeamsInviteOrgMember(teams);
31584
31918
  registerTeamsOrgInsights(teams);
31585
31919
  registerTeamsOrgMetrics(teams);
31586
31920
  registerTeamsOrgUsage(teams);
31587
31921
  }
31588
31922
  __name(registerTeams, "registerTeams");
31589
31923
 
31590
- // src/commands/whoami.ts
31591
- function registerWhoami(program) {
31592
- program.command("whoami").description(
31593
- "Print the active profile, the authenticated user's name and email, the team ID that subsequent commands will act on, and the auth type"
31594
- ).action(/* @__PURE__ */ __name(async function whoamiAction() {
31595
- const resolved = await requireAuthenticatedConfig(this);
31596
- const profileLabel = resolved.profileName ?? "(env-only, no stored profile)";
31597
- console.log(`Profile ${profileLabel}`);
31598
- const userLine = await fetchUserLine(resolved);
31599
- if (userLine !== null) {
31600
- console.log(`User ${userLine}`);
31601
- }
31602
- const teamId = await resolveActiveTeamId(resolved, getTeamFlag(this));
31603
- if (teamId !== null) {
31604
- console.log(`Team ${teamId}`);
31605
- }
31606
- const authTypeLabel = resolved.authType === "oauth" ? "OAuth" : "API key";
31607
- console.log(`Auth type ${authTypeLabel}`);
31608
- }, "whoamiAction"));
31924
+ // src/version/fetch-latest-binary-version.ts
31925
+ var CLI_RELEASES_BASE_URL = "https://storage.googleapis.com/duvo-cli-releases";
31926
+ var LATEST_POINTER_TIMEOUT_MS = 5e3;
31927
+ async function fetchLatestBinaryVersion() {
31928
+ const response = await fetch(`${CLI_RELEASES_BASE_URL}/latest`, {
31929
+ signal: AbortSignal.timeout(LATEST_POINTER_TIMEOUT_MS)
31930
+ });
31931
+ if (!response.ok) {
31932
+ throw new Error(`releases bucket responded with ${response.status}`);
31933
+ }
31934
+ const version2 = (await response.text()).trim().replace(/^v/, "");
31935
+ if (!/^\d+\.\d+\.\d+$/.test(version2)) {
31936
+ throw new Error(`releases bucket returned an invalid version: ${version2}`);
31937
+ }
31938
+ return version2;
31609
31939
  }
31610
- __name(registerWhoami, "registerWhoami");
31611
- async function fetchUserLine(config) {
31612
- try {
31613
- const raw = await httpRequest({
31614
- method: "GET",
31615
- path: "/v2/profile",
31616
- apiKey: config.apiKey,
31617
- apiBaseUrl: config.apiBaseUrl
31618
- });
31619
- const parsed = publicProfileResponseSchema.safeParse(raw);
31620
- if (!parsed.success) {
31621
- return null;
31940
+ __name(fetchLatestBinaryVersion, "fetchLatestBinaryVersion");
31941
+
31942
+ // src/version/fetch-latest-npm-version.ts
31943
+ var REGISTRY_TIMEOUT_MS = 5e3;
31944
+ async function fetchLatestNpmVersion(packageName, timeoutMs = REGISTRY_TIMEOUT_MS) {
31945
+ const response = await fetch(
31946
+ `https://registry.npmjs.org/-/package/${packageName}/dist-tags`,
31947
+ {
31948
+ signal: AbortSignal.timeout(timeoutMs),
31949
+ headers: { accept: "application/json" }
31622
31950
  }
31623
- const { name, email } = parsed.data.profile;
31624
- return name ? `${name} <${email}>` : email;
31625
- } catch {
31626
- return null;
31951
+ );
31952
+ if (!response.ok) {
31953
+ throw new Error(`npm registry responded with ${response.status}`);
31954
+ }
31955
+ const body = await response.json();
31956
+ if (body === null || typeof body !== "object" || typeof body.latest !== "string") {
31957
+ throw new Error("npm registry response is missing the latest dist-tag");
31627
31958
  }
31959
+ return body.latest;
31628
31960
  }
31629
- __name(fetchUserLine, "fetchUserLine");
31630
- async function resolveActiveTeamId(config, override) {
31631
- try {
31632
- return await resolveRequiredTeamId(config, { override });
31633
- } catch {
31961
+ __name(fetchLatestNpmVersion, "fetchLatestNpmVersion");
31962
+
31963
+ // src/version/is-newer-version.ts
31964
+ function isSafeNumericIdentifier(value) {
31965
+ return Number(value) <= Number.MAX_SAFE_INTEGER;
31966
+ }
31967
+ __name(isSafeNumericIdentifier, "isSafeNumericIdentifier");
31968
+ function parseVersion(version2) {
31969
+ 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(
31970
+ version2.trim()
31971
+ );
31972
+ if (!match) {
31973
+ return null;
31974
+ }
31975
+ const prerelease = match[4] ? match[4].split(".") : [];
31976
+ const numericIdentifiers = [
31977
+ match[1],
31978
+ match[2],
31979
+ match[3],
31980
+ ...prerelease.filter((identifier) => /^\d+$/.test(identifier))
31981
+ ];
31982
+ if (!numericIdentifiers.every(isSafeNumericIdentifier)) {
31634
31983
  return null;
31635
31984
  }
31985
+ return {
31986
+ core: [Number(match[1]), Number(match[2]), Number(match[3])],
31987
+ prerelease
31988
+ };
31636
31989
  }
31637
- __name(resolveActiveTeamId, "resolveActiveTeamId");
31638
-
31639
- // src/bin/create-program.ts
31640
- var version = resolveVersion();
31641
- function resolveVersion() {
31642
- if (true) {
31643
- return "1.28.1";
31990
+ __name(parseVersion, "parseVersion");
31991
+ function comparePrereleaseIdentifiers(a, b) {
31992
+ const aIsNumeric = /^\d+$/.test(a);
31993
+ const bIsNumeric = /^\d+$/.test(b);
31994
+ if (aIsNumeric && bIsNumeric) {
31995
+ return Math.sign(Number(a) - Number(b));
31644
31996
  }
31645
- const packageJsonPath = join3(
31646
- dirname3(fileURLToPath2(import.meta.url)),
31647
- "../../package.json"
31648
- );
31649
- const { version: v } = JSON.parse(readFileSync8(packageJsonPath, "utf8"));
31650
- return v;
31997
+ if (aIsNumeric !== bIsNumeric) {
31998
+ return aIsNumeric ? -1 : 1;
31999
+ }
32000
+ if (a === b) {
32001
+ return 0;
32002
+ }
32003
+ return a < b ? -1 : 1;
31651
32004
  }
31652
- __name(resolveVersion, "resolveVersion");
31653
- function createProgram() {
31654
- const program = new Command();
31655
- program.name("duvo").description("Command-line interface for the Duvo public API").version(version).option(
31656
- "--profile <name>",
31657
- "use a specific profile for this invocation (overrides default profile)"
31658
- ).option(
31659
- "--team <id>",
31660
- "use a specific team for this invocation (overrides DUVO_TEAM_ID and profile default; API-key profiles are pinned to the key's team, so a different value is rejected by the server)"
31661
- ).addOption(
31662
- new Option2(
31663
- "--no-update-notifier",
31664
- "skip the update check for this invocation"
31665
- ).hideHelp()
32005
+ __name(comparePrereleaseIdentifiers, "comparePrereleaseIdentifiers");
32006
+ function compareVersions(a, b) {
32007
+ for (let index = 0; index < 3; index += 1) {
32008
+ if (a.core[index] !== b.core[index]) {
32009
+ return Math.sign(a.core[index] - b.core[index]);
32010
+ }
32011
+ }
32012
+ if (a.prerelease.length === 0 || b.prerelease.length === 0) {
32013
+ return Math.sign(b.prerelease.length - a.prerelease.length);
32014
+ }
32015
+ const sharedLength = Math.min(a.prerelease.length, b.prerelease.length);
32016
+ for (let index = 0; index < sharedLength; index += 1) {
32017
+ const result = comparePrereleaseIdentifiers(
32018
+ a.prerelease[index],
32019
+ b.prerelease[index]
32020
+ );
32021
+ if (result !== 0) {
32022
+ return result;
32023
+ }
32024
+ }
32025
+ return Math.sign(a.prerelease.length - b.prerelease.length);
32026
+ }
32027
+ __name(compareVersions, "compareVersions");
32028
+ function isNewerVersion(candidate, current) {
32029
+ const parsedCandidate = parseVersion(candidate);
32030
+ const parsedCurrent = parseVersion(current);
32031
+ if (!parsedCandidate || !parsedCurrent) {
32032
+ return false;
32033
+ }
32034
+ return compareVersions(parsedCandidate, parsedCurrent) > 0;
32035
+ }
32036
+ __name(isNewerVersion, "isNewerVersion");
32037
+
32038
+ // src/version/is-standalone-binary.ts
32039
+ function isStandaloneBinary(moduleUrl = import.meta.url) {
32040
+ return moduleUrl.includes("$bunfs") || moduleUrl.includes("~BUN");
32041
+ }
32042
+ __name(isStandaloneBinary, "isStandaloneBinary");
32043
+
32044
+ // src/version/package-meta.ts
32045
+ import { createRequire } from "node:module";
32046
+ function getPackageMeta() {
32047
+ if (true) {
32048
+ return { name: "@duvoai/cli", version: "1.31.0" };
32049
+ }
32050
+ const require2 = createRequire(import.meta.url);
32051
+ const raw = require2("../../package.json");
32052
+ if (typeof raw !== "object" || raw === null || !("name" in raw) || !("version" in raw) || typeof raw.name !== "string" || typeof raw.version !== "string") {
32053
+ throw new Error("package.json is missing name or version");
32054
+ }
32055
+ const typed = raw;
32056
+ return { name: typed.name, version: typed.version };
32057
+ }
32058
+ __name(getPackageMeta, "getPackageMeta");
32059
+
32060
+ // src/commands/update/self-update-binary.ts
32061
+ import { createHash as createHash2 } from "node:crypto";
32062
+ import { rename, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
32063
+ import { dirname as dirname3 } from "node:path";
32064
+ var DOWNLOAD_TIMEOUT_MS = 12e4;
32065
+ var EXECUTABLE_MODE = 493;
32066
+ var BINARY_ASSETS = {
32067
+ "linux-x64": "duvo-linux-x64",
32068
+ "linux-arm64": "duvo-linux-arm64",
32069
+ "darwin-x64": "duvo-darwin-x64",
32070
+ "darwin-arm64": "duvo-darwin-arm64"
32071
+ };
32072
+ function resolveBinaryAsset(platform2 = process.platform, arch = process.arch) {
32073
+ const asset = BINARY_ASSETS[`${platform2}-${arch}`];
32074
+ if (!asset) {
32075
+ throw new CliError(
32076
+ `no prebuilt duvo binary for ${platform2}-${arch} (supported: ${Object.keys(BINARY_ASSETS).join(", ")})`
32077
+ );
32078
+ }
32079
+ return asset;
32080
+ }
32081
+ __name(resolveBinaryAsset, "resolveBinaryAsset");
32082
+ async function selfUpdateBinary({
32083
+ version: version2,
32084
+ asset,
32085
+ execPath = process.execPath,
32086
+ fetchImpl = fetch
32087
+ }) {
32088
+ const url = `${CLI_RELEASES_BASE_URL}/v${version2}/${asset}`;
32089
+ const [binaryResponse, checksumResponse] = await Promise.all([
32090
+ fetchImpl(url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS) }),
32091
+ fetchImpl(`${url}.sha256`, {
32092
+ signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
32093
+ })
32094
+ ]);
32095
+ if (!binaryResponse.ok) {
32096
+ throw new CliError(
32097
+ `failed to download ${url} (HTTP ${binaryResponse.status})`
32098
+ );
32099
+ }
32100
+ if (!checksumResponse.ok) {
32101
+ throw new CliError(
32102
+ `failed to download ${url}.sha256 (HTTP ${checksumResponse.status})`
32103
+ );
32104
+ }
32105
+ const bytes = Buffer.from(await binaryResponse.arrayBuffer());
32106
+ const expected = (await checksumResponse.text()).trim().split(/\s+/)[0];
32107
+ const actual = createHash2("sha256").update(bytes).digest("hex");
32108
+ if (expected !== actual) {
32109
+ throw new CliError(
32110
+ `checksum mismatch for ${asset} (expected ${expected}, got ${actual}) \u2014 not installing`
32111
+ );
32112
+ }
32113
+ const stagedPath = `${execPath}.update-${process.pid}`;
32114
+ try {
32115
+ await writeFile4(stagedPath, bytes, { mode: EXECUTABLE_MODE });
32116
+ await rename(stagedPath, execPath);
32117
+ } catch (error) {
32118
+ await rm2(stagedPath, { force: true });
32119
+ if (isPermissionError(error)) {
32120
+ throw new CliError(
32121
+ `cannot write to ${dirname3(execPath)} \u2014 re-run the installer, which handles sudo:
32122
+ curl -fsSL https://duvo.ai/install-cli.sh | sh`
32123
+ );
32124
+ }
32125
+ throw error;
32126
+ }
32127
+ }
32128
+ __name(selfUpdateBinary, "selfUpdateBinary");
32129
+ function isPermissionError(error) {
32130
+ if (!(error instanceof Error) || !("code" in error)) {
32131
+ return false;
32132
+ }
32133
+ const { code } = error;
32134
+ return code === "EACCES" || code === "EPERM" || code === "EROFS";
32135
+ }
32136
+ __name(isPermissionError, "isPermissionError");
32137
+
32138
+ // src/commands/update/self-update-npm.ts
32139
+ import { spawn as spawn2 } from "node:child_process";
32140
+ function selfUpdateNpm(packageName, { quiet = false, spawnImpl = spawn2 } = {}) {
32141
+ return new Promise((resolve, reject) => {
32142
+ const child = spawnImpl("npm", ["install", "-g", `${packageName}@latest`], {
32143
+ stdio: quiet ? ["ignore", "ignore", "inherit"] : "inherit"
32144
+ });
32145
+ child.on("error", (error) => {
32146
+ reject(
32147
+ new CliError(
32148
+ `failed to run npm: ${error.message} \u2014 is npm on your PATH?`
32149
+ )
32150
+ );
32151
+ });
32152
+ child.on("close", (code) => {
32153
+ if (code === 0) {
32154
+ resolve();
32155
+ } else {
32156
+ reject(
32157
+ new CliError(
32158
+ `\`npm install -g ${packageName}@latest\` exited with code ${String(code)}`
32159
+ )
32160
+ );
32161
+ }
32162
+ });
32163
+ });
32164
+ }
32165
+ __name(selfUpdateNpm, "selfUpdateNpm");
32166
+
32167
+ // src/commands/update/index.ts
32168
+ function registerUpdate3(program) {
32169
+ program.command("update").description(
32170
+ "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."
32171
+ ).option("--check", "check for a newer version without installing it").option("--json", "output raw JSON").action(async (options) => {
32172
+ await runUpdate(options);
32173
+ });
32174
+ }
32175
+ __name(registerUpdate3, "registerUpdate");
32176
+ async function runUpdate(options) {
32177
+ const pkg = getPackageMeta();
32178
+ const installMethod = isStandaloneBinary() ? "binary" : "npm";
32179
+ const latestVersion = await resolveLatestVersion(installMethod, pkg.name);
32180
+ const updateAvailable = isNewerVersion(latestVersion, pkg.version);
32181
+ if (options.check) {
32182
+ printCheckResult(pkg.version, latestVersion, installMethod, options);
32183
+ return;
32184
+ }
32185
+ if (!updateAvailable) {
32186
+ if (options.json) {
32187
+ printJson({
32188
+ currentVersion: pkg.version,
32189
+ latestVersion,
32190
+ installMethod,
32191
+ updated: false
32192
+ });
32193
+ } else {
32194
+ console.log(`Already up to date (v${pkg.version}).`);
32195
+ }
32196
+ return;
32197
+ }
32198
+ if (installMethod === "binary") {
32199
+ await updateStandaloneBinary(pkg.version, latestVersion, options);
32200
+ } else {
32201
+ await updateNpmInstall(pkg.name, pkg.version, latestVersion, options);
32202
+ }
32203
+ }
32204
+ __name(runUpdate, "runUpdate");
32205
+ async function resolveLatestVersion(installMethod, packageName) {
32206
+ try {
32207
+ return installMethod === "binary" ? await fetchLatestBinaryVersion() : await fetchLatestNpmVersion(packageName);
32208
+ } catch (error) {
32209
+ const message = error instanceof Error ? error.message : String(error);
32210
+ throw new CliError(`failed to determine the latest version: ${message}`);
32211
+ }
32212
+ }
32213
+ __name(resolveLatestVersion, "resolveLatestVersion");
32214
+ function printCheckResult(currentVersion, latestVersion, installMethod, options) {
32215
+ const updateAvailable = isNewerVersion(latestVersion, currentVersion);
32216
+ if (options.json) {
32217
+ printJson({
32218
+ currentVersion,
32219
+ latestVersion,
32220
+ installMethod,
32221
+ updateAvailable
32222
+ });
32223
+ return;
32224
+ }
32225
+ console.log(`Current ${currentVersion}`);
32226
+ console.log(`Latest ${latestVersion}`);
32227
+ console.log(
32228
+ `Install ${installMethod === "binary" ? "standalone binary (curl installer)" : "npm"}`
31666
32229
  );
31667
- program.addHelpText(
31668
- "before",
31669
- [
31670
- "Start here (for AI agents):",
31671
- " duvo guide get duvo",
31672
- "",
31673
- "Guides ship with the CLI (always version-matched) and cover auth,",
31674
- "workflows, and copy-paste examples. Prefer them over guessing",
31675
- "commands from flag docs alone. List them with `duvo guide list`.",
31676
- ""
31677
- ].join("\n")
32230
+ console.log(
32231
+ updateAvailable ? "Update available \u2014 run `duvo update` to install it." : "Already up to date."
31678
32232
  );
31679
- registerLogin(program);
31680
- registerLogout(program);
31681
- registerWhoami(program);
31682
- registerProfiles(program);
31683
- registerApi(program);
31684
- registerAgents(program);
31685
- registerAgentFolders(program);
31686
- registerBuilds(program);
31687
- registerBuildIntegrations(program);
31688
- registerIntegrations(program);
31689
- registerConnections(program);
31690
- registerOauth(program);
31691
- registerRuns(program);
31692
- registerQueues(program);
31693
- registerQueueLabels(program);
31694
- registerCases(program);
31695
- registerSandboxes(program);
31696
- registerFiles(program);
31697
- registerPlugins(program);
31698
- registerSkills(program);
31699
- registerGuide(program);
31700
- registerSuggestions(program);
31701
- registerTeam(program);
31702
- registerTeams(program);
31703
- registerSecrets(program);
31704
- registerCredentials(program);
31705
- registerRevisionSecrets(program);
31706
- registerRevisionLogins(program);
31707
- registerClarity(program);
31708
- registerPulse(program);
31709
- return program;
31710
32233
  }
31711
- __name(createProgram, "createProgram");
32234
+ __name(printCheckResult, "printCheckResult");
32235
+ async function updateStandaloneBinary(currentVersion, latestVersion, options) {
32236
+ const asset = resolveBinaryAsset();
32237
+ if (!options.json) {
32238
+ console.log(
32239
+ `Updating duvo ${currentVersion} \u2192 ${latestVersion} (standalone binary)`
32240
+ );
32241
+ console.log(`Downloading ${asset}\u2026`);
32242
+ }
32243
+ await selfUpdateBinary({ version: latestVersion, asset });
32244
+ if (options.json) {
32245
+ printJson({
32246
+ currentVersion,
32247
+ latestVersion,
32248
+ installMethod: "binary",
32249
+ updated: true
32250
+ });
32251
+ } else {
32252
+ console.log(`Updated ${process.execPath} to v${latestVersion}.`);
32253
+ }
32254
+ }
32255
+ __name(updateStandaloneBinary, "updateStandaloneBinary");
32256
+ async function updateNpmInstall(packageName, currentVersion, latestVersion, options) {
32257
+ if (!options.json) {
32258
+ console.log(`Updating duvo ${currentVersion} \u2192 ${latestVersion} (npm)`);
32259
+ console.log(`Running \`npm install -g ${packageName}@latest\`\u2026`);
32260
+ }
32261
+ await selfUpdateNpm(packageName, { quiet: options.json === true });
32262
+ if (options.json) {
32263
+ printJson({
32264
+ currentVersion,
32265
+ latestVersion,
32266
+ installMethod: "npm",
32267
+ updated: true
32268
+ });
32269
+ } else {
32270
+ console.log(`Updated to v${latestVersion}.`);
32271
+ }
32272
+ }
32273
+ __name(updateNpmInstall, "updateNpmInstall");
32274
+
32275
+ // src/commands/whoami.ts
32276
+ function registerWhoami(program) {
32277
+ program.command("whoami").description(
32278
+ "Print the active profile, the authenticated user's name and email, the team ID that subsequent commands will act on, and the auth type"
32279
+ ).action(/* @__PURE__ */ __name(async function whoamiAction() {
32280
+ const resolved = await requireAuthenticatedConfig(this);
32281
+ const profileLabel = resolved.profileName ?? "(env-only, no stored profile)";
32282
+ console.log(`Profile ${profileLabel}`);
32283
+ const userLine = await fetchUserLine(resolved);
32284
+ if (userLine !== null) {
32285
+ console.log(`User ${userLine}`);
32286
+ }
32287
+ const teamId = await resolveActiveTeamId(resolved, getTeamFlag(this));
32288
+ if (teamId !== null) {
32289
+ console.log(`Team ${teamId}`);
32290
+ }
32291
+ const authTypeLabel = resolved.authType === "oauth" ? "OAuth" : "API key";
32292
+ console.log(`Auth type ${authTypeLabel}`);
32293
+ }, "whoamiAction"));
32294
+ }
32295
+ __name(registerWhoami, "registerWhoami");
32296
+ async function fetchUserLine(config) {
32297
+ try {
32298
+ const raw = await httpRequest({
32299
+ method: "GET",
32300
+ path: "/v2/profile",
32301
+ apiKey: config.apiKey,
32302
+ apiBaseUrl: config.apiBaseUrl
32303
+ });
32304
+ const parsed = publicProfileResponseSchema.safeParse(raw);
32305
+ if (!parsed.success) {
32306
+ return null;
32307
+ }
32308
+ const { name, email } = parsed.data.profile;
32309
+ return name ? `${name} <${email}>` : email;
32310
+ } catch {
32311
+ return null;
32312
+ }
32313
+ }
32314
+ __name(fetchUserLine, "fetchUserLine");
32315
+ async function resolveActiveTeamId(config, override) {
32316
+ try {
32317
+ return await resolveRequiredTeamId(config, { override });
32318
+ } catch {
32319
+ return null;
32320
+ }
32321
+ }
32322
+ __name(resolveActiveTeamId, "resolveActiveTeamId");
31712
32323
 
31713
32324
  // src/update-check.ts
31714
- import { mkdir as mkdir2, readFile as readFile10, writeFile as writeFile4 } from "node:fs/promises";
31715
- import { createRequire } from "node:module";
32325
+ import { readFileSync as readFileSync8 } from "node:fs";
32326
+ import { mkdir as mkdir2, readFile as readFile10, writeFile as writeFile5 } from "node:fs/promises";
31716
32327
  import { dirname as dirname4 } from "node:path";
32328
+
32329
+ // src/output/notice-box.ts
32330
+ var ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
32331
+ var HORIZONTAL_PADDING = 3;
32332
+ function visibleLength(line) {
32333
+ return line.replace(ANSI_PATTERN, "").length;
32334
+ }
32335
+ __name(visibleLength, "visibleLength");
32336
+ function renderNoticeBox(lines) {
32337
+ const contentWidth = Math.max(...lines.map(visibleLength));
32338
+ const innerWidth = contentWidth + HORIZONTAL_PADDING * 2;
32339
+ const pad2 = " ".repeat(HORIZONTAL_PADDING);
32340
+ const emptyRow = `${yellow("\u2502")}${" ".repeat(innerWidth)}${yellow("\u2502")}`;
32341
+ const body = lines.map((line) => {
32342
+ const fill = " ".repeat(contentWidth - visibleLength(line));
32343
+ return `${yellow("\u2502")}${pad2}${line}${fill}${pad2}${yellow("\u2502")}`;
32344
+ });
32345
+ return [
32346
+ yellow(`\u256D${"\u2500".repeat(innerWidth)}\u256E`),
32347
+ emptyRow,
32348
+ ...body,
32349
+ emptyRow,
32350
+ yellow(`\u2570${"\u2500".repeat(innerWidth)}\u256F`)
32351
+ ].join("\n");
32352
+ }
32353
+ __name(renderNoticeBox, "renderNoticeBox");
32354
+
32355
+ // src/update-check.ts
31717
32356
  var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
31718
- var REGISTRY_TIMEOUT_MS = 2e3;
32357
+ var REGISTRY_TIMEOUT_MS2 = 2e3;
31719
32358
  var DIR_MODE2 = 448;
31720
32359
  function checkForUpdate() {
31721
32360
  if (isUpdateCheckDisabled()) {
@@ -31725,16 +32364,30 @@ function checkForUpdate() {
31725
32364
  });
31726
32365
  }
31727
32366
  __name(checkForUpdate, "checkForUpdate");
32367
+ function getPendingUpdateNotice() {
32368
+ if (isUpdateCheckDisabled()) {
32369
+ return null;
32370
+ }
32371
+ const pkg = getPackageMeta();
32372
+ const cache = readCacheSync();
32373
+ if (cache && isNewerVersion(cache.latestVersion, pkg.version)) {
32374
+ return renderUpdateNotice(pkg, cache.latestVersion);
32375
+ }
32376
+ return null;
32377
+ }
32378
+ __name(getPendingUpdateNotice, "getPendingUpdateNotice");
31728
32379
  function isUpdateCheckDisabled() {
31729
32380
  const ci = process.env.CI;
31730
32381
  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");
31731
32382
  }
31732
32383
  __name(isUpdateCheckDisabled, "isUpdateCheckDisabled");
31733
32384
  async function runUpdateCheck() {
31734
- const pkg = loadPackageMeta();
32385
+ const pkg = getPackageMeta();
31735
32386
  const cache = await readCache();
31736
32387
  if (cache && isNewerVersion(cache.latestVersion, pkg.version)) {
31737
- printUpdateNotice(pkg, cache.latestVersion);
32388
+ console.error(`
32389
+ ${renderUpdateNotice(pkg, cache.latestVersion)}
32390
+ `);
31738
32391
  }
31739
32392
  const isFresh = cache && Date.now() - cache.lastCheckedAtMs < ONE_DAY_MS;
31740
32393
  if (isFresh) {
@@ -31745,7 +32398,10 @@ async function runUpdateCheck() {
31745
32398
  __name(runUpdateCheck, "runUpdateCheck");
31746
32399
  async function refreshCache(pkg, previous) {
31747
32400
  try {
31748
- const latestVersion = await fetchLatestVersion(pkg.name);
32401
+ const latestVersion = await fetchLatestNpmVersion(
32402
+ pkg.name,
32403
+ REGISTRY_TIMEOUT_MS2
32404
+ );
31749
32405
  await writeCache({ lastCheckedAtMs: Date.now(), latestVersion });
31750
32406
  } catch {
31751
32407
  await writeCache({
@@ -31755,96 +32411,112 @@ async function refreshCache(pkg, previous) {
31755
32411
  }
31756
32412
  }
31757
32413
  __name(refreshCache, "refreshCache");
31758
- function printUpdateNotice(pkg, latestVersion) {
31759
- const updateCommand = resolveUpdateCommand(pkg.name, isStandaloneBinary());
31760
- console.error(
31761
- `
31762
- Update available for ${pkg.name}: ${pkg.version} \u2192 ${latestVersion}
31763
- Run \`${updateCommand}\` to update.
31764
- `
31765
- );
31766
- }
31767
- __name(printUpdateNotice, "printUpdateNotice");
31768
- function resolveUpdateCommand(packageName, isStandalone) {
31769
- return isStandalone ? "curl -fsSL https://duvo.ai/install-cli.sh | sh" : `npm install -g ${packageName}`;
31770
- }
31771
- __name(resolveUpdateCommand, "resolveUpdateCommand");
31772
- function isStandaloneBinary() {
31773
- return import.meta.url.includes("$bunfs") || import.meta.url.includes("~BUN");
32414
+ function renderUpdateNotice(pkg, latestVersion) {
32415
+ const fallbackCommand = isStandaloneBinary() ? "curl -fsSL https://duvo.ai/install-cli.sh | sh" : `npm install -g ${pkg.name}`;
32416
+ return renderNoticeBox([
32417
+ `Update available for ${bold(pkg.name)}: ${dim(pkg.version)} \u2192 ${green(latestVersion)}`,
32418
+ `Run ${cyan("duvo update")} (or \`${fallbackCommand}\`) to update.`
32419
+ ]);
31774
32420
  }
31775
- __name(isStandaloneBinary, "isStandaloneBinary");
31776
- async function fetchLatestVersion(packageName) {
31777
- const response = await fetch(
31778
- `https://registry.npmjs.org/-/package/${packageName}/dist-tags`,
31779
- {
31780
- signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS),
31781
- headers: { accept: "application/json" }
31782
- }
31783
- );
31784
- if (!response.ok) {
31785
- throw new Error(`npm registry responded with ${response.status}`);
31786
- }
31787
- const body = await response.json();
31788
- if (body === null || typeof body !== "object" || typeof body.latest !== "string") {
31789
- throw new Error("npm registry response is missing the latest dist-tag");
32421
+ __name(renderUpdateNotice, "renderUpdateNotice");
32422
+ function parseCache(raw) {
32423
+ const parsed = JSON.parse(raw);
32424
+ if (parsed === null || typeof parsed !== "object" || typeof parsed.lastCheckedAtMs !== "number" || typeof parsed.latestVersion !== "string") {
32425
+ return null;
31790
32426
  }
31791
- return body.latest;
32427
+ return parsed;
31792
32428
  }
31793
- __name(fetchLatestVersion, "fetchLatestVersion");
32429
+ __name(parseCache, "parseCache");
31794
32430
  async function readCache() {
31795
32431
  try {
31796
- const raw = await readFile10(getUpdateCheckCachePath(), "utf8");
31797
- const parsed = JSON.parse(raw);
31798
- if (parsed === null || typeof parsed !== "object" || typeof parsed.lastCheckedAtMs !== "number" || typeof parsed.latestVersion !== "string") {
31799
- return null;
31800
- }
31801
- return parsed;
32432
+ return parseCache(await readFile10(getUpdateCheckCachePath(), "utf8"));
31802
32433
  } catch {
31803
32434
  return null;
31804
32435
  }
31805
32436
  }
31806
32437
  __name(readCache, "readCache");
32438
+ function readCacheSync() {
32439
+ try {
32440
+ return parseCache(readFileSync8(getUpdateCheckCachePath(), "utf8"));
32441
+ } catch {
32442
+ return null;
32443
+ }
32444
+ }
32445
+ __name(readCacheSync, "readCacheSync");
31807
32446
  async function writeCache(cache) {
31808
32447
  const path = getUpdateCheckCachePath();
31809
32448
  await mkdir2(dirname4(path), { recursive: true, mode: DIR_MODE2 });
31810
- await writeFile4(path, JSON.stringify(cache), "utf8");
32449
+ await writeFile5(path, JSON.stringify(cache), "utf8");
31811
32450
  }
31812
32451
  __name(writeCache, "writeCache");
31813
- function parseVersion(version2) {
31814
- const match = /^v?(\d+)\.(\d+)\.(\d+)/.exec(version2.trim());
31815
- if (!match) {
31816
- return null;
31817
- }
31818
- return [Number(match[1]), Number(match[2]), Number(match[3])];
31819
- }
31820
- __name(parseVersion, "parseVersion");
31821
- function isNewerVersion(candidate, current) {
31822
- const parsedCandidate = parseVersion(candidate);
31823
- const parsedCurrent = parseVersion(current);
31824
- if (!parsedCandidate || !parsedCurrent) {
31825
- return false;
31826
- }
31827
- for (let index = 0; index < 3; index += 1) {
31828
- if (parsedCandidate[index] !== parsedCurrent[index]) {
31829
- return parsedCandidate[index] > parsedCurrent[index];
31830
- }
31831
- }
31832
- return false;
31833
- }
31834
- __name(isNewerVersion, "isNewerVersion");
31835
- function loadPackageMeta() {
31836
- if (true) {
31837
- return { name: "@duvoai/cli", version: "1.28.1" };
31838
- }
31839
- const require2 = createRequire(import.meta.url);
31840
- const raw = require2("../package.json");
31841
- if (typeof raw !== "object" || raw === null || !("name" in raw) || !("version" in raw) || typeof raw.name !== "string" || typeof raw.version !== "string") {
31842
- throw new Error("package.json is missing name or version");
31843
- }
31844
- const typed = raw;
31845
- return { name: typed.name, version: typed.version };
32452
+
32453
+ // src/bin/create-program.ts
32454
+ var { version } = getPackageMeta();
32455
+ function createProgram() {
32456
+ const program = new Command();
32457
+ program.name("duvo").description("Command-line interface for the Duvo public API").version(version).option(
32458
+ "--profile <name>",
32459
+ "use a specific profile for this invocation (overrides default profile)"
32460
+ ).option(
32461
+ "--team <id>",
32462
+ "use a specific team for this invocation (overrides DUVO_TEAM_ID and profile default; API-key profiles are pinned to the key's team, so a different value is rejected by the server)"
32463
+ ).addOption(
32464
+ new Option2(
32465
+ "--no-update-notifier",
32466
+ "skip the update check for this invocation"
32467
+ ).hideHelp()
32468
+ );
32469
+ program.addHelpText(
32470
+ "before",
32471
+ [
32472
+ "Start here (for AI agents):",
32473
+ " duvo guide get duvo",
32474
+ "",
32475
+ "Guides ship with the CLI (always version-matched) and cover auth,",
32476
+ "workflows, and copy-paste examples. Prefer them over guessing",
32477
+ "commands from flag docs alone. List them with `duvo guide list`.",
32478
+ ""
32479
+ ].join("\n")
32480
+ );
32481
+ program.addHelpText("afterAll", () => {
32482
+ const notice = getPendingUpdateNotice();
32483
+ return notice ? `
32484
+ ${notice}` : "";
32485
+ });
32486
+ registerLogin(program);
32487
+ registerLogout(program);
32488
+ registerWhoami(program);
32489
+ registerProfiles(program);
32490
+ registerApi(program);
32491
+ registerAgents(program);
32492
+ registerAgentFolders(program);
32493
+ registerBuilds(program);
32494
+ registerBuildIntegrations(program);
32495
+ registerIntegrations(program);
32496
+ registerConnections(program);
32497
+ registerOauth(program);
32498
+ registerRuns(program);
32499
+ registerQueues(program);
32500
+ registerQueueLabels(program);
32501
+ registerCases(program);
32502
+ registerSandboxes(program);
32503
+ registerFiles(program);
32504
+ registerPlugins(program);
32505
+ registerSkills(program);
32506
+ registerGuide(program);
32507
+ registerSuggestions(program);
32508
+ registerTeam(program);
32509
+ registerTeams(program);
32510
+ registerSecrets(program);
32511
+ registerCredentials(program);
32512
+ registerRevisionSecrets(program);
32513
+ registerRevisionLogins(program);
32514
+ registerClarity(program);
32515
+ registerPulse(program);
32516
+ registerUpdate3(program);
32517
+ return program;
31846
32518
  }
31847
- __name(loadPackageMeta, "loadPackageMeta");
32519
+ __name(createProgram, "createProgram");
31848
32520
 
31849
32521
  // src/bin/duvo.ts
31850
32522
  void checkForUpdate();