@doist/automations-cli 1.20.2 → 1.21.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/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  collectSkillStatus,
8
8
  getInstaller,
9
9
  updateAllInstalledSkills
10
- } from "./chunk-GUWS3EHG.js";
10
+ } from "./chunk-ZWFZ2DD3.js";
11
11
 
12
12
  // ../../node_modules/ajv/dist/compile/codegen/code.js
13
13
  var require_code = __commonJS({
@@ -6899,7 +6899,7 @@ import { fileURLToPath } from "node:url";
6899
6899
  // package.json
6900
6900
  var package_default = {
6901
6901
  name: "@doist/automations-cli",
6902
- version: "1.20.2",
6902
+ version: "1.21.0",
6903
6903
  description: "Command-line client for Todoist Automations",
6904
6904
  type: "module",
6905
6905
  bin: {
@@ -6945,7 +6945,7 @@ var package_default = {
6945
6945
  dependencies: {
6946
6946
  "@doist/cli-core": "1.7.0",
6947
6947
  "@napi-rs/keyring": "2.1.0",
6948
- ai: "7.0.86",
6948
+ ai: "7.0.137",
6949
6949
  commander: "15.0.0",
6950
6950
  oauth4webapi: "3.8.8",
6951
6951
  open: "11.0.4"
@@ -6953,7 +6953,7 @@ var package_default = {
6953
6953
  devDependencies: {
6954
6954
  "@doist/automations-core": "*",
6955
6955
  "@doist/automations-sdk": "*",
6956
- "@types/node": "24.19.1",
6956
+ "@types/node": "24.19.2",
6957
6957
  "conventional-changelog-conventionalcommits": "9.3.1",
6958
6958
  esbuild: "0.28.2",
6959
6959
  "semantic-release": "25.0.9",
@@ -28149,6 +28149,7 @@ var cronScheduleSchema = (() => {
28149
28149
  });
28150
28150
  })();
28151
28151
  var scheduleValueSchema = external_exports.union([intervalScheduleSchema, cronScheduleSchema]).meta({ description: "The schedule definition for the trigger." });
28152
+ var TRIGGER_TYPES = ["schedule", "webhook", "api"];
28152
28153
  var scheduleTriggerSchema = external_exports.object({
28153
28154
  type: external_exports.literal("schedule"),
28154
28155
  value: scheduleValueSchema,
@@ -28986,7 +28987,7 @@ var ImportLocalOAuthConnectionBodySchema = external_exports.object({
28986
28987
  * matched to it.
28987
28988
  */
28988
28989
  repairConnectionId: external_exports.uuid().optional()
28989
- });
28990
+ }).meta({ id: "ImportLocalOAuthConnection" });
28990
28991
  var LocalOAuthSetupSchema = external_exports.object({
28991
28992
  /** RFC 7591 registration endpoint; null when the server offers none. */
28992
28993
  registrationEndpoint: external_exports.string().url().nullable(),
@@ -29138,20 +29139,20 @@ var updateAutomationSchema = external_exports.object({
29138
29139
  manifest: manifestSchema.optional()
29139
29140
  }).refine((data) => Object.keys(data).length > 0, {
29140
29141
  message: "At least one field must be provided"
29141
- });
29142
+ }).meta({ id: "UpdateAutomation" });
29142
29143
  var updateAutomationMetadataSchema = external_exports.object({
29143
29144
  name: external_exports.string().min(1),
29144
29145
  description: external_exports.string()
29145
- });
29146
+ }).meta({ id: "UpdateAutomationMetadata" });
29146
29147
  var updateAutomationScheduleSchema = external_exports.object({
29147
29148
  value: scheduleValueSchema
29148
- });
29149
+ }).meta({ id: "UpdateAutomationSchedule" });
29149
29150
  var updateAutomationVisibilitySchema = external_exports.object({
29150
29151
  visibility: external_exports.enum(AUTOMATION_VISIBILITIES)
29151
- });
29152
+ }).meta({ id: "UpdateAutomationVisibility" });
29152
29153
  var moveAutomationSchema = external_exports.object({
29153
29154
  visibility: external_exports.enum(AUTOMATION_VISIBILITIES).default("workspace")
29154
- });
29155
+ }).meta({ id: "MoveAutomation" });
29155
29156
 
29156
29157
  // ../../packages/core/dist/esm/schemas/automation-connection.schema.js
29157
29158
  var AutomationConnectionMappingSchema = external_exports.object({
@@ -29168,7 +29169,7 @@ var UpsertAutomationConnectionSchema = external_exports.object({
29168
29169
  * the service infers the role from `connection.capabilities[0]`.
29169
29170
  */
29170
29171
  connectionType: external_exports.enum(CONNECTION_TYPES).optional()
29171
- }).strict();
29172
+ }).strict().meta({ id: "UpsertAutomationConnection" });
29172
29173
  var SetAutomationConnectionsSchema = external_exports.object({
29173
29174
  mappings: external_exports.array(AutomationConnectionMappingSchema).nonempty("mappings cannot be empty")
29174
29175
  }).strict();
