@duvoai/cli 1.81.0 → 1.82.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin/duvo.js +410 -154
  2. package/package.json +1 -1
package/dist/bin/duvo.js CHANGED
@@ -5092,7 +5092,11 @@ var CLAUDE_MODEL_IDS = [
5092
5092
  "claude-sonnet-5-5",
5093
5093
  "claude-sonnet-5-5[1m]",
5094
5094
  "claude-opus-5",
5095
- "claude-opus-5[1m]"
5095
+ "claude-opus-5[1m]",
5096
+ // Opt-in Preview entry behind `claude_opus_5_5` (see
5097
+ // PREVIEW_CLAUDE_MODEL_IDS). Opus 5 stays the Opus pin everywhere else.
5098
+ "claude-opus-5-5",
5099
+ "claude-opus-5-5[1m]"
5096
5100
  ];
5097
5101
  var OSS_MODEL_IDS = [
5098
5102
  // Kimi K3 served by Fireworks. Internal-only behind `oss_models`; the
@@ -5187,8 +5191,19 @@ var ClaudeModelIdSchema = z15.enum([
5187
5191
  ...LEGACY_MODEL_IDS
5188
5192
  ]);
5189
5193
  var PREVIEW_CLAUDE_MODEL_IDS = [
5194
+ "claude-opus-5-5[1m]",
5190
5195
  "claude-sonnet-5-5[1m]"
5191
5196
  ];
5197
+ var PREVIEW_CLAUDE_MODEL_ACCESS = {
5198
+ "claude-opus-5-5[1m]": {
5199
+ flag: "claude_opus_5_5",
5200
+ fallback: "claude-opus-5[1m]"
5201
+ },
5202
+ "claude-sonnet-5-5[1m]": {
5203
+ flag: "claude_sonnet_5_5_preview",
5204
+ fallback: PLATFORM_DEFAULT_MODELS.agent.model
5205
+ }
5206
+ };
5192
5207
  var AgentModelIdSchema = extensibleEnum([
5193
5208
  ...CLAUDE_MODEL_IDS,
5194
5209
  ...OSS_MODEL_IDS,
@@ -5224,6 +5239,16 @@ var AVAILABLE_AGENT_MODELS = {
5224
5239
  "claude-opus-5[1m]": {
5225
5240
  displayName: "Claude Opus 5",
5226
5241
  description: "Our most capable model \u2014 best for complex work"
5242
+ },
5243
+ "claude-opus-5-5": {
5244
+ displayName: "Claude Opus 5.5",
5245
+ description: "Newest Opus model \u2014 best for complex, long-running work",
5246
+ isBeta: true
5247
+ },
5248
+ "claude-opus-5-5[1m]": {
5249
+ displayName: "Claude Opus 5.5",
5250
+ description: "Newest Opus model \u2014 best for complex, long-running work",
5251
+ isBeta: true
5227
5252
  }
5228
5253
  };
5229
5254
  var BrowsingModelIdSchema = z15.enum([
@@ -5244,9 +5269,11 @@ var LEGACY_MODEL_REMAP = {
5244
5269
  // Same for bare Opus 5: natively 1M at the API, but through the LiteLLM
5245
5270
  // gateway the CLI budgets 200K unless the ID carries [1m].
5246
5271
  "claude-opus-5": "claude-opus-5[1m]",
5247
- // Same for bare Sonnet 5.5 (opt-in Preview): [1m] so the pinned CLI budgets
5248
- // the real 1M window instead of its 200K unknown-id fallback.
5272
+ // Same for bare Sonnet 5.5 and Opus 5.5 (opt-in Preview): [1m] so the
5273
+ // pinned CLI budgets the real 1M window instead of its 200K unknown-id
5274
+ // fallback.
5249
5275
  "claude-sonnet-5-5": "claude-sonnet-5-5[1m]",
5276
+ "claude-opus-5-5": "claude-opus-5-5[1m]",
5250
5277
  "claude-sonnet-4-6": "claude-sonnet-5[1m]",
5251
5278
  "claude-sonnet-4-6[1m]": "claude-sonnet-5[1m]",
5252
5279
  // All retired Opus IDs (bare and [1m]) point directly at claude-opus-5[1m]:
@@ -5312,11 +5339,22 @@ function isPreviewClaudeModelId(model) {
5312
5339
  }
5313
5340
  __name(isPreviewClaudeModelId, "isPreviewClaudeModelId");
5314
5341
  __name2(isPreviewClaudeModelId, "isPreviewClaudeModelId");
5315
- function getEnabledPreviewClaudeModelIds(flags) {
5316
- if (flags.claudeSonnet55Preview) {
5317
- return PREVIEW_CLAUDE_MODEL_IDS;
5342
+ function getPreviewClaudeModelAccess(model) {
5343
+ if (!isPreviewClaudeModelId(model)) {
5344
+ return void 0;
5318
5345
  }
5319
- return [];
5346
+ return PREVIEW_CLAUDE_MODEL_ACCESS[resolveAgentModel(model)];
5347
+ }
5348
+ __name(getPreviewClaudeModelAccess, "getPreviewClaudeModelAccess");
5349
+ __name2(getPreviewClaudeModelAccess, "getPreviewClaudeModelAccess");
5350
+ function getEnabledPreviewClaudeModelIds(flags) {
5351
+ const enabledFlags = {
5352
+ claude_opus_5_5: flags.claudeOpus55,
5353
+ claude_sonnet_5_5_preview: flags.claudeSonnet55Preview
5354
+ };
5355
+ return PREVIEW_CLAUDE_MODEL_IDS.filter(
5356
+ (id) => enabledFlags[PREVIEW_CLAUDE_MODEL_ACCESS[id].flag]
5357
+ );
5320
5358
  }
5321
5359
  __name(getEnabledPreviewClaudeModelIds, "getEnabledPreviewClaudeModelIds");
5322
5360
  __name2(getEnabledPreviewClaudeModelIds, "getEnabledPreviewClaudeModelIds");
@@ -5455,6 +5493,14 @@ function caseManualStatusTargetsFor(status) {
5455
5493
  }
5456
5494
  __name(caseManualStatusTargetsFor, "caseManualStatusTargetsFor");
5457
5495
  __name2(caseManualStatusTargetsFor, "caseManualStatusTargetsFor");
5496
+ var CASE_RESOLVED_OUTCOMES = [
5497
+ "success",
5498
+ "completed"
5499
+ ];
5500
+ var CASE_NEEDS_REVIEW_OUTCOMES = [
5501
+ "issues",
5502
+ "failed"
5503
+ ];
5458
5504
  var CASE_QUEUE_BATCH_REQUEST_LIMIT = 100;
5459
5505
  var CASE_PRIORITY = {
5460
5506
  NONE: "none",
@@ -10208,6 +10254,9 @@ var automationSummaryApiSchema = z41.object({
10208
10254
  folder_id: z41.string().nullable().default(null).describe(
10209
10255
  "The agent folder this automation sits in, or null when it sits at the root. Automations reuse the team's existing agent_folder tree rather than a parallel one, so a converted team keeps the grouping it already had. Defaulted rather than required for the same reason is_setting_up is: the client parses this response, and a backend that predates the column must not throw and take the automation's name down with it."
10210
10256
  ),
10257
+ pinned_at: z41.string().nullable().default(null).describe(
10258
+ "When the calling user pinned this automation to the top of their Automations list, or null when they have not. A pin is per user, like an Agent pin: teammates each keep their own. Defaulted rather than required for the same reason folder_id is."
10259
+ ),
10211
10260
  is_setting_up: z41.boolean().default(false).describe(
10212
10261
  "True while this Module automation's setup is under way. setup_started_at is stamped when the team starts setting up (and again by reopen-setup) and cleared when setup finishes, so this reads as currently in setup, not as a record of a past one. Read together with is_demo, which lives on the detail response: both true is a demo with a build under way; is_demo alone is a demo nobody has begun. On the summary rather than the detail so that a client holding only a list, create or patch response knows the state too, and so every write onto the shared automation collection carries it. Defaulted rather than required: the client parses this response, so a backend that predates the column must not throw and take the automation's name down with it, and nothing on the wire has always meant an automation nobody has set up."
10213
10262
  ),
@@ -10313,6 +10362,9 @@ var createAutomationResponseApiSchema = z41.object({
10313
10362
  var updateAutomationResponseApiSchema = z41.object({
10314
10363
  automation: automationSummaryApiSchema
10315
10364
  });
10365
+ var automationPinResponseApiSchema = z41.object({
10366
+ pinned_at: z41.string().nullable()
10367
+ });
10316
10368
  var deleteAutomationResponseApiSchema = z41.object({
10317
10369
  success: z41.boolean()
10318
10370
  });
@@ -12134,7 +12186,17 @@ var jobListItemSchema = z54.object({
12134
12186
  });
12135
12187
  var jobListResponseSchema = z54.object({
12136
12188
  data: z54.array(jobListItemSchema),
12137
- total: z54.number()
12189
+ total: z54.number().nullable().describe(
12190
+ "Total runs matching the filters, ignoring pagination. Null when no count was requested (a `cursor` page without `include_total=true`, or `include_total=false`) \u2014 distinct from a count of 0."
12191
+ ),
12192
+ // Defaults let a client parse a response from a server that predates
12193
+ // cursor paging; the route always sends both.
12194
+ has_more: z54.boolean().default(false).describe(
12195
+ "Whether another page exists past this one, determined by looking one row ahead. False on a count_only response."
12196
+ ),
12197
+ next_cursor: z54.string().nullable().default(null).describe(
12198
+ "Pass as `cursor` (same filters, same sort_order) to fetch the next page. Null when `has_more` is false. Continues right after the last run on this page."
12199
+ )
12138
12200
  });
12139
12201
  var jobFilterOptionsSchema = z54.object({
12140
12202
  agents: z54.array(
@@ -18507,7 +18569,11 @@ var CLAUDE_MODEL_IDS2 = [
18507
18569
  "claude-sonnet-5-5",
18508
18570
  "claude-sonnet-5-5[1m]",
18509
18571
  "claude-opus-5",
18510
- "claude-opus-5[1m]"
18572
+ "claude-opus-5[1m]",
18573
+ // Opt-in Preview entry behind `claude_opus_5_5` (see
18574
+ // PREVIEW_CLAUDE_MODEL_IDS). Opus 5 stays the Opus pin everywhere else.
18575
+ "claude-opus-5-5",
18576
+ "claude-opus-5-5[1m]"
18511
18577
  ];
18512
18578
  var OSS_MODEL_IDS2 = [
18513
18579
  // Kimi K3 served by Fireworks. Internal-only behind `oss_models`; the
@@ -18602,8 +18668,19 @@ var ClaudeModelIdSchema2 = z162.enum([
18602
18668
  ...LEGACY_MODEL_IDS2
18603
18669
  ]);
18604
18670
  var PREVIEW_CLAUDE_MODEL_IDS2 = [
18671
+ "claude-opus-5-5[1m]",
18605
18672
  "claude-sonnet-5-5[1m]"
18606
18673
  ];
18674
+ var PREVIEW_CLAUDE_MODEL_ACCESS2 = {
18675
+ "claude-opus-5-5[1m]": {
18676
+ flag: "claude_opus_5_5",
18677
+ fallback: "claude-opus-5[1m]"
18678
+ },
18679
+ "claude-sonnet-5-5[1m]": {
18680
+ flag: "claude_sonnet_5_5_preview",
18681
+ fallback: PLATFORM_DEFAULT_MODELS2.agent.model
18682
+ }
18683
+ };
18607
18684
  var AgentModelIdSchema2 = extensibleEnum2([
18608
18685
  ...CLAUDE_MODEL_IDS2,
18609
18686
  ...OSS_MODEL_IDS2,
@@ -18639,6 +18716,16 @@ var AVAILABLE_AGENT_MODELS2 = {
18639
18716
  "claude-opus-5[1m]": {
18640
18717
  displayName: "Claude Opus 5",
18641
18718
  description: "Our most capable model \u2014 best for complex work"
18719
+ },
18720
+ "claude-opus-5-5": {
18721
+ displayName: "Claude Opus 5.5",
18722
+ description: "Newest Opus model \u2014 best for complex, long-running work",
18723
+ isBeta: true
18724
+ },
18725
+ "claude-opus-5-5[1m]": {
18726
+ displayName: "Claude Opus 5.5",
18727
+ description: "Newest Opus model \u2014 best for complex, long-running work",
18728
+ isBeta: true
18642
18729
  }
18643
18730
  };
18644
18731
  var BrowsingModelIdSchema2 = z162.enum([
@@ -18659,9 +18746,11 @@ var LEGACY_MODEL_REMAP2 = {
18659
18746
  // Same for bare Opus 5: natively 1M at the API, but through the LiteLLM
18660
18747
  // gateway the CLI budgets 200K unless the ID carries [1m].
18661
18748
  "claude-opus-5": "claude-opus-5[1m]",
18662
- // Same for bare Sonnet 5.5 (opt-in Preview): [1m] so the pinned CLI budgets
18663
- // the real 1M window instead of its 200K unknown-id fallback.
18749
+ // Same for bare Sonnet 5.5 and Opus 5.5 (opt-in Preview): [1m] so the
18750
+ // pinned CLI budgets the real 1M window instead of its 200K unknown-id
18751
+ // fallback.
18664
18752
  "claude-sonnet-5-5": "claude-sonnet-5-5[1m]",
18753
+ "claude-opus-5-5": "claude-opus-5-5[1m]",
18665
18754
  "claude-sonnet-4-6": "claude-sonnet-5[1m]",
18666
18755
  "claude-sonnet-4-6[1m]": "claude-sonnet-5[1m]",
18667
18756
  // All retired Opus IDs (bare and [1m]) point directly at claude-opus-5[1m]:
@@ -18727,11 +18816,22 @@ function isPreviewClaudeModelId2(model) {
18727
18816
  }
18728
18817
  __name(isPreviewClaudeModelId2, "isPreviewClaudeModelId");
18729
18818
  __name3(isPreviewClaudeModelId2, "isPreviewClaudeModelId");
18730
- function getEnabledPreviewClaudeModelIds2(flags) {
18731
- if (flags.claudeSonnet55Preview) {
18732
- return PREVIEW_CLAUDE_MODEL_IDS2;
18819
+ function getPreviewClaudeModelAccess2(model) {
18820
+ if (!isPreviewClaudeModelId2(model)) {
18821
+ return void 0;
18733
18822
  }
18734
- return [];
18823
+ return PREVIEW_CLAUDE_MODEL_ACCESS2[resolveAgentModel2(model)];
18824
+ }
18825
+ __name(getPreviewClaudeModelAccess2, "getPreviewClaudeModelAccess");
18826
+ __name3(getPreviewClaudeModelAccess2, "getPreviewClaudeModelAccess");
18827
+ function getEnabledPreviewClaudeModelIds2(flags) {
18828
+ const enabledFlags = {
18829
+ claude_opus_5_5: flags.claudeOpus55,
18830
+ claude_sonnet_5_5_preview: flags.claudeSonnet55Preview
18831
+ };
18832
+ return PREVIEW_CLAUDE_MODEL_IDS2.filter(
18833
+ (id) => enabledFlags[PREVIEW_CLAUDE_MODEL_ACCESS2[id].flag]
18834
+ );
18735
18835
  }
18736
18836
  __name(getEnabledPreviewClaudeModelIds2, "getEnabledPreviewClaudeModelIds");
18737
18837
  __name3(getEnabledPreviewClaudeModelIds2, "getEnabledPreviewClaudeModelIds");
@@ -30497,6 +30597,20 @@ function orgInvitationState(expiresAt, now) {
30497
30597
  }
30498
30598
  __name(orgInvitationState, "orgInvitationState");
30499
30599
  __name3(orgInvitationState, "orgInvitationState");
30600
+ var CATEGORY_LABELS = {
30601
+ incident: "Live incident or outage",
30602
+ customer_request: "Customer asked for help",
30603
+ proactive_repair: "Proactive repair",
30604
+ service_account: "Operating a service account",
30605
+ build_for_customer: "Building Agents for the customer",
30606
+ other: "Other",
30607
+ legacy: "Not recorded"
30608
+ };
30609
+ function impersonationReasonCategoryLabel(category) {
30610
+ return Object.hasOwn(CATEGORY_LABELS, category) ? CATEGORY_LABELS[category] : category;
30611
+ }
30612
+ __name(impersonationReasonCategoryLabel, "impersonationReasonCategoryLabel");
30613
+ __name3(impersonationReasonCategoryLabel, "impersonationReasonCategoryLabel");
30500
30614
  var ORG_ROLE2 = {
30501
30615
  EXECUTIVE: "organization:executive",
30502
30616
  OWNER: "organization:owner",
@@ -30954,8 +31068,8 @@ var ALLOWED_GET_PATTERNS = [
30954
31068
  new RegExp(`^teams/${UUID}/runs/active$`),
30955
31069
  new RegExp(`^runs/in-flight$`),
30956
31070
  new RegExp(`^teams/${UUID}/runs/in-flight$`),
30957
- new RegExp(`^agents/eval-counts$`),
30958
- // aggregate counts only (rationale is Tier 2)
31071
+ // Aggregate counts only (rationale is Tier 2).
31072
+ new RegExp(`^teams/${UUID}/agents/eval-counts$`),
30959
31073
  new RegExp(`^teams/${UUID}/agents/run-stats$`),
30960
31074
  // list/aggregate metadata for the remaining dashboardable entities
30961
31075
  new RegExp(`^teams/${UUID}/skills$`),
@@ -31008,6 +31122,9 @@ var ALLOWED_GET_PATTERNS = [
31008
31122
  new RegExp(`^organizations/me$`),
31009
31123
  new RegExp(`^organizations/mine$`)
31010
31124
  ];
31125
+ var V1_ONLY_ALLOWED_GET_PATTERNS = [
31126
+ new RegExp(`^agents/eval-counts$`)
31127
+ ];
31011
31128
  var UNCONFINED_POST_PATTERNS = [
31012
31129
  new RegExp("^artifacts/llm$"),
31013
31130
  new RegExp("^artifacts/mcp/call$")
@@ -31180,7 +31297,7 @@ function isAllowedPulseRequest(version2, segments, method) {
31180
31297
  return true;
31181
31298
  }
31182
31299
  if (upperMethod === "GET") {
31183
- return EXACT_ALLOWED_GET_PATTERNS.some((pattern) => pattern.test(path));
31300
+ return EXACT_ALLOWED_GET_PATTERNS.some((pattern) => pattern.test(path)) || version2 === "v1" && V1_ONLY_ALLOWED_GET_PATTERNS.some((pattern) => pattern.test(path));
31184
31301
  }
31185
31302
  if (upperMethod === "POST") {
31186
31303
  return EXACT_UNCONFINED_POST_PATTERNS.some((pattern) => pattern.test(path)) || EXACT_CONFINED_DATA_POST_PATTERNS.some((pattern) => pattern.test(path)) || EXACT_ALLOWED_ACTION_POST_PATTERNS.some((pattern) => pattern.test(path));
@@ -36698,6 +36815,12 @@ var connectionSnapshotSchema = z85.object({
36698
36815
  /** Why the connection failed to resolve this turn. Set only on dropped connections. */
36699
36816
  reason: z85.string().max(500).optional()
36700
36817
  });
36818
+ var pulseConnectionSnapshotSchema = z85.object({
36819
+ name: z85.string(),
36820
+ integrationType: z85.string(),
36821
+ serverLabel: z85.string(),
36822
+ catalogIdentifier: z85.string().nullable()
36823
+ });
36701
36824
  var AGENT_CHAT_RUNTIME_VERSIONS = ["v1", "v2"];
36702
36825
  var AGENT_CHAT_TRANSPORTS = ["mcp", "cli"];
36703
36826
  var AGENT_CHAT_RUNTIME_FALLBACK_REASONS = [
@@ -36759,6 +36882,21 @@ var agentChatMessageMetadataSchema = z85.object({
36759
36882
  /** Branch point when the user was previewing an older version (mirrors the panel's `from_revision_id`). */
36760
36883
  fromRevisionId: z85.guid().optional()
36761
36884
  }).optional(),
36885
+ /**
36886
+ * The Connections of the Pulse dashboard this turn is bound to, as dispatch
36887
+ * mounted them (`pulse_edit_in_ask_duvo` only). `prepare_pulse_workspace`
36888
+ * lists them in `context.md`, so the subagent learns which dashboard
36889
+ * Connections it has tools for without resolving them again. Deliberately
36890
+ * NOT in the response projection, like `connections`.
36891
+ */
36892
+ pulseConnections: z85.object({
36893
+ /** Null only with `loadFailed`: the chat's dashboard couldn't be looked up. */
36894
+ artifactId: z85.guid().nullable(),
36895
+ resolved: pulseConnectionSnapshotSchema.array(),
36896
+ dropped: pulseConnectionSnapshotSchema.array(),
36897
+ /** They couldn't be read this turn, so both lists are empty. */
36898
+ loadFailed: z85.literal(true).optional()
36899
+ }).optional(),
36762
36900
  /** Artifact produced/edited by this turn — renders the transcript chip. */
36763
36901
  artifact: agentChatMessageArtifactRefSchema2.optional(),
36764
36902
  /**
@@ -37672,6 +37810,9 @@ var automationSummaryApiSchema2 = z93.object({
37672
37810
  folder_id: z93.string().nullable().default(null).describe(
37673
37811
  "The agent folder this automation sits in, or null when it sits at the root. Automations reuse the team's existing agent_folder tree rather than a parallel one, so a converted team keeps the grouping it already had. Defaulted rather than required for the same reason is_setting_up is: the client parses this response, and a backend that predates the column must not throw and take the automation's name down with it."
37674
37812
  ),
37813
+ pinned_at: z93.string().nullable().default(null).describe(
37814
+ "When the calling user pinned this automation to the top of their Automations list, or null when they have not. A pin is per user, like an Agent pin: teammates each keep their own. Defaulted rather than required for the same reason folder_id is."
37815
+ ),
37675
37816
  is_setting_up: z93.boolean().default(false).describe(
37676
37817
  "True while this Module automation's setup is under way. setup_started_at is stamped when the team starts setting up (and again by reopen-setup) and cleared when setup finishes, so this reads as currently in setup, not as a record of a past one. Read together with is_demo, which lives on the detail response: both true is a demo with a build under way; is_demo alone is a demo nobody has begun. On the summary rather than the detail so that a client holding only a list, create or patch response knows the state too, and so every write onto the shared automation collection carries it. Defaulted rather than required: the client parses this response, so a backend that predates the column must not throw and take the automation's name down with it, and nothing on the wire has always meant an automation nobody has set up."
37677
37818
  ),
@@ -37777,6 +37918,9 @@ var createAutomationResponseApiSchema2 = z93.object({
37777
37918
  var updateAutomationResponseApiSchema2 = z93.object({
37778
37919
  automation: automationSummaryApiSchema2
37779
37920
  });
37921
+ var automationPinResponseApiSchema2 = z93.object({
37922
+ pinned_at: z93.string().nullable()
37923
+ });
37780
37924
  var deleteAutomationResponseApiSchema2 = z93.object({
37781
37925
  success: z93.boolean()
37782
37926
  });
@@ -39782,7 +39926,7 @@ var FEATURE_FLAG_CATALOGUE = {
39782
39926
  AGENT_SDK_CANARY: {
39783
39927
  key: "agent_sdk_canary",
39784
39928
  defaultValue: false,
39785
- description: "Routes newly created cc-server sandboxes to the Agent SDK canary E2B template instead of the regular one, so a new `@anthropic-ai/claude-agent-sdk` release can take a small slice of real traffic before the pin moves. CI builds the canary template on every staging push and production release from the same cc-server commit and Dockerfile as the regular template, with the SDK and its CLI binary package pinned to the version in `cc-server/e2b-templates/canary/agent-sdk-version.txt`. Set it per user, team or organization; a global override is ignored, so the canary never reaches every sandbox at once. Every sandbox creation path reads it \u2014 agent Runs, Ask Duvo, the builder, Clarity, code steps, Pulse, the public API and the rest. A sandbox that belongs to one user resolves user, then team, then organization. A sandbox that teammates share (a Pulse, a workflow-builder plan, a builder draft) and a system job with no acting user resolve team and organization only, so a user-level override neither moves nor excludes those. A sandbox keeps the SDK it was created with: turning the flag off moves new sandboxes back at once, while existing chats and resumed Runs stay on the canary until their sandbox is replaced. Does nothing where `E2B_SDK_CANARY_TEMPLATE` is unset (local development, previews) or with the Docker sandbox provider, and flagged sandboxes run the pinned SDK whenever the version file is empty or matches the pin. Off by default."
39929
+ description: "Routes newly created cc-server sandboxes to the Agent SDK canary E2B template instead of the regular one, so a new `@anthropic-ai/claude-agent-sdk` release can take real traffic before the pin moves, from a small slice up to every new sandbox. CI builds the canary template on every staging push and production release from the same cc-server commit and Dockerfile as the regular template, with the SDK and its CLI binary package pinned to the version in `cc-server/e2b-templates/canary/agent-sdk-version.txt`. Set it per user, team or organization, or globally to move every new sandbox onto the canary before promoting it; under a global on, a user, team or organization override set to off keeps that scope on the pin, except for any team or user inside it with its own on override, since the most specific override wins. Every sandbox creation path reads it \u2014 agent Runs, Ask Duvo, the builder, Clarity, code steps, Pulse, the public API and the rest. A sandbox that belongs to one user resolves user, then team, then organization. A sandbox that teammates share (a Pulse, a workflow-builder plan, a builder draft) and a system job with no acting user resolve team and organization only, so a user-level override neither moves nor excludes those. A sandbox keeps the SDK it was created with: turning the flag off moves new sandboxes back at once, while existing chats and resumed Runs stay on the canary until their sandbox is replaced. Does nothing where `E2B_SDK_CANARY_TEMPLATE` is unset (local development, previews) or with the Docker sandbox provider, and flagged sandboxes run the pinned SDK whenever the version file is empty or matches the pin. Off by default."
39786
39930
  },
39787
39931
  BROWSING_RECORDING_SCREENSHOTS: {
39788
39932
  key: "browsing_recording_screenshots",
@@ -39943,10 +40087,15 @@ var FEATURE_FLAG_CATALOGUE = {
39943
40087
  defaultValue: false,
39944
40088
  description: "Routes Clarity interviews (voice-only AND voice+screenshare) to the Google Gemini Live conversational provider. When off, interviews use OpenAI Realtime."
39945
40089
  },
40090
+ CLAUDE_OPUS_5_5: {
40091
+ key: "claude_opus_5_5",
40092
+ defaultValue: false,
40093
+ description: "Makes Claude Opus 5.5 (`claude-opus-5-5[1m]`, one of `PREVIEW_CLAUDE_MODEL_IDS`, shown with a BETA badge) selectable as the Agent-run model, next to Claude Opus 5. When on, the builder model picker lists Claude Opus 5.5 and build configs may store its id (and the bare companion). When off, the id is rejected at save and Agents already configured with it run on Claude Opus 5 at dispatch (no data migration; turning the flag back on restores Opus 5.5). Scoped to the Agent-run model only; server-side Opus pins (advisor, exports, pipelines) stay on Opus 5. LiteLLM routes the model on every provider: Anthropic with a Vertex fallback for `default` organizations, and the EU geo profile on Bedrock for `bedrock` organizations. The Bedrock route is bedrock-runtime, not mantle (AWS has no EU mantle region for this model): it buffers the first turn and sends no pings, so a turn that sends no bytes for longer than the LiteLLM 600s timeout fails; soak a long run on staging Bedrock before enabling for a `bedrock` organization. Enable per team or organization, not per user: scheduled, triggered and queued runs resolve the flag for the run's user, not for the user who holds a user-scoped override. Enable only after LiteLLM in that environment lists `claude-opus-5-5` on GET /v1/models. Off by default for staged rollout; also the kill switch."
40094
+ },
39946
40095
  CLAUDE_SONNET_5_5_PREVIEW: {
39947
40096
  key: "claude_sonnet_5_5_preview",
39948
40097
  defaultValue: false,
39949
- description: "Enables the Claude Sonnet 5.5 opt-in Preview entry (`PREVIEW_CLAUDE_MODEL_IDS`: claude-sonnet-5-5[1m], shown as a beta) for Agent runs. When on, the builder model picker shows Claude Sonnet 5.5 under Preview models and build configs may store that id (and the bare companion). When off, the Preview row is hidden, saves that pick are rejected, and existing Agents configured with Sonnet 5.5 silently run on the platform default Claude model at dispatch (no data migration; re-enabling restores Sonnet 5.5 execution). Scoped to the Agent-run model only \u2014 no other LLM surface reads this flag. Off-by-default so picker exposure can wait until LiteLLM in that environment already lists and routes `claude-sonnet-5-5` (check GET /v1/models before enabling per env); both the rollout control and the kill-switch for Sonnet 5.5 Preview."
40098
+ description: "Enables the Claude Sonnet 5.5 opt-in Preview entry (`claude-sonnet-5-5[1m]`, one of `PREVIEW_CLAUDE_MODEL_IDS`, shown as a beta) for Agent runs. When on, the builder model picker lists Claude Sonnet 5.5 with the Claude models and build configs may store that id (and the bare companion). When off, the Preview row is hidden, saves that pick are rejected, and existing Agents configured with Sonnet 5.5 silently run on the platform default Claude model at dispatch (no data migration; re-enabling restores Sonnet 5.5 execution). Scoped to the Agent-run model only \u2014 no other LLM surface reads this flag. Off-by-default so picker exposure can wait until LiteLLM in that environment already lists and routes `claude-sonnet-5-5` (check GET /v1/models before enabling per env); both the rollout control and the kill-switch for Sonnet 5.5 Preview."
39950
40099
  },
39951
40100
  EDI_CONNECTION: {
39952
40101
  key: "edi_connection",
@@ -40535,7 +40684,17 @@ var jobListItemSchema2 = z117.object({
40535
40684
  });
40536
40685
  var jobListResponseSchema2 = z117.object({
40537
40686
  data: z117.array(jobListItemSchema2),
40538
- total: z117.number()
40687
+ total: z117.number().nullable().describe(
40688
+ "Total runs matching the filters, ignoring pagination. Null when no count was requested (a `cursor` page without `include_total=true`, or `include_total=false`) \u2014 distinct from a count of 0."
40689
+ ),
40690
+ // Defaults let a client parse a response from a server that predates
40691
+ // cursor paging; the route always sends both.
40692
+ has_more: z117.boolean().default(false).describe(
40693
+ "Whether another page exists past this one, determined by looking one row ahead. False on a count_only response."
40694
+ ),
40695
+ next_cursor: z117.string().nullable().default(null).describe(
40696
+ "Pass as `cursor` (same filters, same sort_order) to fetch the next page. Null when `has_more` is false. Continues right after the last run on this page."
40697
+ )
40539
40698
  });
40540
40699
  var jobFilterOptionsSchema2 = z117.object({
40541
40700
  agents: z117.array(
@@ -43066,6 +43225,33 @@ function isLabelHue(value) {
43066
43225
  }
43067
43226
  __name(isLabelHue, "isLabelHue");
43068
43227
  __name3(isLabelHue, "isLabelHue");
43228
+ async function mapWithConcurrency(items, limit, task) {
43229
+ if (limit <= 0) {
43230
+ throw new Error(`mapWithConcurrency: limit must be positive, got ${limit}`);
43231
+ }
43232
+ const results = Array.from({ length: items.length });
43233
+ let cursor = 0;
43234
+ let hasFailed = false;
43235
+ const workerCount = Math.min(limit, items.length);
43236
+ const workers = Array.from({ length: workerCount }, async () => {
43237
+ while (!hasFailed) {
43238
+ const idx = cursor++;
43239
+ if (idx >= items.length) {
43240
+ return;
43241
+ }
43242
+ try {
43243
+ results[idx] = await task(items[idx], idx);
43244
+ } catch (error) {
43245
+ hasFailed = true;
43246
+ throw error;
43247
+ }
43248
+ }
43249
+ });
43250
+ await Promise.all(workers);
43251
+ return results;
43252
+ }
43253
+ __name(mapWithConcurrency, "mapWithConcurrency");
43254
+ __name3(mapWithConcurrency, "mapWithConcurrency");
43069
43255
  function sleep(ms) {
43070
43256
  return new Promise((resolve) => setTimeout(resolve, ms));
43071
43257
  }
@@ -43400,6 +43586,8 @@ var processAccessSchema = z134.object({
43400
43586
  automation_id: z134.guid(),
43401
43587
  name: z134.string(),
43402
43588
  description: z134.string().nullable(),
43589
+ // Optional so a frontend rolled out before the backend still parses the grants.
43590
+ role_label: z134.string().optional(),
43403
43591
  can_act_on_cases: z134.boolean(),
43404
43592
  can_view_manage: z134.boolean(),
43405
43593
  dashboards: z134.array(processDashboardAccessSchema)
@@ -49724,12 +49912,135 @@ __name(registerCasesDelete, "registerCasesDelete");
49724
49912
 
49725
49913
  // src/commands/cases/export.ts
49726
49914
  import { writeFileSync } from "node:fs";
49727
- var SORT_FIELDS = ["created_at", "updated_at", "postponed_to"];
49915
+
49916
+ // src/commands/cases/parse-case-filters.ts
49917
+ var SORT_FIELDS = [
49918
+ "created_at",
49919
+ "updated_at",
49920
+ "postponed_to"
49921
+ ];
49728
49922
  var SORT_ORDERS = ["asc", "desc"];
49923
+ var LEGACY_STATUS_REPLACEMENT = {
49924
+ claimed: {
49925
+ bucket: "processing",
49926
+ displayStatuses: ["in_progress", "evaluating"]
49927
+ },
49928
+ completed: {
49929
+ bucket: "resolved",
49930
+ displayStatuses: CASE_RESOLVED_OUTCOMES
49931
+ },
49932
+ failed: {
49933
+ bucket: "needs_review",
49934
+ displayStatuses: CASE_NEEDS_REVIEW_OUTCOMES
49935
+ }
49936
+ };
49937
+ function parseStatuses(raw) {
49938
+ if (raw === void 0) {
49939
+ return void 0;
49940
+ }
49941
+ const parts = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
49942
+ if (parts.length === 0) {
49943
+ throw new CliError(
49944
+ `Invalid --status value "${raw}". Allowed: ${CASE_FILTER_STATUS_BUCKETS.join(", ")}.`
49945
+ );
49946
+ }
49947
+ const allowed = new Set(CASE_FILTER_STATUS_BUCKETS);
49948
+ const legacy = parts.filter(
49949
+ (p) => CASE_FILTER_STATUS_LEGACY.includes(p)
49950
+ );
49951
+ const invalid = parts.filter(
49952
+ (p) => !allowed.has(p) && !CASE_FILTER_STATUS_LEGACY.includes(p)
49953
+ );
49954
+ const problems = [];
49955
+ for (const value of legacy) {
49956
+ const replacement = LEGACY_STATUS_REPLACEMENT[value];
49957
+ problems.push(
49958
+ `--status value "${value}" is a deprecated alias that filters on display status (${replacement.displayStatuses.join(", ")}), not the Case's own status. Use "${replacement.bucket}" instead.`
49959
+ );
49960
+ }
49961
+ if (invalid.length > 0) {
49962
+ problems.push(
49963
+ `Invalid --status value(s): ${invalid.join(", ")}. Allowed: ${CASE_FILTER_STATUS_BUCKETS.join(", ")}.`
49964
+ );
49965
+ }
49966
+ if (problems.length > 0) {
49967
+ throw new CliError(problems.join("; "));
49968
+ }
49969
+ return parts;
49970
+ }
49971
+ __name(parseStatuses, "parseStatuses");
49972
+ function parseSeverities(raw) {
49973
+ if (raw === void 0) {
49974
+ return void 0;
49975
+ }
49976
+ const parts = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
49977
+ if (parts.length === 0) {
49978
+ throw new CliError(
49979
+ `Invalid --issue-severity value "${raw}". Allowed: ${caseIssueSeverityFilterSchema.options.join(", ")}.`
49980
+ );
49981
+ }
49982
+ const allowed = new Set(caseIssueSeverityFilterSchema.options);
49983
+ const invalid = parts.filter((p) => !allowed.has(p));
49984
+ if (invalid.length > 0) {
49985
+ throw new CliError(
49986
+ `Invalid --issue-severity value(s): ${invalid.join(", ")}. Allowed: ${caseIssueSeverityFilterSchema.options.join(", ")}.`
49987
+ );
49988
+ }
49989
+ return parts;
49990
+ }
49991
+ __name(parseSeverities, "parseSeverities");
49992
+ function parsePriorities(raw) {
49993
+ if (raw === void 0) {
49994
+ return void 0;
49995
+ }
49996
+ const parts = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
49997
+ if (parts.length === 0) {
49998
+ throw new CliError(
49999
+ `Invalid --priority value "${raw}". Allowed: ${casePriorityFilterSchema.options.join(", ")}.`
50000
+ );
50001
+ }
50002
+ const allowed = new Set(casePriorityFilterSchema.options);
50003
+ const invalid = parts.filter((p) => !allowed.has(p));
50004
+ if (invalid.length > 0) {
50005
+ throw new CliError(
50006
+ `Invalid --priority value(s): ${invalid.join(", ")}. Allowed: ${casePriorityFilterSchema.options.join(", ")}.`
50007
+ );
50008
+ }
50009
+ return parts;
50010
+ }
50011
+ __name(parsePriorities, "parsePriorities");
50012
+ function parseSortBy(raw) {
50013
+ if (raw === void 0) {
50014
+ return void 0;
50015
+ }
50016
+ if (!SORT_FIELDS.includes(raw)) {
50017
+ throw new CliError(
50018
+ `Invalid --sort-by value "${raw}". Allowed: ${SORT_FIELDS.join(", ")}.`
50019
+ );
50020
+ }
50021
+ return raw;
50022
+ }
50023
+ __name(parseSortBy, "parseSortBy");
50024
+ function parseSortOrder(raw) {
50025
+ if (raw === void 0) {
50026
+ return void 0;
50027
+ }
50028
+ if (!SORT_ORDERS.includes(raw)) {
50029
+ throw new CliError(
50030
+ `Invalid --sort-order value "${raw}". Allowed: ${SORT_ORDERS.join(", ")}.`
50031
+ );
50032
+ }
50033
+ return raw;
50034
+ }
50035
+ __name(parseSortOrder, "parseSortOrder");
50036
+
50037
+ // src/commands/cases/export.ts
50038
+ var SORT_FIELDS2 = ["created_at", "updated_at", "postponed_to"];
50039
+ var SORT_ORDERS2 = ["asc", "desc"];
49729
50040
  function registerCasesExport(cases) {
49730
50041
  cases.command("export").description("Export a queue's cases as a CSV file (or stdout)").requiredOption("--queue <id>", "ID of the queue to export cases from").option(
49731
50042
  "--status <statuses>",
49732
- `comma-separated status buckets (${CASE_FILTER_STATUS_BUCKETS.join(", ")})`
50043
+ `comma-separated display-status buckets (${CASE_FILTER_STATUS_BUCKETS.join(", ")}); filters on each Case's display_status, not its raw status`
49733
50044
  ).option(
49734
50045
  "--issue-severity <levels>",
49735
50046
  `comma-separated issue severities (${caseIssueSeverityFilterSchema.options.join(", ")}); narrows within the issues outcome`
@@ -49745,15 +50056,15 @@ function registerCasesExport(cases) {
49745
50056
  ).option(
49746
50057
  "--updated-at-from <iso>",
49747
50058
  "include cases updated on or after this ISO-8601 timestamp"
49748
- ).option("--sort-by <field>", `sort field (${SORT_FIELDS.join(", ")})`).option(
50059
+ ).option("--sort-by <field>", `sort field (${SORT_FIELDS2.join(", ")})`).option(
49749
50060
  "--sort-order <order>",
49750
- `sort direction (${SORT_ORDERS.join(", ")})`
50061
+ `sort direction (${SORT_ORDERS2.join(", ")})`
49751
50062
  ).option("--output <file>", "write the CSV to this file instead of stdout").action(/* @__PURE__ */ __name(async function exportAction(options) {
49752
50063
  const statuses = parseStatuses(options.status);
49753
- const severities = parseSeverities(options.issueSeverity);
49754
- const priorities = parsePriorities(options.priority);
49755
- const sortBy = parseSortBy(options.sortBy);
49756
- const sortOrder = parseSortOrder(options.sortOrder);
50064
+ const severities = parseSeverities2(options.issueSeverity);
50065
+ const priorities = parsePriorities2(options.priority);
50066
+ const sortBy = parseSortBy2(options.sortBy);
50067
+ const sortOrder = parseSortOrder2(options.sortOrder);
49757
50068
  const filters = {};
49758
50069
  if (statuses) {
49759
50070
  filters.status = statuses;
@@ -49825,46 +50136,42 @@ function parseCommaList(raw, allowed, optionName) {
49825
50136
  return parts;
49826
50137
  }
49827
50138
  __name(parseCommaList, "parseCommaList");
49828
- function parseStatuses(raw) {
49829
- return parseCommaList(raw, caseFilterStatusSchema.options, "--status");
49830
- }
49831
- __name(parseStatuses, "parseStatuses");
49832
- function parseSeverities(raw) {
50139
+ function parseSeverities2(raw) {
49833
50140
  return parseCommaList(
49834
50141
  raw,
49835
50142
  caseIssueSeverityFilterSchema.options,
49836
50143
  "--issue-severity"
49837
50144
  );
49838
50145
  }
49839
- __name(parseSeverities, "parseSeverities");
49840
- function parsePriorities(raw) {
50146
+ __name(parseSeverities2, "parseSeverities");
50147
+ function parsePriorities2(raw) {
49841
50148
  return parseCommaList(raw, casePriorityFilterSchema.options, "--priority");
49842
50149
  }
49843
- __name(parsePriorities, "parsePriorities");
49844
- function parseSortBy(raw) {
50150
+ __name(parsePriorities2, "parsePriorities");
50151
+ function parseSortBy2(raw) {
49845
50152
  if (raw === void 0) {
49846
50153
  return void 0;
49847
50154
  }
49848
- if (!SORT_FIELDS.includes(raw)) {
50155
+ if (!SORT_FIELDS2.includes(raw)) {
49849
50156
  throw new CliError(
49850
- `Invalid --sort-by value "${raw}". Allowed: ${SORT_FIELDS.join(", ")}.`
50157
+ `Invalid --sort-by value "${raw}". Allowed: ${SORT_FIELDS2.join(", ")}.`
49851
50158
  );
49852
50159
  }
49853
50160
  return raw;
49854
50161
  }
49855
- __name(parseSortBy, "parseSortBy");
49856
- function parseSortOrder(raw) {
50162
+ __name(parseSortBy2, "parseSortBy");
50163
+ function parseSortOrder2(raw) {
49857
50164
  if (raw === void 0) {
49858
50165
  return void 0;
49859
50166
  }
49860
- if (!SORT_ORDERS.includes(raw)) {
50167
+ if (!SORT_ORDERS2.includes(raw)) {
49861
50168
  throw new CliError(
49862
- `Invalid --sort-order value "${raw}". Allowed: ${SORT_ORDERS.join(", ")}.`
50169
+ `Invalid --sort-order value "${raw}". Allowed: ${SORT_ORDERS2.join(", ")}.`
49863
50170
  );
49864
50171
  }
49865
50172
  return raw;
49866
50173
  }
49867
- __name(parseSortOrder, "parseSortOrder");
50174
+ __name(parseSortOrder2, "parseSortOrder");
49868
50175
 
49869
50176
  // src/commands/cases/get.ts
49870
50177
  function registerCasesGet(cases) {
@@ -50097,98 +50404,6 @@ function parseLabel(input) {
50097
50404
  }
50098
50405
  __name(parseLabel, "parseLabel");
50099
50406
 
50100
- // src/commands/cases/parse-case-filters.ts
50101
- var SORT_FIELDS2 = [
50102
- "created_at",
50103
- "updated_at",
50104
- "postponed_to"
50105
- ];
50106
- var SORT_ORDERS2 = ["asc", "desc"];
50107
- function parseStatuses2(raw) {
50108
- if (raw === void 0) {
50109
- return void 0;
50110
- }
50111
- const parts = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
50112
- if (parts.length === 0) {
50113
- throw new CliError(
50114
- `Invalid --status value "${raw}". Allowed: ${CASE_FILTER_STATUS_BUCKETS.join(", ")}.`
50115
- );
50116
- }
50117
- const allowed = new Set(caseFilterStatusSchema.options);
50118
- const invalid = parts.filter((p) => !allowed.has(p));
50119
- if (invalid.length > 0) {
50120
- throw new CliError(
50121
- `Invalid --status value(s): ${invalid.join(", ")}. Allowed: ${CASE_FILTER_STATUS_BUCKETS.join(", ")}.`
50122
- );
50123
- }
50124
- return parts;
50125
- }
50126
- __name(parseStatuses2, "parseStatuses");
50127
- function parseSeverities2(raw) {
50128
- if (raw === void 0) {
50129
- return void 0;
50130
- }
50131
- const parts = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
50132
- if (parts.length === 0) {
50133
- throw new CliError(
50134
- `Invalid --issue-severity value "${raw}". Allowed: ${caseIssueSeverityFilterSchema.options.join(", ")}.`
50135
- );
50136
- }
50137
- const allowed = new Set(caseIssueSeverityFilterSchema.options);
50138
- const invalid = parts.filter((p) => !allowed.has(p));
50139
- if (invalid.length > 0) {
50140
- throw new CliError(
50141
- `Invalid --issue-severity value(s): ${invalid.join(", ")}. Allowed: ${caseIssueSeverityFilterSchema.options.join(", ")}.`
50142
- );
50143
- }
50144
- return parts;
50145
- }
50146
- __name(parseSeverities2, "parseSeverities");
50147
- function parsePriorities2(raw) {
50148
- if (raw === void 0) {
50149
- return void 0;
50150
- }
50151
- const parts = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
50152
- if (parts.length === 0) {
50153
- throw new CliError(
50154
- `Invalid --priority value "${raw}". Allowed: ${casePriorityFilterSchema.options.join(", ")}.`
50155
- );
50156
- }
50157
- const allowed = new Set(casePriorityFilterSchema.options);
50158
- const invalid = parts.filter((p) => !allowed.has(p));
50159
- if (invalid.length > 0) {
50160
- throw new CliError(
50161
- `Invalid --priority value(s): ${invalid.join(", ")}. Allowed: ${casePriorityFilterSchema.options.join(", ")}.`
50162
- );
50163
- }
50164
- return parts;
50165
- }
50166
- __name(parsePriorities2, "parsePriorities");
50167
- function parseSortBy2(raw) {
50168
- if (raw === void 0) {
50169
- return void 0;
50170
- }
50171
- if (!SORT_FIELDS2.includes(raw)) {
50172
- throw new CliError(
50173
- `Invalid --sort-by value "${raw}". Allowed: ${SORT_FIELDS2.join(", ")}.`
50174
- );
50175
- }
50176
- return raw;
50177
- }
50178
- __name(parseSortBy2, "parseSortBy");
50179
- function parseSortOrder2(raw) {
50180
- if (raw === void 0) {
50181
- return void 0;
50182
- }
50183
- if (!SORT_ORDERS2.includes(raw)) {
50184
- throw new CliError(
50185
- `Invalid --sort-order value "${raw}". Allowed: ${SORT_ORDERS2.join(", ")}.`
50186
- );
50187
- }
50188
- return raw;
50189
- }
50190
- __name(parseSortOrder2, "parseSortOrder");
50191
-
50192
50407
  // src/commands/cases/list.ts
50193
50408
  var DEFAULT_LIMIT4 = 20;
50194
50409
  var MIN_LIMIT4 = 1;
@@ -50203,7 +50418,7 @@ var TABLE_COLUMNS22 = [
50203
50418
  function registerCasesList(cases) {
50204
50419
  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_LIMIT4}-${MAX_LIMIT4})`).option("--offset <n>", "number of cases to skip").option(
50205
50420
  "--status <statuses>",
50206
- `comma-separated status buckets (${CASE_FILTER_STATUS_BUCKETS.join(", ")})`
50421
+ `comma-separated display-status buckets (${CASE_FILTER_STATUS_BUCKETS.join(", ")}); filters on each Case's display_status, not its raw status`
50207
50422
  ).option(
50208
50423
  "--issue-severity <levels>",
50209
50424
  `comma-separated issue severities (${caseIssueSeverityFilterSchema.options.join(", ")}); narrows within the issues outcome`
@@ -50225,9 +50440,9 @@ function registerCasesList(cases) {
50225
50440
  ).option(
50226
50441
  "--updated-at-to <iso>",
50227
50442
  "include cases updated before this ISO-8601 timestamp"
50228
- ).option("--sort-by <field>", `sort field (${SORT_FIELDS2.join(", ")})`).option(
50443
+ ).option("--sort-by <field>", `sort field (${SORT_FIELDS.join(", ")})`).option(
50229
50444
  "--sort-order <order>",
50230
- `sort direction (${SORT_ORDERS2.join(", ")})`
50445
+ `sort direction (${SORT_ORDERS.join(", ")})`
50231
50446
  ).option("--count-only", "return only the matching Case total").option(
50232
50447
  "--field <filter>",
50233
50448
  `filter on a field of a typed queue's json_data, as ${CASE_FIELD_FILTER_SYNTAX} (e.g. '$.invoice.amount:gte:5000'); repeatable, and all entries must match`,
@@ -50240,11 +50455,11 @@ function registerCasesList(cases) {
50240
50455
  max: MAX_LIMIT4
50241
50456
  });
50242
50457
  const offset = parseOffset(options.offset);
50243
- const statuses = parseStatuses2(options.status);
50244
- const severities = parseSeverities2(options.issueSeverity);
50245
- const priorities = parsePriorities2(options.priority);
50246
- const sortBy = parseSortBy2(options.sortBy);
50247
- const sortOrder = parseSortOrder2(options.sortOrder);
50458
+ const statuses = parseStatuses(options.status);
50459
+ const severities = parseSeverities(options.issueSeverity);
50460
+ const priorities = parsePriorities(options.priority);
50461
+ const sortBy = parseSortBy(options.sortBy);
50462
+ const sortOrder = parseSortOrder(options.sortOrder);
50248
50463
  const fieldFilters = options.field ?? [];
50249
50464
  for (const filter of fieldFilters) {
50250
50465
  const parsed2 = parseCaseFieldFilter(filter);
@@ -50516,7 +50731,7 @@ function registerCasesSearch(cases) {
50516
50731
  "Search cases in a queue with richer filters than `cases list` (label filters and structured json_data field filters)"
50517
50732
  ).requiredOption("--queue <id>", "ID of the queue to search cases in").option("--limit <n>", `page size (${MIN_LIMIT6}-${MAX_LIMIT6})`).option("--offset <n>", "number of cases to skip").option(
50518
50733
  "--status <statuses>",
50519
- `comma-separated status buckets (${CASE_FILTER_STATUS_BUCKETS.join(", ")})`
50734
+ `comma-separated display-status buckets (${CASE_FILTER_STATUS_BUCKETS.join(", ")}); filters on each Case's display_status, not its raw status`
50520
50735
  ).option(
50521
50736
  "--issue-severity <levels>",
50522
50737
  `comma-separated issue severities (${caseIssueSeverityFilterSchema.options.join(", ")}); narrows within the issues outcome`
@@ -50535,9 +50750,9 @@ function registerCasesSearch(cases) {
50535
50750
  ).option(
50536
50751
  "--updated-at-to <iso>",
50537
50752
  "include cases updated before this ISO-8601 timestamp"
50538
- ).option("--sort-by <field>", `sort field (${SORT_FIELDS2.join(", ")})`).option(
50753
+ ).option("--sort-by <field>", `sort field (${SORT_FIELDS.join(", ")})`).option(
50539
50754
  "--sort-order <order>",
50540
- `sort direction (${SORT_ORDERS2.join(", ")})`
50755
+ `sort direction (${SORT_ORDERS.join(", ")})`
50541
50756
  ).option("--count-only", "return only the matching Case total").option(
50542
50757
  "--field <filter>",
50543
50758
  `filter on a field of a typed queue's json_data, as ${CASE_FIELD_FILTER_SYNTAX} (e.g. '$.invoice.amount:gte:5000'); repeatable, and all entries must match`,
@@ -50555,11 +50770,11 @@ function registerCasesSearch(cases) {
50555
50770
  max: MAX_LIMIT6
50556
50771
  });
50557
50772
  const offset = parseOffset(options.offset);
50558
- const statuses = parseStatuses2(options.status);
50559
- const severities = parseSeverities2(options.issueSeverity);
50560
- const priorities = parsePriorities2(options.priority);
50561
- const sortBy = parseSortBy2(options.sortBy);
50562
- const sortOrder = parseSortOrder2(options.sortOrder);
50773
+ const statuses = parseStatuses(options.status);
50774
+ const severities = parseSeverities(options.issueSeverity);
50775
+ const priorities = parsePriorities(options.priority);
50776
+ const sortBy = parseSortBy(options.sortBy);
50777
+ const sortOrder = parseSortOrder(options.sortOrder);
50563
50778
  const jsonData = parseJsonDataFilters(options.field ?? []);
50564
50779
  const labels = parseLabelFilters(options.label ?? []);
50565
50780
  const { apiKey, apiBaseUrl } = await requireAuthenticatedConfig(this);
@@ -70186,6 +70401,10 @@ var deleteSkillRevisionResponseSchema = z178.object({
70186
70401
  success: z178.boolean(),
70187
70402
  message: z178.string()
70188
70403
  });
70404
+ var deleteSkillRevisionFileResponseSchema = z178.object({
70405
+ success: z178.boolean(),
70406
+ message: z178.string()
70407
+ });
70189
70408
  var skillRevisionFileSchema = z178.object({
70190
70409
  name: z178.string(),
70191
70410
  path: z178.string(),
@@ -70284,6 +70503,42 @@ function registerSkillsRevisionsDelete(revisions) {
70284
70503
  }
70285
70504
  __name(registerSkillsRevisionsDelete, "registerSkillsRevisionsDelete");
70286
70505
 
70506
+ // src/commands/skills/revisions/file-delete.ts
70507
+ function registerSkillsRevisionsFileDelete(revisions) {
70508
+ revisions.command("file-delete <revision-id> <path>").description(
70509
+ "Delete a file from a skill revision (path is the relative file path inside the revision). Deleting from a draft leaves the active version untouched until you promote it. SKILL.md can't be deleted."
70510
+ ).option("-y, --yes", "skip the confirmation prompt").option("--json", "output raw JSON from the API").action(/* @__PURE__ */ __name(async function fileDeleteAction(revisionId, filePath, options) {
70511
+ const id = trimRequired(revisionId, "<revision-id>");
70512
+ const path = trimRequired(filePath, "<path>");
70513
+ const { apiKey, apiBaseUrl } = await requireAuthenticatedConfig(this);
70514
+ await confirmDestructive({
70515
+ message: `Delete "${path}" from revision "${id}"?`,
70516
+ skip: options.yes ?? false
70517
+ });
70518
+ const raw = await httpRequest({
70519
+ method: "DELETE",
70520
+ path: `/v2/skill-revisions/${encodeURIComponent(id)}/files/${encodeFilePath(path)}`,
70521
+ apiKey,
70522
+ apiBaseUrl
70523
+ });
70524
+ if (options.json) {
70525
+ printJson(raw);
70526
+ return;
70527
+ }
70528
+ const parsed = deleteSkillRevisionFileResponseSchema.safeParse(raw);
70529
+ if (!parsed.success) {
70530
+ throw new CliError(
70531
+ `Unexpected response from the API: ${parsed.error.message}`
70532
+ );
70533
+ }
70534
+ if (!parsed.data.success) {
70535
+ throw new CliError(`Failed to delete file: ${parsed.data.message}`);
70536
+ }
70537
+ console.log(green(`File "${path}" deleted.`));
70538
+ }, "fileDeleteAction"));
70539
+ }
70540
+ __name(registerSkillsRevisionsFileDelete, "registerSkillsRevisionsFileDelete");
70541
+
70287
70542
  // src/commands/skills/revisions/file-get.ts
70288
70543
  function registerSkillsRevisionsFileGet(revisions) {
70289
70544
  revisions.command("file-get <revision-id> <path>").description(
@@ -70625,6 +70880,7 @@ function registerSkillsRevisions(skills) {
70625
70880
  registerSkillsRevisionsFiles(revisions);
70626
70881
  registerSkillsRevisionsFileGet(revisions);
70627
70882
  registerSkillsRevisionsFileUpdate(revisions);
70883
+ registerSkillsRevisionsFileDelete(revisions);
70628
70884
  registerSkillsRevisionsPromote(revisions);
70629
70885
  registerSkillsRevisionsUpdate(revisions);
70630
70886
  registerSkillsRevisionsDelete(revisions);
@@ -72362,7 +72618,7 @@ __name(isStandaloneBinary, "isStandaloneBinary");
72362
72618
  import { createRequire } from "node:module";
72363
72619
  function getPackageMeta() {
72364
72620
  if (true) {
72365
- return { name: "@duvoai/cli", version: "1.81.0" };
72621
+ return { name: "@duvoai/cli", version: "1.82.0" };
72366
72622
  }
72367
72623
  const require2 = createRequire(import.meta.url);
72368
72624
  const raw = require2("../../package.json");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duvoai/cli",
3
- "version": "1.81.0",
3
+ "version": "1.82.0",
4
4
  "description": "Command-line interface for the Duvo public API",
5
5
  "bin": {
6
6
  "duvo": "./dist/bin/duvo.js"