@@ -29326,8 +29327,29 @@ var automationDraftListResponseSchema = external_exports.object({
29326
29327
  var finalizeAutomationDraftResponseSchema = external_exports.object({
29327
29328
  automation: automationSchema
29328
29329
  });
29330
+ var draftTestTriggerSelectorSchema = external_exports.union([
29331
+ external_exports.object({ index: external_exports.int().min(0) }),
29332
+ external_exports.object({ event: external_exports.string().min(1) })
29333
+ ]);
29334
+ var testAutomationDraftRequestSchema = external_exports.object({
29335
+ trigger: draftTestTriggerSelectorSchema.optional(),
29336
+ payload: external_exports.unknown().optional(),
29337
+ metadata: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
29338
+ }).meta({ id: "TestAutomationDraftRequest" });
29339
+ var draftTestTriggerSchema = external_exports.object({
29340
+ index: external_exports.int().min(0),
29341
+ count: external_exports.int().min(1),
29342
+ type: external_exports.enum(TRIGGER_TYPES),
29343
+ event: external_exports.string().optional(),
29344
+ inputSource: external_exports.enum(["schedule", "sample-event", "supplied", "empty"])
29345
+ });
29329
29346
  var testAutomationDraftResponseSchema = external_exports.object({
29330
- success: external_exports.literal(true)
29347
+ success: external_exports.literal(true),
29348
+ draftId: external_exports.string(),
29349
+ testRunId: external_exports.string(),
29350
+ status: external_exports.enum(AUTOMATION_RUN_STATUSES),
29351
+ connectorCalls: external_exports.literal("mocked"),
29352
+ trigger: draftTestTriggerSchema
29331
29353
  });
29332
29354
  var AUTOMATION_OPEN_DRAFT_CONFLICT_CODE = "automation_open_draft_conflict";
29333
29355
  var AutomationOpenDraftConflictSchema = external_exports.object({
@@ -29340,13 +29362,25 @@ var AutomationDraftNotReadySchema = external_exports.object({
29340
29362
  code: external_exports.literal(AUTOMATION_DRAFT_NOT_READY_CODE),
29341
29363
  message: external_exports.string()
29342
29364
  });
29365
+ var DRAFT_TEST_REQUEST_ERROR_CODES = [
29366
+ "draft_test_not_ready",
29367
+ "draft_test_trigger_not_found",
29368
+ "draft_test_payload_required",
29369
+ "draft_test_payload_filtered",
29370
+ "draft_test_payload_invalid",
29371
+ "draft_test_payload_unsupported"
29372
+ ];
29373
+ var DraftTestRequestErrorSchema = external_exports.object({
29374
+ code: external_exports.enum(DRAFT_TEST_REQUEST_ERROR_CODES),
29375
+ message: external_exports.string()
29376
+ });
29343
29377
 
29344
29378
  // ../../packages/core/dist/esm/schemas/automation-draft-connection.schema.js
29345
29379
  var CreateAutomationDraftConnectionSchema = external_exports.object({
29346
29380
  connectorId: external_exports.string().trim().min(1, "connectorId is required"),
29347
29381
  connectionType: external_exports.enum(CONNECTION_TYPES),
29348
29382
  connectionId: uuidv7Schema.min(1, "connectionId is required")
29349
- }).strict();
29383
+ }).strict().meta({ id: "CreateAutomationDraftConnection" });
29350
29384
  var AutomationDraftConnectionSchema = external_exports.object({
29351
29385
  draftId: external_exports.string(),
29352
29386
  connectorId: external_exports.string(),
@@ -29515,13 +29549,13 @@ var getChatConversationsQuerySchema = external_exports.object({
29515
29549
  });
29516
29550
  var createChatConversationSchema = external_exports.object({
29517
29551
  title: external_exports.string().nullable().optional()
29518
- });
29552
+ }).meta({ id: "CreateChatConversation" });
29519
29553
  var updateChatConversationSchema = external_exports.object({
29520
29554
  title: external_exports.string().nullable().optional(),
29521
29555
  isArchived: external_exports.boolean().optional()
29522
29556
  }).refine((value) => value.title !== void 0 || value.isArchived !== void 0, {
29523
29557
  message: "At least one field must be provided"
29524
- });
29558
+ }).meta({ id: "UpdateChatConversation" });
29525
29559
 
29526
29560
  // ../../packages/core/dist/esm/schemas/automation-preview-artifact.schema.js
29527
29561
  var automationPreviewSources = ["synthetic", "run"];
@@ -29651,10 +29685,23 @@ var automationTestRunStepStatusSchema = external_exports.object({
29651
29685
  stepId: external_exports.string().min(1),
29652
29686
  status: external_exports.enum(AUTOMATION_RUN_STATUSES)
29653
29687
  });
29688
+ var automationTestRunFailedStepSchema = external_exports.object({
29689
+ stepId: external_exports.string().min(1),
29690
+ description: external_exports.string().optional(),
29691
+ error: external_exports.string().optional()
29692
+ });
29654
29693
  var automationTestRunProgressSchema = external_exports.object({
29655
29694
  draftId: external_exports.string().min(1),
29656
29695
  status: external_exports.enum(AUTOMATION_RUN_STATUSES),
29657
- steps: external_exports.array(automationTestRunStepStatusSchema).default([])
29696
+ steps: external_exports.array(automationTestRunStepStatusSchema).default([]),
29697
+ // Optional so results stored before these fields existed still parse.
29698
+ runId: external_exports.string().min(1).optional(),
29699
+ failedStep: automationTestRunFailedStepSchema.optional(),
29700
+ /** Why a failed or skipped run stopped. */
29701
+ error: external_exports.string().optional(),
29702
+ result: AutomationRunResultSchema.nullable().optional(),
29703
+ /** A test run simulates every connector call, reads included. */
29704
+ connectorCalls: external_exports.literal("mocked").optional()
29658
29705
  });
29659
29706
  var automationTestRunPreviewTriggerSchema = external_exports.union([
29660
29707
  external_exports.object({
@@ -29947,6 +29994,47 @@ var cohortMatrixResponseSchema = external_exports.object({
29947
29994
  rows: external_exports.array(cohortMatrixRowSchema)
29948
29995
  });
29949
29996
 
29997
+ // ../../packages/core/dist/esm/schemas/draft-test-run.schema.js
29998
+ var DraftTestRunFailedStepSchema = external_exports.object({
29999
+ stepId: external_exports.string(),
30000
+ description: external_exports.string(),
30001
+ error: external_exports.string().nullable()
30002
+ });
30003
+ var draftTestRunDetailDtoBaseShape = {
30004
+ id: external_exports.string(),
30005
+ draftId: external_exports.string(),
30006
+ // The automation an edit draft belongs to; null for a draft of a new automation.
30007
+ automationId: external_exports.string().nullable(),
30008
+ mode: external_exports.literal("test"),
30009
+ // A test run simulates every connector call, reads included, with a model.
30010
+ connectorCalls: external_exports.literal("mocked"),
30011
+ createdAt: external_exports.string(),
30012
+ updatedAt: external_exports.string(),
30013
+ result: AutomationRunResultSchema.nullable(),
30014
+ temporalUrl: external_exports.string().nullish(),
30015
+ steps: external_exports.array(AutomationRunStepDtoSchema),
30016
+ failedStep: DraftTestRunFailedStepSchema.nullable()
30017
+ };
30018
+ var DraftTestRunDetailDtoSchema = external_exports.discriminatedUnion("status", [
30019
+ external_exports.object({ ...draftTestRunDetailDtoBaseShape, status: external_exports.literal("pending") }),
30020
+ external_exports.object({ ...draftTestRunDetailDtoBaseShape, status: external_exports.literal("running") }),
30021
+ external_exports.object({ ...draftTestRunDetailDtoBaseShape, status: external_exports.literal("completed") }),
30022
+ external_exports.object({ ...draftTestRunDetailDtoBaseShape, status: external_exports.literal("cancelled") }),
30023
+ external_exports.object({ ...draftTestRunDetailDtoBaseShape, status: external_exports.literal("data-expired") }),
30024
+ external_exports.object({
30025
+ ...draftTestRunDetailDtoBaseShape,
30026
+ status: external_exports.literal("failed"),
30027
+ failureReason: external_exports.string().nullish(),
30028
+ failureCategory: external_exports.enum(FAILURE_CATEGORIES).nullish().catch(null)
30029
+ }),
30030
+ external_exports.object({
30031
+ ...draftTestRunDetailDtoBaseShape,
30032
+ status: external_exports.literal("skipped"),
30033
+ skipReason: external_exports.string().nullish(),
30034
+ skipCategory: external_exports.enum(SKIP_CATEGORIES).nullish()
30035
+ })
30036
+ ]);
30037
+
29950
30038
  // ../../packages/core/dist/esm/types/workspace.types.js
29951
30039
  var WORKSPACE_PLANS = ["STARTER", "BUSINESS"];
29952
30040
  var WORKSPACE_ROLES = ["ADMIN", "MEMBER", "GUEST"];
@@ -30139,7 +30227,7 @@ var NotificationResponseSchema = external_exports.object({
30139
30227
  const isStatusResponse = data.status !== void 0 && data.action === void 0;
30140
30228
  const isAnswer = data.action === "answer" && data.value !== void 0 && data.status === void 0;
30141
30229
  return isStatusResponse || isAnswer;
30142
- }, { message: 'Provide either { status } or { action: "answer", value }' });
30230
+ }, { message: 'Provide either { status } or { action: "answer", value }' }).meta({ id: "NotificationResponse" });
30143
30231
  var NOTIFICATION_STATUSES = [
30144
30232
  ...INFO_NOTIFICATION_STATUSES,
30145
30233
  ...PROMPT_NOTIFICATION_STATUSES
@@ -30322,10 +30410,10 @@ var RegisterPushSubscriptionSchema = external_exports.object({
30322
30410
  endpoint: external_exports.url().max(768),
30323
30411
  keys: PushSubscriptionKeysSchema,
30324
30412
  deviceName: external_exports.string().max(255).optional()
30325
- });
30413
+ }).meta({ id: "RegisterPushSubscription" });
30326
30414
  var UpdatePushSubscriptionSchema = external_exports.object({
30327
30415
  deviceName: external_exports.string().max(255).nullable().optional()
30328
- });
30416
+ }).meta({ id: "UpdatePushSubscription" });
30329
30417
  var RemovePushSubscriptionByEndpointQuerySchema = external_exports.object({
30330
30418
  endpoint: external_exports.url().max(768)
30331
30419
  });
@@ -30359,7 +30447,7 @@ var createSubscriptionSchema = external_exports.object({
30359
30447
  triggerEventId: external_exports.string().min(1, "Trigger event ID is required"),
30360
30448
  outputSchema: external_exports.record(external_exports.string(), external_exports.unknown()),
30361
30449
  inputSchema: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
30362
- });
30450
+ }).meta({ id: "CreateSubscription" });
30363
30451
  var subscriptionResponseSchema = external_exports.object({
30364
30452
  id: external_exports.string(),
30365
30453
  agentId: external_exports.string(),
@@ -30395,7 +30483,7 @@ var UserOnboardingStateSchema = external_exports.object({
30395
30483
  });
30396
30484
  var AcceptTermsSchema = external_exports.object({
30397
30485
  version: external_exports.string().trim().min(1).max(64)
30398
- });
30486
+ }).meta({ id: "AcceptTerms" });
30399
30487
  var ConnectorIdSchema = external_exports.string().trim().min(1);
30400
30488
  var InterestedConnectorIdsSchema = external_exports.array(ConnectorIdSchema).max(100);
30401
30489
  var ConnectorPreferencesSchema = external_exports.object({
@@ -30442,7 +30530,7 @@ var UserPreferencesSchema = external_exports.object({
30442
30530
  });
30443
30531
  var CompleteOnboardingSchema = external_exports.object({
30444
30532
  connectors: ConnectorPreferencesUpdateSchema.optional()
30445
- }).default({});
30533
+ }).default({}).meta({ id: "CompleteOnboarding" });
30446
30534
  var UpdateUserPreferencesSchema = external_exports.object({
30447
30535
  connectors: ConnectorPreferencesUpdateSchema.optional(),
30448
30536
  notifications: NotificationPreferencesUpdateSchema.optional(),
@@ -30461,7 +30549,7 @@ var UpdateUserPreferencesSchema = external_exports.object({
30461
30549
  value.notifications?.usageBalance
30462
30550
  ];
30463
30551
  return channelGroups.some((group) => group && ("email" in group && group.email !== void 0 || group.push !== void 0));
30464
- }, { message: "At least one preference field must be provided" });
30552
+ }, { message: "At least one preference field must be provided" }).meta({ id: "UpdateUserPreferences" });
30465
30553
 
30466
30554
  // ../../packages/core/dist/esm/schemas/webhook-events/automation-created.event.js
30467
30555
  var AutomationCreatedDataSchema = external_exports.object({
@@ -30637,14 +30725,14 @@ var CreateWebhookEventSubscriptionRequestSchema = external_exports.object({
30637
30725
  eventTypes: external_exports.array(external_exports.enum(WEBHOOK_EVENT_TYPES)).min(1),
30638
30726
  subjectAutomationId: external_exports.string().optional(),
30639
30727
  description: external_exports.string().max(WEBHOOK_EVENT_SUBSCRIPTION_DESCRIPTION_MAX_LENGTH).optional()
30640
- }).superRefine(rejectAccountScopedWithSubject);
30728
+ }).superRefine(rejectAccountScopedWithSubject).meta({ id: "CreateWebhookEventSubscriptionRequest" });
30641
30729
  var UpdateWebhookEventSubscriptionRequestSchema = external_exports.object({
30642
30730
  url: WebhookEndpointUrlSchema,
30643
30731
  eventTypes: external_exports.array(external_exports.enum(WEBHOOK_EVENT_TYPES)).min(1),
30644
30732
  status: external_exports.enum(WEBHOOK_EVENT_SUBSCRIPTION_STATUSES),
30645
30733
  description: external_exports.string().max(WEBHOOK_EVENT_SUBSCRIPTION_DESCRIPTION_MAX_LENGTH).nullable(),
30646
30734
  subjectAutomationId: external_exports.string().nullable()
30647
- }).partial().superRefine(rejectAccountScopedWithSubject);
30735
+ }).partial().superRefine(rejectAccountScopedWithSubject).meta({ id: "UpdateWebhookEventSubscriptionRequest" });
30648
30736
  var WebhookEventDeliveryDtoSchema = external_exports.object({
30649
30737
  id: external_exports.string(),
30650
30738
  eventType: external_exports.enum(WEBHOOK_EVENT_TYPES),
@@ -31117,7 +31205,8 @@ var automationDraftsEndpoints = {
31117
31205
  list: root3,
31118
31206
  detail: (id) => `${root3}/${encodeURIComponent(id)}`,
31119
31207
  finalize: (id) => `${root3}/${encodeURIComponent(id)}/finalize`,
31120
- test: (id) => `${root3}/${encodeURIComponent(id)}/test`
31208
+ test: (id) => `${root3}/${encodeURIComponent(id)}/test`,
31209
+ testRun: (id, runId) => `${root3}/${encodeURIComponent(id)}/test-runs/${encodeURIComponent(runId)}`
31121
31210
  };
31122
31211
 
31123
31212
  // ../../packages/sdk/dist/esm/clients/automation-drafts/automation-drafts-client.js
@@ -31131,6 +31220,16 @@ function getDraftNotReadyError(error62) {
31131
31220
  const parsed = AutomationDraftNotReadySchema.safeParse(error62.responseData);
31132
31221
  return parsed.success ? parsed.data : null;
31133
31222
  }
31223
+ function getDraftTestRequestError(error62) {
31224
+ if (!(error62 instanceof AutomationsRequestError) || error62.httpStatusCode !== 400) {
31225
+ return null;
31226
+ }
31227
+ const parsed = DraftTestRequestErrorSchema.safeParse(error62.responseData);
31228
+ return parsed.success ? parsed.data : null;
31229
+ }
31230
+ function isRequestOptions(value) {
31231
+ return Boolean(value && ("signal" in value || "headers" in value));
31232
+ }
31134
31233
  var AutomationDraftsClient = class extends BaseClient {
31135
31234
  async list(args = {}, options) {
31136
31235
  const { cursor, limit } = CursorPaginationSchema.parse(args);
@@ -31191,16 +31290,35 @@ var AutomationDraftsClient = class extends BaseClient {
31191
31290
  });
31192
31291
  return finalizeAutomationDraftResponseSchema.parse(data);
31193
31292
  }
31194
- async test(draftId, options) {
31293
+ /** Starts a test run; `request` picks the trigger and supplies the event to test with. */
31294
+ async test(draftId, requestOrOptions, options) {
31195
31295
  const id = IdSchema.parse(draftId);
31296
+ const request2 = isRequestOptions(requestOrOptions) ? void 0 : requestOrOptions;
31196
31297
  const data = await this.request({
31197
31298
  method: "POST",
31198
31299
  path: automationDraftsEndpoints.test(id),
31199
- options
31300
+ body: request2 ? testAutomationDraftRequestSchema.parse(request2) : void 0,
31301
+ options: isRequestOptions(requestOrOptions) ? requestOrOptions : options
31200
31302
  });
31201
31303
  return testAutomationDraftResponseSchema.parse(data);
31202
31304
  }
31305
+ /** A test run of this draft, with its steps; `args` match the run detail's. */
31306
+ async getTestRun(draftId, runId, args = {}, options) {
31307
+ const data = await this.request({
31308
+ method: "GET",
31309
+ path: automationDraftsEndpoints.testRun(IdSchema.parse(draftId), IdSchema.parse(runId)),
31310
+ query: toTestRunQuery(args),
31311
+ options
31312
+ });
31313
+ return DraftTestRunDetailDtoSchema.parse(data);
31314
+ }
31203
31315
  };
31316
+ function toTestRunQuery(args) {
31317
+ return {
31318
+ includeGeneratedCode: args.includeGeneratedCode ? true : void 0,
31319
+ includeToolCallPreviews: args.includeToolCallPreviews
31320
+ };
31321
+ }
31204
31322
 
31205
31323
  // ../../packages/sdk/dist/esm/clients/automation-runs/endpoints.js
31206
31324
  var automationRunsEndpoints = {
@@ -31209,7 +31327,7 @@ var automationRunsEndpoints = {
31209
31327
  };
31210
31328
 
31211
31329
  // ../../packages/sdk/dist/esm/clients/automation-runs/automation-runs-client.js
31212
- function isRequestOptions(value) {
31330
+ function isRequestOptions2(value) {
31213
31331
  return Boolean(value && ("signal" in value || "headers" in value));
31214
31332
  }
31215
31333
  var AutomationRunsClient = class extends BaseClient {
@@ -31228,8 +31346,8 @@ var AutomationRunsClient = class extends BaseClient {
31228
31346
  async get(automationId, runId, argsOrOptions, options) {
31229
31347
  const aId = IdSchema.parse(automationId);
31230
31348
  const rId = IdSchema.parse(runId);
31231
- const args = isRequestOptions(argsOrOptions) ? void 0 : argsOrOptions;
31232
- const requestOptions = isRequestOptions(argsOrOptions) ? argsOrOptions : options;
31349
+ const args = isRequestOptions2(argsOrOptions) ? void 0 : argsOrOptions;
31350
+ const requestOptions = isRequestOptions2(argsOrOptions) ? argsOrOptions : options;
31233
31351
  const data = await this.request({
31234
31352
  method: "GET",
31235
31353
  path: automationRunsEndpoints.detail(aId, rId),
@@ -31488,7 +31606,9 @@ var WorkspaceAutomationDraftConnectionsClient = class extends BaseClient {
31488
31606
  var workspaceAutomationDraftsEndpoints = {
31489
31607
  list: (workspaceId) => `${root7(workspaceId)}`,
31490
31608
  detail: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}`,
31491
- finalize: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/finalize`
31609
+ finalize: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/finalize`,
31610
+ test: (workspaceId, id) => `${root7(workspaceId)}/${encodeURIComponent(id)}/test`,
31611
+ testRun: (workspaceId, id, runId) => `${root7(workspaceId)}/${encodeURIComponent(id)}/test-runs/${encodeURIComponent(runId)}`
31492
31612
  };
31493
31613
  function root7(workspaceId) {
31494
31614
  return `/workspaces/${encodeURIComponent(workspaceId)}/automation-drafts`;
@@ -31554,6 +31674,24 @@ var WorkspaceAutomationDraftsClient = class extends BaseClient {
31554
31674
  });
31555
31675
  return finalizeAutomationDraftResponseSchema.parse(data);
31556
31676
  }
31677
+ async test(workspaceId, draftId, request2 = {}, options) {
31678
+ const data = await this.request({
31679
+ method: "POST",
31680
+ path: workspaceAutomationDraftsEndpoints.test(IdSchema.parse(workspaceId), IdSchema.parse(draftId)),
31681
+ body: testAutomationDraftRequestSchema.parse(request2),
31682
+ options
31683
+ });
31684
+ return testAutomationDraftResponseSchema.parse(data);
31685
+ }
31686
+ async getTestRun(workspaceId, draftId, runId, args = {}, options) {
31687
+ const data = await this.request({
31688
+ method: "GET",
31689
+ path: workspaceAutomationDraftsEndpoints.testRun(IdSchema.parse(workspaceId), IdSchema.parse(draftId), IdSchema.parse(runId)),
31690
+ query: toTestRunQuery(args),
31691
+ options
31692
+ });
31693
+ return DraftTestRunDetailDtoSchema.parse(data);
31694
+ }
31557
31695
  };
31558
31696
 
31559
31697
  // ../../packages/sdk/dist/esm/clients/workspace-chat/endpoints.js
@@ -32497,25 +32635,47 @@ function summarizeRun(run) {
32497
32635
  result: run.result,
32498
32636
  temporalUrl: run.temporalUrl,
32499
32637
  triggeredBy: run.triggeredBy,
32500
- steps: run.steps.map((step) => ({
32501
- stepId: step.stepId,
32502
- type: step.type,
32503
- description: step.description,
32504
- status: step.status,
32505
- startedAt: step.startedAt,
32506
- completedAt: step.completedAt,
32507
- error: step.error,
32508
- toolCalls: step.toolCalls?.map((toolCall) => ({
32509
- id: toolCall.id,
32510
- name: toolCall.name,
32511
- argumentKeys: toolCall.argumentKeys,
32512
- hasResult: toolCall.hasResult,
32513
- hasError: toolCall.hasError,
32514
- resultPreview: toolCall.resultPreview,
32515
- errorPreview: toolCall.errorPreview,
32516
- timestamp: toolCall.timestamp
32517
- }))
32638
+ steps: summarizeRunSteps(run.steps)
32639
+ };
32640
+ }
32641
+ function summarizeRunSteps(steps) {
32642
+ return steps.map((step) => ({
32643
+ stepId: step.stepId,
32644
+ type: step.type,
32645
+ description: step.description,
32646
+ status: step.status,
32647
+ startedAt: step.startedAt,
32648
+ completedAt: step.completedAt,
32649
+ error: step.error,
32650
+ toolCalls: step.toolCalls?.map((toolCall) => ({
32651
+ id: toolCall.id,
32652
+ name: toolCall.name,
32653
+ argumentKeys: toolCall.argumentKeys,
32654
+ hasResult: toolCall.hasResult,
32655
+ hasError: toolCall.hasError,
32656
+ resultPreview: toolCall.resultPreview,
32657
+ errorPreview: toolCall.errorPreview,
32658
+ timestamp: toolCall.timestamp
32518
32659
  }))
32660
+ }));
32661
+ }
32662
+
32663
+ // ../../packages/sdk/dist/esm/summaries/draft-test-run-summary.js
32664
+ function summarizeDraftTestRun(run) {
32665
+ return {
32666
+ id: run.id,
32667
+ draftId: run.draftId,
32668
+ automationId: run.automationId,
32669
+ status: run.status,
32670
+ connectorCalls: run.connectorCalls,
32671
+ createdAt: run.createdAt,
32672
+ updatedAt: run.updatedAt,
32673
+ failureCategory: getRunOutcomeCategory(run),
32674
+ failureReason: getRunOutcomeReason(run),
32675
+ failedStep: run.failedStep,
32676
+ result: run.result,
32677
+ temporalUrl: run.temporalUrl,
32678
+ steps: summarizeRunSteps(run.steps)
32519
32679
  };
32520
32680
  }
32521
32681
 
@@ -34168,7 +34328,9 @@ async function runApiCommand(command, operation, presentation, execution = {}) {
34168
34328
  try {
34169
34329
  const globalOptions = getGlobalOptions(command);
34170
34330
  mode = getOutputMode(globalOptions);
34171
- const apiConfiguration = await resolveApiConfiguration(globalOptions);
34331
+ const apiConfiguration = await resolveApiConfiguration(globalOptions, {
34332
+ minimumTokenLifetimeMs: execution.minimumTokenLifetimeMs
34333
+ });
34172
34334
  source = apiConfiguration.source;
34173
34335
  const context = {
34174
34336
  api: createAutomationsApi(apiConfiguration),
@@ -34184,6 +34346,8 @@ async function runApiCommand(command, operation, presentation, execution = {}) {
34184
34346
  );
34185
34347
  stopEarlySpinner();
34186
34348
  writeResult(mode, result, presentation);
34349
+ const exitCode = execution.exitCode?.(result);
34350
+ if (exitCode !== void 0) process.exitCode = exitCode;
34187
34351
  } catch (error62) {
34188
34352
  if (abortController.signal.aborted) {
34189
34353
  writeFailure(mode, "interrupted", {
@@ -34351,16 +34515,21 @@ function formatRun(run) {
34351
34515
  `Failure reason: ${getRunOutcomeReason(run) ?? "none"}`,
34352
34516
  `Result: ${run.result?.text ?? "none"}`,
34353
34517
  `Steps: ${run.steps.length}`,
34354
- ...isInsufficientCredit(run) ? ["", topUpAdvisory()] : []
34518
+ ...isInsufficientCredit(run) ? ["", topUpAdvisory()] : [],
34519
+ ...formatRunSteps(run.steps)
34355
34520
  ];
34356
- for (const [index, step] of run.steps.entries()) {
34521
+ return lines.join("\n");
34522
+ }
34523
+ function formatRunSteps(steps, { toolCallLabel = "Tool" } = {}) {
34524
+ const lines = [];
34525
+ for (const [index, step] of steps.entries()) {
34357
34526
  lines.push("", `${index + 1}. ${step.stepId} [${step.status}] ${step.description}`);
34358
34527
  lines.push(` Type: ${step.type}`);
34359
34528
  if (step.startedAt) lines.push(` Started: ${step.startedAt}`);
34360
34529
  if (step.completedAt) lines.push(` Completed: ${step.completedAt}`);
34361
34530
  if (step.error) lines.push(` Error: ${step.error}`);
34362
34531
  for (const toolCall of step.toolCalls ?? []) {
34363
- lines.push(` Tool: ${toolCall.name} (${toolCall.id})`);
34532
+ lines.push(` ${toolCallLabel}: ${toolCall.name} (${toolCall.id})`);
34364
34533
  if (toolCall.argumentKeys.length > 0) {
34365
34534
  lines.push(` Args: ${toolCall.argumentKeys.join(", ")}`);
34366
34535
  }
@@ -34370,7 +34539,7 @@ function formatRun(run) {
34370
34539
  if (toolCall.resultPreview) lines.push(` Result preview: ${toolCall.resultPreview}`);
34371
34540
  }
34372
34541
  }
34373
- return lines.join("\n");
34542
+ return lines;
34374
34543
  }
34375
34544
  function getResourceName(manifest) {
34376
34545
  if (!isRecord2(manifest)) return "(unnamed)";
@@ -36842,6 +37011,8 @@ async function readSource(options, input2) {
36842
37011
 
36843
37012
  // src/commands/draft/draft-service.ts
36844
37013
  import { CliError as CliError4, getErrorMessage as getErrorMessage7 } from "@doist/cli-core";
37014
+ import { readFile as readFile3 } from "node:fs/promises";
37015
+ import { setTimeout as wait2 } from "node:timers/promises";
36845
37016
 
36846
37017
  // src/lib/manifest-diff.ts
36847
37018
  function stableStringify(value) {
@@ -36904,7 +37075,11 @@ function resolveDraftApi(api, workspaceId, signal) {
36904
37075
  upsertConnection: (draftId, body) => api.automationDraftConnections.upsert(draftId, body, { signal }),
36905
37076
  getConnectionStatus: async (draftId) => (await api.automationDraftConnections.getStatus(draftId, { signal })).validation,
36906
37077
  finalize: (draftId) => api.automationDrafts.finalize(draftId, { signal }),
36907
- getAutomation: (automationId) => api.automations.get(automationId, { signal })
37078
+ getAutomation: (automationId) => api.automations.get(automationId, { signal }),
37079
+ test: (draftId, request2) => api.automationDrafts.test(draftId, request2, { signal }),
37080
+ getTestRun: (draftId, runId, args, requestSignal) => api.automationDrafts.getTestRun(draftId, runId, args, {
37081
+ signal: requestSignal ?? signal
37082
+ })
36908
37083
  };
36909
37084
  }
36910
37085
  return {
@@ -36918,7 +37093,11 @@ function resolveDraftApi(api, workspaceId, signal) {
36918
37093
  signal
36919
37094
  })).validation,
36920
37095
  finalize: (draftId) => api.workspaceAutomationDrafts.finalize(workspaceId, draftId, { signal }),
36921
- getAutomation: (automationId) => api.workspaceAutomations.get(workspaceId, automationId, { signal })
37096
+ getAutomation: (automationId) => api.workspaceAutomations.get(workspaceId, automationId, { signal }),
37097
+ test: (draftId, request2) => api.workspaceAutomationDrafts.test(workspaceId, draftId, request2, { signal }),
37098
+ getTestRun: (draftId, runId, args, requestSignal) => api.workspaceAutomationDrafts.getTestRun(workspaceId, draftId, runId, args, {
37099
+ signal: requestSignal ?? signal
37100
+ })
36922
37101
  };
36923
37102
  }
36924
37103
  async function createDraft(draftApi, { manifest, automationId }) {
@@ -37054,12 +37233,7 @@ async function publishDraft(draftApi, { draftId, confirmed }) {
37054
37233
  } catch (error62) {
37055
37234
  const notReady = getDraftNotReadyError(error62);
37056
37235
  if (!notReady) throw error62;
37057
- throw new CliError4("DRAFT_NOT_READY", notReady.message, {
37058
- hints: [
37059
- `See the issues: tda draft view ${draftId}`,
37060
- `Bind connections: tda draft connect ${draftId} --auto`
37061
- ]
37062
- });
37236
+ throw draftNotReadyError(notReady.message, draftId, draftApi.scope);
37063
37237
  }
37064
37238
  const automationId = published.automation.id;
37065
37239
  let automation;
@@ -37137,6 +37311,136 @@ function normaliseManifest(manifest) {
37137
37311
  const parsed = manifestSchema.safeParse(manifest);
37138
37312
  return parsed.success ? parsed.data : manifest;
37139
37313
  }
37314
+ var DEFAULT_POLL_INTERVALS_MS = { first: 2e3, max: 1e4 };
37315
+ var STATUS_REQUEST_GRACE_MS = 1e4;
37316
+ var OPEN_RUN_STATUSES = /* @__PURE__ */ new Set([
37317
+ "pending",
37318
+ "running"
37319
+ ]);
37320
+ async function startDraftTest(draftApi, {
37321
+ draftId,
37322
+ request: request2,
37323
+ wait: waitFor,
37324
+ signal
37325
+ }) {
37326
+ let started;
37327
+ try {
37328
+ started = await draftApi.test(draftId, request2);
37329
+ } catch (error62) {
37330
+ const refusal = getDraftTestRequestError(error62);
37331
+ if (!refusal) throw error62;
37332
+ throw toDraftTestCliError(refusal, draftId, draftApi.scope);
37333
+ }
37334
+ const base = {
37335
+ draftId,
37336
+ testRunId: started.testRunId,
37337
+ trigger: started.trigger,
37338
+ connectorCalls: started.connectorCalls,
37339
+ command: `tda draft test-run ${draftId} ${started.testRunId} ${scopeFlag(draftApi.scope)}`
37340
+ };
37341
+ if (!waitFor) {
37342
+ return { action: "test_started", ...base, status: started.status };
37343
+ }
37344
+ const intervals = waitFor.pollIntervalsMs ?? DEFAULT_POLL_INTERVALS_MS;
37345
+ const deadline = Date.now() + waitFor.timeoutMs;
37346
+ let intervalMs = intervals.first;
37347
+ let last = null;
37348
+ while (true) {
37349
+ const requestTimeout = AbortSignal.timeout(
37350
+ Math.max(deadline - Date.now(), 0) + (waitFor.requestGraceMs ?? STATUS_REQUEST_GRACE_MS)
37351
+ );
37352
+ try {
37353
+ last = await draftApi.getTestRun(
37354
+ draftId,
37355
+ started.testRunId,
37356
+ void 0,
37357
+ AbortSignal.any([signal, requestTimeout])
37358
+ );
37359
+ } catch (error62) {
37360
+ if (signal.aborted || !requestTimeout.aborted) throw error62;
37361
+ return toFinished(base, last, "timed_out");
37362
+ }
37363
+ if (!OPEN_RUN_STATUSES.has(last.status)) {
37364
+ return toFinished(base, last, toOutcome(last.status));
37365
+ }
37366
+ const remainingMs = deadline - Date.now();
37367
+ if (remainingMs <= 0) {
37368
+ return toFinished(base, last, "timed_out");
37369
+ }
37370
+ await wait2(Math.min(intervalMs, remainingMs), void 0, { signal });
37371
+ intervalMs = Math.min(intervalMs * 2, intervals.max);
37372
+ }
37373
+ }
37374
+ function toFinished(base, run, outcome) {
37375
+ return {
37376
+ action: "test_finished",
37377
+ ...base,
37378
+ outcome,
37379
+ status: run?.status ?? "pending",
37380
+ failedStep: run?.failedStep ?? null,
37381
+ error: run?.failedStep?.error ?? (run ? getRunOutcomeReason(run) : null) ?? (run?.status === "data-expired" ? "Temporal no longer holds this run's history, so its outcome is unknown" : null),
37382
+ result: run?.result ?? null
37383
+ };
37384
+ }
37385
+ function toOutcome(status) {
37386
+ switch (status) {
37387
+ case "completed":
37388
+ return "passed";
37389
+ case "skipped":
37390
+ return "skipped";
37391
+ case "cancelled":
37392
+ return "cancelled";
37393
+ default:
37394
+ return "failed";
37395
+ }
37396
+ }
37397
+ function draftNotReadyError(message, draftId, scope) {
37398
+ const flag = scopeFlag(scope);
37399
+ return new CliError4("DRAFT_NOT_READY", message, {
37400
+ hints: [
37401
+ `See the issues: tda draft view ${draftId} ${flag}`,
37402
+ `Bind connections: tda draft connect ${draftId} --auto ${flag}`
37403
+ ]
37404
+ });
37405
+ }
37406
+ function toDraftTestCliError(refusal, draftId, scope) {
37407
+ const flag = scopeFlag(scope);
37408
+ switch (refusal.code) {
37409
+ case "draft_test_not_ready":
37410
+ return draftNotReadyError(refusal.message, draftId, scope);
37411
+ case "draft_test_payload_required":
37412
+ case "draft_test_payload_filtered":
37413
+ return new CliError4(refusal.code.toUpperCase(), refusal.message, {
37414
+ hints: [
37415
+ `Test with a real event: tda draft test ${draftId} --trigger <event> --payload-file <path> ${flag}`
37416
+ ]
37417
+ });
37418
+ default:
37419
+ return new CliError4(refusal.code.toUpperCase(), refusal.message);
37420
+ }
37421
+ }
37422
+ function parseTriggerOption(value) {
37423
+ return /^\d+$/.test(value) ? { index: Number(value) } : { event: value };
37424
+ }
37425
+ async function readTestPayloadFile(path) {
37426
+ let content;
37427
+ try {
37428
+ content = await readFile3(path, "utf8");
37429
+ } catch (error62) {
37430
+ throw new CliError4(
37431
+ "PAYLOAD_UNREADABLE",
37432
+ `Could not read ${path}: ${getErrorMessage7(error62)}`
37433
+ );
37434
+ }
37435
+ try {
37436
+ return JSON.parse(content);
37437
+ } catch (error62) {
37438
+ throw new CliError4(
37439
+ "PAYLOAD_UNREADABLE",
37440
+ `${path} is not valid JSON: ${getErrorMessage7(error62)}`
37441
+ );
37442
+ }
37443
+ }
37140
37444
 
37141
37445
  // src/commands/draft/format.ts
37142
37446
  function formatDraftDelete(result) {
@@ -37246,6 +37550,72 @@ function describeDiff(diff) {
37246
37550
  if (diff.steps.reordered) parts.push("steps reordered");
37247
37551
  return parts.join("; ");
37248
37552
  }
37553
+ var MOCKED_CONNECTOR_CALLS_LINE = "Connector calls: mocked (simulated by a model; nothing was read from or written to your services)";
37554
+ function formatDraftTestRun(run) {
37555
+ const reason = getRunOutcomeReason(run);
37556
+ const lines = [
37557
+ `Test run: ${run.id}`,
37558
+ `Draft: ${run.draftId}`,
37559
+ `Automation: ${run.automationId ?? "none (the draft creates a new one)"}`,
37560
+ `Status: ${run.status}`,
37561
+ MOCKED_CONNECTOR_CALLS_LINE,
37562
+ `Created: ${run.createdAt}`,
37563
+ `Updated: ${run.updatedAt}`
37564
+ ];
37565
+ if (run.failedStep) {
37566
+ lines.push(
37567
+ `Failed step: ${run.failedStep.stepId} (${run.failedStep.description})`,
37568
+ `Error: ${run.failedStep.error ?? reason ?? "none reported"}`
37569
+ );
37570
+ } else if (reason) {
37571
+ lines.push(`${run.status === "skipped" ? "Skip" : "Failure"} reason: ${reason}`);
37572
+ }
37573
+ lines.push(
37574
+ `Result: ${run.result?.text ?? "none"}`,
37575
+ `Steps: ${run.steps.length}`,
37576
+ ...formatRunSteps(run.steps, { toolCallLabel: "Tool (mocked)" })
37577
+ );
37578
+ return lines.join("\n");
37579
+ }
37580
+ var INPUT_SOURCE_LABELS = {
37581
+ schedule: "as a scheduled run",
37582
+ "sample-event": "with the built-in sample event",
37583
+ supplied: "with the supplied payload",
37584
+ empty: "with an empty request body"
37585
+ };
37586
+ var OUTCOME_LABELS = {
37587
+ passed: "passed",
37588
+ failed: "failed",
37589
+ skipped: "was skipped",
37590
+ cancelled: "was cancelled",
37591
+ timed_out: "did not finish before the timeout"
37592
+ };
37593
+ function formatDraftTest(result) {
37594
+ const { trigger } = result;
37595
+ const which = trigger.type === "webhook" ? `webhook ${trigger.event}` : trigger.type;
37596
+ const lines = [
37597
+ result.action === "test_started" ? `Started test run ${result.testRunId} for draft ${result.draftId}.` : `Test run ${result.testRunId} for draft ${result.draftId} ${OUTCOME_LABELS[result.outcome]}.`,
37598
+ `Trigger: ${trigger.index} of ${trigger.count} (${which}), ${INPUT_SOURCE_LABELS[trigger.inputSource]}`
37599
+ ];
37600
+ if (result.action === "test_finished") {
37601
+ if (result.outcome === "timed_out") lines.push(`Status: ${result.status}`);
37602
+ if (result.failedStep) {
37603
+ lines.push(
37604
+ `Failed step: ${result.failedStep.stepId} (${result.failedStep.description})`
37605
+ );
37606
+ }
37607
+ if (result.error)
37608
+ lines.push(`${result.outcome === "skipped" ? "Reason" : "Error"}: ${result.error}`);
37609
+ if (result.result) lines.push(`Result: ${result.result.text}`);
37610
+ }
37611
+ lines.push(MOCKED_CONNECTOR_CALLS_LINE, `Details: ${result.command}`);
37612
+ if (trigger.count > 1) {
37613
+ lines.push(
37614
+ `This draft has ${trigger.count} triggers; test another with --trigger <index|event>.`
37615
+ );
37616
+ }
37617
+ return lines.join("\n");
37618
+ }
37249
37619
 
37250
37620
  // src/commands/draft/validate-command.ts
37251
37621
  import { CliError as CliError5 } from "@doist/cli-core";
@@ -37300,8 +37670,10 @@ function formatManifestValidation(result) {
37300
37670
  }
37301
37671
 
37302
37672
  // src/commands/draft/index.ts
37673
+ var DEFAULT_TEST_WAIT = "10m";
37674
+ var TOKEN_LIFETIME_MARGIN_MS = 2 * 60 * 1e3;
37303
37675
  function registerDraftCommand(program) {
37304
- const draft = program.command("draft").description("Author and inspect automation drafts");
37676
+ const draft = program.command("draft").description("Author, test and inspect automation drafts");
37305
37677
  registerDraftValidateCommand(draft);
37306
37678
  addWorkspaceScopeOptions(
37307
37679
  addCursorPaginationOptions(
@@ -37425,6 +37797,63 @@ function registerDraftCommand(program) {
37425
37797
  { spinner: options.yes === true ? "Publishing..." : "Loading draft..." }
37426
37798
  );
37427
37799
  });
37800
+ addWorkspaceScopeOptions(
37801
+ draft.command("test").description("Start a test run of a draft, with mocked connector calls").argument("<draft-id>", "Draft ID").option("--wait", "Wait for the run to end and exit 1 unless it passed").option(
37802
+ "--timeout <duration>",
37803
+ `How long --wait waits, such as 90s or 15m (default ${DEFAULT_TEST_WAIT})`
37804
+ ).option(
37805
+ "--trigger <index|event>",
37806
+ "The trigger to test: its position in the manifest's triggers, or a webhook event"
37807
+ ).option(
37808
+ "--payload-file <path>",
37809
+ "A JSON event to test with: a webhook trigger's event or an API trigger's body"
37810
+ )
37811
+ ).action(async (draftId, options, command) => {
37812
+ await runApiCommand(
37813
+ command,
37814
+ async ({ api, signal }) => {
37815
+ if (options.timeout !== void 0 && options.wait !== true) {
37816
+ throw new Error("--timeout only applies with --wait.");
37817
+ }
37818
+ const timeoutMs = parseTestTimeout(options.timeout ?? DEFAULT_TEST_WAIT);
37819
+ const draftApi = resolveDraftApi(api, await resolveWorkspaceScope(options), signal);
37820
+ return startDraftTest(draftApi, {
37821
+ draftId,
37822
+ request: {
37823
+ ...options.trigger !== void 0 ? { trigger: parseTriggerOption(options.trigger) } : {},
37824
+ ...options.payloadFile !== void 0 ? { payload: await readTestPayloadFile(options.payloadFile) } : {}
37825
+ },
37826
+ wait: options.wait === true ? { timeoutMs } : null,
37827
+ signal
37828
+ });
37829
+ },
37830
+ { human: formatDraftTest },
37831
+ {
37832
+ spinner: options.wait === true ? "Testing draft..." : "Starting test run...",
37833
+ minimumTokenLifetimeMs: options.wait === true ? tryParseTestTimeout(options.timeout ?? DEFAULT_TEST_WAIT) + TOKEN_LIFETIME_MARGIN_MS : void 0,
37834
+ exitCode: (result) => result.action === "test_finished" && result.outcome !== "passed" ? 1 : void 0
37835
+ }
37836
+ );
37837
+ });
37838
+ addWorkspaceScopeOptions(
37839
+ draft.command("test-run").description("Show a draft's test run with step and failure details").argument("<draft-id>", "Draft ID").argument("<run-id>", "Test run ID").option("--full", "Include raw step results and generated code in machine output")
37840
+ ).action(async (draftId, runId, options, command) => {
37841
+ await runApiCommand(
37842
+ command,
37843
+ async ({ api, signal }) => {
37844
+ const draftApi = resolveDraftApi(api, await resolveWorkspaceScope(options), signal);
37845
+ return draftApi.getTestRun(draftId, runId, {
37846
+ includeGeneratedCode: options.full === true,
37847
+ includeToolCallPreviews: true
37848
+ });
37849
+ },
37850
+ {
37851
+ human: formatDraftTestRun,
37852
+ json: options.full === true ? void 0 : summarizeDraftTestRun
37853
+ },
37854
+ { spinner: "Loading test run..." }
37855
+ );
37856
+ });
37428
37857
  addWorkspaceScopeOptions(
37429
37858
  draft.command("delete").description("Delete a draft after previewing which one it is").argument("<draft-id>", "Draft ID").option("--yes", "Confirm deletion")
37430
37859
  ).action(async (draftId, options, command) => {
@@ -37461,6 +37890,20 @@ function streamDraftList(options, fetchPage) {
37461
37890
  async (args) => summarizeDraftListPage(await fetchPage(args))
37462
37891
  );
37463
37892
  }
37893
+ function tryParseTestTimeout(value) {
37894
+ try {
37895
+ return durationStringToMilliseconds(value);
37896
+ } catch {
37897
+ return 0;
37898
+ }
37899
+ }
37900
+ function parseTestTimeout(value) {
37901
+ try {
37902
+ return durationStringToMilliseconds(value);
37903
+ } catch {
37904
+ throw new Error(`Invalid --timeout ${value}; use a duration such as 90s, 15m or 1h.`);
37905
+ }
37906
+ }
37464
37907
 
37465
37908
  // src/commands/run/index.ts
37466
37909
  import { Option as Option7 } from "commander";