@autonoma-ai/planner 0.1.27 → 0.1.29

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
@@ -549,7 +549,7 @@ var init_theme = __esm({
549
549
  });
550
550
 
551
551
  // src/ui/components/render-content.ts
552
- import matter from "gray-matter";
552
+ import matter from "@11ty/gray-matter";
553
553
  import { z as z2 } from "zod";
554
554
  function renderContent(text2, kind, name) {
555
555
  if (memo != null && memo.text === text2 && memo.kind === kind && memo.name === name) return memo.lines;
@@ -2101,6 +2101,14 @@ var init_prompts = __esm({
2101
2101
  }
2102
2102
  });
2103
2103
 
2104
+ // ../../packages/types/src/types/previewkit.ts
2105
+ var init_previewkit = __esm({
2106
+ "../../packages/types/src/types/previewkit.ts"() {
2107
+ "use strict";
2108
+ init_esm_shims();
2109
+ }
2110
+ });
2111
+
2104
2112
  // ../../packages/types/src/types/step-overlay-points.ts
2105
2113
  import { z as z4 } from "zod";
2106
2114
  var overlayPointSchema, pointSchema, outputWithPointsSchema;
@@ -2288,11 +2296,12 @@ function analysisVerdictPlane(category) {
2288
2296
  const tier = analysisFindingTier(category);
2289
2297
  return tier === "bug" || tier === "passed" ? "app_health" : "coverage";
2290
2298
  }
2291
- var analysisVerdictSchema, ANALYSIS_VERDICT, VERDICT_TIER, coverageVerdicts, analysisTestOriginSchema, coverageCategoryCountSchema, coverageSummarySchema, analysisClassificationReportSchema, analysisClassificationSummarySchema, analysisFindingViewSchema, analysisReportDataSchema, analysisIssueKindSchema, analysisIssueSeveritySchema, analysisIssueStatusSchema, resolvedPrimaryScreenshotSchema, analysisIssueSummarySchema, analysisIssueFindingInstanceSchema, analysisIssueDetailSchema, analysisPrCoveredTestSchema, analysisPrIssueSchema, analysisPrNewerRunSchema, analysisForPrSchema, mainOpenProblemSchema, analysisSnapshotIssueChangesSchema;
2299
+ var analysisVerdictSchema, ANALYSIS_VERDICT, VERDICT_TIER, coverageVerdicts, analysisFlowStatusSchema, analysisFlowOwnerSchema, analysisFlowSchema, analysisTestOriginSchema, coverageCategoryCountSchema, coverageSummarySchema, analysisClassificationReportSchema, analysisClassificationSummarySchema, analysisFindingViewSchema, analysisReportDataSchema, analysisIssueKindSchema, analysisIssueSeveritySchema, analysisIssueStatusSchema, resolvedPrimaryScreenshotSchema, analysisIssueSummarySchema, analysisIssueFindingInstanceSchema, analysisIssueDetailSchema, analysisPrCoveredTestSchema, analysisPrIssueSchema, analysisPrNewerRunSchema, analysisForPrSchema, mainOpenProblemSchema, analysisSnapshotIssueChangesSchema;
2292
2300
  var init_analysis = __esm({
2293
2301
  "../../packages/types/src/schemas/analysis.ts"() {
2294
2302
  "use strict";
2295
2303
  init_esm_shims();
2304
+ init_previewkit();
2296
2305
  init_step_overlay_points();
2297
2306
  init_evidence_tokens();
2298
2307
  init_investigation_report();
@@ -2322,6 +2331,26 @@ var init_analysis = __esm({
2322
2331
  coverageVerdicts = analysisVerdictSchema.options.filter(
2323
2332
  (verdict) => analysisVerdictPlane(verdict) === "coverage"
2324
2333
  );
2334
+ analysisFlowStatusSchema = z8.enum(["broken", "verified", "partial", "unverified"]);
2335
+ analysisFlowOwnerSchema = z8.enum(["client", "autonoma", "none"]);
2336
+ analysisFlowSchema = z8.object({
2337
+ /** The reader-facing name, authored by the Reporter: "Guest checkout", not `checkout-guest-express-lane`. */
2338
+ title: z8.string().min(1),
2339
+ /** One sentence, authored by the Reporter: what was confirmed, or why it could not be. */
2340
+ detail: z8.string(),
2341
+ status: analysisFlowStatusSchema,
2342
+ owner: analysisFlowOwnerSchema,
2343
+ /** Cited tests whose last-known verdict confirmed the app. */
2344
+ passedCount: z8.number().int().nonnegative(),
2345
+ /** Cited tests whose last-known verdict is a coverage-plane gap. */
2346
+ gapCount: z8.number().int().nonnegative(),
2347
+ /** Cited tests whose last-known verdict is a client bug. */
2348
+ bugCount: z8.number().int().nonnegative(),
2349
+ /** How many cited verdicts came from the run being reported. Zero means the whole flow is carried from earlier. */
2350
+ checkedThisRunCount: z8.number().int().nonnegative(),
2351
+ /** The tests this flow covers. Every test in the branch's map lands in exactly one flow. */
2352
+ testSlugs: z8.array(z8.string())
2353
+ });
2325
2354
  analysisTestOriginSchema = z8.enum(["pre_existing", "proposed"]);
2326
2355
  coverageCategoryCountSchema = z8.object({
2327
2356
  category: analysisVerdictSchema,
@@ -2417,17 +2446,24 @@ var init_analysis = __esm({
2417
2446
  /** The Impact Analysis stage's account of why it selected the tests it did (admin-only on the snapshot page). */
2418
2447
  impactReasoning: z8.string().optional(),
2419
2448
  /**
2420
- * The Reporter's holistic PR report prose (Markdown), the hero of the PR page and the snapshot per-job view.
2421
- * Absent while a run is still authoring it (the page keeps polling) or when the run degraded to a
2422
- * finding-derived verdict with no prose. Its inline `evidence:` image tokens resolve against `reportEvidence`;
2423
- * `issue:`/`finding:` link tokens resolve against the branch's issues and this report's findings.
2449
+ * The Reporter's holistic PR report prose (Markdown), the hero of the PR page and the snapshot per-job view. Its
2450
+ * inline `evidence:` image tokens resolve against `reportEvidence`; `issue:`/`finding:` link tokens resolve
2451
+ * against the branch's issues and this report's findings.
2452
+ *
2453
+ * Never empty: a report row exists only once the Reporter has authored one, and `finish` refuses prose that
2454
+ * sanitizing emptied.
2424
2455
  */
2425
- reportMarkdown: z8.string().optional(),
2456
+ reportMarkdown: z8.string(),
2426
2457
  /**
2427
- * The Reporter's one-paragraph summary of the run, for the surfaces that show prose but not a document: the PR
2428
- * page's verdict subtitle. Absent on a run that predates the Reporter (those rows were backfilled to empty).
2458
+ * The Reporter's title for the PR as a whole (about eight words). EMPTY on a report written before the Reporter
2459
+ * authored titles - `analysisPrTitle` is the one place that reads it as unauthored, and it also overrides the
2460
+ * authored value for an open bug and for a run that needed no tests.
2429
2461
  */
2430
- summary: z8.string().optional(),
2462
+ title: z8.string(),
2463
+ /** The Reporter's headline: the CUMULATIVE state of the branch in 1-3 plain sentences. Never empty. */
2464
+ headline: z8.string(),
2465
+ /** The branch's flow itemization: what this PR has established and what it has not. Empty on a pre-flows run. */
2466
+ flows: z8.array(analysisFlowSchema),
2431
2467
  /** The signed assets `reportMarkdown` may embed inline by `evidence:<assetId>` token (referenced ones only). */
2432
2468
  reportEvidence: z8.array(resolvedEvidenceAssetSchema),
2433
2469
  /** The persisted app-health verdict for the run (issue-derived at finalize): `client_bug` or `passed`. */
@@ -2526,8 +2562,16 @@ var init_analysis = __esm({
2526
2562
  status: z8.literal("complete"),
2527
2563
  /** The app-health verdict: `client_bug` when the branch has an open bug issue, else `passed`. */
2528
2564
  verdict: analysisVerdictSchema,
2529
- /** The Reporter's one-paragraph summary of the run. */
2530
- summary: z8.string().optional(),
2565
+ /** The Reporter's title for the PR as a whole. Empty on a report written before the Reporter authored one. */
2566
+ title: z8.string(),
2567
+ /** The Reporter's headline: the cumulative state of the branch in 1-3 plain sentences. */
2568
+ headline: z8.string(),
2569
+ /**
2570
+ * The branch's flow itemization: which parts of the app this PR has established and which it has not. A
2571
+ * consumer reading `verdict` alone learns only whether a bug was found - these say how much was covered, which
2572
+ * is the difference between "nothing broke" and "we checked".
2573
+ */
2574
+ flows: z8.array(analysisFlowSchema),
2531
2575
  /** The Reporter's holistic report prose. Its `evidence:` image tokens resolve against `reportEvidence`, and
2532
2576
  * its `issue:` tokens against the `issues` below. */
2533
2577
  reportMarkdown: z8.string().optional(),
@@ -3087,6 +3131,97 @@ var init_api_key = __esm({
3087
3131
  }
3088
3132
  });
3089
3133
 
3134
+ // ../../packages/types/src/schemas/organization.ts
3135
+ import { z as z14 } from "zod";
3136
+ var InvitationStatusSchema, InviteMemberInputSchema, RevokeInvitationInputSchema, RemoveMemberInputSchema, InvitationIdInputSchema, SetActiveOrganizationInputSchema, RenameOrganizationInputSchema, LeaveOrganizationInputSchema, InvitationOutcomeSchema, InvitationPreviewSchema, MyOrganizationSchema, AppSlugOwnerSchema, AppSlugOwnersInputSchema, OrganizationMemberSchema, PendingInvitationSchema;
3137
+ var init_organization = __esm({
3138
+ "../../packages/types/src/schemas/organization.ts"() {
3139
+ "use strict";
3140
+ init_esm_shims();
3141
+ InvitationStatusSchema = z14.enum(["pending", "accepted", "rejected", "canceled"]);
3142
+ InviteMemberInputSchema = z14.object({
3143
+ email: z14.email("Enter a valid email address").trim().toLowerCase()
3144
+ });
3145
+ RevokeInvitationInputSchema = z14.object({
3146
+ invitationId: z14.string().min(1)
3147
+ });
3148
+ RemoveMemberInputSchema = z14.object({
3149
+ userId: z14.string().min(1)
3150
+ });
3151
+ InvitationIdInputSchema = z14.object({
3152
+ invitationId: z14.string().min(1)
3153
+ });
3154
+ SetActiveOrganizationInputSchema = z14.object({
3155
+ organizationId: z14.string().min(1)
3156
+ });
3157
+ RenameOrganizationInputSchema = z14.object({
3158
+ organizationId: z14.string().min(1),
3159
+ name: z14.string().trim().min(1, "Enter a name").max(100, "Keep it under 100 characters")
3160
+ });
3161
+ LeaveOrganizationInputSchema = z14.object({
3162
+ organizationId: z14.string().min(1)
3163
+ });
3164
+ InvitationOutcomeSchema = z14.enum([
3165
+ "joinable",
3166
+ "wrong-account",
3167
+ "already-member",
3168
+ "expired",
3169
+ "revoked",
3170
+ "accepted",
3171
+ "declined"
3172
+ ]);
3173
+ InvitationPreviewSchema = z14.object({
3174
+ invitationId: z14.string(),
3175
+ organizationName: z14.string(),
3176
+ inviterName: z14.string(),
3177
+ invitedEmail: z14.string(),
3178
+ outcome: InvitationOutcomeSchema
3179
+ });
3180
+ MyOrganizationSchema = z14.object({
3181
+ id: z14.string(),
3182
+ name: z14.string(),
3183
+ slug: z14.string(),
3184
+ /** Which one the current session is acting as. Session-scoped: switching does not persist. */
3185
+ isActive: z14.boolean(),
3186
+ memberCount: z14.number().int().positive(),
3187
+ applicationCount: z14.number().int().nonnegative(),
3188
+ joinedAt: z14.date(),
3189
+ /**
3190
+ * Why leaving is refused, if it is. `last-organization` - it is their only one, and an
3191
+ * account with no organization cannot reach anything. `last-member` - nobody would be
3192
+ * left who could reach the organization's applications.
3193
+ */
3194
+ leaveBlockedReason: z14.enum(["last-organization", "last-member"]).optional()
3195
+ });
3196
+ AppSlugOwnerSchema = z14.object({
3197
+ organizationId: z14.string(),
3198
+ organizationName: z14.string(),
3199
+ organizationSlug: z14.string()
3200
+ });
3201
+ AppSlugOwnersInputSchema = z14.object({
3202
+ appSlug: z14.string().min(1)
3203
+ });
3204
+ OrganizationMemberSchema = z14.object({
3205
+ userId: z14.string(),
3206
+ name: z14.string(),
3207
+ email: z14.string(),
3208
+ image: z14.string().optional(),
3209
+ role: z14.string(),
3210
+ joinedAt: z14.date(),
3211
+ /** True for the member making the request - the row that can't be removed. */
3212
+ isSelf: z14.boolean()
3213
+ });
3214
+ PendingInvitationSchema = z14.object({
3215
+ id: z14.string(),
3216
+ email: z14.string(),
3217
+ inviterName: z14.string(),
3218
+ expiresAt: z14.date(),
3219
+ /** Where to send the invitee if the email never arrives and someone wants to paste the link. */
3220
+ acceptUrl: z14.string()
3221
+ });
3222
+ }
3223
+ });
3224
+
3090
3225
  // ../../packages/types/src/schemas/previewkit-builtins.ts
3091
3226
  function isReservedPreviewkitEnvKey(key) {
3092
3227
  return PREVIEWKIT_BUILTIN_ENV_KEYS.has(key);
@@ -3138,7 +3273,7 @@ var init_previewkit_builtins = __esm({
3138
3273
  });
3139
3274
 
3140
3275
  // ../../packages/types/src/schemas/secrets.ts
3141
- import { z as z14 } from "zod";
3276
+ import { z as z15 } from "zod";
3142
3277
  var SECRET_KEY_REGEX, APP_NAME_REGEX, SecretKeySchema, AppNameSchema, SecretItemSchema, ListSecretAppsInputSchema, ListSecretsInputSchema, UpsertSecretsInputSchema, DeleteSecretInputSchema, PreviewkitConfigAppSecretsSchema, PreviewkitConfigSecretsSchema;
3143
3278
  var init_secrets = __esm({
3144
3279
  "../../packages/types/src/schemas/secrets.ts"() {
@@ -3147,12 +3282,12 @@ var init_secrets = __esm({
3147
3282
  init_previewkit_builtins();
3148
3283
  SECRET_KEY_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;
3149
3284
  APP_NAME_REGEX = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
3150
- SecretKeySchema = z14.string().min(1).max(256).regex(
3285
+ SecretKeySchema = z15.string().min(1).max(256).regex(
3151
3286
  SECRET_KEY_REGEX,
3152
3287
  "Keys must start with a letter or underscore and contain only letters, numbers, and underscores"
3153
3288
  );
3154
- AppNameSchema = z14.string().min(2).max(63).regex(APP_NAME_REGEX, "App name must be lowercase alphanumeric with hyphens (Kubernetes label-compatible)");
3155
- SecretItemSchema = z14.object({
3289
+ AppNameSchema = z15.string().min(2).max(63).regex(APP_NAME_REGEX, "App name must be lowercase alphanumeric with hyphens (Kubernetes label-compatible)");
3290
+ SecretItemSchema = z15.object({
3156
3291
  key: SecretKeySchema.superRefine((key, ctx) => {
3157
3292
  if (isReservedPreviewkitEnvKey(key)) {
3158
3293
  ctx.addIssue({
@@ -3166,31 +3301,50 @@ var init_secrets = __esm({
3166
3301
  });
3167
3302
  }
3168
3303
  }),
3169
- value: z14.string().min(1).max(65536)
3304
+ value: z15.string().min(1).max(65536)
3170
3305
  });
3171
- ListSecretAppsInputSchema = z14.object({
3172
- applicationId: z14.string()
3306
+ ListSecretAppsInputSchema = z15.object({
3307
+ applicationId: z15.string()
3173
3308
  });
3174
- ListSecretsInputSchema = z14.object({
3175
- applicationId: z14.string(),
3309
+ ListSecretsInputSchema = z15.object({
3310
+ applicationId: z15.string(),
3176
3311
  appName: AppNameSchema
3177
3312
  });
3178
- UpsertSecretsInputSchema = z14.object({
3179
- applicationId: z14.string(),
3313
+ UpsertSecretsInputSchema = z15.object({
3314
+ applicationId: z15.string(),
3180
3315
  appName: AppNameSchema,
3181
- items: z14.array(SecretItemSchema).min(1).max(200)
3316
+ items: z15.array(SecretItemSchema).min(1).max(200)
3182
3317
  });
3183
- DeleteSecretInputSchema = z14.object({
3184
- applicationId: z14.string(),
3318
+ DeleteSecretInputSchema = z15.object({
3319
+ applicationId: z15.string(),
3185
3320
  appName: AppNameSchema,
3186
3321
  key: SecretKeySchema
3187
3322
  });
3188
- PreviewkitConfigAppSecretsSchema = z14.object({
3323
+ PreviewkitConfigAppSecretsSchema = z15.object({
3189
3324
  appName: AppNameSchema,
3190
- upserts: z14.array(SecretItemSchema).max(200).default([]),
3191
- deletes: z14.array(SecretKeySchema).max(200).default([])
3325
+ upserts: z15.array(SecretItemSchema).max(200).default([]),
3326
+ deletes: z15.array(SecretKeySchema).max(200).default([])
3192
3327
  });
3193
- PreviewkitConfigSecretsSchema = z14.array(PreviewkitConfigAppSecretsSchema).max(50);
3328
+ PreviewkitConfigSecretsSchema = z15.array(PreviewkitConfigAppSecretsSchema).max(50);
3329
+ }
3330
+ });
3331
+
3332
+ // ../../packages/types/src/parse-url.ts
3333
+ var init_parse_url = __esm({
3334
+ "../../packages/types/src/parse-url.ts"() {
3335
+ "use strict";
3336
+ init_esm_shims();
3337
+ }
3338
+ });
3339
+
3340
+ // ../../packages/types/src/sdk-endpoint.ts
3341
+ var DEFAULT_SDK_PATH;
3342
+ var init_sdk_endpoint = __esm({
3343
+ "../../packages/types/src/sdk-endpoint.ts"() {
3344
+ "use strict";
3345
+ init_esm_shims();
3346
+ init_parse_url();
3347
+ DEFAULT_SDK_PATH = "/api/autonoma";
3194
3348
  }
3195
3349
  });
3196
3350
 
@@ -3619,7 +3773,7 @@ var init_previewkit_presets = __esm({
3619
3773
  });
3620
3774
 
3621
3775
  // ../../packages/types/src/schemas/previewkit-config.ts
3622
- import { z as z15 } from "zod";
3776
+ import { z as z16 } from "zod";
3623
3777
  function buildResourcesSchema(role, allowCustomResources) {
3624
3778
  return resourcesInput.transform((input) => {
3625
3779
  if (!allowCustomResources || input == null) {
@@ -3634,86 +3788,96 @@ function buildResourcesSchema(role, allowCustomResources) {
3634
3788
  });
3635
3789
  }
3636
3790
  function singleLineCommand(label) {
3637
- return z15.string().min(1).regex(/^[^\r\n]+$/, `${label} must be a single line (no line breaks)`);
3791
+ return z16.string().min(1).regex(/^[^\r\n]+$/, `${label} must be a single line (no line breaks)`);
3638
3792
  }
3639
3793
  function heredocSafeScript(label) {
3640
- return z15.string().min(1).refine(
3794
+ return z16.string().min(1).refine(
3641
3795
  (value) => !value.split("\n").includes(PREVIEWKIT_BUILD_SCRIPT_HEREDOC),
3642
3796
  `${label} cannot contain a line equal to "${PREVIEWKIT_BUILD_SCRIPT_HEREDOC}" (reserved heredoc delimiter)`
3643
3797
  );
3644
3798
  }
3645
3799
  function nodeFrameworkBuildSchema(framework) {
3646
- return z15.object({
3647
- framework: z15.literal(framework),
3648
- package_manager: z15.enum(["npm", "pnpm", "yarn"]).default("pnpm"),
3649
- node_version: z15.string().regex(nodeVersionRegex, "must look like 22, 22.5, or 22.5.0").default("22"),
3650
- install_command: z15.string().min(1).optional(),
3651
- build_command: z15.string().min(1).optional(),
3652
- run_command: z15.string().min(1).optional(),
3800
+ return z16.object({
3801
+ framework: z16.literal(framework),
3802
+ package_manager: z16.enum(["npm", "pnpm", "yarn"]).default("pnpm"),
3803
+ node_version: z16.string().regex(nodeVersionRegex, "must look like 22, 22.5, or 22.5.0").default("22"),
3804
+ install_command: z16.string().min(1).optional(),
3805
+ build_command: z16.string().min(1).optional(),
3806
+ run_command: z16.string().min(1).optional(),
3653
3807
  build_context: buildContextSchema
3654
3808
  });
3655
3809
  }
3656
3810
  function buildPreviewConfigSchema(build, allowCustomResources) {
3657
- const appSchema = z15.object({
3658
- name: z15.string().regex(k8sNameRegex, "Must be a valid Kubernetes name"),
3659
- repository: z15.string().regex(repoFullNameRegex, "Must be an owner/repo full name").describe(
3811
+ const appSchema = z16.object({
3812
+ name: z16.string().regex(k8sNameRegex, "Must be a valid Kubernetes name"),
3813
+ repository: z16.string().regex(repoFullNameRegex, "Must be an owner/repo full name").describe(
3660
3814
  "The owner/repo full name of the GitHub repository this app builds from. Mandatory even in single-repo setups. Any value other than the application's own repository makes this app a multirepo dependency: that repo is cloned at the branch the branch_convention (or its repositories[] fallback_branch) resolves to."
3661
3815
  ),
3662
- path: z15.string().default("."),
3663
- build_context: z15.string().optional(),
3664
- dockerfile: z15.string().optional(),
3816
+ path: z16.string().default("."),
3817
+ build_context: z16.string().optional(),
3818
+ dockerfile: z16.string().optional(),
3665
3819
  build: build.optional(),
3666
3820
  // The preset-based deploy model, mutually exclusive with `build` (enforced
3667
3821
  // by the superRefine below). Lowered to a `runtime` Build by the generator.
3668
3822
  blueprint: blueprintSchema.optional(),
3669
3823
  // The AWS-secret keys to also inject at build time (Docker build args).
3670
3824
  // Runtime secret values live in AWS Secrets Manager, never in this document.
3671
- build_secrets: z15.array(z15.string()).default([]),
3672
- port: z15.number().int().positive(),
3825
+ build_secrets: z16.array(z16.string()).default([]),
3826
+ port: z16.number().int().positive(),
3673
3827
  // Non-secret variables wired to the topology, resolved at deploy time.
3674
3828
  // All user-typed values are secrets (AWS), so they never appear here.
3675
- connections: z15.array(connectionSchema).default([]),
3676
- command: z15.string().optional(),
3677
- health_check: z15.string().optional(),
3678
- primary: z15.boolean().optional(),
3679
- // This app serves the Environment Factory handler (`/api/autonoma`), so
3680
- // scenario up/down calls go to its preview URL. Independent of `primary`:
3681
- // a full-stack app (Next.js, Rails) is both the browsed frontend and the
3682
- // SDK host, while a split topology mounts the handler on its API service.
3683
- sdk_implemented: z15.boolean().optional(),
3829
+ connections: z16.array(connectionSchema).default([]),
3830
+ command: z16.string().optional(),
3831
+ health_check: z16.string().optional(),
3832
+ primary: z16.boolean().optional(),
3833
+ // This app serves the Environment Factory handler, so scenario up/down
3834
+ // calls go to its preview URL. Independent of `primary`: a full-stack app
3835
+ // (Next.js, Rails) is both the browsed frontend and the SDK host, while a
3836
+ // split topology mounts the handler on its API service.
3837
+ sdk_implemented: z16.boolean().optional(),
3838
+ // Where on that app the handler is mounted. Deliberately NO `.default()`:
3839
+ // absent has to stay distinguishable from an explicit `/api/autonoma`,
3840
+ // because it is what tells a caller to leave an already-stored endpoint
3841
+ // URL alone (see `applySdkPath`). Give it a default and every endpoint a
3842
+ // customer registered by hand at another path gets rewritten to the
3843
+ // convention.
3844
+ sdk_path: z16.string().regex(
3845
+ SDK_PATH_PATTERN,
3846
+ `Must be an absolute path with no query or fragment, like "${DEFAULT_SDK_PATH}"`
3847
+ ).optional(),
3684
3848
  resources: buildResourcesSchema("app", allowCustomResources),
3685
- depends_on: z15.array(z15.string()).optional()
3849
+ depends_on: z16.array(z16.string()).optional()
3686
3850
  }).superRefine((app, ctx) => {
3687
3851
  if (app.build != null && app.blueprint != null) {
3688
3852
  ctx.addIssue({
3689
- code: z15.ZodIssueCode.custom,
3853
+ code: z16.ZodIssueCode.custom,
3690
3854
  message: "an app cannot set both `build` and `blueprint` - `blueprint` is the preset-based deploy model, `build` is the manual one",
3691
3855
  path: ["blueprint"]
3692
3856
  });
3693
3857
  }
3694
3858
  });
3695
- const serviceSchema = z15.object({
3696
- name: z15.string().regex(k8sNameRegex, "Must be a valid Kubernetes name"),
3697
- recipe: z15.string(),
3698
- version: z15.string().optional(),
3859
+ const serviceSchema = z16.object({
3860
+ name: z16.string().regex(k8sNameRegex, "Must be a valid Kubernetes name"),
3861
+ recipe: z16.string(),
3862
+ version: z16.string().optional(),
3699
3863
  // Recipe-functional knobs (e.g. postgres user/database, or a docker-image
3700
3864
  // service's image/ports/env) live in `options`, validated per-recipe.
3701
- options: z15.record(z15.string(), z15.unknown()).default({}),
3865
+ options: z16.record(z16.string(), z16.unknown()).default({}),
3702
3866
  // Guided setup for database-recipe services (schema, seed, migrations),
3703
3867
  // run with the repo checked out. Empty for non-database services.
3704
- setup_tasks: z15.array(databaseSetupTaskSchema).default([]),
3868
+ setup_tasks: z16.array(databaseSetupTaskSchema).default([]),
3705
3869
  resources: buildResourcesSchema("service", allowCustomResources),
3706
- s3: z15.boolean().optional(),
3707
- sqs: z15.boolean().optional(),
3708
- sns: z15.boolean().optional()
3870
+ s3: z16.boolean().optional(),
3871
+ sqs: z16.boolean().optional(),
3872
+ sns: z16.boolean().optional()
3709
3873
  });
3710
- return z15.object({
3711
- version: z15.literal(2),
3712
- domain: z15.string().optional(),
3713
- registry: z15.string().optional(),
3874
+ return z16.object({
3875
+ version: z16.literal(PREVIEW_CONFIG_VERSION),
3876
+ domain: z16.string().optional(),
3877
+ registry: z16.string().optional(),
3714
3878
  // Per-repository overrides + deploy provenance; the repo set itself
3715
3879
  // is derived from `apps[].repository`. See repositorySettingsSchema.
3716
- repositories: z15.array(repositorySettingsSchema).default([]).describe(
3880
+ repositories: z16.array(repositorySettingsSchema).default([]).describe(
3717
3881
  "Optional per-repository settings. The topology's repositories are derived from apps[].repository - an entry here only overrides defaults (fallback_branch: which branch to clone when the PR's branch does not exist in that repo; default main)."
3718
3882
  ),
3719
3883
  // Topology-wide: how a dependency repo's branch is derived from the
@@ -3721,8 +3885,8 @@ function buildPreviewConfigSchema(build, allowCustomResources) {
3721
3885
  branch_convention: branchConventionSchema.optional().describe(
3722
3886
  "How a dependency repo's branch is derived from the PR branch: same_branch_name (default), regex (pattern + replacement rewrite), or manual (always the fallback_branch)."
3723
3887
  ),
3724
- apps: z15.array(appSchema).min(1, "At least one app is required"),
3725
- services: z15.array(serviceSchema).default([]),
3888
+ apps: z16.array(appSchema).min(1, "At least one app is required"),
3889
+ services: z16.array(serviceSchema).default([]),
3726
3890
  hooks: hooksSchema
3727
3891
  }).superRefine((cfg, ctx) => {
3728
3892
  const seen = /* @__PURE__ */ new Map();
@@ -3730,7 +3894,7 @@ function buildPreviewConfigSchema(build, allowCustomResources) {
3730
3894
  const existing = seen.get(name);
3731
3895
  if (existing != null) {
3732
3896
  ctx.addIssue({
3733
- code: z15.ZodIssueCode.custom,
3897
+ code: z16.ZodIssueCode.custom,
3734
3898
  message: `Name "${name}" is used by both a ${existing} and an ${kind} - names must be unique across apps and services`
3735
3899
  });
3736
3900
  return;
@@ -3744,7 +3908,7 @@ function buildPreviewConfigSchema(build, allowCustomResources) {
3744
3908
  const key = settings.repo.toLowerCase();
3745
3909
  if (seenRepos.has(key)) {
3746
3910
  ctx.addIssue({
3747
- code: z15.ZodIssueCode.custom,
3911
+ code: z16.ZodIssueCode.custom,
3748
3912
  path: ["repositories", index, "repo"],
3749
3913
  message: `Repository "${settings.repo}" has more than one settings entry`
3750
3914
  });
@@ -3761,11 +3925,12 @@ function standardResources(role) {
3761
3925
  memoryLimit: standard.memoryLimit
3762
3926
  };
3763
3927
  }
3764
- var STANDARD_RESOURCES, k8sNameRegex, repoFullNameRegex, resourcesInput, branchConventionSchema, repositorySettingsSchema, hookStepSchema, hooksSchema, databaseSetupLocationSchema, databaseSetupTaskSchema, nodeVersionRegex, buildContextSchema, PREVIEWKIT_BUILD_SCRIPT_HEREDOC, imageTagSchema, DEPRECATED_BUILD_FRAMEWORKS, UNSUPPORTED_BUILD_METHOD_MESSAGE, deprecatedBuildArms, authoredBuildArms, authoredBuildSchema, storedBuildSchema, presetBlueprintSchema, dockerfileBlueprintSchema, blueprintSchema, connectionSchema, previewConfigSchema, trustedPreviewConfigSchema, authoringPreviewConfigSchema;
3928
+ var STANDARD_RESOURCES, PREVIEW_CONFIG_VERSION, k8sNameRegex, SDK_PATH_PATTERN, repoFullNameRegex, DEFAULT_DEPENDENCY_FALLBACK_BRANCH, resourcesInput, branchConventionSchema, repositorySettingsSchema, hookStepSchema, hooksSchema, databaseSetupLocationSchema, databaseSetupTaskSchema, nodeVersionRegex, buildContextSchema, PREVIEWKIT_BUILD_SCRIPT_HEREDOC, imageTagSchema, DEPRECATED_BUILD_FRAMEWORKS, UNSUPPORTED_BUILD_METHOD_MESSAGE, deprecatedBuildArms, authoredBuildArms, authoredBuildSchema, storedBuildSchema, presetBlueprintSchema, dockerfileBlueprintSchema, blueprintSchema, connectionSchema, previewConfigSchema, trustedPreviewConfigSchema, authoringPreviewConfigSchema, appRoleSchema, sdkPathDocumentSchema;
3765
3929
  var init_previewkit_config = __esm({
3766
3930
  "../../packages/types/src/schemas/previewkit-config.ts"() {
3767
3931
  "use strict";
3768
3932
  init_esm_shims();
3933
+ init_sdk_endpoint();
3769
3934
  init_previewkit_builtins();
3770
3935
  init_previewkit_node_pm();
3771
3936
  init_previewkit_presets();
@@ -3775,19 +3940,22 @@ var init_previewkit_config = __esm({
3775
3940
  app: { cpu: "250m", memoryRequest: "512Mi", memoryLimit: "1Gi" },
3776
3941
  service: { cpu: "100m", memoryRequest: "256Mi", memoryLimit: "1Gi" }
3777
3942
  };
3943
+ PREVIEW_CONFIG_VERSION = 2;
3778
3944
  k8sNameRegex = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
3945
+ SDK_PATH_PATTERN = /^\/[^\s?#]*$/;
3779
3946
  repoFullNameRegex = /^[^/\s]+\/[^/\s]+$/;
3780
- resourcesInput = z15.object({
3781
- cpu: z15.string().optional(),
3782
- memory: z15.string().optional(),
3783
- memoryRequest: z15.string().optional(),
3784
- memoryLimit: z15.string().optional()
3947
+ DEFAULT_DEPENDENCY_FALLBACK_BRANCH = "main";
3948
+ resourcesInput = z16.object({
3949
+ cpu: z16.string().optional(),
3950
+ memory: z16.string().optional(),
3951
+ memoryRequest: z16.string().optional(),
3952
+ memoryLimit: z16.string().optional()
3785
3953
  }).optional();
3786
- branchConventionSchema = z15.discriminatedUnion("type", [
3787
- z15.object({ type: z15.literal("same_branch_name") }),
3788
- z15.object({
3789
- type: z15.literal("regex"),
3790
- pattern: z15.string().refine((pattern) => {
3954
+ branchConventionSchema = z16.discriminatedUnion("type", [
3955
+ z16.object({ type: z16.literal("same_branch_name") }),
3956
+ z16.object({
3957
+ type: z16.literal("regex"),
3958
+ pattern: z16.string().refine((pattern) => {
3791
3959
  try {
3792
3960
  new RegExp(pattern);
3793
3961
  return true;
@@ -3795,13 +3963,13 @@ var init_previewkit_config = __esm({
3795
3963
  return false;
3796
3964
  }
3797
3965
  }, "Invalid regular expression pattern"),
3798
- replacement: z15.string()
3966
+ replacement: z16.string()
3799
3967
  }),
3800
- z15.object({ type: z15.literal("manual") })
3968
+ z16.object({ type: z16.literal("manual") })
3801
3969
  ]);
3802
- repositorySettingsSchema = z15.object({
3803
- repo: z15.string().regex(repoFullNameRegex, "Must be an owner/repo full name"),
3804
- fallback_branch: z15.string().default("main"),
3970
+ repositorySettingsSchema = z16.object({
3971
+ repo: z16.string().regex(repoFullNameRegex, "Must be an owner/repo full name"),
3972
+ fallback_branch: z16.string().default(DEFAULT_DEPENDENCY_FALLBACK_BRANCH),
3805
3973
  /**
3806
3974
  * The concrete commit SHA the repository was deployed at. Absent in
3807
3975
  * user-authored config: previewkit resolves each dependency repo's branch to
@@ -3809,60 +3977,60 @@ var init_previewkit_config = __esm({
3809
3977
  * `resolvedConfig` (deploy provenance, not authored input). Multi-repo
3810
3978
  * grounding reads this back to inspect the exact code that was live.
3811
3979
  */
3812
- sha: z15.string().optional()
3980
+ sha: z16.string().optional()
3813
3981
  });
3814
- hookStepSchema = z15.object({
3815
- app: z15.string(),
3816
- command: z15.string()
3982
+ hookStepSchema = z16.object({
3983
+ app: z16.string(),
3984
+ command: z16.string()
3817
3985
  });
3818
- hooksSchema = z15.object({
3819
- pre_deploy: z15.array(hookStepSchema).default([]),
3820
- post_deploy: z15.array(hookStepSchema).default([])
3986
+ hooksSchema = z16.object({
3987
+ pre_deploy: z16.array(hookStepSchema).default([]),
3988
+ post_deploy: z16.array(hookStepSchema).default([])
3821
3989
  }).default({ pre_deploy: [], post_deploy: [] });
3822
- databaseSetupLocationSchema = z15.discriminatedUnion("type", [
3823
- z15.object({
3824
- type: z15.literal("in_build"),
3825
- app: z15.string().min(1, "an app is required for an in-build task"),
3826
- position: z15.enum(["before", "after"])
3990
+ databaseSetupLocationSchema = z16.discriminatedUnion("type", [
3991
+ z16.object({
3992
+ type: z16.literal("in_build"),
3993
+ app: z16.string().min(1, "an app is required for an in-build task"),
3994
+ position: z16.enum(["before", "after"])
3827
3995
  }),
3828
- z15.object({
3829
- type: z15.literal("separate_job"),
3830
- repo: z15.string().optional()
3996
+ z16.object({
3997
+ type: z16.literal("separate_job"),
3998
+ repo: z16.string().optional()
3831
3999
  })
3832
4000
  ]);
3833
- databaseSetupTaskSchema = z15.object({
3834
- command: z15.string(),
3835
- frequency: z15.enum(["on_create", "every_commit"]),
4001
+ databaseSetupTaskSchema = z16.object({
4002
+ command: z16.string(),
4003
+ frequency: z16.enum(["on_create", "every_commit"]),
3836
4004
  location: databaseSetupLocationSchema
3837
4005
  });
3838
4006
  nodeVersionRegex = /^\d+(\.\d+)?(\.\d+)?$/;
3839
- buildContextSchema = z15.enum(["app", "root"]).default("app");
4007
+ buildContextSchema = z16.enum(["app", "root"]).default("app");
3840
4008
  PREVIEWKIT_BUILD_SCRIPT_HEREDOC = "AUTONOMA_BUILD_EOF";
3841
- imageTagSchema = z15.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/, "must be a valid image tag");
4009
+ imageTagSchema = z16.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/, "must be a valid image tag");
3842
4010
  DEPRECATED_BUILD_FRAMEWORKS = ["node", "next", "vite", "bun"];
3843
4011
  UNSUPPORTED_BUILD_METHOD_MESSAGE = `Unsupported build method. Use "runtime" (pick a runtime, then write a bash build_script and a single-line entrypoint) or "dockerfile" (build a Dockerfile committed in the repo). The ${DEPRECATED_BUILD_FRAMEWORKS.join(" / ")} framework presets are retired and can no longer be saved - express them as "runtime" with the install and build commands in build_script and the start command as entrypoint.`;
3844
4012
  deprecatedBuildArms = [
3845
4013
  nodeFrameworkBuildSchema("node"),
3846
4014
  nodeFrameworkBuildSchema("next"),
3847
4015
  nodeFrameworkBuildSchema("vite"),
3848
- z15.object({
3849
- framework: z15.literal("bun"),
3850
- install_command: z15.string().min(1).optional(),
3851
- build_command: z15.string().min(1).optional(),
3852
- run_command: z15.string().min(1).optional(),
4016
+ z16.object({
4017
+ framework: z16.literal("bun"),
4018
+ install_command: z16.string().min(1).optional(),
4019
+ build_command: z16.string().min(1).optional(),
4020
+ run_command: z16.string().min(1).optional(),
3853
4021
  build_context: buildContextSchema
3854
4022
  })
3855
4023
  ];
3856
4024
  authoredBuildArms = [
3857
- z15.object({
3858
- framework: z15.literal("dockerfile"),
3859
- dockerfile: z15.string().min(1, "dockerfile path is required"),
3860
- target: z15.string().min(1).optional(),
4025
+ z16.object({
4026
+ framework: z16.literal("dockerfile"),
4027
+ dockerfile: z16.string().min(1, "dockerfile path is required"),
4028
+ target: z16.string().min(1).optional(),
3861
4029
  build_context: buildContextSchema
3862
4030
  }),
3863
- z15.object({
3864
- framework: z15.literal("runtime"),
3865
- runtime: z15.enum(PREVIEWKIT_RUNTIME_IDS),
4031
+ z16.object({
4032
+ framework: z16.literal("runtime"),
4033
+ runtime: z16.enum(PREVIEWKIT_RUNTIME_IDS),
3866
4034
  // Image tag version, e.g. "22" for node. Optional - defaults to the
3867
4035
  // catalog's default per runtime. The user picks it so a repo pinned to an
3868
4036
  // older toolchain is not forced onto our default (which would defeat the
@@ -3879,12 +4047,12 @@ var init_previewkit_config = __esm({
3879
4047
  build_context: buildContextSchema
3880
4048
  })
3881
4049
  ];
3882
- authoredBuildSchema = z15.discriminatedUnion("framework", authoredBuildArms, {
4050
+ authoredBuildSchema = z16.discriminatedUnion("framework", authoredBuildArms, {
3883
4051
  error: () => UNSUPPORTED_BUILD_METHOD_MESSAGE
3884
4052
  });
3885
- storedBuildSchema = z15.discriminatedUnion("framework", [...authoredBuildArms, ...deprecatedBuildArms]);
3886
- presetBlueprintSchema = z15.object({
3887
- preset: z15.enum(PREVIEWKIT_PRESET_IDS),
4053
+ storedBuildSchema = z16.discriminatedUnion("framework", [...authoredBuildArms, ...deprecatedBuildArms]);
4054
+ presetBlueprintSchema = z16.object({
4055
+ preset: z16.enum(PREVIEWKIT_PRESET_IDS),
3888
4056
  // Overridable per app; each defaults from the preset (version from the runtime catalog).
3889
4057
  version: imageTagSchema.optional(),
3890
4058
  // These overrides flow into the generated Dockerfile via blueprintToBuild, so they
@@ -3904,82 +4072,98 @@ var init_previewkit_config = __esm({
3904
4072
  const toolchain = previewkitPresetSpec(blueprint.preset).toolchain;
3905
4073
  if (toolchain === "node" && blueprint.version != null && !nodeVersionRegex.test(blueprint.version)) {
3906
4074
  ctx.addIssue({
3907
- code: z15.ZodIssueCode.custom,
4075
+ code: z16.ZodIssueCode.custom,
3908
4076
  message: "version must look like 22, 22.5, or 22.5.0 for a node preset",
3909
4077
  path: ["version"]
3910
4078
  });
3911
4079
  }
3912
4080
  });
3913
- dockerfileBlueprintSchema = z15.object({
4081
+ dockerfileBlueprintSchema = z16.object({
3914
4082
  // Path to a committed Dockerfile, built as-is - ALWAYS relative to the app dir,
3915
4083
  // whatever the build context (the pipeline resolves it against the context).
3916
4084
  // `target` selects a stage in a multi-stage build.
3917
- dockerfile: z15.string().min(1, "dockerfile path is required"),
3918
- target: z15.string().min(1).optional(),
4085
+ dockerfile: z16.string().min(1, "dockerfile path is required"),
4086
+ target: z16.string().min(1).optional(),
3919
4087
  // Monorepo: `root` builds from the repo root (so a workspace-aware Dockerfile can reach
3920
4088
  // sibling packages); `app` (absent) builds from the app dir.
3921
4089
  build_context: buildContextSchema.removeDefault().optional()
3922
4090
  }).strict();
3923
- blueprintSchema = z15.union([presetBlueprintSchema, dockerfileBlueprintSchema]);
3924
- connectionSchema = z15.object({
4091
+ blueprintSchema = z16.union([presetBlueprintSchema, dockerfileBlueprintSchema]);
4092
+ connectionSchema = z16.object({
3925
4093
  key: SecretKeySchema.superRefine((key, ctx) => {
3926
4094
  if (isReservedPreviewkitEnvKey(key)) {
3927
4095
  ctx.addIssue({
3928
- code: z15.ZodIssueCode.custom,
4096
+ code: z16.ZodIssueCode.custom,
3929
4097
  message: `${key} is a reserved built-in variable and cannot be set.`
3930
4098
  });
3931
4099
  }
3932
4100
  }).describe("The env var name to inject into the app at runtime (e.g. DATABASE_URL)."),
3933
- value: z15.string().min(1, "value is required").describe(
4101
+ value: z16.string().min(1, "value is required").describe(
3934
4102
  "Template resolved at deploy time. {{name.property}} tokens reference apps/services in this config by name. For a service: {{db.url}} = the full canonical connection string (postgres -> postgresql://preview:preview@<host>:<port>/preview; redis -> redis://...; mongodb -> mongodb://...), {{db.host}} = in-cluster DNS name, {{db.port}}. For an app: {{api.url}} = its public HTTPS URL, {{api.hostname}}. Also available: {{pr}}, {{namespace}}, {{owner}}. Tokens can mix with literal text ('postgresql://user:pass@{{db.host}}:5432/mydb'), or be a plain literal ('production'). Prefer {{db.url}} to wire a database."
3935
4103
  ),
3936
- build_time: z15.boolean().default(false).describe("Also pass the resolved value as a Docker build arg.")
4104
+ build_time: z16.boolean().default(false).describe("Also pass the resolved value as a Docker build arg.")
3937
4105
  });
3938
4106
  previewConfigSchema = buildPreviewConfigSchema(storedBuildSchema, false);
3939
4107
  trustedPreviewConfigSchema = buildPreviewConfigSchema(storedBuildSchema, true);
3940
4108
  authoringPreviewConfigSchema = buildPreviewConfigSchema(authoredBuildSchema, false);
4109
+ appRoleSchema = z16.object({
4110
+ name: z16.string(),
4111
+ primary: z16.boolean().nullish(),
4112
+ sdk_implemented: z16.boolean().nullish(),
4113
+ sdk_path: z16.string().nullish()
4114
+ });
4115
+ sdkPathDocumentSchema = z16.object({ apps: z16.array(appRoleSchema) });
4116
+ }
4117
+ });
4118
+
4119
+ // ../../packages/types/src/schemas/previewkit-config-rows.ts
4120
+ var init_previewkit_config_rows = __esm({
4121
+ "../../packages/types/src/schemas/previewkit-config-rows.ts"() {
4122
+ "use strict";
4123
+ init_esm_shims();
4124
+ init_previewkit_config();
3941
4125
  }
3942
4126
  });
3943
4127
 
3944
4128
  // ../../packages/types/src/schemas/previewkit-job-spec.ts
3945
- import { z as z16 } from "zod";
4129
+ import { z as z17 } from "zod";
3946
4130
  var deployTargetSchema, redeployTargetSchema, teardownTargetSchema, previewJobSpecSchema;
3947
4131
  var init_previewkit_job_spec = __esm({
3948
4132
  "../../packages/types/src/schemas/previewkit-job-spec.ts"() {
3949
4133
  "use strict";
3950
4134
  init_esm_shims();
3951
- deployTargetSchema = z16.object({
3952
- repoFullName: z16.string().min(1),
3953
- prNumber: z16.number().int().nonnegative(),
3954
- organizationId: z16.string().min(1),
3955
- githubRepositoryId: z16.number().int(),
3956
- headSha: z16.string().min(1),
3957
- headRef: z16.string().min(1),
3958
- branchId: z16.string().optional()
4135
+ deployTargetSchema = z17.object({
4136
+ repoFullName: z17.string().min(1),
4137
+ prNumber: z17.number().int().nonnegative(),
4138
+ organizationId: z17.string().min(1),
4139
+ githubRepositoryId: z17.number().int(),
4140
+ headSha: z17.string().min(1),
4141
+ headRef: z17.string().min(1),
4142
+ branchId: z17.string().optional()
3959
4143
  });
3960
- redeployTargetSchema = z16.object({
3961
- repoFullName: z16.string().min(1),
3962
- prNumber: z16.number().int().nonnegative(),
3963
- organizationId: z16.string().min(1),
3964
- githubRepositoryId: z16.number().int(),
3965
- headSha: z16.string().min(1),
3966
- headRef: z16.string().min(1)
4144
+ redeployTargetSchema = z17.object({
4145
+ repoFullName: z17.string().min(1),
4146
+ prNumber: z17.number().int().nonnegative(),
4147
+ organizationId: z17.string().min(1),
4148
+ githubRepositoryId: z17.number().int(),
4149
+ headSha: z17.string().min(1),
4150
+ headRef: z17.string().min(1)
3967
4151
  });
3968
- teardownTargetSchema = z16.object({
3969
- repoFullName: z16.string().min(1),
3970
- prNumber: z16.number().int().nonnegative(),
3971
- organizationId: z16.string().min(1),
3972
- headSha: z16.string().min(1).optional()
4152
+ teardownTargetSchema = z17.object({
4153
+ repoFullName: z17.string().min(1),
4154
+ prNumber: z17.number().int().nonnegative(),
4155
+ organizationId: z17.string().min(1),
4156
+ headSha: z17.string().min(1).optional()
3973
4157
  });
3974
- previewJobSpecSchema = z16.discriminatedUnion("mode", [
3975
- z16.object({ mode: z16.literal("deploy"), target: deployTargetSchema }),
3976
- z16.object({ mode: z16.literal("teardown"), target: teardownTargetSchema }),
3977
- z16.object({
3978
- mode: z16.literal("redeploy-app"),
4158
+ previewJobSpecSchema = z17.discriminatedUnion("mode", [
4159
+ z17.object({ mode: z17.literal("deploy"), target: deployTargetSchema }),
4160
+ z17.object({ mode: z17.literal("teardown"), target: teardownTargetSchema }),
4161
+ z17.object({
4162
+ mode: z17.literal("redeploy-app"),
3979
4163
  target: redeployTargetSchema,
3980
- namespace: z16.string().min(1),
3981
- appName: z16.string().min(1),
3982
- redeployMode: z16.enum(["rebuild", "restart"])
4164
+ namespace: z17.string().min(1),
4165
+ appName: z17.string().min(1),
4166
+ redeployMode: z17.enum(["rebuild", "restart"])
3983
4167
  })
3984
4168
  ]);
3985
4169
  }
@@ -4004,29 +4188,29 @@ var init_previewkit_authorable_config = __esm({
4004
4188
  });
4005
4189
 
4006
4190
  // ../../packages/types/src/schemas/previewkit-redeploy-app.ts
4007
- import { z as z17 } from "zod";
4191
+ import { z as z18 } from "zod";
4008
4192
  var RedeployPreviewkitAppInputSchema;
4009
4193
  var init_previewkit_redeploy_app = __esm({
4010
4194
  "../../packages/types/src/schemas/previewkit-redeploy-app.ts"() {
4011
4195
  "use strict";
4012
4196
  init_esm_shims();
4013
- RedeployPreviewkitAppInputSchema = z17.object({
4014
- applicationId: z17.string().min(1),
4015
- environmentId: z17.string().min(1),
4016
- app: z17.string().min(1),
4017
- mode: z17.enum(["rebuild", "restart"])
4197
+ RedeployPreviewkitAppInputSchema = z18.object({
4198
+ applicationId: z18.string().min(1),
4199
+ environmentId: z18.string().min(1),
4200
+ app: z18.string().min(1),
4201
+ mode: z18.enum(["rebuild", "restart"])
4018
4202
  });
4019
4203
  }
4020
4204
  });
4021
4205
 
4022
4206
  // ../../packages/types/src/schemas/previewkit-service-suggestion.ts
4023
- import { z as z18 } from "zod";
4207
+ import { z as z19 } from "zod";
4024
4208
  var SuggestableServiceRecipeSchema, SuggestionAppRefSchema, SuggestServicesInputSchema, SuggestedServiceSchema, SuggestServicesResultSchema;
4025
4209
  var init_previewkit_service_suggestion = __esm({
4026
4210
  "../../packages/types/src/schemas/previewkit-service-suggestion.ts"() {
4027
4211
  "use strict";
4028
4212
  init_esm_shims();
4029
- SuggestableServiceRecipeSchema = z18.enum([
4213
+ SuggestableServiceRecipeSchema = z19.enum([
4030
4214
  "postgres",
4031
4215
  "redis",
4032
4216
  "valkey",
@@ -4035,144 +4219,133 @@ var init_previewkit_service_suggestion = __esm({
4035
4219
  "temporal",
4036
4220
  "docker-image"
4037
4221
  ]);
4038
- SuggestionAppRefSchema = z18.object({
4039
- name: z18.string(),
4040
- path: z18.string(),
4041
- primary: z18.boolean().optional()
4222
+ SuggestionAppRefSchema = z19.object({
4223
+ name: z19.string(),
4224
+ path: z19.string(),
4225
+ primary: z19.boolean().optional()
4042
4226
  });
4043
- SuggestServicesInputSchema = z18.object({
4044
- applicationId: z18.string(),
4045
- githubRepositoryId: z18.number().int().positive().optional(),
4046
- apps: z18.array(SuggestionAppRefSchema)
4227
+ SuggestServicesInputSchema = z19.object({
4228
+ applicationId: z19.string(),
4229
+ githubRepositoryId: z19.number().int().positive().optional(),
4230
+ apps: z19.array(SuggestionAppRefSchema)
4047
4231
  });
4048
- SuggestedServiceSchema = z18.object({
4232
+ SuggestedServiceSchema = z19.object({
4049
4233
  recipe: SuggestableServiceRecipeSchema,
4050
- name: z18.string(),
4051
- version: z18.string().optional(),
4052
- confidence: z18.enum(["high", "medium", "low"]),
4053
- evidence: z18.array(z18.string())
4234
+ name: z19.string(),
4235
+ version: z19.string().optional(),
4236
+ confidence: z19.enum(["high", "medium", "low"]),
4237
+ evidence: z19.array(z19.string())
4054
4238
  });
4055
- SuggestServicesResultSchema = z18.object({
4056
- status: z18.enum(["ok", "unavailable"]),
4057
- reason: z18.string().optional(),
4058
- services: z18.array(SuggestedServiceSchema)
4239
+ SuggestServicesResultSchema = z19.object({
4240
+ status: z19.enum(["ok", "unavailable"]),
4241
+ reason: z19.string().optional(),
4242
+ services: z19.array(SuggestedServiceSchema)
4059
4243
  });
4060
4244
  }
4061
4245
  });
4062
4246
 
4063
4247
  // ../../packages/types/src/schemas/previewkit-env-suggestion.ts
4064
- import { z as z19 } from "zod";
4248
+ import { z as z20 } from "zod";
4065
4249
  var SuggestionServiceRefSchema, SuggestEnvVarsInputSchema, SuggestedEnvVarSchema, SuggestedEnvGroupSchema, SuggestEnvVarsResultSchema;
4066
4250
  var init_previewkit_env_suggestion = __esm({
4067
4251
  "../../packages/types/src/schemas/previewkit-env-suggestion.ts"() {
4068
4252
  "use strict";
4069
4253
  init_esm_shims();
4070
4254
  init_previewkit_service_suggestion();
4071
- SuggestionServiceRefSchema = z19.object({
4072
- name: z19.string(),
4255
+ SuggestionServiceRefSchema = z20.object({
4256
+ name: z20.string(),
4073
4257
  recipe: SuggestableServiceRecipeSchema
4074
4258
  });
4075
- SuggestEnvVarsInputSchema = z19.object({
4076
- applicationId: z19.string(),
4077
- githubRepositoryId: z19.number().int().positive().optional(),
4078
- apps: z19.array(SuggestionAppRefSchema),
4079
- services: z19.array(SuggestionServiceRefSchema)
4259
+ SuggestEnvVarsInputSchema = z20.object({
4260
+ applicationId: z20.string(),
4261
+ githubRepositoryId: z20.number().int().positive().optional(),
4262
+ apps: z20.array(SuggestionAppRefSchema),
4263
+ services: z20.array(SuggestionServiceRefSchema)
4080
4264
  });
4081
- SuggestedEnvVarSchema = z19.object({
4082
- key: z19.string(),
4083
- value: z19.string().optional(),
4084
- reference: z19.string().optional(),
4085
- sensitive: z19.boolean(),
4265
+ SuggestedEnvVarSchema = z20.object({
4266
+ key: z20.string(),
4267
+ value: z20.string().optional(),
4268
+ reference: z20.string().optional(),
4269
+ sensitive: z20.boolean(),
4086
4270
  /**
4087
4271
  * Whether the value must be present during the image BUILD (not just at
4088
4272
  * runtime) - e.g. framework vars inlined into the client bundle
4089
4273
  * (`NEXT_PUBLIC_*`, `VITE_*`) or values read by the build/install command.
4090
4274
  * Maps to the row's "also inject at build time" switch. Omitted = runtime-only.
4091
4275
  */
4092
- build_time: z19.boolean().optional(),
4093
- description: z19.string().optional(),
4094
- confidence: z19.enum(["high", "medium", "low"]),
4095
- evidence: z19.array(z19.string())
4276
+ build_time: z20.boolean().optional(),
4277
+ description: z20.string().optional(),
4278
+ confidence: z20.enum(["high", "medium", "low"]),
4279
+ evidence: z20.array(z20.string())
4096
4280
  });
4097
- SuggestedEnvGroupSchema = z19.object({
4098
- name: z19.string(),
4099
- vars: z19.array(SuggestedEnvVarSchema)
4281
+ SuggestedEnvGroupSchema = z20.object({
4282
+ name: z20.string(),
4283
+ vars: z20.array(SuggestedEnvVarSchema)
4100
4284
  });
4101
- SuggestEnvVarsResultSchema = z19.object({
4102
- status: z19.enum(["ok", "unavailable"]),
4103
- reason: z19.string().optional(),
4104
- apps: z19.array(SuggestedEnvGroupSchema),
4105
- services: z19.array(SuggestedEnvGroupSchema)
4285
+ SuggestEnvVarsResultSchema = z20.object({
4286
+ status: z20.enum(["ok", "unavailable"]),
4287
+ reason: z20.string().optional(),
4288
+ apps: z20.array(SuggestedEnvGroupSchema),
4289
+ services: z20.array(SuggestedEnvGroupSchema)
4106
4290
  });
4107
4291
  }
4108
4292
  });
4109
4293
 
4110
4294
  // ../../packages/types/src/schemas/previewkit-diagnosis.ts
4111
- import { z as z20 } from "zod";
4112
- var DiagnosePreviewkitDeployInputSchema, PreviewDiagnosisCategorySchema, PreviewDiagnosisActionSchema, PreviewDiagnosisFindingSchema, DiagnosePreviewkitDeployResultSchema, AiDiagnosisResultSchema;
4295
+ import { z as z21 } from "zod";
4296
+ var DiagnosePreviewkitDeployInputSchema, PreviewDiagnosisCategorySchema, PreviewDiagnosisActionSchema, PreviewDiagnosisFindingSchema;
4113
4297
  var init_previewkit_diagnosis = __esm({
4114
4298
  "../../packages/types/src/schemas/previewkit-diagnosis.ts"() {
4115
4299
  "use strict";
4116
4300
  init_esm_shims();
4117
4301
  init_previewkit_env_suggestion();
4118
- DiagnosePreviewkitDeployInputSchema = z20.object({
4119
- applicationId: z20.string(),
4302
+ DiagnosePreviewkitDeployInputSchema = z21.object({
4303
+ applicationId: z21.string(),
4120
4304
  /**
4121
4305
  * Which preview environment to diagnose. Omitted defaults (in the service) to
4122
- * 0 - the main-branch (onboarding) preview - so the original onboarding caller
4123
- * is unchanged; MCP / per-PR callers pass the real PR number.
4306
+ * 0 - the main-branch preview; per-PR callers pass the real PR number.
4124
4307
  */
4125
- prNumber: z20.number().int().min(0).optional(),
4126
- deployFingerprint: z20.string().optional()
4308
+ prNumber: z21.number().int().min(0).optional(),
4309
+ deployFingerprint: z21.string().optional()
4127
4310
  });
4128
- PreviewDiagnosisCategorySchema = z20.enum(["missing_env_var", "user_setup", "autonoma_error", "unknown"]);
4129
- PreviewDiagnosisActionSchema = z20.enum(["edit_config", "edit_secrets", "redeploy", "contact_support"]);
4130
- PreviewDiagnosisFindingSchema = z20.object({
4311
+ PreviewDiagnosisCategorySchema = z21.enum(["missing_env_var", "user_setup", "autonoma_error", "unknown"]);
4312
+ PreviewDiagnosisActionSchema = z21.enum(["edit_config", "edit_secrets", "redeploy", "contact_support"]);
4313
+ PreviewDiagnosisFindingSchema = z21.object({
4131
4314
  category: PreviewDiagnosisCategorySchema,
4132
- severity: z20.enum(["blocking", "warning", "info"]),
4133
- title: z20.string(),
4134
- explanation: z20.string(),
4135
- fixSteps: z20.array(z20.string()),
4136
- appName: z20.string().optional(),
4137
- fieldPath: z20.string().optional(),
4315
+ severity: z21.enum(["blocking", "warning", "info"]),
4316
+ title: z21.string(),
4317
+ explanation: z21.string(),
4318
+ fixSteps: z21.array(z21.string()),
4319
+ appName: z21.string().optional(),
4320
+ fieldPath: z21.string().optional(),
4138
4321
  action: PreviewDiagnosisActionSchema.optional(),
4139
- suggestedEnv: z20.array(SuggestedEnvVarSchema).optional(),
4140
- confidence: z20.enum(["high", "medium", "low"]),
4141
- evidence: z20.array(z20.string())
4142
- });
4143
- DiagnosePreviewkitDeployResultSchema = z20.object({
4144
- status: z20.enum(["ok", "unavailable"]),
4145
- reason: z20.string().optional(),
4146
- summary: z20.string().optional(),
4147
- findings: z20.array(PreviewDiagnosisFindingSchema)
4148
- });
4149
- AiDiagnosisResultSchema = z20.object({
4150
- summary: z20.string(),
4151
- findings: z20.array(PreviewDiagnosisFindingSchema)
4322
+ suggestedEnv: z21.array(SuggestedEnvVarSchema).optional(),
4323
+ confidence: z21.enum(["high", "medium", "low"]),
4324
+ evidence: z21.array(z21.string())
4152
4325
  });
4153
4326
  }
4154
4327
  });
4155
4328
 
4156
4329
  // ../../packages/types/src/schemas/snapshot-dependency-pin.ts
4157
- import { z as z21 } from "zod";
4330
+ import { z as z22 } from "zod";
4158
4331
  var snapshotDependencyShaMapSchema;
4159
4332
  var init_snapshot_dependency_pin = __esm({
4160
4333
  "../../packages/types/src/schemas/snapshot-dependency-pin.ts"() {
4161
4334
  "use strict";
4162
4335
  init_esm_shims();
4163
- snapshotDependencyShaMapSchema = z21.record(z21.string(), z21.string());
4336
+ snapshotDependencyShaMapSchema = z22.record(z22.string(), z22.string());
4164
4337
  }
4165
4338
  });
4166
4339
 
4167
4340
  // ../../packages/types/src/schemas/checkpoint-summary.ts
4168
- import { z as z22 } from "zod";
4341
+ import { z as z23 } from "zod";
4169
4342
  var checkpointToneSchema, checkpointExecutionStateSchema, checkpointTestCountsSchema, checkpointAnalysisSummarySchema, checkpointPresentationSummarySchema;
4170
4343
  var init_checkpoint_summary = __esm({
4171
4344
  "../../packages/types/src/schemas/checkpoint-summary.ts"() {
4172
4345
  "use strict";
4173
4346
  init_esm_shims();
4174
- checkpointToneSchema = z22.enum(["success", "critical", "warning", "neutral"]);
4175
- checkpointExecutionStateSchema = z22.enum([
4347
+ checkpointToneSchema = z23.enum(["success", "critical", "warning", "neutral"]);
4348
+ checkpointExecutionStateSchema = z23.enum([
4176
4349
  "not_started",
4177
4350
  "running",
4178
4351
  "stale",
@@ -4181,34 +4354,34 @@ var init_checkpoint_summary = __esm({
4181
4354
  "pipeline_failed",
4182
4355
  "unknown"
4183
4356
  ]);
4184
- checkpointTestCountsSchema = z22.object({
4185
- assigned: z22.number(),
4186
- run: z22.number(),
4187
- passed: z22.number(),
4188
- failed: z22.number(),
4357
+ checkpointTestCountsSchema = z23.object({
4358
+ assigned: z23.number(),
4359
+ run: z23.number(),
4360
+ passed: z23.number(),
4361
+ failed: z23.number(),
4189
4362
  // Tests that never ran because their scenario setup failed.
4190
- setupFailed: z22.number(),
4191
- running: z22.number(),
4192
- notRun: z22.number()
4363
+ setupFailed: z23.number(),
4364
+ running: z23.number(),
4365
+ notRun: z23.number()
4193
4366
  });
4194
- checkpointAnalysisSummarySchema = z22.object({
4367
+ checkpointAnalysisSummarySchema = z23.object({
4195
4368
  // The AnalysisJob lifecycle. Mirrors the `AnalysisJobStatus` db enum (types cannot import it).
4196
- jobStatus: z22.enum(["running", "completed", "failed"]),
4369
+ jobStatus: z23.enum(["running", "completed", "failed"]),
4197
4370
  // Client-bug findings - the only plane that counts against the PR (turns the checkpoint red).
4198
- bugCount: z22.number().int().nonnegative(),
4371
+ bugCount: z23.number().int().nonnegative(),
4199
4372
  // Findings that passed on the app-health plane.
4200
- passedCount: z22.number().int().nonnegative(),
4373
+ passedCount: z23.number().int().nonnegative(),
4201
4374
  // Coverage-plane findings (engine_artifact / environment_failure / scenario_issue / delete) - never a
4202
4375
  // failure; surfaced as "couldn't confirm".
4203
- coverageCount: z22.number().int().nonnegative()
4376
+ coverageCount: z23.number().int().nonnegative()
4204
4377
  });
4205
- checkpointPresentationSummarySchema = z22.object({
4378
+ checkpointPresentationSummarySchema = z23.object({
4206
4379
  tone: checkpointToneSchema,
4207
- label: z22.string(),
4208
- reason: z22.string().optional(),
4380
+ label: z23.string(),
4381
+ reason: z23.string().optional(),
4209
4382
  executionState: checkpointExecutionStateSchema,
4210
4383
  testCounts: checkpointTestCountsSchema,
4211
- suiteChangeCount: z22.number(),
4384
+ suiteChangeCount: z23.number(),
4212
4385
  // Set only for authoritative-analysis snapshots; absent for legacy diffs/shadow snapshots.
4213
4386
  analysis: checkpointAnalysisSummarySchema.optional()
4214
4387
  });
@@ -4216,65 +4389,65 @@ var init_checkpoint_summary = __esm({
4216
4389
  });
4217
4390
 
4218
4391
  // ../../packages/types/src/schemas/snapshot-report.ts
4219
- import { z as z23 } from "zod";
4392
+ import { z as z24 } from "zod";
4220
4393
  var reportHealthSchema, reportTestStatusSchema, reportCommitFileSchema, snapshotReportTriggerSchema, snapshotReportTestResultSchema, snapshotReportResultsSchema, snapshotReportHealthCountsSchema, snapshotReportSchema;
4221
4394
  var init_snapshot_report = __esm({
4222
4395
  "../../packages/types/src/schemas/snapshot-report.ts"() {
4223
4396
  "use strict";
4224
4397
  init_esm_shims();
4225
4398
  init_checkpoint_summary();
4226
- reportHealthSchema = z23.enum(["healthy", "critical", "running", "unknown"]);
4227
- reportTestStatusSchema = z23.enum(["passed", "failed", "setup_failed", "running", "pending"]);
4228
- reportCommitFileSchema = z23.object({
4229
- filename: z23.string(),
4230
- status: z23.string(),
4231
- additions: z23.number(),
4232
- deletions: z23.number()
4399
+ reportHealthSchema = z24.enum(["healthy", "critical", "running", "unknown"]);
4400
+ reportTestStatusSchema = z24.enum(["passed", "failed", "setup_failed", "running", "pending"]);
4401
+ reportCommitFileSchema = z24.object({
4402
+ filename: z24.string(),
4403
+ status: z24.string(),
4404
+ additions: z24.number(),
4405
+ deletions: z24.number()
4233
4406
  });
4234
- snapshotReportTriggerSchema = z23.object({
4235
- headSha: z23.string().optional(),
4236
- baseSha: z23.string().optional(),
4237
- source: z23.string(),
4238
- createdAt: z23.date(),
4239
- commit: z23.object({ message: z23.string(), authorLogin: z23.string().optional() }).optional(),
4240
- filesChanged: z23.array(reportCommitFileSchema),
4241
- filesChangedTruncated: z23.boolean()
4407
+ snapshotReportTriggerSchema = z24.object({
4408
+ headSha: z24.string().optional(),
4409
+ baseSha: z24.string().optional(),
4410
+ source: z24.string(),
4411
+ createdAt: z24.date(),
4412
+ commit: z24.object({ message: z24.string(), authorLogin: z24.string().optional() }).optional(),
4413
+ filesChanged: z24.array(reportCommitFileSchema),
4414
+ filesChangedTruncated: z24.boolean()
4242
4415
  });
4243
- snapshotReportTestResultSchema = z23.object({
4244
- testCaseId: z23.string(),
4245
- name: z23.string(),
4246
- slug: z23.string(),
4416
+ snapshotReportTestResultSchema = z24.object({
4417
+ testCaseId: z24.string(),
4418
+ name: z24.string(),
4419
+ slug: z24.string(),
4247
4420
  status: reportTestStatusSchema,
4248
- runId: z23.string().optional(),
4249
- durationMs: z23.number().optional()
4421
+ runId: z24.string().optional(),
4422
+ durationMs: z24.number().optional()
4250
4423
  });
4251
- snapshotReportResultsSchema = z23.object({
4252
- durationMs: z23.number().optional(),
4253
- passed: z23.number(),
4254
- failed: z23.number(),
4255
- setupFailed: z23.number(),
4256
- pending: z23.number(),
4257
- running: z23.number(),
4258
- total: z23.number(),
4259
- tests: z23.array(snapshotReportTestResultSchema)
4424
+ snapshotReportResultsSchema = z24.object({
4425
+ durationMs: z24.number().optional(),
4426
+ passed: z24.number(),
4427
+ failed: z24.number(),
4428
+ setupFailed: z24.number(),
4429
+ pending: z24.number(),
4430
+ running: z24.number(),
4431
+ total: z24.number(),
4432
+ tests: z24.array(snapshotReportTestResultSchema)
4260
4433
  });
4261
- snapshotReportHealthCountsSchema = z23.object({
4262
- failing: z23.number(),
4263
- passing: z23.number(),
4264
- running: z23.number(),
4265
- setupFailed: z23.number(),
4266
- notAffected: z23.number(),
4267
- totalTests: z23.number()
4434
+ snapshotReportHealthCountsSchema = z24.object({
4435
+ failing: z24.number(),
4436
+ passing: z24.number(),
4437
+ running: z24.number(),
4438
+ setupFailed: z24.number(),
4439
+ notAffected: z24.number(),
4440
+ totalTests: z24.number()
4268
4441
  });
4269
- snapshotReportSchema = z23.object({
4270
- snapshot: z23.object({
4271
- id: z23.string(),
4272
- status: z23.string(),
4273
- source: z23.string(),
4274
- headSha: z23.string().optional(),
4275
- baseSha: z23.string().optional(),
4276
- createdAt: z23.date(),
4277
- branch: z23.object({ id: z23.string(), name: z23.string(), prNumber: z23.number().optional() })
4442
+ snapshotReportSchema = z24.object({
4443
+ snapshot: z24.object({
4444
+ id: z24.string(),
4445
+ status: z24.string(),
4446
+ source: z24.string(),
4447
+ headSha: z24.string().optional(),
4448
+ baseSha: z24.string().optional(),
4449
+ createdAt: z24.date(),
4450
+ branch: z24.object({ id: z24.string(), name: z24.string(), prNumber: z24.number().optional() })
4278
4451
  }),
4279
4452
  trigger: snapshotReportTriggerSchema,
4280
4453
  results: snapshotReportResultsSchema,
@@ -4286,35 +4459,35 @@ var init_snapshot_report = __esm({
4286
4459
  });
4287
4460
 
4288
4461
  // ../../packages/types/src/schemas/pr-pipeline-status.ts
4289
- import { z as z24 } from "zod";
4462
+ import { z as z25 } from "zod";
4290
4463
  var prPipelineStatusSchema;
4291
4464
  var init_pr_pipeline_status = __esm({
4292
4465
  "../../packages/types/src/schemas/pr-pipeline-status.ts"() {
4293
4466
  "use strict";
4294
4467
  init_esm_shims();
4295
4468
  init_checkpoint_summary();
4296
- prPipelineStatusSchema = z24.discriminatedUnion("kind", [
4297
- z24.object({ kind: z24.literal("checkpoint"), summary: checkpointPresentationSummarySchema }),
4298
- z24.object({ kind: z24.literal("building") }),
4299
- z24.object({ kind: z24.literal("pending_checks") }),
4300
- z24.object({ kind: z24.literal("analyzing") }),
4301
- z24.object({ kind: z24.literal("analysis_failed") }),
4302
- z24.object({ kind: z24.literal("build_failed") }),
4303
- z24.object({ kind: z24.literal("none") })
4469
+ prPipelineStatusSchema = z25.discriminatedUnion("kind", [
4470
+ z25.object({ kind: z25.literal("checkpoint"), summary: checkpointPresentationSummarySchema }),
4471
+ z25.object({ kind: z25.literal("building") }),
4472
+ z25.object({ kind: z25.literal("pending_checks") }),
4473
+ z25.object({ kind: z25.literal("analyzing") }),
4474
+ z25.object({ kind: z25.literal("analysis_failed") }),
4475
+ z25.object({ kind: z25.literal("build_failed") }),
4476
+ z25.object({ kind: z25.literal("none") })
4304
4477
  ]);
4305
4478
  }
4306
4479
  });
4307
4480
 
4308
4481
  // ../../packages/types/src/schemas/step-output.ts
4309
- import { z as z25 } from "zod";
4482
+ import { z as z26 } from "zod";
4310
4483
  var pointSchema2, stepOutputDataSchema;
4311
4484
  var init_step_output = __esm({
4312
4485
  "../../packages/types/src/schemas/step-output.ts"() {
4313
4486
  "use strict";
4314
4487
  init_esm_shims();
4315
- pointSchema2 = z25.object({ x: z25.number(), y: z25.number() });
4316
- stepOutputDataSchema = z25.object({
4317
- outcome: z25.string().optional(),
4488
+ pointSchema2 = z26.object({ x: z26.number(), y: z26.number() });
4489
+ stepOutputDataSchema = z26.object({
4490
+ outcome: z26.string().optional(),
4318
4491
  point: pointSchema2.optional(),
4319
4492
  startPoint: pointSchema2.optional(),
4320
4493
  endPoint: pointSchema2.optional()
@@ -4323,7 +4496,7 @@ var init_step_output = __esm({
4323
4496
  });
4324
4497
 
4325
4498
  // ../../packages/types/src/schemas/activation-triggers.ts
4326
- import { z as z26 } from "zod";
4499
+ import { z as z27 } from "zod";
4327
4500
  var MAX_LABEL_LENGTH, CONTROL_CHARS, AnalysisTriggerLabelSchema, TriggerConfigSchema;
4328
4501
  var init_activation_triggers = __esm({
4329
4502
  "../../packages/types/src/schemas/activation-triggers.ts"() {
@@ -4331,10 +4504,10 @@ var init_activation_triggers = __esm({
4331
4504
  init_esm_shims();
4332
4505
  MAX_LABEL_LENGTH = 50;
4333
4506
  CONTROL_CHARS = /[\u0000-\u001F\u007F]/;
4334
- AnalysisTriggerLabelSchema = z26.string().trim().min(1, "Label cannot be empty").max(MAX_LABEL_LENGTH, `Label must be at most ${MAX_LABEL_LENGTH} characters`).refine((value) => !CONTROL_CHARS.test(value), "Label cannot contain control characters");
4335
- TriggerConfigSchema = z26.object({
4507
+ AnalysisTriggerLabelSchema = z27.string().trim().min(1, "Label cannot be empty").max(MAX_LABEL_LENGTH, `Label must be at most ${MAX_LABEL_LENGTH} characters`).refine((value) => !CONTROL_CHARS.test(value), "Label cannot contain control characters");
4508
+ TriggerConfigSchema = z27.object({
4336
4509
  /** Whether marking a PR ready-for-review automatically starts an analysis run. */
4337
- autoRunOnReadyForReview: z26.boolean(),
4510
+ autoRunOnReadyForReview: z27.boolean(),
4338
4511
  /** The PR label whose addition starts an analysis run. */
4339
4512
  analysisTriggerLabel: AnalysisTriggerLabelSchema
4340
4513
  });
@@ -4342,67 +4515,67 @@ var init_activation_triggers = __esm({
4342
4515
  });
4343
4516
 
4344
4517
  // ../../packages/types/src/schemas/suite-health.ts
4345
- import { z as z27 } from "zod";
4518
+ import { z as z28 } from "zod";
4346
4519
  var SUITE_HEALTH_LEVELS, suiteHealthLevelSchema, suiteHealthDriverSchema, suiteHealthGateSchema, suiteHealthEvidenceSchema, suiteHealthBreakdownSchema, suiteHealthSchema;
4347
4520
  var init_suite_health = __esm({
4348
4521
  "../../packages/types/src/schemas/suite-health.ts"() {
4349
4522
  "use strict";
4350
4523
  init_esm_shims();
4351
4524
  SUITE_HEALTH_LEVELS = ["degraded", "at_risk", "calibrating", "steady", "proven"];
4352
- suiteHealthLevelSchema = z27.enum(SUITE_HEALTH_LEVELS);
4353
- suiteHealthDriverSchema = z27.enum(["environment", "scenario", "plan", "engine", "balanced", "none"]);
4354
- suiteHealthGateSchema = z27.enum(["runs", "pull_requests", "age", "stale_issues", "no_triage"]);
4355
- suiteHealthEvidenceSchema = z27.object({
4525
+ suiteHealthLevelSchema = z28.enum(SUITE_HEALTH_LEVELS);
4526
+ suiteHealthDriverSchema = z28.enum(["environment", "scenario", "plan", "engine", "balanced", "none"]);
4527
+ suiteHealthGateSchema = z28.enum(["runs", "pull_requests", "age", "stale_issues", "no_triage"]);
4528
+ suiteHealthEvidenceSchema = z28.object({
4356
4529
  /** Analysis runs in the window. A run that selected no tests is not one. */
4357
- runs: z27.number().int(),
4530
+ runs: z28.number().int(),
4358
4531
  /** Distinct branches those runs covered. */
4359
- pullRequests: z27.number().int(),
4532
+ pullRequests: z28.number().int(),
4360
4533
  /** Tests the agent re-planned and re-ran, that then passed. */
4361
- selfHeals: z27.number().int(),
4534
+ selfHeals: z28.number().int(),
4362
4535
  /** Tests the agent re-planned and re-ran at all - the denominator of the self-heal rate. */
4363
- selfHealAttempts: z27.number().int(),
4536
+ selfHealAttempts: z28.number().int(),
4364
4537
  /** Total findings in the window - the denominator of the trust rate. */
4365
- findings: z27.number().int(),
4538
+ findings: z28.number().int(),
4366
4539
  /** Whole days since the app's first analysis run of any pipeline. */
4367
- ageDays: z27.number().int(),
4540
+ ageDays: z28.number().int(),
4368
4541
  /** Whole days since its most recent run. Drives the inactivity decay. */
4369
- daysSinceLastRun: z27.number().int()
4542
+ daysSinceLastRun: z28.number().int()
4370
4543
  });
4371
- suiteHealthBreakdownSchema = z27.object({
4372
- passed: z27.number().int(),
4373
- clientBug: z27.number().int(),
4374
- environmentFailure: z27.number().int(),
4375
- scenarioIssue: z27.number().int(),
4376
- planMismatch: z27.number().int(),
4377
- engineArtifact: z27.number().int(),
4378
- invalidTest: z27.number().int()
4544
+ suiteHealthBreakdownSchema = z28.object({
4545
+ passed: z28.number().int(),
4546
+ clientBug: z28.number().int(),
4547
+ environmentFailure: z28.number().int(),
4548
+ scenarioIssue: z28.number().int(),
4549
+ planMismatch: z28.number().int(),
4550
+ engineArtifact: z28.number().int(),
4551
+ invalidTest: z28.number().int()
4379
4552
  });
4380
- suiteHealthSchema = z27.object({
4553
+ suiteHealthSchema = z28.object({
4381
4554
  level: suiteHealthLevelSchema,
4382
4555
  /** 1-5. Always `suiteHealthRank(level)`; sent so clients never re-derive it. */
4383
- rank: z27.number().int(),
4556
+ rank: z28.number().int(),
4384
4557
  /** 0-100, after modifiers. Display-only - the level is what surfaces read. */
4385
- score: z27.number(),
4558
+ score: z28.number(),
4386
4559
  /**
4387
4560
  * `(passed + client_bug) / findings`, 0-100, before modifiers. The headline fact: of the tests the agent
4388
4561
  * investigated, how many produced a verdict you can act on.
4389
4562
  */
4390
- trust: z27.number(),
4563
+ trust: z28.number(),
4391
4564
  evidence: suiteHealthEvidenceSchema,
4392
4565
  breakdown: suiteHealthBreakdownSchema,
4393
4566
  driver: suiteHealthDriverSchema,
4394
4567
  /** Open issues older than a week on a branch that is still live. What DEGRADED is actually made of. */
4395
- staleIssues: z27.number().int(),
4568
+ staleIssues: z28.number().int(),
4396
4569
  /** The gate holding the level down, if the score alone would have placed it higher. */
4397
4570
  gatedBy: suiteHealthGateSchema.optional(),
4398
4571
  /** False before the first analysis run ever - the meter shows "waiting for your first pull request". */
4399
- hasEverRun: z27.boolean()
4572
+ hasEverRun: z28.boolean()
4400
4573
  });
4401
4574
  }
4402
4575
  });
4403
4576
 
4404
4577
  // ../../packages/types/src/schemas/suite-health-fix-plan.ts
4405
- import { z as z28 } from "zod";
4578
+ import { z as z29 } from "zod";
4406
4579
  var suiteHealthFixKindSchema, suiteHealthFixSeveritySchema, suiteHealthFixIssueSchema, suiteHealthFixBranchStateSchema, suiteHealthFixBranchSchema, suiteHealthFixClusterSchema, suiteHealthFixPlanSchema;
4407
4580
  var init_suite_health_fix_plan = __esm({
4408
4581
  "../../packages/types/src/schemas/suite-health-fix-plan.ts"() {
@@ -4411,70 +4584,70 @@ var init_suite_health_fix_plan = __esm({
4411
4584
  init_analysis();
4412
4585
  suiteHealthFixKindSchema = analysisIssueKindSchema;
4413
4586
  suiteHealthFixSeveritySchema = analysisIssueSeveritySchema;
4414
- suiteHealthFixIssueSchema = z28.object({
4415
- id: z28.string(),
4587
+ suiteHealthFixIssueSchema = z29.object({
4588
+ id: z29.string(),
4416
4589
  kind: suiteHealthFixKindSchema,
4417
4590
  severity: suiteHealthFixSeveritySchema,
4418
- title: z28.string(),
4419
- ageDays: z28.number().int()
4591
+ title: z29.string(),
4592
+ ageDays: z29.number().int()
4420
4593
  });
4421
- suiteHealthFixBranchStateSchema = z28.enum(["open", "merged", "closed", "main"]);
4422
- suiteHealthFixBranchSchema = z28.object({
4423
- branchId: z28.string(),
4424
- branchName: z28.string(),
4594
+ suiteHealthFixBranchStateSchema = z29.enum(["open", "merged", "closed", "main"]);
4595
+ suiteHealthFixBranchSchema = z29.object({
4596
+ branchId: z29.string(),
4597
+ branchName: z29.string(),
4425
4598
  state: suiteHealthFixBranchStateSchema,
4426
- prNumber: z28.number().int().optional(),
4427
- prTitle: z28.string().optional(),
4428
- prUrl: z28.string().optional(),
4599
+ prNumber: z29.number().int().optional(),
4600
+ prTitle: z29.string().optional(),
4601
+ prUrl: z29.string().optional(),
4429
4602
  /** The findings shown. Capped - `issueCount` is the true total. */
4430
- issues: z28.array(suiteHealthFixIssueSchema),
4431
- issueCount: z28.number().int(),
4603
+ issues: z29.array(suiteHealthFixIssueSchema),
4604
+ issueCount: z29.number().int(),
4432
4605
  /** Kind tally over EVERY finding on the branch, not just the shown ones - those two routinely differ. */
4433
- byKind: z28.object({
4434
- bug: z28.number().int(),
4435
- environment: z28.number().int(),
4436
- scenario: z28.number().int()
4606
+ byKind: z29.object({
4607
+ bug: z29.number().int(),
4608
+ environment: z29.number().int(),
4609
+ scenario: z29.number().int()
4437
4610
  }),
4438
4611
  /** Age of the oldest unresolved finding on this branch, in whole days. */
4439
- oldestAgeDays: z28.number().int()
4612
+ oldestAgeDays: z29.number().int()
4440
4613
  });
4441
- suiteHealthFixClusterSchema = z28.object({
4442
- title: z28.string(),
4614
+ suiteHealthFixClusterSchema = z29.object({
4615
+ title: z29.string(),
4443
4616
  kind: suiteHealthFixKindSchema,
4444
4617
  /** Distinct branches carrying it. */
4445
- branches: z28.number().int(),
4618
+ branches: z29.number().int(),
4446
4619
  /** How many of those are still-open pull requests - the ones a fix unblocks today. */
4447
- openBranches: z28.number().int(),
4448
- findings: z28.number().int()
4620
+ openBranches: z29.number().int(),
4621
+ findings: z29.number().int()
4449
4622
  });
4450
- suiteHealthFixPlanSchema = z28.object({
4623
+ suiteHealthFixPlanSchema = z29.object({
4451
4624
  /**
4452
4625
  * `owner/repo`, which every MCP tool is keyed by. Absent when it cannot be resolved without asking GitHub,
4453
4626
  * in which case the prompt tells the agent to read the git remote instead - which is what the MCP's own
4454
4627
  * instructions tell it to do anyway.
4455
4628
  */
4456
- repoFullName: z28.string().optional(),
4629
+ repoFullName: z29.string().optional(),
4457
4630
  /** Unresolved findings across every branch. */
4458
- totalIssues: z28.number().int(),
4459
- byKind: z28.object({
4460
- bug: z28.number().int(),
4461
- environment: z28.number().int(),
4462
- scenario: z28.number().int()
4631
+ totalIssues: z29.number().int(),
4632
+ byKind: z29.object({
4633
+ bug: z29.number().int(),
4634
+ environment: z29.number().int(),
4635
+ scenario: z29.number().int()
4463
4636
  }),
4464
4637
  /** Age of the oldest unresolved finding anywhere on the app, in whole days. */
4465
- oldestAgeDays: z28.number().int(),
4638
+ oldestAgeDays: z29.number().int(),
4466
4639
  /** True when the scan hit its cap, so `totalIssues` is a floor rather than the count. Never hide this. */
4467
- truncated: z28.boolean(),
4640
+ truncated: z29.boolean(),
4468
4641
  /** Repeated findings, most-shared first. Empty when nothing repeats. */
4469
- clusters: z28.array(suiteHealthFixClusterSchema),
4642
+ clusters: z29.array(suiteHealthFixClusterSchema),
4470
4643
  /** The prompt the user copies. Authored from the rows above. */
4471
- prompt: z28.string()
4644
+ prompt: z29.string()
4472
4645
  });
4473
4646
  }
4474
4647
  });
4475
4648
 
4476
4649
  // ../../packages/types/src/schemas/index.ts
4477
- import { z as z29 } from "zod";
4650
+ import { z as z30 } from "zod";
4478
4651
  var PlatformSchema, TestStatusSchema;
4479
4652
  var init_schemas = __esm({
4480
4653
  "../../packages/types/src/schemas/index.ts"() {
@@ -4488,9 +4661,11 @@ var init_schemas = __esm({
4488
4661
  init_evidence_tokens();
4489
4662
  init_generation();
4490
4663
  init_api_key();
4664
+ init_organization();
4491
4665
  init_secrets();
4492
4666
  init_previewkit_builtins();
4493
4667
  init_previewkit_config();
4668
+ init_previewkit_config_rows();
4494
4669
  init_previewkit_job_spec();
4495
4670
  init_previewkit_node_build();
4496
4671
  init_previewkit_node_pm();
@@ -4510,8 +4685,8 @@ var init_schemas = __esm({
4510
4685
  init_activation_triggers();
4511
4686
  init_suite_health();
4512
4687
  init_suite_health_fix_plan();
4513
- PlatformSchema = z29.enum(["web", "ios", "android"]);
4514
- TestStatusSchema = z29.enum(["pending", "running", "passed", "failed", "cancelled"]);
4688
+ PlatformSchema = z30.enum(["web", "ios", "android"]);
4689
+ TestStatusSchema = z30.enum(["pending", "running", "passed", "failed", "cancelled"]);
4515
4690
  }
4516
4691
  });
4517
4692
 
@@ -4546,16 +4721,16 @@ var init_billing = __esm({
4546
4721
  });
4547
4722
 
4548
4723
  // ../../packages/types/src/schemas/billing.ts
4549
- import { z as z30 } from "zod";
4724
+ import { z as z31 } from "zod";
4550
4725
  var BillingTransactionSchema, BillingStatusSchema, CreateCheckoutInputSchema, AutoTopUpInputSchema, RunCompletedSchema;
4551
4726
  var init_billing2 = __esm({
4552
4727
  "../../packages/types/src/schemas/billing.ts"() {
4553
4728
  "use strict";
4554
4729
  init_esm_shims();
4555
4730
  init_billing();
4556
- BillingTransactionSchema = z30.object({
4557
- id: z30.string(),
4558
- type: z30.enum([
4731
+ BillingTransactionSchema = z31.object({
4732
+ id: z31.string(),
4733
+ type: z31.enum([
4559
4734
  "SUBSCRIPTION_GRANT",
4560
4735
  "SUBSCRIPTION_RESET",
4561
4736
  "TOPUP_PURCHASE",
@@ -4564,70 +4739,70 @@ var init_billing2 = __esm({
4564
4739
  "GENERATION_REFUND",
4565
4740
  "RUN_CONSUMPTION"
4566
4741
  ]),
4567
- amount: z30.number(),
4568
- balanceAfter: z30.number(),
4569
- generationId: z30.string().optional(),
4570
- runId: z30.string().optional(),
4571
- stripePaymentIntentId: z30.string().optional(),
4572
- stripeInvoiceId: z30.string().optional(),
4573
- stripeRefundId: z30.string().optional(),
4574
- createdAt: z30.date()
4742
+ amount: z31.number(),
4743
+ balanceAfter: z31.number(),
4744
+ generationId: z31.string().optional(),
4745
+ runId: z31.string().optional(),
4746
+ stripePaymentIntentId: z31.string().optional(),
4747
+ stripeInvoiceId: z31.string().optional(),
4748
+ stripeRefundId: z31.string().optional(),
4749
+ createdAt: z31.date()
4575
4750
  });
4576
- BillingStatusSchema = z30.object({
4577
- creditBalance: z30.number(),
4578
- subscriptionCreditBalance: z30.number(),
4579
- topupCreditBalance: z30.number(),
4580
- subscriptionStatus: z30.enum(["active", "canceled", "past_due", "unpaid", "trialing", "paused", "incomplete", "incomplete_expired"]).optional(),
4581
- currentPeriodEnd: z30.date().optional(),
4582
- cancelAtPeriodEnd: z30.boolean(),
4583
- gracePeriodEndsAt: z30.date().optional(),
4584
- autoTopUpEnabled: z30.boolean(),
4585
- autoTopUpThreshold: z30.number(),
4586
- transactions: z30.array(BillingTransactionSchema)
4751
+ BillingStatusSchema = z31.object({
4752
+ creditBalance: z31.number(),
4753
+ subscriptionCreditBalance: z31.number(),
4754
+ topupCreditBalance: z31.number(),
4755
+ subscriptionStatus: z31.enum(["active", "canceled", "past_due", "unpaid", "trialing", "paused", "incomplete", "incomplete_expired"]).optional(),
4756
+ currentPeriodEnd: z31.date().optional(),
4757
+ cancelAtPeriodEnd: z31.boolean(),
4758
+ gracePeriodEndsAt: z31.date().optional(),
4759
+ autoTopUpEnabled: z31.boolean(),
4760
+ autoTopUpThreshold: z31.number(),
4761
+ transactions: z31.array(BillingTransactionSchema)
4587
4762
  });
4588
- CreateCheckoutInputSchema = z30.object({
4589
- type: z30.enum([BILLING_CHECKOUT_TYPES.SUBSCRIPTION, BILLING_CHECKOUT_TYPES.TOPUP])
4763
+ CreateCheckoutInputSchema = z31.object({
4764
+ type: z31.enum([BILLING_CHECKOUT_TYPES.SUBSCRIPTION, BILLING_CHECKOUT_TYPES.TOPUP])
4590
4765
  });
4591
- AutoTopUpInputSchema = z30.object({
4592
- enabled: z30.boolean(),
4593
- threshold: z30.number().int().min(0)
4766
+ AutoTopUpInputSchema = z31.object({
4767
+ enabled: z31.boolean(),
4768
+ threshold: z31.number().int().min(0)
4594
4769
  });
4595
- RunCompletedSchema = z30.object({
4596
- generationId: z30.string()
4770
+ RunCompletedSchema = z31.object({
4771
+ generationId: z31.string()
4597
4772
  });
4598
4773
  }
4599
4774
  });
4600
4775
 
4601
4776
  // ../../packages/types/src/schemas/github.ts
4602
- import { z as z31 } from "zod";
4777
+ import { z as z32 } from "zod";
4603
4778
  var GitHubInstallationStatusSchema, GithubInstallationSchema;
4604
4779
  var init_github = __esm({
4605
4780
  "../../packages/types/src/schemas/github.ts"() {
4606
4781
  "use strict";
4607
4782
  init_esm_shims();
4608
- GitHubInstallationStatusSchema = z31.enum(["active", "suspended", "deleted"]);
4609
- GithubInstallationSchema = z31.object({
4610
- id: z31.string(),
4611
- installationId: z31.number(),
4612
- organizationId: z31.string(),
4613
- accountLogin: z31.string(),
4614
- accountId: z31.number(),
4615
- accountType: z31.string(),
4783
+ GitHubInstallationStatusSchema = z32.enum(["active", "suspended", "deleted"]);
4784
+ GithubInstallationSchema = z32.object({
4785
+ id: z32.string(),
4786
+ installationId: z32.number(),
4787
+ organizationId: z32.string(),
4788
+ accountLogin: z32.string(),
4789
+ accountId: z32.number(),
4790
+ accountType: z32.string(),
4616
4791
  status: GitHubInstallationStatusSchema,
4617
- createdAt: z31.date(),
4618
- updatedAt: z31.date()
4792
+ createdAt: z32.date(),
4793
+ updatedAt: z32.date()
4619
4794
  });
4620
4795
  }
4621
4796
  });
4622
4797
 
4623
4798
  // ../../packages/types/src/schemas/vercel.ts
4624
- import { z as z32 } from "zod";
4799
+ import { z as z33 } from "zod";
4625
4800
  var VercelInstallationWireStatusSchema;
4626
4801
  var init_vercel = __esm({
4627
4802
  "../../packages/types/src/schemas/vercel.ts"() {
4628
4803
  "use strict";
4629
4804
  init_esm_shims();
4630
- VercelInstallationWireStatusSchema = z32.enum([
4805
+ VercelInstallationWireStatusSchema = z33.enum([
4631
4806
  "ready",
4632
4807
  "pending",
4633
4808
  "onboarding",
@@ -4683,6 +4858,15 @@ var init_preview_url = __esm({
4683
4858
  "../../packages/types/src/preview-url.ts"() {
4684
4859
  "use strict";
4685
4860
  init_esm_shims();
4861
+ init_parse_url();
4862
+ }
4863
+ });
4864
+
4865
+ // ../../packages/types/src/org-domain.ts
4866
+ var init_org_domain = __esm({
4867
+ "../../packages/types/src/org-domain.ts"() {
4868
+ "use strict";
4869
+ init_esm_shims();
4686
4870
  }
4687
4871
  });
4688
4872
 
@@ -4734,6 +4918,32 @@ var init_analytics_headers = __esm({
4734
4918
  }
4735
4919
  });
4736
4920
 
4921
+ // ../../packages/types/src/constants/application-instructions.ts
4922
+ var init_application_instructions = __esm({
4923
+ "../../packages/types/src/constants/application-instructions.ts"() {
4924
+ "use strict";
4925
+ init_esm_shims();
4926
+ }
4927
+ });
4928
+
4929
+ // ../../packages/types/src/constants/auth-cookies.ts
4930
+ var init_auth_cookies = __esm({
4931
+ "../../packages/types/src/constants/auth-cookies.ts"() {
4932
+ "use strict";
4933
+ init_esm_shims();
4934
+ }
4935
+ });
4936
+
4937
+ // ../../packages/types/src/constants/integration-branch.ts
4938
+ var INTEGRATION_BRANCH;
4939
+ var init_integration_branch = __esm({
4940
+ "../../packages/types/src/constants/integration-branch.ts"() {
4941
+ "use strict";
4942
+ init_esm_shims();
4943
+ INTEGRATION_BRANCH = "autonoma-integration";
4944
+ }
4945
+ });
4946
+
4737
4947
  // ../../packages/types/src/constants/pipeline-labels.ts
4738
4948
  var init_pipeline_labels = __esm({
4739
4949
  "../../packages/types/src/constants/pipeline-labels.ts"() {
@@ -4748,7 +4958,10 @@ var init_constants = __esm({
4748
4958
  "use strict";
4749
4959
  init_esm_shims();
4750
4960
  init_analytics_headers();
4961
+ init_application_instructions();
4962
+ init_auth_cookies();
4751
4963
  init_billing();
4964
+ init_integration_branch();
4752
4965
  init_pipeline_labels();
4753
4966
  }
4754
4967
  });
@@ -4761,14 +4974,6 @@ var init_architecture = __esm({
4761
4974
  }
4762
4975
  });
4763
4976
 
4764
- // ../../packages/types/src/types/previewkit.ts
4765
- var init_previewkit = __esm({
4766
- "../../packages/types/src/types/previewkit.ts"() {
4767
- "use strict";
4768
- init_esm_shims();
4769
- }
4770
- });
4771
-
4772
4977
  // ../../packages/types/src/types/parse-string-record.ts
4773
4978
  var init_parse_string_record = __esm({
4774
4979
  "../../packages/types/src/types/parse-string-record.ts"() {
@@ -4805,7 +5010,10 @@ var init_src = __esm({
4805
5010
  init_github();
4806
5011
  init_vercel();
4807
5012
  init_sensitive_detection();
5013
+ init_parse_url();
4808
5014
  init_preview_url();
5015
+ init_sdk_endpoint();
5016
+ init_org_domain();
4809
5017
  init_app_links();
4810
5018
  init_agent_handoff_links();
4811
5019
  init_sdk_error_signals();
@@ -5260,7 +5468,7 @@ var init_output = __esm({
5260
5468
  // src/core/preferences.ts
5261
5469
  import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
5262
5470
  import { join as join12 } from "path";
5263
- import { z as z34 } from "zod";
5471
+ import { z as z35 } from "zod";
5264
5472
  async function readPreferences() {
5265
5473
  try {
5266
5474
  const raw = await readFile4(PREFERENCES_FILE, "utf-8");
@@ -5295,9 +5503,9 @@ var init_preferences = __esm({
5295
5503
  init_debug();
5296
5504
  init_output();
5297
5505
  PREFERENCES_FILE = join12(AUTONOMA_HOME3, "preferences.json");
5298
- PreferencesSchema = z34.object({
5506
+ PreferencesSchema = z35.object({
5299
5507
  /** The coding agent id (`claude`, `codex`) last chosen from the picker. */
5300
- agentId: z34.string().optional()
5508
+ agentId: z35.string().optional()
5301
5509
  });
5302
5510
  }
5303
5511
  });
@@ -5314,9 +5522,11 @@ __export(coding_agent_exports, {
5314
5522
  buildAllLaunchers: () => buildAllLaunchers,
5315
5523
  isSpawnedByPlanner: () => isSpawnedByPlanner2,
5316
5524
  parsePermissionMode: () => parsePermissionMode,
5317
- selectLauncher: () => selectLauncher,
5318
- selectPermissionMode: () => selectPermissionMode
5525
+ selectLauncher: () => selectLauncher
5319
5526
  });
5527
+ import { readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
5528
+ import { homedir as homedir5 } from "os";
5529
+ import { join as join13 } from "path";
5320
5530
  import spawn from "cross-spawn";
5321
5531
  import which from "which";
5322
5532
  function isSpawnedByPlanner2(env = process.env) {
@@ -5359,28 +5569,32 @@ async function selectLauncher(launchers, presetId, interactive = true) {
5359
5569
  await updatePreferences({ agentId: selected });
5360
5570
  return available.find((l) => l.id === selected);
5361
5571
  }
5362
- async function selectPermissionMode(preset) {
5363
- if (preset != null) return preset;
5364
- const selected = await select({
5365
- message: "How much autonomy should the agent have?",
5366
- options: [
5367
- { value: "bypassPermissions", label: PERMISSION_MODE_LABELS.bypassPermissions },
5368
- { value: "acceptEdits", label: PERMISSION_MODE_LABELS.acceptEdits },
5369
- { value: "default", label: PERMISSION_MODE_LABELS.default }
5370
- ],
5371
- initialValue: DEFAULT_PERMISSION_MODE
5372
- });
5373
- if (isCancel(selected)) throw new Error("Permission mode selection cancelled");
5374
- return selected;
5375
- }
5376
5572
  function parsePermissionMode(value) {
5377
5573
  if (value === "default" || value === "acceptEdits" || value === "bypassPermissions") return value;
5378
5574
  return void 0;
5379
5575
  }
5576
+ function describeCommandFailure(result, label) {
5577
+ return explainFailureReason(firstLine(result.stderr) || firstLine(result.stdout) || "unknown error", label);
5578
+ }
5579
+ function isClientNotExecutable(output) {
5580
+ return CLIENT_NOT_EXECUTABLE_PATTERNS.some((pattern) => pattern.test(output));
5581
+ }
5582
+ function explainFailureReason(reason, label) {
5583
+ if (!isClientNotExecutable(reason)) return reason;
5584
+ return `${label} is on your PATH but could not be run (${reason}). Reinstall it, then run again.`;
5585
+ }
5586
+ function describeSignInFailure(login, label) {
5587
+ const reason = firstLine(login.stderr);
5588
+ const code = login.code ?? "unknown";
5589
+ return reason.length > 0 ? ` (exit ${code}: ${explainFailureReason(reason, label)})` : ` (exit ${code})`;
5590
+ }
5591
+ function isRecord2(value) {
5592
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5593
+ }
5380
5594
  function firstLine(output) {
5381
5595
  return output.split("\n").find((line) => line.trim().length > 0)?.trim() ?? "";
5382
5596
  }
5383
- var MCP_COMMAND_TIMEOUT_MS, CODEX_BEARER_TOKEN_ENV, CLAUDE_CONNECTED_MARKER, DEFAULT_PERMISSION_MODE, PERMISSION_MODE_LABELS, CLAUDE_ID, CODEX_ID, BaseLauncher, ClaudeLauncher, CodexLauncher;
5597
+ var MCP_COMMAND_TIMEOUT_MS, ATTACHED_STDERR_CAP, CODEX_BEARER_TOKEN_ENV, CLAUDE_CONNECTED_MARKER, CLIENT_NOT_EXECUTABLE_PATTERNS, CLAUDE_AUTH_HEADER_MARKER, CLAUDE_NEEDS_AUTH_CACHE_FILE, CLAUDE_MODEL, CLAUDE_SUBAGENT_MODEL_ENV, DEFAULT_PERMISSION_MODE, PERMISSION_MODE_LABELS, CLAUDE_ID, CODEX_ID, BaseLauncher, ClaudeLauncher, CodexLauncher;
5384
5598
  var init_coding_agent = __esm({
5385
5599
  "src/core/coding-agent.ts"() {
5386
5600
  "use strict";
@@ -5388,11 +5602,23 @@ var init_coding_agent = __esm({
5388
5602
  init_prompts();
5389
5603
  init_agent_env();
5390
5604
  init_debug();
5605
+ init_logs();
5391
5606
  init_preferences();
5392
5607
  init_agent_env();
5393
5608
  MCP_COMMAND_TIMEOUT_MS = 6e4;
5609
+ ATTACHED_STDERR_CAP = 4e3;
5394
5610
  CODEX_BEARER_TOKEN_ENV = "AUTONOMA_MCP_TOKEN";
5395
5611
  CLAUDE_CONNECTED_MARKER = "Connected";
5612
+ CLIENT_NOT_EXECUTABLE_PATTERNS = [
5613
+ /is not recognized as an internal or external command/i,
5614
+ /command not found/i,
5615
+ /\bENOENT\b/,
5616
+ /no such file or directory/i
5617
+ ];
5618
+ CLAUDE_AUTH_HEADER_MARKER = "Authorization:";
5619
+ CLAUDE_NEEDS_AUTH_CACHE_FILE = "mcp-needs-auth-cache.json";
5620
+ CLAUDE_MODEL = "opus";
5621
+ CLAUDE_SUBAGENT_MODEL_ENV = "CLAUDE_CODE_SUBAGENT_MODEL";
5396
5622
  DEFAULT_PERMISSION_MODE = "bypassPermissions";
5397
5623
  PERMISSION_MODE_LABELS = {
5398
5624
  default: "Approve each command",
@@ -5479,40 +5705,107 @@ var init_coding_agent = __esm({
5479
5705
  /**
5480
5706
  * Sign this client in to a server through its own browser flow.
5481
5707
  *
5482
- * Refused outright without a terminal. The flow prints a URL, opens a browser and
5483
- * blocks on the callback, so a run with nobody at the keyboard would not fail - it
5484
- * would hang, indefinitely, on a prompt nobody can see. A run without a terminal
5485
- * is meant to have passed an API token instead, and the error says so rather than
5486
- * describing the sign-in that could not happen.
5708
+ * Never throws. A sign-in is a convenience over the credential the run is already
5709
+ * holding, so every way it can fail - no terminal to open a browser from, a
5710
+ * client that exits non-zero - resolves to a result the caller can fall back on.
5711
+ * Refusing without a terminal is still the right call: the flow prints a URL and
5712
+ * blocks on a callback, so with nobody at the keyboard it would not fail, it would
5713
+ * hang indefinitely on a prompt nobody can see.
5487
5714
  */
5488
5715
  async signIn(serverName) {
5489
5716
  if (process.stdin.isTTY !== true) {
5490
- throw new Error(
5491
- `Cannot sign ${this.label} in to the ${serverName} MCP server without a terminal: that flow opens a browser and waits for it. Set AUTONOMA_API_TOKEN so the run authorizes with an API key instead.`
5492
- );
5717
+ return { ok: false, detail: " (no terminal to run a browser sign-in from)", clientUnusable: false };
5493
5718
  }
5494
5719
  log.info(`Authorizing ${this.label} with Autonoma - approve it in the browser that opens.`);
5495
5720
  const login = await this.runAttached(["mcp", "login", serverName]);
5496
- if (login !== 0) {
5721
+ if (login.code === 0) return { ok: true, detail: "", clientUnusable: false };
5722
+ debugLog(`${this.label} sign-in failed`, { serverName, code: login.code, stderr: login.stderr });
5723
+ return {
5724
+ ok: false,
5725
+ detail: describeSignInFailure(login, this.label),
5726
+ clientUnusable: isClientNotExecutable(login.stderr)
5727
+ };
5728
+ }
5729
+ /**
5730
+ * The credential a registration must have when no browser sign-in is on the table.
5731
+ * Its absence is a configuration error worth stating now, rather than an
5732
+ * unauthorized server the spawned agent discovers on its first tool call.
5733
+ */
5734
+ requireHeadlessToken(spec) {
5735
+ if (spec.apiToken != null) return spec.apiToken;
5736
+ throw new Error(
5737
+ `Cannot authorize the ${spec.name} MCP server for ${this.label} without a terminal: a browser sign-in needs someone to approve it. Set AUTONOMA_API_TOKEN so the run authorizes with an API key instead.`
5738
+ );
5739
+ }
5740
+ /**
5741
+ * Authorize a server that a browser sign-in was preferred for, and say how it
5742
+ * ended up authorized so the caller can register it accordingly.
5743
+ *
5744
+ * A failed sign-in is not the end of the run. The token that falls back here is
5745
+ * the same one that already authorized every API call made to get this far, so
5746
+ * refusing to use it loses the run to a browser that would not open. It also
5747
+ * repairs what the attempt broke: a failed `mcp login` clears whatever stored
5748
+ * credentials the client had, which is why a first failure used to make every
5749
+ * later run fail too.
5750
+ */
5751
+ async authorizeInteractively(spec) {
5752
+ const signIn = await this.signIn(spec.name);
5753
+ if (signIn.ok) return { via: "sign-in" };
5754
+ return { via: "token", ...this.fallBackToToken(spec, signIn) };
5755
+ }
5756
+ /**
5757
+ * Switch to the run's own API token after a browser sign-in did not happen, for
5758
+ * whatever reason - it was refused, it failed, or the client folded it into a
5759
+ * registration that failed. Throws only when there is no token to switch to.
5760
+ */
5761
+ fallBackToToken(spec, signIn) {
5762
+ const detail = signIn.detail;
5763
+ if (signIn.clientUnusable) {
5764
+ throw new Error(`Could not register the ${spec.name} MCP server with ${this.label}:${detail}`);
5765
+ }
5766
+ if (spec.apiToken == null) {
5497
5767
  throw new Error(
5498
- `${this.label} could not sign in to the ${serverName} MCP server (exit ${login ?? "unknown"}).`
5768
+ `${this.label} could not sign in to the ${spec.name} MCP server${detail}, and this run has no API token to fall back on. Set AUTONOMA_API_TOKEN and run again.`
5499
5769
  );
5500
5770
  }
5771
+ captureLog("warn", "Browser sign-in failed; authorizing the MCP server with the run's API token", {
5772
+ source: "coding_agent",
5773
+ agent: this.id,
5774
+ detail
5775
+ });
5776
+ log.warn(
5777
+ `${this.label} couldn't sign in to the ${spec.name} MCP server${detail}. Authorizing it with this run's API token instead.`
5778
+ );
5779
+ return { apiToken: spec.apiToken };
5501
5780
  }
5502
5781
  /**
5503
5782
  * Run a subcommand that hands the terminal over - an interactive OAuth sign-in.
5504
- * The client prints a URL, opens a browser and waits on the callback, so it needs
5505
- * this process's stdio rather than pipes.
5783
+ * The client prints a URL, opens a browser and waits on the callback, so stdin and
5784
+ * stdout stay attached to this process.
5785
+ *
5786
+ * stderr is the exception: it is piped so the client's own diagnosis can be quoted
5787
+ * back and reported, and echoed as it arrives so the user still watches it live.
5788
+ * Inheriting it would put that text on screen and nowhere else, which is what made
5789
+ * every sign-in failure look identical from the outside.
5506
5790
  */
5507
5791
  runAttached(args) {
5508
5792
  debugLog(`Running ${this.command} ${args.join(" ")} attached`);
5509
5793
  return new Promise((resolve6) => {
5510
- const proc = spawn(this.command, args, { cwd: this.opts.cwd, env: this.opts.env, stdio: "inherit" });
5794
+ const proc = spawn(this.command, args, {
5795
+ cwd: this.opts.cwd,
5796
+ env: this.opts.env,
5797
+ stdio: ["inherit", "inherit", "pipe"]
5798
+ });
5799
+ let stderr = "";
5800
+ proc.stderr?.on("data", (chunk) => {
5801
+ process.stderr.write(chunk);
5802
+ if (stderr.length < ATTACHED_STDERR_CAP) stderr += chunk.toString();
5803
+ });
5511
5804
  proc.on("error", (err) => {
5512
5805
  debugLog(`${this.command} ${args[0] ?? ""} failed to spawn`, { err });
5513
- resolve6(void 0);
5806
+ resolve6({ code: void 0, stderr: err.message });
5514
5807
  });
5515
- proc.on("close", (code) => resolve6(code ?? void 0));
5808
+ proc.on("close", (code) => resolve6({ code: code ?? void 0, stderr }));
5516
5809
  });
5517
5810
  }
5518
5811
  };
@@ -5521,36 +5814,113 @@ var init_coding_agent = __esm({
5521
5814
  label = "Claude Code";
5522
5815
  command = CLAUDE_ID;
5523
5816
  buildArgs(message, permissionMode, interactive) {
5524
- return interactive ? ["--permission-mode", permissionMode, message] : ["-p", message, "--permission-mode", permissionMode, "--verbose"];
5817
+ return interactive ? ["--permission-mode", permissionMode, "--model", CLAUDE_MODEL, message] : ["-p", message, "--permission-mode", permissionMode, "--model", CLAUDE_MODEL, "--verbose"];
5818
+ }
5819
+ /** Carry the model floor into the session's subagents, which read it from the env. */
5820
+ spawnEnv(extra) {
5821
+ return { ...super.spawnEnv(extra), [CLAUDE_SUBAGENT_MODEL_ENV]: CLAUDE_MODEL };
5525
5822
  }
5526
5823
  /**
5527
- * `--scope user` and not the default (`local`): the default binds the server to the
5528
- * directory the command ran in. The planner can be invoked from anywhere in a repo,
5529
- * and a server registered against the wrong directory looks exactly like one that
5530
- * was never authorized - the agent simply has no Autonoma tools.
5531
- *
5532
- * With a token the header goes into Claude's own config and there is nothing to
5533
- * sign in to. Without one, the browser sign-in runs attached to the terminal.
5824
+ * Headless registers with the bearer header outright - there is no browser to sign
5825
+ * in with. Interactively the registration goes in without one so the client's own
5826
+ * sign-in can claim it, and the header is applied only if that sign-in fails.
5534
5827
  */
5535
5828
  async registerMcpServer(spec) {
5536
- const add = ["mcp", "add", "--transport", "http", "--scope", "user", spec.name, spec.url];
5537
- if (spec.apiToken != null) add.push("--header", `Authorization: Bearer ${spec.apiToken}`);
5538
- const existing = await this.runCommand(["mcp", "get", spec.name]);
5539
- if (existing.code === 0 && !existing.stdout.includes(spec.url)) {
5540
- debugLog("Replacing an MCP registration that points elsewhere", { server: spec.name, url: spec.url });
5541
- await this.runCommand(["mcp", "remove", spec.name, "-s", "user"]);
5829
+ const registration = await this.register(spec);
5830
+ await this.forgetNeedsAuthVerdict(spec.name);
5831
+ return registration;
5832
+ }
5833
+ /**
5834
+ * Forget Claude's cached "this server needs authorization" verdict for this name.
5835
+ *
5836
+ * Claude caches that verdict per server NAME and then skips connecting on every
5837
+ * later session - "Skipping connection (cached needs-auth)" in its own debug log -
5838
+ * whatever the registration now holds. The health check this class runs to decide
5839
+ * whether to sign in is itself what writes the entry, and a successful one does not
5840
+ * clear it. Without this, a registration can report Connected, answer tool calls
5841
+ * over HTTP, and still be invisible to the agent we spawn: no Autonoma tools, and
5842
+ * nothing on screen saying why.
5843
+ *
5844
+ * Best effort by design. It reaches into another tool's internal state, so a missing
5845
+ * file, a changed format or an unwritable home degrades to a debug line rather than
5846
+ * failing a registration that is otherwise fine.
5847
+ */
5848
+ async forgetNeedsAuthVerdict(serverName) {
5849
+ const configDir = this.opts.env.CLAUDE_CONFIG_DIR ?? join13(homedir5(), ".claude");
5850
+ const cachePath = join13(configDir, CLAUDE_NEEDS_AUTH_CACHE_FILE);
5851
+ try {
5852
+ const parsed = JSON.parse(await readFile5(cachePath, "utf-8"));
5853
+ if (!isRecord2(parsed) || !(serverName in parsed)) return;
5854
+ const remaining = { ...parsed };
5855
+ delete remaining[serverName];
5856
+ await writeFile4(cachePath, JSON.stringify(remaining), "utf-8");
5857
+ debugLog("Cleared a cached needs-auth verdict", { server: serverName });
5858
+ } catch (err) {
5859
+ debugLog("Could not clear the cached needs-auth verdict", { cachePath, err });
5860
+ }
5861
+ }
5862
+ async register(spec) {
5863
+ await this.dropRegistrationPointingElsewhere(spec);
5864
+ if (!spec.browserSignIn) {
5865
+ await this.addServer(spec, this.requireHeadlessToken(spec));
5866
+ return { env: {} };
5542
5867
  }
5868
+ const registered = await this.addServer(spec, void 0);
5869
+ if (registered.includes(CLAUDE_CONNECTED_MARKER)) return { env: {} };
5870
+ const authorizable = registered.includes(CLAUDE_AUTH_HEADER_MARKER) ? await this.clearBearerHeader(spec) : registered;
5871
+ if (authorizable.includes(CLAUDE_CONNECTED_MARKER)) return { env: {} };
5872
+ const authorization = await this.authorizeInteractively(spec);
5873
+ if (authorization.via === "sign-in") return { env: {} };
5874
+ await this.runCommand(["mcp", "remove", spec.name, "-s", "user"]);
5875
+ await this.addServer(spec, authorization.apiToken);
5876
+ return { env: {} };
5877
+ }
5878
+ /**
5879
+ * An existing registration is only useful if it points where this run does. `mcp
5880
+ * add` will not update one, so a registration left over from another environment
5881
+ * would be reused in silence and the agent would work against the wrong Autonoma.
5882
+ * Replace it rather than inherit it.
5883
+ */
5884
+ async dropRegistrationPointingElsewhere(spec) {
5885
+ const existing = await this.runCommand(["mcp", "get", spec.name]);
5886
+ if (existing.code !== 0 || existing.stdout.includes(spec.url)) return;
5887
+ debugLog("Replacing an MCP registration that points elsewhere", { server: spec.name, url: spec.url });
5888
+ await this.runCommand(["mcp", "remove", spec.name, "-s", "user"]);
5889
+ }
5890
+ /**
5891
+ * Re-register without the bearer header, so a browser sign-in becomes possible
5892
+ * again. Returns what `get` then reported - which may be Connected on its own, if
5893
+ * the client still holds OAuth credentials the header had been masking.
5894
+ */
5895
+ async clearBearerHeader(spec) {
5896
+ debugLog("Clearing a bearer header that would block the browser sign-in", { server: spec.name });
5897
+ await this.runCommand(["mcp", "remove", spec.name, "-s", "user"]);
5898
+ return await this.addServer(spec, void 0);
5899
+ }
5900
+ /**
5901
+ * Add the server and confirm the client actually holds it, returning what `get`
5902
+ * reported so the caller can also read whether it is authorized.
5903
+ *
5904
+ * `mcp add` exits non-zero when the server is already registered, which is the
5905
+ * normal case on every run after the first, so its exit code is a hint and `get`
5906
+ * is the verdict.
5907
+ *
5908
+ * `--scope user` and not the default (`local`): the default binds the server to
5909
+ * the directory the command ran in. The planner can be invoked from anywhere in a
5910
+ * repo, and a server registered against the wrong directory looks exactly like one
5911
+ * that was never authorized - the agent simply has no Autonoma tools.
5912
+ */
5913
+ async addServer(spec, apiToken) {
5914
+ const add = ["mcp", "add", "--transport", "http", "--scope", "user", spec.name, spec.url];
5915
+ if (apiToken != null) add.push("--header", `Authorization: Bearer ${apiToken}`);
5543
5916
  await this.runCommand(add);
5544
5917
  const registered = await this.runCommand(["mcp", "get", spec.name]);
5545
5918
  if (registered.code !== 0) {
5546
5919
  throw new Error(
5547
- `Could not register the ${spec.name} MCP server with ${this.label}: ${firstLine(registered.stderr) || firstLine(registered.stdout) || "unknown error"}`
5920
+ `Could not register the ${spec.name} MCP server with ${this.label}: ${describeCommandFailure(registered, this.label)}`
5548
5921
  );
5549
5922
  }
5550
- if (spec.apiToken == null && !registered.stdout.includes(CLAUDE_CONNECTED_MARKER)) {
5551
- await this.signIn(spec.name);
5552
- }
5553
- return { env: {} };
5923
+ return registered.stdout;
5554
5924
  }
5555
5925
  };
5556
5926
  CodexLauncher = class extends BaseLauncher {
@@ -5587,19 +5957,53 @@ var init_coding_agent = __esm({
5587
5957
  * server overwrites its entry, so a re-run cannot leave a stale URL behind.
5588
5958
  */
5589
5959
  async registerMcpServer(spec) {
5960
+ if (!spec.browserSignIn) {
5961
+ const apiToken = this.requireHeadlessToken(spec);
5962
+ await this.addServer(spec, apiToken);
5963
+ return { env: { [CODEX_BEARER_TOKEN_ENV]: apiToken } };
5964
+ }
5965
+ const signIn = await this.addServerAndSignIn(spec);
5966
+ if (signIn.ok) return { env: {} };
5967
+ const authorization = this.fallBackToToken(spec, signIn);
5968
+ await this.addServer(spec, authorization.apiToken);
5969
+ return { env: { [CODEX_BEARER_TOKEN_ENV]: authorization.apiToken } };
5970
+ }
5971
+ /**
5972
+ * Register the server the interactive way, which for Codex is one step rather than
5973
+ * two: given a `--url` and no bearer token, `codex mcp add` detects the server's
5974
+ * OAuth support, prints an authorization URL, opens a browser and waits on the
5975
+ * callback - all inside the add.
5976
+ *
5977
+ * Two consequences. It needs the terminal: run through a pipe, the URL it tells the
5978
+ * user to "copy above manually" when the browser fails to open goes into a buffer
5979
+ * nobody reads, turning a recoverable prompt into a dead end. And a clean exit means
5980
+ * the server is registered AND signed in, so following it with `mcp login` would
5981
+ * only open a second browser flow for a session that is already authorized.
5982
+ */
5983
+ async addServerAndSignIn(spec) {
5984
+ if (process.stdin.isTTY !== true) {
5985
+ return { ok: false, detail: " (no terminal to run a browser sign-in from)", clientUnusable: false };
5986
+ }
5987
+ log.info(`Authorizing ${this.label} with Autonoma - approve it in the browser that opens.`);
5988
+ const added = await this.runAttached(["mcp", "add", spec.name, "--url", spec.url]);
5989
+ if (added.code === 0) return { ok: true, detail: "", clientUnusable: false };
5990
+ debugLog(`${this.label} registration sign-in failed`, { code: added.code, stderr: added.stderr });
5991
+ return {
5992
+ ok: false,
5993
+ detail: describeSignInFailure(added, this.label),
5994
+ clientUnusable: isClientNotExecutable(added.stderr)
5995
+ };
5996
+ }
5997
+ /** Add (or overwrite) the server, with the token read from an env var by name. */
5998
+ async addServer(spec, apiToken) {
5590
5999
  const add = ["mcp", "add", spec.name, "--url", spec.url];
5591
- if (spec.apiToken != null) add.push("--bearer-token-env-var", CODEX_BEARER_TOKEN_ENV);
6000
+ if (apiToken != null) add.push("--bearer-token-env-var", CODEX_BEARER_TOKEN_ENV);
5592
6001
  const added = await this.runCommand(add);
5593
6002
  if (added.code !== 0) {
5594
6003
  throw new Error(
5595
- `Could not register the ${spec.name} MCP server with ${this.label}: ${firstLine(added.stderr) || firstLine(added.stdout) || "unknown error"}`
6004
+ `Could not register the ${spec.name} MCP server with ${this.label}: ${describeCommandFailure(added, this.label)}`
5596
6005
  );
5597
6006
  }
5598
- if (spec.apiToken == null) {
5599
- await this.signIn(spec.name);
5600
- return { env: {} };
5601
- }
5602
- return { env: { [CODEX_BEARER_TOKEN_ENV]: spec.apiToken } };
5603
6007
  }
5604
6008
  };
5605
6009
  }
@@ -6242,10 +6646,41 @@ var init_interrupt = __esm({
6242
6646
  }
6243
6647
  });
6244
6648
 
6649
+ // src/core/permission-mode.ts
6650
+ async function resolvePermissionMode(request) {
6651
+ const known = request.preset ?? runPermissionMode ?? request.remembered;
6652
+ if (known != null) {
6653
+ runPermissionMode = known;
6654
+ return known;
6655
+ }
6656
+ if (!request.interactive) return DEFAULT_PERMISSION_MODE;
6657
+ const selected = await select({
6658
+ message: "How much autonomy should the agent have?",
6659
+ options: [
6660
+ { value: "bypassPermissions", label: PERMISSION_MODE_LABELS.bypassPermissions },
6661
+ { value: "acceptEdits", label: PERMISSION_MODE_LABELS.acceptEdits },
6662
+ { value: "default", label: PERMISSION_MODE_LABELS.default }
6663
+ ],
6664
+ initialValue: DEFAULT_PERMISSION_MODE
6665
+ });
6666
+ if (isCancel(selected)) throw new Error("Permission mode selection cancelled");
6667
+ runPermissionMode = selected;
6668
+ return selected;
6669
+ }
6670
+ var runPermissionMode;
6671
+ var init_permission_mode = __esm({
6672
+ "src/core/permission-mode.ts"() {
6673
+ "use strict";
6674
+ init_esm_shims();
6675
+ init_prompts();
6676
+ init_coding_agent();
6677
+ }
6678
+ });
6679
+
6245
6680
  // src/core/preview-phase.ts
6246
6681
  function previewPrompt(code, interactive) {
6247
6682
  const instruction = `set up my preview environments with the ${MCP_SERVER_NAME} MCP, code ${code}`;
6248
- return interactive ? instruction : `${instruction}.${HEADLESS_GUIDANCE}`;
6683
+ return interactive ? `${instruction}.${BRANCH_GUIDANCE}` : `${instruction}.${BRANCH_GUIDANCE}${HEADLESS_GUIDANCE}`;
6249
6684
  }
6250
6685
  async function runPreviewPhase(deps) {
6251
6686
  const timing = deps.timing ?? DEFAULT_PHASE_TIMING;
@@ -6253,7 +6688,8 @@ async function runPreviewPhase(deps) {
6253
6688
  const registration = await deps.launcher.registerMcpServer({
6254
6689
  name: MCP_SERVER_NAME,
6255
6690
  url: deps.mcpUrl,
6256
- apiToken: deps.apiToken
6691
+ apiToken: deps.apiToken,
6692
+ browserSignIn: deps.interactive
6257
6693
  });
6258
6694
  const code = await deps.client.createAgentPairing(deps.applicationId);
6259
6695
  captureLog("info", "Handing the preview environment to a coding agent", {
@@ -6313,11 +6749,12 @@ async function readVerifiedState(client, applicationId) {
6313
6749
  });
6314
6750
  return client.getOnboardingState(applicationId);
6315
6751
  }
6316
- var MCP_SERVER_NAME, PHASE_POLL_MS, PHASE_EXIT_GRACE_MS, KILL_ESCALATION_MS, DEFAULT_PHASE_TIMING, HEADLESS_GUIDANCE;
6752
+ var MCP_SERVER_NAME, PHASE_POLL_MS, PHASE_EXIT_GRACE_MS, KILL_ESCALATION_MS, DEFAULT_PHASE_TIMING, HEADLESS_GUIDANCE, BRANCH_GUIDANCE;
6317
6753
  var init_preview_phase = __esm({
6318
6754
  "src/core/preview-phase.ts"() {
6319
6755
  "use strict";
6320
6756
  init_esm_shims();
6757
+ init_src();
6321
6758
  init_prompts();
6322
6759
  init_debug();
6323
6760
  init_logs();
@@ -6332,6 +6769,7 @@ var init_preview_phase = __esm({
6332
6769
  killMs: KILL_ESCALATION_MS
6333
6770
  };
6334
6771
  HEADLESS_GUIDANCE = " You are running with no human to answer you, so where you would ask a question, choose the safer option and say which you chose. You are not finished when you have tried - you are finished when the preview is verified. If a deploy fails, read its logs, fix the cause and deploy again. Never report success you have not confirmed.";
6772
+ BRANCH_GUIDANCE = ` Before you change any file: if you are not already on the \`${INTEGRATION_BRANCH}\` branch, create it off the repo's default branch and switch to it now - read the default branch from the remote (\`git symbolic-ref refs/remotes/origin/HEAD\`) rather than assuming it is called main, and never commit onto it. If the working tree already has uncommitted changes they are the developer's: branch off the current HEAD instead and keep them out of your commits. Push the branch before you name it to Autonoma.`;
6335
6773
  }
6336
6774
  });
6337
6775
 
@@ -6351,7 +6789,8 @@ async function runSdkRepairPhase(deps) {
6351
6789
  const registration = await deps.launcher.registerMcpServer({
6352
6790
  name: MCP_SERVER_NAME,
6353
6791
  url: deps.mcpUrl,
6354
- apiToken: deps.apiToken
6792
+ apiToken: deps.apiToken,
6793
+ browserSignIn: deps.interactive
6355
6794
  });
6356
6795
  const code = await deps.client.createAgentPairing(deps.applicationId);
6357
6796
  captureLog("info", "Handing the SDK and dry run to a coding agent", {
@@ -6461,8 +6900,10 @@ async function runPreviewHandoff(deps) {
6461
6900
  captureLog("warn", "No coding agent available for the preview phase", { source: "front_door" });
6462
6901
  return { kind: "no-agent" };
6463
6902
  }
6464
- const preset = parsePermissionMode(config.permissionMode);
6465
- const permissionMode = interactive ? await selectPermissionMode(preset) : preset ?? DEFAULT_PERMISSION_MODE;
6903
+ const permissionMode = await resolvePermissionMode({
6904
+ preset: parsePermissionMode(config.permissionMode),
6905
+ interactive
6906
+ });
6466
6907
  suspend();
6467
6908
  let outcome;
6468
6909
  try {
@@ -6471,7 +6912,7 @@ async function runPreviewHandoff(deps) {
6471
6912
  applicationId: plan.applicationId,
6472
6913
  launcher,
6473
6914
  permissionMode,
6474
- apiToken: interactive ? void 0 : config.autonomaApiToken,
6915
+ apiToken: config.autonomaApiToken,
6475
6916
  mcpUrl: resolveMcpUrl(config.autonomaApiUrl),
6476
6917
  interactive
6477
6918
  });
@@ -6504,8 +6945,10 @@ async function runSdkRepairHandoff(deps) {
6504
6945
  captureLog("warn", "No coding agent available for the SDK repair phase", { source: "front_door" });
6505
6946
  return void 0;
6506
6947
  }
6507
- const preset = parsePermissionMode(config.permissionMode);
6508
- const permissionMode = interactive ? await selectPermissionMode(preset) : preset ?? DEFAULT_PERMISSION_MODE;
6948
+ const permissionMode = await resolvePermissionMode({
6949
+ preset: parsePermissionMode(config.permissionMode),
6950
+ interactive
6951
+ });
6509
6952
  suspend();
6510
6953
  try {
6511
6954
  return await runSdkRepairPhase({
@@ -6513,7 +6956,7 @@ async function runSdkRepairHandoff(deps) {
6513
6956
  applicationId: plan.applicationId,
6514
6957
  launcher,
6515
6958
  permissionMode,
6516
- apiToken: interactive ? void 0 : config.autonomaApiToken,
6959
+ apiToken: config.autonomaApiToken,
6517
6960
  mcpUrl: resolveMcpUrl(config.autonomaApiUrl),
6518
6961
  interactive
6519
6962
  });
@@ -6540,6 +6983,7 @@ var init_front_door = __esm({
6540
6983
  init_interrupt();
6541
6984
  init_logs();
6542
6985
  init_onboarding_phase();
6986
+ init_permission_mode();
6543
6987
  init_preview_phase();
6544
6988
  init_sdk_repair_phase();
6545
6989
  }
@@ -6598,16 +7042,16 @@ var init_notify = __esm({
6598
7042
  });
6599
7043
 
6600
7044
  // src/core/project-map.ts
6601
- import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
6602
- import { join as join14 } from "path";
6603
- import { z as z35 } from "zod";
7045
+ import { readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
7046
+ import { join as join15 } from "path";
7047
+ import { z as z36 } from "zod";
6604
7048
  async function saveProjectMap(outputDir, map) {
6605
- await writeFile5(join14(outputDir, PROJECT_MAP_FILE), JSON.stringify(map, null, 2), "utf-8");
7049
+ await writeFile6(join15(outputDir, PROJECT_MAP_FILE), JSON.stringify(map, null, 2), "utf-8");
6606
7050
  }
6607
7051
  async function loadProjectMap(outputDir) {
6608
- const path3 = join14(outputDir, PROJECT_MAP_FILE);
7052
+ const path3 = join15(outputDir, PROJECT_MAP_FILE);
6609
7053
  try {
6610
- const raw = await readFile6(path3, "utf-8");
7054
+ const raw = await readFile7(path3, "utf-8");
6611
7055
  const parsed = ProjectMapSchema.safeParse(JSON.parse(raw));
6612
7056
  if (parsed.success) return parsed.data;
6613
7057
  debugLog("project-map.json failed schema validation, ignoring it", { path: path3, issues: parsed.error.issues });
@@ -6709,34 +7153,34 @@ var init_project_map = __esm({
6709
7153
  "use strict";
6710
7154
  init_esm_shims();
6711
7155
  init_debug();
6712
- FrontendEntry = z35.object({
6713
- path: z35.string().min(1).describe("Repo-relative path to the frontend app/directory (the UI surface)."),
6714
- framework: z35.string().describe("Detected UI framework/stack, or 'unknown' if not obvious (e.g. next, react, vue, svelte)."),
6715
- dependsOn: z35.array(z35.string()).describe(
7156
+ FrontendEntry = z36.object({
7157
+ path: z36.string().min(1).describe("Repo-relative path to the frontend app/directory (the UI surface)."),
7158
+ framework: z36.string().describe("Detected UI framework/stack, or 'unknown' if not obvious (e.g. next, react, vue, svelte)."),
7159
+ dependsOn: z36.array(z36.string()).describe(
6716
7160
  "Repo-relative paths (each matching a backend in this map) that THIS frontend needs in order to function - the API/service(s) it calls and the data layer(s) that own the records it renders. These are pre-selected when the user picks this frontend, so only list backends this frontend actually depends on. Empty if it needs none."
6717
7161
  ),
6718
- why: z35.string().min(1).describe("One line: the evidence that made you classify this as a frontend.")
7162
+ why: z36.string().min(1).describe("One line: the evidence that made you classify this as a frontend.")
6719
7163
  });
6720
- BackendEntry = z35.object({
6721
- path: z35.string().min(1).describe("Repo-relative path to the backend/API/service or the package that owns the data layer."),
6722
- language: z35.string().describe("Primary language, or 'unknown' (e.g. typescript, python, go, rust)."),
6723
- framework: z35.string().describe("Web/service framework or ORM stack, or 'unknown' (e.g. express, hono, fastapi, rails)."),
6724
- dataLayer: z35.object({
6725
- kind: z35.string().describe("How models are defined (e.g. prisma, drizzle, sqlalchemy, typeorm, raw-sql, unknown)."),
6726
- schemaPath: z35.string().optional().describe("Repo-relative path to the schema/models definition, if found.")
7164
+ BackendEntry = z36.object({
7165
+ path: z36.string().min(1).describe("Repo-relative path to the backend/API/service or the package that owns the data layer."),
7166
+ language: z36.string().describe("Primary language, or 'unknown' (e.g. typescript, python, go, rust)."),
7167
+ framework: z36.string().describe("Web/service framework or ORM stack, or 'unknown' (e.g. express, hono, fastapi, rails)."),
7168
+ dataLayer: z36.object({
7169
+ kind: z36.string().describe("How models are defined (e.g. prisma, drizzle, sqlalchemy, typeorm, raw-sql, unknown)."),
7170
+ schemaPath: z36.string().optional().describe("Repo-relative path to the schema/models definition, if found.")
6727
7171
  }).optional().describe("Where this backend's database models live. Omit if this backend owns no data layer."),
6728
- why: z35.string().min(1).describe("One line: the evidence that made you classify this as a backend.")
7172
+ why: z36.string().min(1).describe("One line: the evidence that made you classify this as a backend.")
6729
7173
  });
6730
- IgnoreEntry = z35.object({
6731
- path: z35.string().min(1).describe("Repo-relative path to a directory that is NOT relevant to testing this app."),
6732
- why: z35.string().min(1).describe("One line: why it is irrelevant (e.g. docs site, infra, tooling, examples, unrelated app).")
7174
+ IgnoreEntry = z36.object({
7175
+ path: z36.string().min(1).describe("Repo-relative path to a directory that is NOT relevant to testing this app."),
7176
+ why: z36.string().min(1).describe("One line: why it is irrelevant (e.g. docs site, infra, tooling, examples, unrelated app).")
6733
7177
  });
6734
- ProjectMapSchema = z35.object({
6735
- frontends: z35.array(FrontendEntry).describe("The UI surface(s) whose pages/flows get tested. Usually 1; may be more."),
6736
- backends: z35.array(BackendEntry).describe(
7178
+ ProjectMapSchema = z36.object({
7179
+ frontends: z36.array(FrontendEntry).describe("The UI surface(s) whose pages/flows get tested. Usually 1; may be more."),
7180
+ backends: z36.array(BackendEntry).describe(
6737
7181
  "The API/service(s) and data layer(s) that own the models we seed. May be 0 (frontend-only), 1, or many."
6738
7182
  ),
6739
- ignore: z35.array(IgnoreEntry).describe("Directories judged irrelevant to this app's tests, so later steps skip them.")
7183
+ ignore: z36.array(IgnoreEntry).describe("Directories judged irrelevant to this app's tests, so later steps skip them.")
6740
7184
  });
6741
7185
  PROJECT_MAP_FILE = "project-map.json";
6742
7186
  }
@@ -6747,11 +7191,11 @@ var parse_entity_audit_exports = {};
6747
7191
  __export(parse_entity_audit_exports, {
6748
7192
  parseEntityNames: () => parseEntityNames
6749
7193
  });
6750
- import { readFile as readFile8 } from "fs/promises";
6751
- import { join as join16 } from "path";
7194
+ import { readFile as readFile9 } from "fs/promises";
7195
+ import { join as join17 } from "path";
6752
7196
  async function parseEntityNames(outputDir) {
6753
7197
  try {
6754
- const content = await readFile8(join16(outputDir, "entity-audit.md"), "utf-8");
7198
+ const content = await readFile9(join17(outputDir, "entity-audit.md"), "utf-8");
6755
7199
  const names = [];
6756
7200
  for (const line of content.split("\n")) {
6757
7201
  const match = line.match(/^\s+-\s+name:\s+(.+)$/);
@@ -6786,7 +7230,7 @@ var init_count_generated_tests = __esm({
6786
7230
  });
6787
7231
 
6788
7232
  // src/core/display.ts
6789
- import { join as join17 } from "path";
7233
+ import { join as join18 } from "path";
6790
7234
  function formatArgs(input, keys) {
6791
7235
  const parts = [];
6792
7236
  for (const key of keys) {
@@ -6878,7 +7322,7 @@ function logToStore(store, agentId, info, stats) {
6878
7322
  const folder = String(tc.input.folder ?? "");
6879
7323
  const filename = String(tc.input.filename ?? "");
6880
7324
  if (folder && filename) {
6881
- store.noteWrite(join17(TESTS_DIR, folder, normalizeTestFilename(filename)));
7325
+ store.noteWrite(join18(TESTS_DIR, folder, normalizeTestFilename(filename)));
6882
7326
  }
6883
7327
  }
6884
7328
  if (tc.name === "bash") {
@@ -7186,8 +7630,8 @@ var init_agent = __esm({
7186
7630
  });
7187
7631
 
7188
7632
  // src/core/gitignore.ts
7189
- import { readFile as readFile9 } from "fs/promises";
7190
- import { join as join18, relative as relative2 } from "path";
7633
+ import { readFile as readFile10 } from "fs/promises";
7634
+ import { join as join19, relative as relative2 } from "path";
7191
7635
  import { glob as glob2 } from "glob";
7192
7636
  async function loadGitignorePatterns(projectRoot) {
7193
7637
  const patterns = [
@@ -7207,10 +7651,10 @@ async function loadGitignorePatterns(projectRoot) {
7207
7651
  ];
7208
7652
  const matches = await glob2("**/.gitignore", { cwd: projectRoot, dot: true });
7209
7653
  for (const match of matches) {
7210
- const fullPath = join18(projectRoot, match);
7654
+ const fullPath = join19(projectRoot, match);
7211
7655
  try {
7212
- const content = await readFile9(fullPath, "utf-8");
7213
- const prefix = relative2(projectRoot, join18(projectRoot, match, ".."));
7656
+ const content = await readFile10(fullPath, "utf-8");
7657
+ const prefix = relative2(projectRoot, join19(projectRoot, match, ".."));
7214
7658
  const parsed = parseGitignore(content, prefix);
7215
7659
  patterns.push(...parsed);
7216
7660
  } catch (err) {
@@ -7273,7 +7717,7 @@ var init_exec_error = __esm({
7273
7717
  import { execFile as execFile3 } from "child_process";
7274
7718
  import { promisify as promisify2 } from "util";
7275
7719
  import { tool } from "ai";
7276
- import { z as z36 } from "zod";
7720
+ import { z as z37 } from "zod";
7277
7721
  function validateCommand(command, allowed) {
7278
7722
  const trimmed = command.trim();
7279
7723
  if (trimmed.length === 0) return "Empty command";
@@ -7339,8 +7783,8 @@ var init_bash = __esm({
7339
7783
  DEFAULT_ALLOWED = /* @__PURE__ */ new Set(["git", "wc", "sort", "head", "tail", "cat", "ls", "find", "diff", "echo"]);
7340
7784
  TIMEOUT_MS = 3e4;
7341
7785
  MAX_OUTPUT_BYTES = 1024 * 512;
7342
- inputSchema = z36.object({
7343
- command: z36.string().describe("Shell command to execute")
7786
+ inputSchema = z37.object({
7787
+ command: z37.string().describe("Shell command to execute")
7344
7788
  });
7345
7789
  }
7346
7790
  });
@@ -7348,7 +7792,7 @@ var init_bash = __esm({
7348
7792
  // src/tools/glob.ts
7349
7793
  import { tool as tool2 } from "ai";
7350
7794
  import { glob as glob3 } from "glob";
7351
- import { z as z37 } from "zod";
7795
+ import { z as z38 } from "zod";
7352
7796
  async function executeGlob(pattern, cwd, ignorePatterns = DEFAULT_IGNORE) {
7353
7797
  try {
7354
7798
  const matches = await glob3(pattern, {
@@ -7382,9 +7826,9 @@ var init_glob = __esm({
7382
7826
  "src/tools/glob.ts"() {
7383
7827
  "use strict";
7384
7828
  init_esm_shims();
7385
- inputSchema2 = z37.object({
7386
- pattern: z37.string().describe("Glob pattern to match files (e.g. '**/*.ts', 'src/**/*.py')"),
7387
- cwd: z37.string().optional().describe("Directory to search in. Defaults to working directory.")
7829
+ inputSchema2 = z38.object({
7830
+ pattern: z38.string().describe("Glob pattern to match files (e.g. '**/*.ts', 'src/**/*.py')"),
7831
+ cwd: z38.string().optional().describe("Directory to search in. Defaults to working directory.")
7388
7832
  });
7389
7833
  DEFAULT_IGNORE = [
7390
7834
  "**/node_modules/**",
@@ -7402,7 +7846,7 @@ var init_glob = __esm({
7402
7846
  import { execFile as execFile4 } from "child_process";
7403
7847
  import { promisify as promisify3 } from "util";
7404
7848
  import { tool as tool3 } from "ai";
7405
- import { z as z38 } from "zod";
7849
+ import { z as z39 } from "zod";
7406
7850
  function buildGrepTool(workingDirectory) {
7407
7851
  return tool3({
7408
7852
  description: "Search file contents with ripgrep. Returns matching lines with file paths and line numbers.",
@@ -7446,10 +7890,10 @@ var init_grep = __esm({
7446
7890
  init_esm_shims();
7447
7891
  init_exec_error();
7448
7892
  execFileAsync3 = promisify3(execFile4);
7449
- inputSchema3 = z38.object({
7450
- pattern: z38.string().describe("Regex pattern to search for in file contents"),
7451
- glob: z38.string().optional().describe("Glob to filter files (e.g. '*.ts')"),
7452
- path: z38.string().optional().describe("File or directory to search in")
7893
+ inputSchema3 = z39.object({
7894
+ pattern: z39.string().describe("Regex pattern to search for in file contents"),
7895
+ glob: z39.string().optional().describe("Glob to filter files (e.g. '*.ts')"),
7896
+ path: z39.string().optional().describe("File or directory to search in")
7453
7897
  });
7454
7898
  }
7455
7899
  });
@@ -7457,10 +7901,10 @@ var init_grep = __esm({
7457
7901
  // src/tools/list-directory.ts
7458
7902
  import { readdir } from "fs/promises";
7459
7903
  import { stat } from "fs/promises";
7460
- import { join as join19, relative as relative3 } from "path";
7904
+ import { join as join20, relative as relative3 } from "path";
7461
7905
  import { tool as tool4 } from "ai";
7462
7906
  import { minimatch } from "minimatch";
7463
- import { z as z39 } from "zod";
7907
+ import { z as z40 } from "zod";
7464
7908
  function buildMatcher(patterns) {
7465
7909
  const positive = patterns.filter((p) => !p.startsWith("!"));
7466
7910
  const negative = patterns.filter((p) => p.startsWith("!")).map((p) => p.slice(1));
@@ -7482,7 +7926,7 @@ async function buildTree(dirPath, maxDepth, currentDepth, isIgnored, relativeBas
7482
7926
  const withTypes = [];
7483
7927
  for (const name of rawEntries) {
7484
7928
  try {
7485
- const s = await stat(join19(dirPath, name));
7929
+ const s = await stat(join20(dirPath, name));
7486
7930
  withTypes.push({ name, isDir: s.isDirectory() });
7487
7931
  } catch {
7488
7932
  withTypes.push({ name, isDir: false });
@@ -7502,7 +7946,7 @@ async function buildTree(dirPath, maxDepth, currentDepth, isIgnored, relativeBas
7502
7946
  }
7503
7947
  if (entry.isDir) {
7504
7948
  const children = await buildTree(
7505
- join19(dirPath, entry.name),
7949
+ join20(dirPath, entry.name),
7506
7950
  maxDepth,
7507
7951
  currentDepth + 1,
7508
7952
  isIgnored,
@@ -7540,10 +7984,10 @@ async function buildListDirectoryTool(workingDirectory) {
7540
7984
  const isIgnored = buildMatcher(patterns);
7541
7985
  return tool4({
7542
7986
  description: "List directory structure as a tree. Use this for an overview of the project layout. Start at the root (path='.') with depth 3, then increase depth or narrow path if needed. Do NOT call this on every subdirectory - use glob to find specific files instead. Returns cached result if the same path+depth was already requested.",
7543
- inputSchema: z39.object({
7544
- path: z39.string().default(".").describe("Directory path relative to project root. Defaults to root."),
7545
- depth: z39.number().min(1).max(15).default(10).describe("Max depth to traverse (1-15). Default 10."),
7546
- gitignore: z39.boolean().describe(
7987
+ inputSchema: z40.object({
7988
+ path: z40.string().default(".").describe("Directory path relative to project root. Defaults to root."),
7989
+ depth: z40.number().min(1).max(15).default(10).describe("Max depth to traverse (1-15). Default 10."),
7990
+ gitignore: z40.boolean().describe(
7547
7991
  "Whether to respect the gitignore or to ignore it. true will respect it. false will ignore it. Default true"
7548
7992
  ).default(true)
7549
7993
  }),
@@ -7555,7 +7999,7 @@ async function buildListDirectoryTool(workingDirectory) {
7555
7999
  };
7556
8000
  }
7557
8001
  seen.add(cacheKey);
7558
- const targetDir = input.path === "." ? workingDirectory : join19(workingDirectory, input.path);
8002
+ const targetDir = input.path === "." ? workingDirectory : join20(workingDirectory, input.path);
7559
8003
  try {
7560
8004
  const s = await stat(targetDir);
7561
8005
  if (!s.isDirectory()) {
@@ -7591,10 +8035,10 @@ var init_list_directory = __esm({
7591
8035
  });
7592
8036
 
7593
8037
  // src/tools/read-file.ts
7594
- import { readFile as readFile10 } from "fs/promises";
8038
+ import { readFile as readFile11 } from "fs/promises";
7595
8039
  import { relative as relative4, resolve as resolve2 } from "path";
7596
8040
  import { tool as tool5 } from "ai";
7597
- import { z as z40 } from "zod";
8041
+ import { z as z41 } from "zod";
7598
8042
  function resolveSandboxedPath(workingDirectory, filePath) {
7599
8043
  const absolutePath = resolve2(workingDirectory, filePath);
7600
8044
  const relativePath = relative4(workingDirectory, absolutePath);
@@ -7619,7 +8063,7 @@ async function executeReadFile(workingDirectory, filePath, offset, limit) {
7619
8063
  const resolved2 = resolveSandboxedPath(workingDirectory, filePath);
7620
8064
  if ("error" in resolved2) return resolved2;
7621
8065
  try {
7622
- const content = await readFile10(resolved2.absolutePath, "utf-8");
8066
+ const content = await readFile11(resolved2.absolutePath, "utf-8");
7623
8067
  const sliced = sliceLines(content, offset ?? 0, limit ?? MAX_LINES);
7624
8068
  if (sliced.numbered.length > MAX_OUTPUT_BYTES2) {
7625
8069
  sliced.numbered = sliced.numbered.slice(0, MAX_OUTPUT_BYTES2) + `
@@ -7652,10 +8096,10 @@ var init_read_file = __esm({
7652
8096
  init_esm_shims();
7653
8097
  MAX_LINES = 2e3;
7654
8098
  MAX_OUTPUT_BYTES2 = 256 * 1024;
7655
- inputSchema4 = z40.object({
7656
- filePath: z40.string().describe("Path to the file (absolute or relative to working directory)"),
7657
- offset: z40.number().int().min(0).optional().describe("Line number to start reading from (0-based)"),
7658
- limit: z40.number().int().min(1).optional().describe("Maximum number of lines to read")
8099
+ inputSchema4 = z41.object({
8100
+ filePath: z41.string().describe("Path to the file (absolute or relative to working directory)"),
8101
+ offset: z41.number().int().min(0).optional().describe("Line number to start reading from (0-based)"),
8102
+ limit: z41.number().int().min(1).optional().describe("Maximum number of lines to read")
7659
8103
  });
7660
8104
  }
7661
8105
  });
@@ -7678,10 +8122,10 @@ var init_pick_string = __esm({
7678
8122
 
7679
8123
  // src/tools/subagent.ts
7680
8124
  import { ToolLoopAgent as ToolLoopAgent2, hasToolCall as hasToolCall2, stepCountIs as stepCountIs2, tool as tool6 } from "ai";
7681
- import { z as z41 } from "zod";
8125
+ import { z as z42 } from "zod";
7682
8126
  function buildSubagentTools(workingDirectory, onFileRead) {
7683
8127
  const baseReadFile = buildReadFileTool(workingDirectory);
7684
- const readFile26 = onFileRead ? tool6({
8128
+ const readFile27 = onFileRead ? tool6({
7685
8129
  description: baseReadFile.description,
7686
8130
  inputSchema: baseReadFile.inputSchema,
7687
8131
  execute: async (input, options) => {
@@ -7694,7 +8138,7 @@ function buildSubagentTools(workingDirectory, onFileRead) {
7694
8138
  bash: buildBashTool(workingDirectory),
7695
8139
  glob: buildGlobTool(workingDirectory),
7696
8140
  grep: buildGrepTool(workingDirectory),
7697
- read_file: readFile26
8141
+ read_file: readFile27
7698
8142
  };
7699
8143
  }
7700
8144
  function buildSubagentTool(model, workingDirectory, onHeartbeat, onFileRead) {
@@ -7751,11 +8195,11 @@ var init_subagent = __esm({
7751
8195
  init_glob();
7752
8196
  init_grep();
7753
8197
  init_read_file();
7754
- inputSchema5 = z41.object({
7755
- instruction: z41.string().describe("Focused task for the subagent. Be specific about files and patterns to investigate.")
8198
+ inputSchema5 = z42.object({
8199
+ instruction: z42.string().describe("Focused task for the subagent. Be specific about files and patterns to investigate.")
7756
8200
  });
7757
- resultSchema = z41.object({
7758
- findings: z41.string().describe("Summary of what was found")
8201
+ resultSchema = z42.object({
8202
+ findings: z42.string().describe("Summary of what was found")
7759
8203
  });
7760
8204
  SYSTEM_PROMPT = `You are a code research assistant. You have tools to explore a codebase: bash (shell commands, mainly git), glob (find files), grep (search content), and read_file (read files).
7761
8205
 
@@ -7766,10 +8210,10 @@ Be thorough but focused - only investigate what's relevant to your instruction.`
7766
8210
  });
7767
8211
 
7768
8212
  // src/tools/write-file.ts
7769
- import { writeFile as writeFile6, mkdir as mkdir3 } from "fs/promises";
8213
+ import { writeFile as writeFile7, mkdir as mkdir3 } from "fs/promises";
7770
8214
  import { dirname as dirname3, relative as relative5, resolve as resolve3 } from "path";
7771
8215
  import { tool as tool7 } from "ai";
7772
- import { z as z42 } from "zod";
8216
+ import { z as z43 } from "zod";
7773
8217
  async function executeWriteFile(outputDirectory, filePath, content) {
7774
8218
  const cleaned = filePath.replace(/^autonoma\//, "");
7775
8219
  const absolutePath = resolve3(outputDirectory, cleaned);
@@ -7779,7 +8223,7 @@ async function executeWriteFile(outputDirectory, filePath, content) {
7779
8223
  }
7780
8224
  try {
7781
8225
  await mkdir3(dirname3(absolutePath), { recursive: true });
7782
- await writeFile6(absolutePath, content, "utf-8");
8226
+ await writeFile7(absolutePath, content, "utf-8");
7783
8227
  return { path: relativePath, bytesWritten: content.length };
7784
8228
  } catch (err) {
7785
8229
  const message = err instanceof Error ? err.message : String(err);
@@ -7798,21 +8242,21 @@ var init_write_file = __esm({
7798
8242
  "src/tools/write-file.ts"() {
7799
8243
  "use strict";
7800
8244
  init_esm_shims();
7801
- inputSchema6 = z42.object({
7802
- filePath: z42.string().describe("Path to write (absolute or relative to output directory)"),
7803
- content: z42.string().describe("File content to write")
8245
+ inputSchema6 = z43.object({
8246
+ filePath: z43.string().describe("Path to write (absolute or relative to output directory)"),
8247
+ content: z43.string().describe("File content to write")
7804
8248
  });
7805
8249
  }
7806
8250
  });
7807
8251
 
7808
8252
  // src/tools/ask-user.ts
7809
8253
  import { tool as tool8 } from "ai";
7810
- import { z as z43 } from "zod";
8254
+ import { z as z44 } from "zod";
7811
8255
  function buildAskUserTool() {
7812
8256
  return tool8({
7813
8257
  description: "Ask the user a question ONLY when the answer is truly unknowable from the codebase. Valid reasons: untyped JSON/JSONB field schemas, business rules not in code, config values not in source. NEVER ask about: field names (read the schema), field types (read the ORM model), enum values (read the code), relationships (read foreign keys), numeric values (read the seed data or defaults). If you can find it by reading a file, DO NOT ask - read the file instead.",
7814
- inputSchema: z43.object({
7815
- question: z43.string().describe(
8258
+ inputSchema: z44.object({
8259
+ question: z44.string().describe(
7816
8260
  "A clear, plain-language question. State exactly what you need to know and why you can't find it in code. BAD: 'What are the decimal values for checking_balance?' - GOOD: 'Your Account model has a metadata JSON column with no type definition. What fields go inside it?'"
7817
8261
  )
7818
8262
  }),
@@ -7872,7 +8316,7 @@ var init_tools = __esm({
7872
8316
 
7873
8317
  // src/agents/00-project-mapper/coverage.ts
7874
8318
  import { readdir as readdir2 } from "fs/promises";
7875
- import { join as join20 } from "path";
8319
+ import { join as join21 } from "path";
7876
8320
  async function findUncoveredDirs(projectRoot, map) {
7877
8321
  const entries = [...map.frontends, ...map.backends, ...map.ignore].map(
7878
8322
  (e) => e.path.replace(/^\.\//, "").replace(/\/+$/, "")
@@ -7896,7 +8340,7 @@ async function findUncoveredDirs(projectRoot, map) {
7896
8340
  const childRel = rel === "" ? child.name : `${rel}/${child.name}`;
7897
8341
  if (underEntry(childRel)) continue;
7898
8342
  if (hasEntryWithin(childRel)) {
7899
- if (depth + 1 < MAX_DEPTH) await walk(join20(abs, child.name), childRel, depth + 1);
8343
+ if (depth + 1 < MAX_DEPTH) await walk(join21(abs, child.name), childRel, depth + 1);
7900
8344
  } else {
7901
8345
  out.push(childRel);
7902
8346
  }
@@ -7923,7 +8367,7 @@ __export(project_mapper_exports, {
7923
8367
  runProjectMapper: () => runProjectMapper
7924
8368
  });
7925
8369
  import { tool as tool9 } from "ai";
7926
- import { z as z44 } from "zod";
8370
+ import { z as z45 } from "zod";
7927
8371
  async function runProjectMapper(input) {
7928
8372
  const model = getModel(input.modelId);
7929
8373
  const { logger, onStepFinish } = buildDefaultStepLogger("project-map", MAX_STEPS);
@@ -7957,7 +8401,7 @@ First build the full inventory (workspace/package manifests + top-level director
7957
8401
  }),
7958
8402
  finish: tool9({
7959
8403
  description: "End this step. Call once set_project_map has recorded a complete map.",
7960
- inputSchema: z44.object({}),
8404
+ inputSchema: z45.object({}),
7961
8405
  execute: () => {
7962
8406
  if (captured == null) {
7963
8407
  return { error: "Cannot finish: no map recorded - call set_project_map first." };
@@ -8001,7 +8445,7 @@ __export(pages_finder_exports, {
8001
8445
  import { existsSync } from "fs";
8002
8446
  import * as path2 from "path";
8003
8447
  import { tool as tool10 } from "ai";
8004
- import { z as z45 } from "zod";
8448
+ import { z as z46 } from "zod";
8005
8449
  async function runPageFinder(input) {
8006
8450
  const model = getModel(input.modelId);
8007
8451
  const pageCollector = new PageCollector();
@@ -8036,12 +8480,12 @@ ${input.extraMessage}`;
8036
8480
  }),
8037
8481
  view_pages: tool10({
8038
8482
  description: "use this tool to view all the pages that you already added",
8039
- inputSchema: z45.object(),
8483
+ inputSchema: z46.object(),
8040
8484
  execute: () => pageCollector.viewPages()
8041
8485
  }),
8042
8486
  finish: tool10({
8043
8487
  description: "End this step. Call once every page in the codebase has been added via add_page.",
8044
- inputSchema: z45.object({}),
8488
+ inputSchema: z46.object({}),
8045
8489
  execute: () => {
8046
8490
  if (pageCollector.pages.size === 0) {
8047
8491
  return {
@@ -8068,10 +8512,10 @@ var init_pages_finder = __esm({
8068
8512
  init_agent();
8069
8513
  init_model();
8070
8514
  init_tools();
8071
- Page = z45.object({
8072
- route: z45.string().min(1),
8073
- path: z45.string().min(1),
8074
- description: z45.string().min(10)
8515
+ Page = z46.object({
8516
+ route: z46.string().min(1),
8517
+ path: z46.string().min(1),
8518
+ description: z46.string().min(10)
8075
8519
  });
8076
8520
  PageCollector = class {
8077
8521
  // the key is the path
@@ -8267,15 +8711,15 @@ var kb_generator_exports = {};
8267
8711
  __export(kb_generator_exports, {
8268
8712
  runKBGenerator: () => runKBGenerator
8269
8713
  });
8270
- import { readFile as readFile11 } from "fs/promises";
8271
- import { join as join21, resolve as resolve5 } from "path";
8714
+ import { readFile as readFile12 } from "fs/promises";
8715
+ import { join as join22, resolve as resolve5 } from "path";
8272
8716
  import { tool as tool11 } from "ai";
8273
- import { z as z46 } from "zod";
8717
+ import { z as z47 } from "zod";
8274
8718
  function buildRegisterPagesTool(tracker) {
8275
8719
  return tool11({
8276
8720
  description: "Register ALL page/route files discovered via glob. Call this ONCE after globbing for page files. The system will track which ones you've read and block finish until all are covered.",
8277
- inputSchema: z46.object({
8278
- pages: z46.array(z46.string()).describe("All page file paths found by glob")
8721
+ inputSchema: z47.object({
8722
+ pages: z47.array(z47.string()).describe("All page file paths found by glob")
8279
8723
  }),
8280
8724
  execute: async (input) => {
8281
8725
  tracker.register(input.pages);
@@ -8289,7 +8733,7 @@ function buildRegisterPagesTool(tracker) {
8289
8733
  function buildPageCoverageTool(tracker) {
8290
8734
  return tool11({
8291
8735
  description: "Check how many registered pages you've read vs how many remain.",
8292
- inputSchema: z46.object({}),
8736
+ inputSchema: z47.object({}),
8293
8737
  execute: async () => tracker.coverage()
8294
8738
  });
8295
8739
  }
@@ -8300,9 +8744,9 @@ function requiredReads(total) {
8300
8744
  function buildFinishTool(tracker, onFinish) {
8301
8745
  return tool11({
8302
8746
  description: "Call when you have finished generating the knowledge base. BLOCKED until you have read enough of the registered routes (every route on a small app; a strong majority on a large one) - call page_coverage first to check how many remain.",
8303
- inputSchema: z46.object({
8304
- summary: z46.string().describe("Summary of what was generated"),
8305
- artifacts: z46.array(z46.string()).describe("List of files written")
8747
+ inputSchema: z47.object({
8748
+ summary: z47.string().describe("Summary of what was generated"),
8749
+ artifacts: z47.array(z47.string()).describe("List of files written")
8306
8750
  }),
8307
8751
  execute: async (input) => {
8308
8752
  const cov = tracker.coverage();
@@ -8381,8 +8825,8 @@ Output files:
8381
8825
  const agentConfig = buildKbAgentConfig(tracker, model, input, onStepFinish, setResult);
8382
8826
  await runAgent(agentConfig, prompt, () => result);
8383
8827
  logger.summary();
8384
- const autonomaPath = join21(input.outputDir, "AUTONOMA.md");
8385
- const autonomaExists = await readFile11(autonomaPath, "utf-8").then(() => true).catch((err) => {
8828
+ const autonomaPath = join22(input.outputDir, "AUTONOMA.md");
8829
+ const autonomaExists = await readFile12(autonomaPath, "utf-8").then(() => true).catch((err) => {
8386
8830
  debugLog("AUTONOMA.md not found while checking step completion", { err });
8387
8831
  return false;
8388
8832
  });
@@ -8568,17 +9012,17 @@ var entity_audit_exports = {};
8568
9012
  __export(entity_audit_exports, {
8569
9013
  runEntityAudit: () => runEntityAudit
8570
9014
  });
8571
- import { readFile as readFile12, writeFile as writeFile7 } from "fs/promises";
8572
- import { join as join22 } from "path";
9015
+ import { readFile as readFile13, writeFile as writeFile8 } from "fs/promises";
9016
+ import { join as join23 } from "path";
8573
9017
  import { tool as tool12 } from "ai";
8574
9018
  import { glob as glob4 } from "glob";
8575
- import { z as z47 } from "zod";
9019
+ import { z as z48 } from "zod";
8576
9020
  function buildRegisterModelsTool(tracker) {
8577
9021
  return tool12({
8578
9022
  description: "Register ALL database models discovered via grep. Call this ONCE after grepping for model definitions. After registering, use next_model to process them one at a time.",
8579
- inputSchema: z47.object({
8580
- models: z47.array(z47.string()).describe("All model/table names found by grep"),
8581
- framework: z47.string().describe("Database framework detected (e.g. 'sqlalchemy', 'prisma', 'drizzle')")
9023
+ inputSchema: z48.object({
9024
+ models: z48.array(z48.string()).describe("All model/table names found by grep"),
9025
+ framework: z48.string().describe("Database framework detected (e.g. 'sqlalchemy', 'prisma', 'drizzle')")
8582
9026
  }),
8583
9027
  execute: async (input) => {
8584
9028
  tracker.register(input.models);
@@ -8594,7 +9038,7 @@ function buildRegisterModelsTool(tracker) {
8594
9038
  function buildNextModelTool(tracker) {
8595
9039
  return tool12({
8596
9040
  description: "Get the next model to audit from the queue. If you called next_model before without calling mark_model_audited, the previous model is auto-skipped (marked as no creation path found). Returns done:true when all models are processed.",
8597
- inputSchema: z47.object({}),
9041
+ inputSchema: z48.object({}),
8598
9042
  execute: async () => {
8599
9043
  const next = tracker.nextModel();
8600
9044
  if (!next) {
@@ -8614,17 +9058,17 @@ function buildNextModelTool(tracker) {
8614
9058
  function buildMarkModelAuditedTool(tracker) {
8615
9059
  return tool12({
8616
9060
  description: "Mark a model as audited after you have determined its creation paths. Call this for EACH model after reading its creation code and determining independently_created + created_by. Include creation_function (e.g. 'UserService.create'), side_effects (list of things the creation does beyond the model itself), and for each created_by entry include owner, via (function name), and why (one sentence explaining the relationship).",
8617
- inputSchema: z47.object({
8618
- model: z47.string().describe("Model name"),
8619
- independently_created: z47.boolean(),
8620
- creation_file: z47.string().optional().describe("File containing the creation function"),
8621
- creation_function: z47.string().optional().describe("Function/method name (e.g. 'UserService.create' or 'create_user')"),
8622
- side_effects: z47.array(z47.string()).optional().describe("Side effects of creation (e.g. 'creates default Settings row', 'hashes password')"),
8623
- created_by: z47.array(
8624
- z47.object({
8625
- owner: z47.string().describe("Owner model name"),
8626
- via: z47.string().optional().describe("Function that creates this model (e.g. 'OrganizationService.create')"),
8627
- why: z47.string().optional().describe("One sentence explaining why this model is created as a side effect")
9061
+ inputSchema: z48.object({
9062
+ model: z48.string().describe("Model name"),
9063
+ independently_created: z48.boolean(),
9064
+ creation_file: z48.string().optional().describe("File containing the creation function"),
9065
+ creation_function: z48.string().optional().describe("Function/method name (e.g. 'UserService.create' or 'create_user')"),
9066
+ side_effects: z48.array(z48.string()).optional().describe("Side effects of creation (e.g. 'creates default Settings row', 'hashes password')"),
9067
+ created_by: z48.array(
9068
+ z48.object({
9069
+ owner: z48.string().describe("Owner model name"),
9070
+ via: z48.string().optional().describe("Function that creates this model (e.g. 'OrganizationService.create')"),
9071
+ why: z48.string().optional().describe("One sentence explaining why this model is created as a side effect")
8628
9072
  })
8629
9073
  ).describe("List of owner models that create this as a side effect, empty array if none")
8630
9074
  }),
@@ -8663,16 +9107,16 @@ function buildMarkModelAuditedTool(tracker) {
8663
9107
  function buildModelCoverageTool(tracker) {
8664
9108
  return tool12({
8665
9109
  description: "Check how many registered models you've audited vs how many remain.",
8666
- inputSchema: z47.object({}),
9110
+ inputSchema: z48.object({}),
8667
9111
  execute: async () => tracker.coverage()
8668
9112
  });
8669
9113
  }
8670
9114
  function buildFinishTool2(tracker, onFinish) {
8671
9115
  return tool12({
8672
9116
  description: "Call when entity audit is complete. BLOCKED if there are unaudited models - call model_coverage first to check.",
8673
- inputSchema: z47.object({
8674
- summary: z47.string().describe("Summary of the audit"),
8675
- artifacts: z47.array(z47.string()).describe("Files written")
9117
+ inputSchema: z48.object({
9118
+ summary: z48.string().describe("Summary of the audit"),
9119
+ artifacts: z48.array(z48.string()).describe("Files written")
8676
9120
  }),
8677
9121
  execute: async (input) => {
8678
9122
  const cov = tracker.coverage();
@@ -8700,7 +9144,7 @@ async function findPrismaSchema(projectRoot) {
8700
9144
  return candidates[0] ?? void 0;
8701
9145
  }
8702
9146
  async function extractPrismaModels(schemaPath) {
8703
- const content = await readFile12(schemaPath, "utf-8");
9147
+ const content = await readFile13(schemaPath, "utf-8");
8704
9148
  return content.split("\n").filter((line) => line.startsWith("model ")).map((line) => line.split(/\s+/)[1]).filter((name) => name != null);
8705
9149
  }
8706
9150
  async function detectFrameworkAndModels(projectRoot) {
@@ -8787,8 +9231,8 @@ ${formatException(err)}`);
8787
9231
  logger.summary();
8788
9232
  const writeCanonicalAudit = async () => {
8789
9233
  if (tracker.auditedModels.size === 0) return void 0;
8790
- const auditPath = join22(input.outputDir, "entity-audit.md");
8791
- await writeFile7(auditPath, tracker.generateAuditMarkdown(), "utf-8");
9234
+ const auditPath = join23(input.outputDir, "entity-audit.md");
9235
+ await writeFile8(auditPath, tracker.generateAuditMarkdown(), "utf-8");
8792
9236
  return auditPath;
8793
9237
  };
8794
9238
  const canonicalPath = await writeCanonicalAudit();
@@ -8802,9 +9246,9 @@ ${formatException(err)}`);
8802
9246
  }
8803
9247
  const reviewed = result;
8804
9248
  if (!reviewed) {
8805
- const auditPath = join22(input.outputDir, "entity-audit.md");
9249
+ const auditPath = join23(input.outputDir, "entity-audit.md");
8806
9250
  try {
8807
- await readFile12(auditPath, "utf-8");
9251
+ await readFile13(auditPath, "utf-8");
8808
9252
  return {
8809
9253
  success: true,
8810
9254
  artifacts: ["entity-audit.md"],
@@ -9008,15 +9452,37 @@ anything the database will refuse a second copy of - must embed a token INSIDE a
9008
9452
  otherwise real-looking value ("admin+{{${TEST_RUN_ID_TOKEN}}}@acme.test",
9009
9453
  "acme-{{${TEST_RUN_SHORT_ID_TOKEN}}}"), never replace the value entirely. Two tests
9010
9454
  run at the same time seed this scenario twice; without the token the second one fails
9011
- on a unique constraint. Everything else stays concrete and static, and no other
9012
- {{token}} or bare {variable} exists - inventing one is rejected.`;
9455
+ on a unique constraint. No other {{token}} or bare {variable} exists - inventing one
9456
+ is rejected.
9457
+
9458
+ ## Data the app compares against the current time
9459
+ This scenario is written once and seeded again, unchanged, before every run for as long
9460
+ as it lives. So a value the application compares against the current time is not static
9461
+ data: a record meant to be upcoming, overdue, expiring soon, still valid, or recent is a
9462
+ fact about WHEN THE TEST RUNS. Written as a calendar date it is right on the day you
9463
+ write it and quietly wrong ever after, and the failure it causes reads as a broken
9464
+ product rather than as stale data.
9465
+
9466
+ For every date or time you write, ask one question: does the app branch on this being
9467
+ before or after now? Look for the answer in its queries - a list split into current and
9468
+ past, a filter against an expiry, a state derived from a deadline. Do not guess from the
9469
+ field name.
9470
+
9471
+ Where the answer is yes, write the value as an offset from the moment of seeding
9472
+ ("starts 3 days after seeding, at 10:00", "ended 2 weeks before seeding") rather than a
9473
+ date. Where it is no - a recurring weekly schedule, a date of birth, a timestamp nothing
9474
+ filters on - a concrete date is correct and an offset would only obscure it.
9475
+
9476
+ An offset is prose in your table, not a token: there is no {{token}} for time, and
9477
+ inventing one is rejected like any other. The recipe builder turns what you write into a
9478
+ value its factories compute at seeding time.`;
9013
9479
  }
9014
9480
  });
9015
9481
 
9016
9482
  // src/agents/03-scenario-recipe/scenario-table.ts
9017
- import { readFile as readFile13 } from "fs/promises";
9018
- import { join as join23 } from "path";
9019
- import matter2 from "gray-matter";
9483
+ import { readFile as readFile14 } from "fs/promises";
9484
+ import { join as join24 } from "path";
9485
+ import matter2 from "@11ty/gray-matter";
9020
9486
  function validateScenarioIsConcrete(content) {
9021
9487
  const errors = findUnknownRecipeTokens(content).map(
9022
9488
  (token) => `unknown token "{{${token}}}" - scenario values must be concrete. Replace it with the exact static value; the only tokens Autonoma substitutes are ${BUILT_IN_RECIPE_TOKEN_LIST}.`
@@ -9050,22 +9516,22 @@ __export(scenario_recipe_exports, {
9050
9516
  feedbackToScenario: () => feedbackToScenario,
9051
9517
  runScenarioRecipe: () => runScenarioRecipe
9052
9518
  });
9053
- import { readFile as readFile14 } from "fs/promises";
9054
- import { join as join24 } from "path";
9519
+ import { readFile as readFile15 } from "fs/promises";
9520
+ import { join as join25 } from "path";
9055
9521
  import { tool as tool13 } from "ai";
9056
- import { z as z48 } from "zod";
9522
+ import { z as z49 } from "zod";
9057
9523
  function buildFinishTool3(requiredEntities, outputDir, onFinish) {
9058
9524
  return tool13({
9059
9525
  description: "Call when scenario design is complete and scenarios.md is written. BLOCKED if any required entities are missing from the scenario.",
9060
- inputSchema: z48.object({
9061
- summary: z48.string().describe("Summary of the scenario"),
9062
- entityCount: z48.number().describe("Number of entity types in the scenario"),
9063
- artifacts: z48.array(z48.string()).describe("Files written")
9526
+ inputSchema: z49.object({
9527
+ summary: z49.string().describe("Summary of the scenario"),
9528
+ entityCount: z49.number().describe("Number of entity types in the scenario"),
9529
+ artifacts: z49.array(z49.string()).describe("Files written")
9064
9530
  }),
9065
9531
  execute: async (input) => {
9066
9532
  let content;
9067
9533
  try {
9068
- content = await readFile14(join24(outputDir, "scenarios.md"), "utf-8");
9534
+ content = await readFile15(join25(outputDir, "scenarios.md"), "utf-8");
9069
9535
  } catch {
9070
9536
  return { error: "Cannot finish: scenarios.md not found. Write it first." };
9071
9537
  }
@@ -9144,9 +9610,9 @@ When done, call finish.`;
9144
9610
  logger.summary();
9145
9611
  const reviewed = result;
9146
9612
  if (!reviewed) {
9147
- const scenariosPath = join24(input.outputDir, "scenarios.md");
9613
+ const scenariosPath = join25(input.outputDir, "scenarios.md");
9148
9614
  try {
9149
- await readFile14(scenariosPath, "utf-8");
9615
+ await readFile15(scenariosPath, "utf-8");
9150
9616
  return {
9151
9617
  success: true,
9152
9618
  artifacts: ["scenarios.md"],
@@ -9205,12 +9671,12 @@ var init_scenario_recipe = __esm({
9205
9671
  });
9206
9672
 
9207
9673
  // src/agents/04-recipe-builder/entity-order.ts
9208
- import { readFile as readFile15 } from "fs/promises";
9209
- import { join as join25 } from "path";
9210
- import matter3 from "gray-matter";
9211
- import { z as z49 } from "zod";
9674
+ import { readFile as readFile16 } from "fs/promises";
9675
+ import { join as join26 } from "path";
9676
+ import matter3 from "@11ty/gray-matter";
9677
+ import { z as z50 } from "zod";
9212
9678
  async function parseEntityAudit(outputDir) {
9213
- const raw = await readFile15(join25(outputDir, "entity-audit.md"), "utf-8");
9679
+ const raw = await readFile16(join26(outputDir, "entity-audit.md"), "utf-8");
9214
9680
  try {
9215
9681
  const parsed = frontmatterSchema.safeParse(matter3(raw).data);
9216
9682
  if (parsed.success && parsed.data.models.length > 0) {
@@ -9371,34 +9837,34 @@ var init_entity_order = __esm({
9371
9837
  "src/agents/04-recipe-builder/entity-order.ts"() {
9372
9838
  "use strict";
9373
9839
  init_esm_shims();
9374
- createdBySchema = z49.object({
9375
- owner: z49.string(),
9376
- via: z49.string().optional(),
9377
- why: z49.string().optional()
9840
+ createdBySchema = z50.object({
9841
+ owner: z50.string(),
9842
+ via: z50.string().optional(),
9843
+ why: z50.string().optional()
9378
9844
  });
9379
- auditedModelSchema = z49.object({
9380
- name: z49.string(),
9381
- independently_created: z49.coerce.boolean().default(false),
9382
- creation_file: z49.string().optional(),
9383
- creation_function: z49.string().optional(),
9384
- side_effects: z49.array(z49.string()).optional(),
9845
+ auditedModelSchema = z50.object({
9846
+ name: z50.string(),
9847
+ independently_created: z50.coerce.boolean().default(false),
9848
+ creation_file: z50.string().optional(),
9849
+ creation_function: z50.string().optional(),
9850
+ side_effects: z50.array(z50.string()).optional(),
9385
9851
  // Tolerate a stray `created_by:` with no entries (parsed as null by YAML).
9386
- created_by: z49.array(createdBySchema).nullish().transform((v) => v ?? [])
9852
+ created_by: z50.array(createdBySchema).nullish().transform((v) => v ?? [])
9387
9853
  });
9388
- frontmatterSchema = z49.object({
9389
- models: z49.array(auditedModelSchema).nullish().transform((v) => v ?? [])
9854
+ frontmatterSchema = z50.object({
9855
+ models: z50.array(auditedModelSchema).nullish().transform((v) => v ?? [])
9390
9856
  });
9391
9857
  }
9392
9858
  });
9393
9859
 
9394
9860
  // src/agents/04-recipe-builder/completion.ts
9395
- import { readFile as readFile16 } from "fs/promises";
9396
- import { join as join26 } from "path";
9397
- import { z as z50 } from "zod";
9861
+ import { readFile as readFile17 } from "fs/promises";
9862
+ import { join as join27 } from "path";
9863
+ import { z as z51 } from "zod";
9398
9864
  async function readCompletion(outputDir) {
9399
9865
  let raw;
9400
9866
  try {
9401
- raw = await readFile16(join26(outputDir, COMPLETION_MARKER_FILE), "utf-8");
9867
+ raw = await readFile17(join27(outputDir, COMPLETION_MARKER_FILE), "utf-8");
9402
9868
  } catch (err) {
9403
9869
  debugLog("No completion marker yet", { err });
9404
9870
  return false;
@@ -9424,7 +9890,7 @@ var init_completion = __esm({
9424
9890
  init_esm_shims();
9425
9891
  init_debug();
9426
9892
  COMPLETION_MARKER_FILE = ".sdk-integration-complete";
9427
- completionSchema = z50.object({ complete: z50.literal(true) });
9893
+ completionSchema = z51.object({ complete: z51.literal(true) });
9428
9894
  }
9429
9895
  });
9430
9896
 
@@ -9432,9 +9898,10 @@ var init_completion = __esm({
9432
9898
  function watchForCompletion(outputDir, proc, timing = DEFAULT_WATCH_TIMING) {
9433
9899
  let graceTimer;
9434
9900
  let killTimer;
9901
+ let stopped = false;
9435
9902
  const poll = setInterval(() => {
9436
9903
  void readCompletion(outputDir).then((complete) => {
9437
- if (!complete || graceTimer != null) return;
9904
+ if (stopped || !complete || graceTimer != null) return;
9438
9905
  debugLog("Completion marker detected while the agent runs; scheduling terminal reclaim");
9439
9906
  clearInterval(poll);
9440
9907
  graceTimer = setTimeout(() => {
@@ -9448,6 +9915,7 @@ function watchForCompletion(outputDir, proc, timing = DEFAULT_WATCH_TIMING) {
9448
9915
  });
9449
9916
  }, timing.pollMs);
9450
9917
  return () => {
9918
+ stopped = true;
9451
9919
  clearInterval(poll);
9452
9920
  if (graceTimer != null) clearTimeout(graceTimer);
9453
9921
  if (killTimer != null) clearTimeout(killTimer);
@@ -9472,8 +9940,8 @@ var init_completion_watch = __esm({
9472
9940
  });
9473
9941
 
9474
9942
  // src/agents/04-recipe-builder/integration-prompt.ts
9475
- import { writeFile as writeFile8 } from "fs/promises";
9476
- import { join as join27 } from "path";
9943
+ import { writeFile as writeFile9 } from "fs/promises";
9944
+ import { join as join28 } from "path";
9477
9945
  function renderIntegrationPrompt(params) {
9478
9946
  const priorFailureSection = params.priorFailure != null ? `
9479
9947
  \u2550\u2550\u2550 A PRIOR SESSION DID NOT COMPLETE - READ THIS FIRST \u2550\u2550\u2550
@@ -9556,7 +10024,10 @@ STOP immediately and say EXACTLY what is missing and why you can't proceed.
9556
10024
  JavaScript/npm package.
9557
10025
  2. Implement ONE endpoint (prefer "${DEFAULT_ENDPOINT_PATH}" unless the repo has a
9558
10026
  clearly better convention) that handles the discover / up / down protocol through
9559
- the SDK handler. The signing secret AUTONOMA_SHARED_SECRET is ALREADY provisioned
10027
+ the SDK handler. If you mount it anywhere OTHER than "${DEFAULT_ENDPOINT_PATH}",
10028
+ say so on its own line in IMPLEMENTATION.md, exactly as
10029
+ "SDK endpoint path: /your/path" - Autonoma assumes the default and the next step
10030
+ of the setup has to be told the real one, or every scenario provision 404s. The signing secret AUTONOMA_SHARED_SECRET is ALREADY provisioned
9560
10031
  in the app's environment - verify the x-signature HMAC against that env value (the
9561
10032
  SDK reads it for you). Do NOT hardcode a secret or overwrite the env value.
9562
10033
  3. Implement a real factory for EVERY entity the entity audit says needs one:
@@ -9631,6 +10102,35 @@ value still reads as real: "admin+{{${TEST_RUN_ID_TOKEN}}}@acme.test", "acme-{{$
9631
10102
  Any OTHER {{token}} is rejected on upload: there is no general variable mechanism, so
9632
10103
  never invent one.
9633
10104
 
10105
+ \u2550\u2550\u2550 DATA THE APP COMPARES AGAINST THE CURRENT TIME \u2550\u2550\u2550
10106
+ Autonoma stores this recipe once and seeds it again, UNCHANGED, before every run for
10107
+ months. So a value the application compares against the current time is wrong the day
10108
+ after you write it. A row meant to be upcoming, overdue, expiring soon, still valid, or
10109
+ recent describes WHEN THE TEST RUNS, not a date on a calendar - and when it goes stale
10110
+ the suite fails in a way that reads as a product bug rather than as stale data. A seeded
10111
+ session or credential that has drifted past its expiry breaks every test at once.
10112
+
10113
+ For every date/time field you seed, ask one question: does the app branch on this being
10114
+ before or after now? Find the answer in the app's own queries - a list partitioned into
10115
+ current and past, a filter against an expiry, a state derived from a deadline. Do not
10116
+ guess from the field name.
10117
+
10118
+ Where the answer is YES, do not put an instant in the recipe. Take an OFFSET as the
10119
+ factory's input, and have the factory add it to the current time as it creates the row -
10120
+ the factory runs at seeding time, so its clock is the right one:
10121
+ recipe: { "startsInMinutes": 4320, "durationMinutes": 30 }
10122
+ factory: reads startsInMinutes, writes the column as (now + 4320 minutes)
10123
+ A factory's input schema is YOUR interface and does not have to mirror its columns -
10124
+ converting an input into the column's real shape inside the factory is normal, and is
10125
+ how a factory already handles any column whose stored form differs from its input. Anchor
10126
+ or round the derived value when the app only accepts particular times.
10127
+
10128
+ Where the answer is NO - a recurring weekly schedule, a date of birth, a timestamp
10129
+ nothing filters on - a concrete value is correct and an offset would only obscure it.
10130
+
10131
+ There is no {{token}} for time. Do not invent one: it is rejected on upload exactly like
10132
+ any other unknown token, and the derivation belongs in the factory anyway.
10133
+
9634
10134
  WHICH fields need a token is not a judgement call and not a guess from the field name.
9635
10135
  Before you write the recipe, ENUMERATE the uniqueness rules for every entity you seed:
9636
10136
  read the schema definitions and migrations, and query the live database you are already
@@ -9694,6 +10194,11 @@ Once every entity passes independently, run the FULL recipe as one pass:
9694
10194
  \u2022 confirm all rows created (DB), then down with the refsToken -> succeeds, rows gone (DB)
9695
10195
  \u2022 confirm a WRONG signature is rejected (the SDK does this for you - do not disable it)
9696
10196
  \u2022 confirm the up response's auth payload contains real credentials, not a placeholder
10197
+ \u2022 for every field you identified as compared against the current time, confirm the
10198
+ seeded row landed on the INTENDED side of now - run the app's own query or open the
10199
+ screen that partitions by time, and see the row where it is supposed to be. A row
10200
+ that exists in the right table but falls on the wrong side of now is the failure this
10201
+ check exists to catch, and "up returned 200" will not reveal it.
9697
10202
 
9698
10203
  \u2550\u2550\u2550 CHECK THE RECIPE FILE - THE GATE YOU CANNOT SKIP \u2550\u2550\u2550
9699
10204
  A recipe that seeds a database perfectly can still be a file Autonoma refuses, because
@@ -9762,7 +10267,7 @@ Write the completion marker once ALL of these hold:
9762
10267
  A step you documented as genuinely blocked NEVER justifies withholding the marker; a
9763
10268
  checklist item you simply have not finished always does. The marker is how the CLI knows
9764
10269
  the session is done and can upload the recipe:
9765
- ${join27(params.outputDir, COMPLETION_MARKER_FILE)}
10270
+ ${join28(params.outputDir, COMPLETION_MARKER_FILE)}
9766
10271
  Its contents MUST be exactly:
9767
10272
  { "complete": true }
9768
10273
  Writing it is not optional: the planner watches for this marker and takes the terminal
@@ -9774,27 +10279,45 @@ or the commit you left behind and what blocked the push - and then says:
9774
10279
  Nothing after that message - no further questions, summaries, or work.`;
9775
10280
  }
9776
10281
  async function writeIntegrationPrompt(params) {
9777
- const path3 = join27(params.outputDir, INTEGRATION_PROMPT_FILE);
9778
- await writeFile8(path3, renderIntegrationPrompt(params), "utf-8");
10282
+ const path3 = join28(params.outputDir, INTEGRATION_PROMPT_FILE);
10283
+ await writeFile9(path3, renderIntegrationPrompt(params), "utf-8");
9779
10284
  return path3;
9780
10285
  }
9781
- var INTEGRATION_PROMPT_VERSION, INTEGRATION_PROMPT_FILE, DEFAULT_ENDPOINT_PATH, INTEGRATION_BRANCH;
10286
+ var INTEGRATION_PROMPT_VERSION, INTEGRATION_PROMPT_FILE, DEFAULT_ENDPOINT_PATH;
9782
10287
  var init_integration_prompt = __esm({
9783
10288
  "src/agents/04-recipe-builder/integration-prompt.ts"() {
9784
10289
  "use strict";
9785
10290
  init_esm_shims();
9786
10291
  init_src();
9787
10292
  init_completion();
9788
- INTEGRATION_PROMPT_VERSION = 10;
10293
+ INTEGRATION_PROMPT_VERSION = 11;
9789
10294
  INTEGRATION_PROMPT_FILE = "integration-prompt.md";
9790
10295
  DEFAULT_ENDPOINT_PATH = "/api/autonoma";
9791
- INTEGRATION_BRANCH = "autonoma-integration";
10296
+ }
10297
+ });
10298
+
10299
+ // src/agents/04-recipe-builder/launch-outcome.ts
10300
+ function describeLaunchOutcome(launch) {
10301
+ const ranTooBriefly = launch.durationMs < FAILED_TO_START_MS;
10302
+ const exitedBadly = launch.exitCode != null && launch.exitCode !== 0;
10303
+ if (!ranTooBriefly || !exitedBadly) return { kind: "ran" };
10304
+ return {
10305
+ kind: "failed-to-start",
10306
+ summary: `${launch.agentLabel} exited immediately (code ${launch.exitCode}, after ${Math.round(launch.durationMs / 1e3)}s) without running the integration. That is the agent itself failing to start, not the integration failing - check that it runs on its own in this terminal.`
10307
+ };
10308
+ }
10309
+ var FAILED_TO_START_MS;
10310
+ var init_launch_outcome = __esm({
10311
+ "src/agents/04-recipe-builder/launch-outcome.ts"() {
10312
+ "use strict";
10313
+ init_esm_shims();
10314
+ FAILED_TO_START_MS = 9e4;
9792
10315
  }
9793
10316
  });
9794
10317
 
9795
10318
  // src/agents/04-recipe-builder/state.ts
9796
- import { readFile as readFile17, writeFile as writeFile9 } from "fs/promises";
9797
- import { join as join28 } from "path";
10319
+ import { readFile as readFile18, writeFile as writeFile10 } from "fs/promises";
10320
+ import { join as join29 } from "path";
9798
10321
  function initialRecipeState() {
9799
10322
  return {
9800
10323
  phase: "tech-detect",
@@ -9804,7 +10327,7 @@ function initialRecipeState() {
9804
10327
  }
9805
10328
  async function loadRecipeState(outputDir) {
9806
10329
  try {
9807
- const raw = await readFile17(join28(outputDir, STATE_FILE2), "utf-8");
10330
+ const raw = await readFile18(join29(outputDir, STATE_FILE2), "utf-8");
9808
10331
  const parsed = JSON.parse(raw);
9809
10332
  return parsed;
9810
10333
  } catch {
@@ -9812,7 +10335,7 @@ async function loadRecipeState(outputDir) {
9812
10335
  }
9813
10336
  }
9814
10337
  async function saveRecipeState(outputDir, state) {
9815
- await writeFile9(join28(outputDir, STATE_FILE2), JSON.stringify(state, null, 2), "utf-8");
10338
+ await writeFile10(join29(outputDir, STATE_FILE2), JSON.stringify(state, null, 2), "utf-8");
9816
10339
  }
9817
10340
  var STATE_FILE2;
9818
10341
  var init_state2 = __esm({
@@ -9825,12 +10348,12 @@ var init_state2 = __esm({
9825
10348
 
9826
10349
  // src/agents/04-recipe-builder/phases/handoff.ts
9827
10350
  import { rm as rm2 } from "fs/promises";
9828
- import { join as join29 } from "path";
10351
+ import { join as join30 } from "path";
9829
10352
  function launchMessage(promptFile) {
9830
10353
  return `Read the file ${promptFile} and follow its instructions exactly to integrate Autonoma into this application. It is your complete spec. Do not stop until every item in it is done and you have written the completion marker it describes.`;
9831
10354
  }
9832
10355
  async function runHandoffPhase(state, deps, outputDir) {
9833
- const recipePath = state.recipePath ?? join29(outputDir, RECIPE_FILE);
10356
+ const recipePath = state.recipePath ?? join30(outputDir, RECIPE_FILE);
9834
10357
  state.recipePath = recipePath;
9835
10358
  const launcher = await selectLauncher(deps.launchers, state.agentId ?? deps.presetAgentId, deps.interactive);
9836
10359
  if (launcher == null) {
@@ -9839,11 +10362,15 @@ async function runHandoffPhase(state, deps, outputDir) {
9839
10362
  }
9840
10363
  return manualFallback(outputDir, recipePath, deps.cliCommand, NO_AGENT_FOUND);
9841
10364
  }
9842
- const permissionMode = deps.interactive ? await selectPermissionMode(state.permissionMode ?? deps.presetPermissionMode) : state.permissionMode ?? deps.presetPermissionMode ?? DEFAULT_PERMISSION_MODE;
10365
+ const permissionMode = await resolvePermissionMode({
10366
+ preset: deps.presetPermissionMode,
10367
+ remembered: state.permissionMode,
10368
+ interactive: deps.interactive
10369
+ });
9843
10370
  state.agentId = launcher.id;
9844
10371
  state.permissionMode = permissionMode;
9845
10372
  await saveRecipeState(outputDir, state);
9846
- await launchAgent(launcher, permissionMode, {
10373
+ state.lastLaunch = await launchAgent(launcher, permissionMode, {
9847
10374
  outputDir,
9848
10375
  recipePath,
9849
10376
  cliCommand: deps.cliCommand,
@@ -9856,7 +10383,7 @@ async function runHandoffPhase(state, deps, outputDir) {
9856
10383
  return { kind: "advance" };
9857
10384
  }
9858
10385
  async function runCompletionPhase(state, deps, outputDir) {
9859
- const recipePath = state.recipePath ?? join29(outputDir, RECIPE_FILE);
10386
+ const recipePath = state.recipePath ?? join30(outputDir, RECIPE_FILE);
9860
10387
  while (true) {
9861
10388
  const [complete, read] = await Promise.all([readCompletion(outputDir), loadRecipe(outputDir)]);
9862
10389
  const uploadProblems = read.status === "ok" ? findRecipeUploadProblems(read.recipe) : [];
@@ -9872,30 +10399,59 @@ async function runCompletionPhase(state, deps, outputDir) {
9872
10399
  return await manualFallback(outputDir, recipePath, deps.cliCommand, NO_AGENT_FOUND);
9873
10400
  }
9874
10401
  const failure = describeIncompleteRecipe(read, uploadProblems, recipePath, deps.cliCommand);
9875
- if (launcher != null && (state.launchAttempts ?? 0) < MAX_LAUNCH_ATTEMPTS) {
9876
- log.warn("The integration isn't complete yet. Launching the agent to finish it...");
9877
- state.agentId = launcher.id;
9878
- state.priorFailure = failure;
9879
- await saveRecipeState(outputDir, state);
9880
- await launchAgent(launcher, state.permissionMode ?? "bypassPermissions", {
9881
- outputDir,
9882
- recipePath,
9883
- cliCommand: deps.cliCommand,
9884
- interactive: deps.interactive,
9885
- priorFailure: failure,
9886
- userGuidance: state.userGuidance
9887
- });
9888
- state.launchAttempts = (state.launchAttempts ?? 0) + 1;
9889
- await saveRecipeState(outputDir, state);
9890
- continue;
9891
- }
9892
- return { kind: "handback", summary: handbackSummary(failure, outputDir) };
10402
+ const retry = await planRetry(state, launcher, deps, failure);
10403
+ if (retry.kind === "give-up") return { kind: "handback", summary: handbackSummary(retry.summary, outputDir) };
10404
+ log.warn(retry.announcement);
10405
+ state.agentId = retry.launcher.id;
10406
+ state.priorFailure = retry.priorFailure;
10407
+ await saveRecipeState(outputDir, state);
10408
+ state.lastLaunch = await launchAgent(retry.launcher, state.permissionMode ?? "bypassPermissions", {
10409
+ outputDir,
10410
+ recipePath,
10411
+ cliCommand: deps.cliCommand,
10412
+ interactive: deps.interactive,
10413
+ priorFailure: retry.priorFailure,
10414
+ userGuidance: state.userGuidance
10415
+ });
10416
+ state.launchAttempts = (state.launchAttempts ?? 0) + 1;
10417
+ await saveRecipeState(outputDir, state);
9893
10418
  }
9894
10419
  }
10420
+ async function planRetry(state, launcher, deps, failure) {
10421
+ const lastLaunch = state.lastLaunch;
10422
+ const outcome = lastLaunch == null ? void 0 : describeLaunchOutcome(lastLaunch);
10423
+ const failedToStart = outcome?.kind === "failed-to-start" ? outcome.summary : void 0;
10424
+ const summary = failedToStart ?? failure;
10425
+ if (launcher == null) return { kind: "give-up", summary };
10426
+ if ((state.launchAttempts ?? 0) >= MAX_LAUNCH_ATTEMPTS) return { kind: "give-up", summary };
10427
+ if (failedToStart != null && lastLaunch != null) {
10428
+ const alternative = await findOtherAvailableAgent(deps.launchers, lastLaunch.agentId);
10429
+ if (alternative == null) return { kind: "give-up", summary: failedToStart };
10430
+ return {
10431
+ kind: "relaunch",
10432
+ launcher: alternative,
10433
+ // No prior failure: nothing was attempted, so telling a fresh agent that a
10434
+ // prior session "did not complete" would send it hunting for work that was
10435
+ // never started.
10436
+ announcement: `${failedToStart} Trying ${alternative.label} instead...`
10437
+ };
10438
+ }
10439
+ return {
10440
+ kind: "relaunch",
10441
+ launcher,
10442
+ priorFailure: failure,
10443
+ announcement: "The integration isn't complete yet. Launching the agent to finish it..."
10444
+ };
10445
+ }
10446
+ async function findOtherAvailableAgent(launchers, failedAgentId) {
10447
+ const others = launchers.filter((l) => l.id !== failedAgentId);
10448
+ const availability = await Promise.all(others.map((l) => l.isAvailable()));
10449
+ return others.find((_, index) => availability[index]);
10450
+ }
9895
10451
  function handbackSummary(failure, outputDir) {
9896
10452
  return `${failure}
9897
10453
 
9898
- Finish the integration (see the prompt at ${join29(outputDir, INTEGRATION_PROMPT_FILE)}), then re-run with --resume.`;
10454
+ Finish the integration (see the prompt at ${join30(outputDir, INTEGRATION_PROMPT_FILE)}), then re-run with --resume.`;
9899
10455
  }
9900
10456
  async function launchAgent(launcher, permissionMode, target) {
9901
10457
  const promptFile = await writeIntegrationPrompt({
@@ -9905,7 +10461,7 @@ async function launchAgent(launcher, permissionMode, target) {
9905
10461
  priorFailure: target.priorFailure,
9906
10462
  userGuidance: target.userGuidance
9907
10463
  });
9908
- await rm2(join29(target.outputDir, COMPLETION_MARKER_FILE), { force: true }).catch((err) => {
10464
+ await rm2(join30(target.outputDir, COMPLETION_MARKER_FILE), { force: true }).catch((err) => {
9909
10465
  debugLog("Could not clear a stale completion marker", { err });
9910
10466
  });
9911
10467
  log.info(`Launching ${launcher.label}. It will implement the integration - watch and steer it as it works.`);
@@ -9922,6 +10478,7 @@ async function launchAgent(launcher, permissionMode, target) {
9922
10478
  });
9923
10479
  }
9924
10480
  suspend();
10481
+ const startedAt = Date.now();
9925
10482
  try {
9926
10483
  const exitCode = await launcher.launch({
9927
10484
  message: launchMessage(promptFile),
@@ -9932,7 +10489,22 @@ async function launchAgent(launcher, permissionMode, target) {
9932
10489
  // own and needs no watcher.
9933
10490
  watch: target.interactive ? (proc) => watchForCompletion(target.outputDir, proc) : void 0
9934
10491
  });
9935
- log.info(`${launcher.label} exited (code ${exitCode ?? "unknown"}). Back to the planner.`);
10492
+ const launch = {
10493
+ agentLabel: launcher.label,
10494
+ agentId: launcher.id,
10495
+ exitCode,
10496
+ durationMs: Date.now() - startedAt
10497
+ };
10498
+ log.info(
10499
+ `${launcher.label} exited (code ${exitCode ?? "unknown"}) after ${Math.round(launch.durationMs / 1e3)}s. Back to the planner.`
10500
+ );
10501
+ track("cli_agent_launch_finished", {
10502
+ agent: launcher.id,
10503
+ exit_code: exitCode,
10504
+ duration_ms: launch.durationMs,
10505
+ outcome: describeLaunchOutcome(launch).kind
10506
+ });
10507
+ return launch;
9936
10508
  } finally {
9937
10509
  resume();
9938
10510
  }
@@ -9979,14 +10551,17 @@ var init_handoff = __esm({
9979
10551
  "src/agents/04-recipe-builder/phases/handoff.ts"() {
9980
10552
  "use strict";
9981
10553
  init_esm_shims();
10554
+ init_analytics();
9982
10555
  init_coding_agent();
9983
10556
  init_debug();
9984
10557
  init_interrupt();
9985
10558
  init_notify();
10559
+ init_permission_mode();
9986
10560
  init_prompts();
9987
10561
  init_completion();
9988
10562
  init_completion_watch();
9989
10563
  init_integration_prompt();
10564
+ init_launch_outcome();
9990
10565
  init_recipe();
9991
10566
  init_state2();
9992
10567
  MAX_LAUNCH_ATTEMPTS = 2;
@@ -10103,17 +10678,17 @@ var init_recipe_builder = __esm({
10103
10678
  });
10104
10679
 
10105
10680
  // src/agents/00b-feature-discovery/index.ts
10106
- import { readFile as readFile18, writeFile as writeFile10 } from "fs/promises";
10107
- import { join as join30 } from "path";
10681
+ import { readFile as readFile19, writeFile as writeFile11 } from "fs/promises";
10682
+ import { join as join31 } from "path";
10108
10683
  import { tool as tool14 } from "ai";
10109
- import { z as z51 } from "zod";
10684
+ import { z as z52 } from "zod";
10110
10685
  async function saveFeatures(outputDir, features) {
10111
10686
  const obj = Object.fromEntries(features);
10112
- await writeFile10(join30(outputDir, FEATURES_FILE), JSON.stringify(obj, null, 2), "utf-8");
10687
+ await writeFile11(join31(outputDir, FEATURES_FILE), JSON.stringify(obj, null, 2), "utf-8");
10113
10688
  }
10114
10689
  async function loadFeatures(outputDir) {
10115
10690
  try {
10116
- const raw = await readFile18(join30(outputDir, FEATURES_FILE), "utf-8");
10691
+ const raw = await readFile19(join31(outputDir, FEATURES_FILE), "utf-8");
10117
10692
  const obj = JSON.parse(raw);
10118
10693
  return new Map(Object.entries(obj));
10119
10694
  } catch {
@@ -10147,7 +10722,7 @@ Process every page. Call add_feature for each sub-feature you discover. When don
10147
10722
  add_feature: tool14({
10148
10723
  description: "Add a discovered sub-feature",
10149
10724
  inputSchema: Feature.extend({
10150
- id: z51.string().min(1).describe("Unique kebab-case ID (e.g. 'settings-notifications-tab')")
10725
+ id: z52.string().min(1).describe("Unique kebab-case ID (e.g. 'settings-notifications-tab')")
10151
10726
  }),
10152
10727
  execute: (featureInput) => {
10153
10728
  const { id, ...rest } = featureInput;
@@ -10161,17 +10736,17 @@ Process every page. Call add_feature for each sub-feature you discover. When don
10161
10736
  }),
10162
10737
  view_features: tool14({
10163
10738
  description: "View all discovered features so far",
10164
- inputSchema: z51.object({}),
10739
+ inputSchema: z52.object({}),
10165
10740
  execute: () => collector.viewFeatures()
10166
10741
  }),
10167
10742
  view_pages: tool14({
10168
10743
  description: "View the pages list to know what to analyze",
10169
- inputSchema: z51.object({}),
10744
+ inputSchema: z52.object({}),
10170
10745
  execute: () => pagesDescription
10171
10746
  }),
10172
10747
  finish: tool14({
10173
10748
  description: "Signal that feature discovery is complete",
10174
- inputSchema: z51.object({ summary: z51.string() }),
10749
+ inputSchema: z52.object({ summary: z52.string() }),
10175
10750
  execute: async (finishInput) => {
10176
10751
  result = {
10177
10752
  success: true,
@@ -10202,13 +10777,13 @@ var init_b_feature_discovery = __esm({
10202
10777
  init_model();
10203
10778
  init_tools();
10204
10779
  FEATURES_FILE = "features.json";
10205
- Feature = z51.object({
10206
- name: z51.string().min(1).describe("Human-readable name (e.g. 'Settings > Notifications Tab', 'Create Project Modal')"),
10207
- type: z51.enum(["tab", "modal", "form", "table", "wizard", "nested-route", "complex-component"]),
10208
- parentPagePath: z51.string().min(1).describe("The page path this feature belongs to (from the pages list)"),
10209
- sourceFiles: z51.array(z51.string()).min(1).describe("Relative paths to the source files for this sub-feature"),
10210
- interactiveElements: z51.number().int().min(0).describe("Count of interactive elements found (buttons, inputs, toggles, etc.)"),
10211
- description: z51.string().min(10).describe("What this sub-feature does")
10780
+ Feature = z52.object({
10781
+ name: z52.string().min(1).describe("Human-readable name (e.g. 'Settings > Notifications Tab', 'Create Project Modal')"),
10782
+ type: z52.enum(["tab", "modal", "form", "table", "wizard", "nested-route", "complex-component"]),
10783
+ parentPagePath: z52.string().min(1).describe("The page path this feature belongs to (from the pages list)"),
10784
+ sourceFiles: z52.array(z52.string()).min(1).describe("Relative paths to the source files for this sub-feature"),
10785
+ interactiveElements: z52.number().int().min(0).describe("Count of interactive elements found (buttons, inputs, toggles, etc.)"),
10786
+ description: z52.string().min(10).describe("What this sub-feature does")
10212
10787
  });
10213
10788
  FeatureCollector = class {
10214
10789
  features = /* @__PURE__ */ new Map();
@@ -10291,21 +10866,21 @@ Use kebab-case IDs that indicate the parent page and feature type:
10291
10866
  });
10292
10867
 
10293
10868
  // src/agents/05-test-generator/graph.ts
10294
- import { readFile as readFile19, writeFile as writeFile11 } from "fs/promises";
10295
- import { join as join31 } from "path";
10869
+ import { readFile as readFile20, writeFile as writeFile12 } from "fs/promises";
10870
+ import { join as join32 } from "path";
10296
10871
  function estimateExpectedTests(written, processed, totalNodes) {
10297
10872
  if (totalNodes <= 0) return written;
10298
10873
  const rate = written > 0 && processed >= LIVE_RATE_MIN_PROCESSED ? written / processed : TESTS_PER_NODE_PRIOR;
10299
10874
  return Math.max(written, Math.round(rate * totalNodes));
10300
10875
  }
10301
10876
  async function saveBfsState(outputDir, state) {
10302
- const path3 = join31(outputDir, state.stateFile);
10303
- await writeFile11(path3, JSON.stringify(state.serialize(), null, 2), "utf-8");
10877
+ const path3 = join32(outputDir, state.stateFile);
10878
+ await writeFile12(path3, JSON.stringify(state.serialize(), null, 2), "utf-8");
10304
10879
  }
10305
10880
  async function loadBfsState(outputDir) {
10306
- const path3 = join31(outputDir, BFS_STATE_FILE);
10881
+ const path3 = join32(outputDir, BFS_STATE_FILE);
10307
10882
  try {
10308
- const raw = await readFile19(path3, "utf-8");
10883
+ const raw = await readFile20(path3, "utf-8");
10309
10884
  return CoverageState.deserialize(JSON.parse(raw));
10310
10885
  } catch {
10311
10886
  return void 0;
@@ -10905,13 +11480,13 @@ When you finish, all dimensions are reported so the user knows what's covered an
10905
11480
  });
10906
11481
 
10907
11482
  // src/agents/05-test-generator/recipe-context.ts
10908
- import { readFile as readFile20 } from "fs/promises";
10909
- import { join as join32 } from "path";
10910
- import { z as z52 } from "zod";
11483
+ import { readFile as readFile21 } from "fs/promises";
11484
+ import { join as join33 } from "path";
11485
+ import { z as z53 } from "zod";
10911
11486
  async function loadRecipeContext(outputDir) {
10912
11487
  let raw;
10913
11488
  try {
10914
- raw = await readFile20(join32(outputDir, "recipe.json"), "utf-8");
11489
+ raw = await readFile21(join33(outputDir, "recipe.json"), "utf-8");
10915
11490
  } catch (err) {
10916
11491
  debugLog("recipe.json not present; test generation falls back to scenarios.md alone", { err });
10917
11492
  return "";
@@ -10969,13 +11544,13 @@ var init_recipe_context = __esm({
10969
11544
  init_debug();
10970
11545
  STRUCTURAL_KEYS = /* @__PURE__ */ new Set(["_alias", "_ref"]);
10971
11546
  TEMPLATE_TOKEN = /\{\{\s*\w+\s*\}\}/;
10972
- recipeRowSchema = z52.record(z52.string(), z52.unknown());
10973
- recipeFileSchema = z52.object({
10974
- recipes: z52.array(
10975
- z52.object({
10976
- name: z52.string(),
10977
- description: z52.string().optional(),
10978
- create: z52.record(z52.string(), z52.array(recipeRowSchema)).optional()
11547
+ recipeRowSchema = z53.record(z53.string(), z53.unknown());
11548
+ recipeFileSchema = z53.object({
11549
+ recipes: z53.array(
11550
+ z53.object({
11551
+ name: z53.string(),
11552
+ description: z53.string().optional(),
11553
+ create: z53.record(z53.string(), z53.array(recipeRowSchema)).optional()
10979
11554
  })
10980
11555
  )
10981
11556
  });
@@ -10983,7 +11558,7 @@ var init_recipe_context = __esm({
10983
11558
  });
10984
11559
 
10985
11560
  // src/agents/05-test-generator/restore-deleted-test.ts
10986
- import { access, mkdir as mkdir4, writeFile as writeFile12 } from "fs/promises";
11561
+ import { access, mkdir as mkdir4, writeFile as writeFile13 } from "fs/promises";
10987
11562
  import { dirname as dirname4 } from "path";
10988
11563
  async function restoreDeletedTest(testPath, originalContent) {
10989
11564
  try {
@@ -10994,7 +11569,7 @@ async function restoreDeletedTest(testPath, originalContent) {
10994
11569
  }
10995
11570
  try {
10996
11571
  await mkdir4(dirname4(testPath), { recursive: true });
10997
- await writeFile12(testPath, originalContent, "utf-8");
11572
+ await writeFile13(testPath, originalContent, "utf-8");
10998
11573
  return true;
10999
11574
  } catch (err) {
11000
11575
  console.warn(` [fix] Could not restore ${testPath}: ${err instanceof Error ? err.message : String(err)}`);
@@ -11061,21 +11636,21 @@ var init_pool = __esm({
11061
11636
  });
11062
11637
 
11063
11638
  // src/agents/05-test-generator/rubrics.ts
11064
- import { z as z53 } from "zod";
11639
+ import { z as z54 } from "zod";
11065
11640
  function reviewResultSchema(shape) {
11066
- return z53.object(shape);
11641
+ return z54.object(shape);
11067
11642
  }
11068
11643
  var dimensionResultSchema, reviewResultRecordSchema, structuralIntentRubric, flowCompletenessRubric, uiTextRubric, dataAccuracyRubric, ALL_RUBRICS;
11069
11644
  var init_rubrics = __esm({
11070
11645
  "src/agents/05-test-generator/rubrics.ts"() {
11071
11646
  "use strict";
11072
11647
  init_esm_shims();
11073
- dimensionResultSchema = z53.object({
11074
- pass: z53.boolean(),
11075
- evidence: z53.string().describe("What you checked and found - cite file paths, line content, or specific strings"),
11076
- suggestion: z53.string().optional().describe("What the planner agent should fix, if failing")
11648
+ dimensionResultSchema = z54.object({
11649
+ pass: z54.boolean(),
11650
+ evidence: z54.string().describe("What you checked and found - cite file paths, line content, or specific strings"),
11651
+ suggestion: z54.string().optional().describe("What the planner agent should fix, if failing")
11077
11652
  });
11078
- reviewResultRecordSchema = z53.record(z53.string(), dimensionResultSchema);
11653
+ reviewResultRecordSchema = z54.record(z54.string(), dimensionResultSchema);
11079
11654
  structuralIntentRubric = {
11080
11655
  name: "structural-intent",
11081
11656
  maxSteps: 8,
@@ -11251,12 +11826,12 @@ When done reviewing, call finish with your structured evaluation.`
11251
11826
  });
11252
11827
 
11253
11828
  // src/agents/05-test-generator/review-pass.ts
11254
- import { basename as basename4 } from "path";
11829
+ import { basename as basename5 } from "path";
11255
11830
  import "ai";
11256
11831
  import { tool as tool15 } from "ai";
11257
11832
  async function runReviewPass(testContent, testPath, rubric, projectRoot, model, scenarioData) {
11258
11833
  let result;
11259
- const agentLabel = `review:${rubric.name}:${basename4(testPath)}`;
11834
+ const agentLabel = `review:${rubric.name}:${basename5(testPath)}`;
11260
11835
  const { onStepFinish } = buildDefaultStepLogger(agentLabel, rubric.maxSteps);
11261
11836
  const finishTool = tool15({
11262
11837
  description: "Submit your structured review. Every dimension must have evidence from your investigation.",
@@ -11321,12 +11896,12 @@ var init_review_pass = __esm({
11321
11896
  });
11322
11897
 
11323
11898
  // src/agents/05-test-generator/review.ts
11324
- import { readFile as readFile21 } from "fs/promises";
11325
- import { join as join33, relative as relative7, basename as basename5 } from "path";
11899
+ import { readFile as readFile22 } from "fs/promises";
11900
+ import { join as join34, relative as relative7, basename as basename6 } from "path";
11326
11901
  import "ai";
11327
11902
  import { glob as glob5 } from "glob";
11328
11903
  function markReview(relativePath, status) {
11329
- getActiveStore()?.setArtifactReview(join33(TESTS_DIR, relativePath), status);
11904
+ getActiveStore()?.setArtifactReview(join34(TESTS_DIR, relativePath), status);
11330
11905
  }
11331
11906
  function mergeRubricResults(reported) {
11332
11907
  const merged = {};
@@ -11360,7 +11935,7 @@ async function reviewOneTest({
11360
11935
  dataContract
11361
11936
  ).catch((err) => {
11362
11937
  console.warn(
11363
- ` [review] ${rubric.name} error on ${basename5(test.relativePath)}: ${err instanceof Error ? err.message : String(err)}`
11938
+ ` [review] ${rubric.name} error on ${basename6(test.relativePath)}: ${err instanceof Error ? err.message : String(err)}`
11364
11939
  );
11365
11940
  return void 0;
11366
11941
  });
@@ -11381,24 +11956,24 @@ async function readDataContract(outputDir) {
11381
11956
  const recipe = await loadRecipeContext(outputDir);
11382
11957
  if (recipe !== "") return recipe;
11383
11958
  try {
11384
- return await readFile21(join33(outputDir, "scenarios.md"), "utf-8");
11959
+ return await readFile22(join34(outputDir, "scenarios.md"), "utf-8");
11385
11960
  } catch (err) {
11386
11961
  debugLog("No data contract available for review", { err });
11387
11962
  return void 0;
11388
11963
  }
11389
11964
  }
11390
11965
  async function runConsolidatedReview(outputDir, projectRoot, model, deadline, settled = /* @__PURE__ */ new Set(), precomputed = [], onProgress) {
11391
- const testsDir = join33(outputDir, TESTS_DIR);
11966
+ const testsDir = join34(outputDir, TESTS_DIR);
11392
11967
  const logger = createStepLogger("review", 5);
11393
11968
  const scenarioData = await readDataContract(outputDir);
11394
- const testFiles = await glob5(join33(testsDir, TEST_FILE_GLOB));
11969
+ const testFiles = await glob5(join34(testsDir, TEST_FILE_GLOB));
11395
11970
  const tests = [];
11396
11971
  for (const testPath of testFiles) {
11397
11972
  if (!isTestFile(testPath)) continue;
11398
11973
  if (testPath.includes("/_invalid/")) continue;
11399
11974
  const relativePath = relative7(testsDir, testPath);
11400
11975
  if (settled.has(relativePath)) continue;
11401
- const content = await readFile21(testPath, "utf-8");
11976
+ const content = await readFile22(testPath, "utf-8");
11402
11977
  const flowMatch = content.match(/^---\n[\s\S]*?flow:\s*["']?([^"'\n]+)["']?\s*\n[\s\S]*?---/m);
11403
11978
  tests.push({ path: testPath, relativePath, content, flow: flowMatch?.[1]?.trim() ?? "unknown" });
11404
11979
  }
@@ -11439,7 +12014,7 @@ async function runConsolidatedReview(outputDir, projectRoot, model, deadline, se
11439
12014
  );
11440
12015
  for (const { item, error } of outcome.failed) {
11441
12016
  console.warn(
11442
- ` [review] ${item.rubric.name} error on ${basename5(item.test.path)}: ${error instanceof Error ? error.message : String(error)}`
12017
+ ` [review] ${item.rubric.name} error on ${basename6(item.test.path)}: ${error instanceof Error ? error.message : String(error)}`
11443
12018
  );
11444
12019
  }
11445
12020
  const record = (relativePath, rubricName, result) => {
@@ -11593,7 +12168,7 @@ var init_review_pipeline = __esm({
11593
12168
  });
11594
12169
 
11595
12170
  // src/agents/05-test-generator/validation.ts
11596
- import matter4 from "gray-matter";
12171
+ import matter4 from "@11ty/gray-matter";
11597
12172
  function isValidVerb(verb) {
11598
12173
  return VALID_VERBS.has(verb);
11599
12174
  }
@@ -11657,7 +12232,7 @@ var init_validation = __esm({
11657
12232
  });
11658
12233
 
11659
12234
  // src/agents/05-test-generator/test-spec.ts
11660
- import { z as z54 } from "zod";
12235
+ import { z as z55 } from "zod";
11661
12236
  function hasPlaceholder(text2) {
11662
12237
  if (text2 == null) return false;
11663
12238
  return PLACEHOLDER_PATTERNS.some(({ pattern }) => pattern.test(text2));
@@ -11708,12 +12283,12 @@ var init_test_spec = __esm({
11708
12283
  { pattern: /(?<!\{)\{[a-z][a-zA-Z]*\}(?!\})/, name: "bare {variable}" },
11709
12284
  { pattern: /\be\.g\./i, name: '"e.g." example' }
11710
12285
  ];
11711
- stepSchema = z54.object({
11712
- verb: z54.enum(STEP_VERBS).describe("The action. Only these verbs exist."),
11713
- description: z54.string().min(1).describe(
12286
+ stepSchema = z55.object({
12287
+ verb: z55.enum(STEP_VERBS).describe("The action. Only these verbs exist."),
12288
+ description: z55.string().min(1).describe(
11714
12289
  `What to do or check, naming the exact visible text. For assert, the thing expected on screen - e.g. 'text "Transfer Successful"'.`
11715
12290
  ),
11716
- location: z54.string().optional().describe(
12291
+ location: z55.string().optional().describe(
11717
12292
  'WHERE on screen the target is - "in the modal", "in the toast notification", "on the Sony WH-1000XM5 product card", "in the dashboard header", "as a page heading". REQUIRED for click, type and assert: the same label routinely appears more than once (a header button and the modal button it opens, "Buy" on every card in a list), and acting on the wrong one fails confusingly. Not needed for scroll or refresh, which act on the page.'
11718
12293
  )
11719
12294
  }).refine((step) => !requiresLocation(step.verb) || (step.location?.trim() ?? "") !== "", {
@@ -11723,27 +12298,27 @@ var init_test_spec = __esm({
11723
12298
  message: "steps carry no variables - use the exact value from the test data, not a placeholder or example",
11724
12299
  path: ["description"]
11725
12300
  });
11726
- testSpecSchema = z54.object({
11727
- title: z54.string().min(1).describe("Short, descriptive test name."),
11728
- description: z54.string().min(1).describe("One sentence explaining what the test verifies."),
11729
- intent: z54.string().min(30).describe(
12301
+ testSpecSchema = z55.object({
12302
+ title: z55.string().min(1).describe("Short, descriptive test name."),
12303
+ description: z55.string().min(1).describe("One sentence explaining what the test verifies."),
12304
+ intent: z55.string().min(30).describe(
11730
12305
  "A specific, falsifiable claim derived from the node's mission: what the user does, what the feature produces, why it matters. Not the steps, not 'the page displays correctly'."
11731
12306
  ),
11732
- criticality: z54.enum(CRITICALITY_LEVELS),
11733
- scenario: z54.string().min(1).describe('Which scenario this test uses (usually "standard").'),
11734
- flow: z54.string().min(1).describe("Which feature/flow this belongs to (must match a flow from AUTONOMA.md)."),
11735
- verification: z54.string().min(20).describe(
12307
+ criticality: z55.enum(CRITICALITY_LEVELS),
12308
+ scenario: z55.string().min(1).describe('Which scenario this test uses (usually "standard").'),
12309
+ flow: z55.string().min(1).describe("Which feature/flow this belongs to (must match a flow from AUTONOMA.md)."),
12310
+ verification: z55.string().min(20).describe(
11736
12311
  "WHERE to navigate and WHAT to assert to prove the mutation worked. Must name the source of truth - a toast, a confirmation dialog or an inline success indicator is an acknowledgment, not proof."
11737
12312
  ),
11738
- setup: z54.string().min(1).describe(
12313
+ setup: z55.string().min(1).describe(
11739
12314
  "Which page the user starts on and how they got there. Never authentication - the user is already signed in."
11740
12315
  ),
11741
- steps: z54.array(stepSchema).min(1).describe("The action sequence, in order."),
11742
- verificationSteps: z54.array(stepSchema).describe(
12316
+ steps: z55.array(stepSchema).min(1).describe("The action sequence, in order."),
12317
+ verificationSteps: z55.array(stepSchema).describe(
11743
12318
  "Steps that navigate to the source of truth and assert the mutation landed. Implements the `verification` field above."
11744
12319
  ),
11745
- expectedResult: z54.string().min(1).describe("What should be true when the test passes."),
11746
- notes: z54.string().optional().describe(
12320
+ expectedResult: z55.string().min(1).describe("What should be true when the test passes."),
12321
+ notes: z55.string().optional().describe(
11747
12322
  "Optional free text for anything you could not resolve or want to flag - an ambiguous default state, a element you could not find in the source, an assumption you had to make. Recorded for humans and NEVER written into the test file, so it will not affect execution. Use it instead of guessing silently."
11748
12323
  )
11749
12324
  }).refine((spec) => spec.steps.filter((step) => isInteractionVerb(step.verb)).length >= MIN_INTERACTIONS, {
@@ -11754,25 +12329,25 @@ var init_test_spec = __esm({
11754
12329
  });
11755
12330
 
11756
12331
  // src/agents/05-test-generator/tools.ts
11757
- import { mkdir as mkdir5, writeFile as writeFile13 } from "fs/promises";
11758
- import { dirname as dirname5, join as join34 } from "path";
12332
+ import { mkdir as mkdir5, writeFile as writeFile14 } from "fs/promises";
12333
+ import { dirname as dirname5, join as join35 } from "path";
11759
12334
  import { hasToolCall as hasToolCall3, stepCountIs as stepCountIs3, tool as tool16, ToolLoopAgent as ToolLoopAgent3 } from "ai";
11760
- import { z as z55 } from "zod";
12335
+ import { z as z56 } from "zod";
11761
12336
  function buildWriteTestTool(state, outputDir, onWritten) {
11762
12337
  return tool16({
11763
12338
  description: "Write one test to qa-tests/{folder}/{filename}.md. You supply the test's parts; the file is rendered for you, so do not write markdown or frontmatter yourself.",
11764
- inputSchema: z55.object({
11765
- folder: z55.string().describe("Subfolder name under qa-tests/"),
11766
- filename: z55.string().describe(`File name ending in ${TEST_FILE_EXT} (e.g. login-valid-credentials${TEST_FILE_EXT})`),
11767
- nodeId: z55.string().describe(
12339
+ inputSchema: z56.object({
12340
+ folder: z56.string().describe("Subfolder name under qa-tests/"),
12341
+ filename: z56.string().describe(`File name ending in ${TEST_FILE_EXT} (e.g. login-valid-credentials${TEST_FILE_EXT})`),
12342
+ nodeId: z56.string().describe(
11768
12343
  "The id next_node returned for this feature, copied verbatim. Not a re-slugged version of it, not a folder path, not the test filename."
11769
12344
  ),
11770
12345
  test: testSpecSchema
11771
12346
  }),
11772
12347
  execute: async (input) => {
11773
12348
  const content = renderTestMarkdown(input.test);
11774
- const relPath = join34(TESTS_DIR, input.folder, normalizeTestFilename(input.filename));
11775
- const absPath = join34(outputDir, relPath);
12349
+ const relPath = join35(TESTS_DIR, input.folder, normalizeTestFilename(input.filename));
12350
+ const absPath = join35(outputDir, relPath);
11776
12351
  const nodeId = state.resolveNodeId(input.nodeId, relPath);
11777
12352
  if (nodeId == null) {
11778
12353
  const stats = state.summary();
@@ -11791,7 +12366,7 @@ function buildWriteTestTool(state, outputDir, onWritten) {
11791
12366
  }
11792
12367
  try {
11793
12368
  await mkdir5(dirname5(absPath), { recursive: true });
11794
- await writeFile13(absPath, content, "utf-8");
12369
+ await writeFile14(absPath, content, "utf-8");
11795
12370
  state.markTested(nodeId, [relPath]);
11796
12371
  await saveBfsState(outputDir, state);
11797
12372
  const notes = input.test.notes?.trim();
@@ -11804,7 +12379,7 @@ function buildWriteTestTool(state, outputDir, onWritten) {
11804
12379
  });
11805
12380
  }
11806
12381
  onWritten?.({
11807
- relativePath: join34(input.folder, normalizeTestFilename(input.filename)),
12382
+ relativePath: join35(input.folder, normalizeTestFilename(input.filename)),
11808
12383
  content,
11809
12384
  flow: input.test.flow
11810
12385
  });
@@ -11842,14 +12417,14 @@ function buildWriteTestTool(state, outputDir, onWritten) {
11842
12417
  function buildCreateFolderTool(outputDir) {
11843
12418
  return tool16({
11844
12419
  description: "Create a folder under qa-tests/ for organizing tests.",
11845
- inputSchema: z55.object({
11846
- folder: z55.string().describe("Folder name (kebab-case)")
12420
+ inputSchema: z56.object({
12421
+ folder: z56.string().describe("Folder name (kebab-case)")
11847
12422
  }),
11848
12423
  execute: async (input) => {
11849
- const absPath = join34(outputDir, TESTS_DIR, input.folder);
12424
+ const absPath = join35(outputDir, TESTS_DIR, input.folder);
11850
12425
  try {
11851
12426
  await mkdir5(absPath, { recursive: true });
11852
- return { path: join34(TESTS_DIR, input.folder) };
12427
+ return { path: join35(TESTS_DIR, input.folder) };
11853
12428
  } catch (err) {
11854
12429
  const message = err instanceof Error ? err.message : String(err);
11855
12430
  return { error: `Failed to create folder: ${message}` };
@@ -11860,7 +12435,7 @@ function buildCreateFolderTool(outputDir) {
11860
12435
  function buildNextNodeTool(state, outputDir) {
11861
12436
  return tool16({
11862
12437
  description: "Get the next node to write tests for. If you called next_node before without writing any tests (via write_test), the previous node is auto-skipped. Returns done:true when all nodes are processed.",
11863
- inputSchema: z55.object({}),
12438
+ inputSchema: z56.object({}),
11864
12439
  execute: async () => {
11865
12440
  const next = state.nextNode();
11866
12441
  await saveBfsState(outputDir, state);
@@ -11894,7 +12469,7 @@ function buildNextNodeTool(state, outputDir) {
11894
12469
  function buildGetProgressTool(state) {
11895
12470
  return tool16({
11896
12471
  description: "Check how many nodes have been tested vs how many remain.",
11897
- inputSchema: z55.object({}),
12472
+ inputSchema: z56.object({}),
11898
12473
  execute: async () => {
11899
12474
  const stats = state.summary();
11900
12475
  const nodes = [...state.nodes.values()].map((n) => ({
@@ -11910,12 +12485,12 @@ function buildGetProgressTool(state) {
11910
12485
  function buildSpawnResearcherTool(model, workingDirectory, onHeartbeat) {
11911
12486
  return tool16({
11912
12487
  description: "Spawn a research subagent to read and analyze source files without polluting your context. Use for complex sub-features where you don't want to read 20 files yourself.",
11913
- inputSchema: z55.object({
11914
- instruction: z55.string().describe("What to research - be specific about files and what to look for")
12488
+ inputSchema: z56.object({
12489
+ instruction: z56.string().describe("What to research - be specific about files and what to look for")
11915
12490
  }),
11916
12491
  execute: async (input) => {
11917
- const resultSchema2 = z55.object({
11918
- findings: z55.string().describe("Summary of what was found")
12492
+ const resultSchema2 = z56.object({
12493
+ findings: z56.string().describe("Summary of what was found")
11919
12494
  });
11920
12495
  let result;
11921
12496
  const subagent = new ToolLoopAgent3({
@@ -11968,11 +12543,11 @@ var init_tools2 = __esm({
11968
12543
  });
11969
12544
 
11970
12545
  // src/agents/05-test-generator/write-index.ts
11971
- import { readFile as readFile22, writeFile as writeFile14 } from "fs/promises";
11972
- import { join as join35 } from "path";
12546
+ import { readFile as readFile23, writeFile as writeFile15 } from "fs/promises";
12547
+ import { join as join36 } from "path";
11973
12548
  async function scanTest(outputDir, path3) {
11974
12549
  try {
11975
- const content = await readFile22(join35(outputDir, path3), "utf-8");
12550
+ const content = await readFile23(join36(outputDir, path3), "utf-8");
11976
12551
  return {
11977
12552
  criticality: content.match(/criticality:\s*(\w+)/)?.[1] ?? "",
11978
12553
  steps: content.match(STEP_VERBS2)?.length ?? 0,
@@ -12043,7 +12618,7 @@ ${folders.map((f) => `| ${f.name} | ${f.test_count} |`).join("\n")}
12043
12618
 
12044
12619
  ${[...testsByFolder.entries()].flatMap(([_folder, tests]) => tests.map((t) => `- \`${t}\``)).join("\n")}
12045
12620
  ${renderSection("Features with no tests", "the run walked these and produced no test for them - re-run the planner to cover them", untested)}${renderSection("Tests lost in review", "the review cycle removed these and nothing could put them back - re-run the planner to regenerate them", lost)}`;
12046
- await writeFile14(join35(outputDir, TESTS_DIR, TEST_INDEX_FILE), content, "utf-8");
12621
+ await writeFile15(join36(outputDir, TESTS_DIR, TEST_INDEX_FILE), content, "utf-8");
12047
12622
  }
12048
12623
  function untestedFeatures(state) {
12049
12624
  const withTests = new Set(state.testsWritten.keys());
@@ -12078,11 +12653,11 @@ __export(test_generator_exports, {
12078
12653
  runTestGenerator: () => runTestGenerator
12079
12654
  });
12080
12655
  import { existsSync as existsSync2 } from "fs";
12081
- import { mkdir as mkdir6, readFile as readFile23, rmdir, unlink, writeFile as writeFile15 } from "fs/promises";
12082
- import { basename as basename6, join as join36 } from "path";
12656
+ import { mkdir as mkdir6, readFile as readFile24, rmdir, unlink, writeFile as writeFile16 } from "fs/promises";
12657
+ import { basename as basename7, join as join37 } from "path";
12083
12658
  import { tool as tool17 } from "ai";
12084
12659
  import { glob as glob6 } from "glob";
12085
- import { z as z56 } from "zod";
12660
+ import { z as z57 } from "zod";
12086
12661
  async function preseedQueue(state, projectRoot, pages, features) {
12087
12662
  let seeded = 0;
12088
12663
  const pageIdByPath = /* @__PURE__ */ new Map();
@@ -12134,8 +12709,8 @@ async function runTestGenerator(input) {
12134
12709
  let result;
12135
12710
  const finishTool = tool17({
12136
12711
  description: "Call when the BFS queue is empty and all routes have been explored.",
12137
- inputSchema: z56.object({
12138
- summary: z56.string().describe("Coverage summary")
12712
+ inputSchema: z57.object({
12713
+ summary: z57.string().describe("Coverage summary")
12139
12714
  }),
12140
12715
  execute: async (finishInput) => {
12141
12716
  const stats = state.summary();
@@ -12163,7 +12738,7 @@ async function runTestGenerator(input) {
12163
12738
  });
12164
12739
  let kbContext = "";
12165
12740
  try {
12166
- const autonomaMd = await readFile23(join36(input.outputDir, "AUTONOMA.md"), "utf-8");
12741
+ const autonomaMd = await readFile24(join37(input.outputDir, "AUTONOMA.md"), "utf-8");
12167
12742
  kbContext += `
12168
12743
  ## Knowledge Base (AUTONOMA.md)
12169
12744
 
@@ -12176,7 +12751,7 @@ ${autonomaMd}
12176
12751
  kbContext += recipeContext;
12177
12752
  } else {
12178
12753
  try {
12179
- const scenariosMd = await readFile23(join36(input.outputDir, "scenarios.md"), "utf-8");
12754
+ const scenariosMd = await readFile24(join37(input.outputDir, "scenarios.md"), "utf-8");
12180
12755
  kbContext += `
12181
12756
  ## Scenarios
12182
12757
 
@@ -12474,20 +13049,20 @@ IMPORTANT: Do NOT try to finish early. Process every node via next_node until it
12474
13049
  }
12475
13050
  state.clearReviewProgress();
12476
13051
  state.setPhase("checking every test");
12477
- const allTestFiles = await glob6(join36(input.outputDir, TESTS_DIR, TEST_FILE_GLOB));
13052
+ const allTestFiles = await glob6(join37(input.outputDir, TESTS_DIR, TEST_FILE_GLOB));
12478
13053
  let markedInvalid = 0;
12479
13054
  for (const testPath of allTestFiles) {
12480
13055
  if (!isTestFile(testPath)) continue;
12481
13056
  if (testPath.includes(`/${INVALID_DIR}/`)) continue;
12482
- const content = await readFile23(testPath, "utf-8");
13057
+ const content = await readFile24(testPath, "utf-8");
12483
13058
  const validation = validateTestContent(content);
12484
13059
  if (!validation.valid) {
12485
- const invalidDir = join36(input.outputDir, TESTS_DIR, INVALID_DIR);
13060
+ const invalidDir = join37(input.outputDir, TESTS_DIR, INVALID_DIR);
12486
13061
  await mkdir6(invalidDir, { recursive: true });
12487
- const dest = join36(invalidDir, basename6(testPath));
13062
+ const dest = join37(invalidDir, basename7(testPath));
12488
13063
  const annotated = `<!-- VALIDATION ERRORS: ${validation.errors.join("; ")} -->
12489
13064
  ${content}`;
12490
- await writeFile15(dest, annotated, "utf-8");
13065
+ await writeFile16(dest, annotated, "utf-8");
12491
13066
  await unlink(testPath);
12492
13067
  markedInvalid++;
12493
13068
  }
@@ -12495,7 +13070,7 @@ ${content}`;
12495
13070
  if (markedInvalid > 0) {
12496
13071
  console.log(` ${markedInvalid} tests still invalid after review cycles - moved to _invalid/`);
12497
13072
  }
12498
- const dirs = await glob6(join36(input.outputDir, TESTS_DIR, "**/"), {
13073
+ const dirs = await glob6(join37(input.outputDir, TESTS_DIR, "**/"), {
12499
13074
  dot: false
12500
13075
  });
12501
13076
  for (const dir of dirs.sort((a, b) => b.length - a.length)) {
@@ -12548,21 +13123,21 @@ async function generateJourneyTests(outputDir, model, projectRoot) {
12548
13123
  let autonomaMd = "";
12549
13124
  let scenariosMd = "";
12550
13125
  try {
12551
- autonomaMd = await readFile23(join36(outputDir, "AUTONOMA.md"), "utf-8");
13126
+ autonomaMd = await readFile24(join37(outputDir, "AUTONOMA.md"), "utf-8");
12552
13127
  } catch (err) {
12553
13128
  debugLog("AUTONOMA.md not present for journey generation", { err });
12554
13129
  }
12555
13130
  try {
12556
- scenariosMd = await readFile23(join36(outputDir, "scenarios.md"), "utf-8");
13131
+ scenariosMd = await readFile24(join37(outputDir, "scenarios.md"), "utf-8");
12557
13132
  } catch (err) {
12558
13133
  debugLog("scenarios.md not present for journey generation", { err });
12559
13134
  }
12560
13135
  if (!autonomaMd) return 0;
12561
- const existingTests = await glob6(join36(outputDir, TESTS_DIR, TEST_FILE_GLOB));
13136
+ const existingTests = await glob6(join37(outputDir, TESTS_DIR, TEST_FILE_GLOB));
12562
13137
  const existingTitles = [];
12563
13138
  for (const t of existingTests) {
12564
13139
  if (!isTestFile(t)) continue;
12565
- const content = await readFile23(t, "utf-8");
13140
+ const content = await readFile24(t, "utf-8");
12566
13141
  const titleMatch = content.match(/title:\s*"([^"]+)"/);
12567
13142
  if (titleMatch) existingTitles.push(titleMatch[1]);
12568
13143
  }
@@ -12608,7 +13183,7 @@ Write 5-8 journey tests using the write_test tool with folder "${JOURNEY_NODE_ID
12608
13183
  let journeyResult;
12609
13184
  const journeyFinish = tool17({
12610
13185
  description: "Signal journey generation is complete.",
12611
- inputSchema: z56.object({ summary: z56.string() }),
13186
+ inputSchema: z57.object({ summary: z57.string() }),
12612
13187
  execute: async (finishInput) => {
12613
13188
  journeyResult = {
12614
13189
  success: true,
@@ -14455,14 +15030,14 @@ var init_session_recorder = __esm({
14455
15030
  });
14456
15031
 
14457
15032
  // src/ui/artifacts/reader.ts
14458
- import { open, readFile as readFile24, stat as stat2 } from "fs/promises";
15033
+ import { open, readFile as readFile25, stat as stat2 } from "fs/promises";
14459
15034
  async function readForLive(absPath) {
14460
15035
  try {
14461
15036
  const info = await stat2(absPath);
14462
15037
  if (!info.isFile()) return void 0;
14463
15038
  const kind = kindOf(absPath);
14464
15039
  if (info.size <= LARGE_BYTES) {
14465
- const text2 = await readFile24(absPath, "utf-8");
15040
+ const text2 = await readFile25(absPath, "utf-8");
14466
15041
  return { text: text2, kind, truncated: false };
14467
15042
  }
14468
15043
  const fh = await open(absPath, "r");
@@ -14756,9 +15331,9 @@ ensureSupportedNode();
14756
15331
 
14757
15332
  // src/index.ts
14758
15333
  init_submit();
14759
- import { readFile as readFile25, writeFile as writeFile16 } from "fs/promises";
15334
+ import { readFile as readFile26, writeFile as writeFile17 } from "fs/promises";
14760
15335
  import { freemem } from "os";
14761
- import { delimiter, join as join37 } from "path";
15336
+ import { delimiter, join as join38 } from "path";
14762
15337
 
14763
15338
  // src/agents/04-recipe-builder/sdk-command.ts
14764
15339
  init_esm_shims();
@@ -14947,7 +15522,7 @@ function shortHash(seed) {
14947
15522
  }
14948
15523
 
14949
15524
  // src/agents/04-recipe-builder/sdk-command.ts
14950
- import { z as z33 } from "zod";
15525
+ import { z as z34 } from "zod";
14951
15526
 
14952
15527
  // src/core/cli-args.ts
14953
15528
  init_esm_shims();
@@ -15106,16 +15681,16 @@ async function down(config, refsToken) {
15106
15681
  init_recipe();
15107
15682
  var DEFAULT_REQUEST_TIMEOUT_MS = 12e4;
15108
15683
  var MIN_REPEAT_INSTANCES = 2;
15109
- var createSchema = z33.record(z33.string(), z33.array(z33.unknown()));
15110
- var recipeSliceSchema = z33.object({ create: createSchema, variables: ScenarioRecipeVariablesSchema.optional() });
15111
- var envelopeSchema = z33.object({ recipes: z33.array(recipeSliceSchema).min(1) });
15112
- var flagsSchema = z33.object({
15113
- url: z33.string().min(1).optional(),
15114
- recipe: z33.string().min(1).optional(),
15115
- "refs-token": z33.string().min(1).optional(),
15116
- "test-run-id": z33.string().min(1).optional(),
15117
- timeout: z33.coerce.number().int().positive().optional(),
15118
- repeat: z33.coerce.number().int().min(MIN_REPEAT_INSTANCES).optional()
15684
+ var createSchema = z34.record(z34.string(), z34.array(z34.unknown()));
15685
+ var recipeSliceSchema = z34.object({ create: createSchema, variables: ScenarioRecipeVariablesSchema.optional() });
15686
+ var envelopeSchema = z34.object({ recipes: z34.array(recipeSliceSchema).min(1) });
15687
+ var flagsSchema = z34.object({
15688
+ url: z34.string().min(1).optional(),
15689
+ recipe: z34.string().min(1).optional(),
15690
+ "refs-token": z34.string().min(1).optional(),
15691
+ "test-run-id": z34.string().min(1).optional(),
15692
+ timeout: z34.coerce.number().int().positive().optional(),
15693
+ repeat: z34.coerce.number().int().min(MIN_REPEAT_INSTANCES).optional()
15119
15694
  });
15120
15695
  var SDK_FLAGS = new Set(Object.keys(flagsSchema.shape));
15121
15696
  async function runSdkCommand(argv, io) {
@@ -15680,6 +16255,24 @@ init_front_door();
15680
16255
  // src/core/help.ts
15681
16256
  init_esm_shims();
15682
16257
  init_colors();
16258
+
16259
+ // src/core/self-invocation.ts
16260
+ init_esm_shims();
16261
+ import { basename as basename4, sep } from "path";
16262
+ var NPX_INVOCATION = "npx @autonoma-ai/planner@latest";
16263
+ var BIN_NAME = "autonoma-planner";
16264
+ function selfInvocation(argv = process.argv, execPath = process.execPath) {
16265
+ const scriptPath = argv[1];
16266
+ if (scriptPath == null || scriptPath === "") return NPX_INVOCATION;
16267
+ if (basename4(scriptPath) === BIN_NAME) return BIN_NAME;
16268
+ if (isNpxCachePath(scriptPath)) return NPX_INVOCATION;
16269
+ return `${execPath} ${scriptPath}`;
16270
+ }
16271
+ function isNpxCachePath(scriptPath) {
16272
+ return scriptPath.split(sep).includes("_npx");
16273
+ }
16274
+
16275
+ // src/core/help.ts
15683
16276
  var DOCS_URL = "https://docs.autonoma.app/test-planner/";
15684
16277
  var LLMS_URL = "https://docs.autonoma.app/llms.txt";
15685
16278
  var LLMS_FULL_URL = "https://docs.autonoma.app/llms-full.txt";
@@ -15782,18 +16375,27 @@ var ENVIRONMENT = [
15782
16375
  " up the preview environment and validates the result; leave it unset",
15783
16376
  " and the planner runs standalone against any repository.",
15784
16377
  " AUTONOMA_API_URL Point at a non-production Autonoma. Defaults to production.",
15785
- " AUTONOMA_DEBUG Set to anything for verbose diagnostics on stderr.",
15786
- " DONT_TRACK Set to anything to turn off analytics, logs and session replay."
16378
+ // Both are read as `1`/`true` exactly (core/posthog.ts, core/debug-sink.ts), so
16379
+ // "set to anything" invites DONT_TRACK=0 - which reads as opted IN.
16380
+ " AUTONOMA_DEBUG Set to 1 or true for diagnostics on stderr, plus a full JSONL",
16381
+ " transcript at ~/.autonoma/debug/<run-id>.jsonl.",
16382
+ " AUTONOMA_DEBUG_FILE Write that transcript to this path instead, without the stderr",
16383
+ " noise. Independent of DONT_TRACK - it never leaves your machine.",
16384
+ " DONT_TRACK Set to 1 or true to turn off analytics, logs and session replay."
15787
16385
  ];
15788
16386
  function renderHelp() {
16387
+ const self = selfInvocation();
15789
16388
  return [
15790
- `${BOLD}autonoma-planner${RESET} - generate an end-to-end test suite from your codebase`,
16389
+ `${BOLD}@autonoma-ai/planner${RESET} - generate an end-to-end test suite from your codebase`,
15791
16390
  "",
16391
+ // Spelled the way this run was actually reached. Almost everyone arrives via
16392
+ // npx, which installs nothing on PATH, so a synopsis written as a bare
16393
+ // `autonoma-planner` teaches a command the reader does not have.
15792
16394
  `${BOLD}USAGE${RESET}`,
15793
- " autonoma-planner [run] [flags] Plan and generate the suite. `run` may be omitted.",
15794
- " autonoma-planner status Show what a previous run completed.",
15795
- " autonoma-planner upload Re-upload an already-generated suite.",
15796
- " autonoma-planner help Print this.",
16395
+ ` ${self} [run] [flags] Plan and generate the suite. \`run\` may be omitted.`,
16396
+ ` ${self} status Show what a previous run completed.`,
16397
+ ` ${self} upload Re-upload an already-generated suite.`,
16398
+ ` ${self} help Print this.`,
15797
16399
  "",
15798
16400
  `${BOLD}WHAT IT DOES${RESET}`,
15799
16401
  ...WHAT_IT_DOES.map(indent),
@@ -15858,8 +16460,8 @@ init_prompts();
15858
16460
  // src/core/git.ts
15859
16461
  init_esm_shims();
15860
16462
  import { execFile } from "child_process";
15861
- import { readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
15862
- import { join as join13 } from "path";
16463
+ import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
16464
+ import { join as join14 } from "path";
15863
16465
  import { promisify } from "util";
15864
16466
  var execFileAsync = promisify(execFile);
15865
16467
  var GIT_INFO_FILE = ".git-info.json";
@@ -15883,11 +16485,11 @@ async function readGitInfo(projectRoot) {
15883
16485
  };
15884
16486
  }
15885
16487
  async function saveGitInfo(outputDir, info) {
15886
- await writeFile4(join13(outputDir, GIT_INFO_FILE), JSON.stringify(info, null, 2), "utf-8");
16488
+ await writeFile5(join14(outputDir, GIT_INFO_FILE), JSON.stringify(info, null, 2), "utf-8");
15887
16489
  }
15888
16490
  async function loadGitInfo(outputDir) {
15889
16491
  try {
15890
- const raw = await readFile5(join13(outputDir, GIT_INFO_FILE), "utf-8");
16492
+ const raw = await readFile6(join14(outputDir, GIT_INFO_FILE), "utf-8");
15891
16493
  const parsed = JSON.parse(raw);
15892
16494
  if (typeof parsed === "object" && parsed != null && "sha" in parsed && typeof parsed.sha === "string") {
15893
16495
  const branch = "branch" in parsed && typeof parsed.branch === "string" ? parsed.branch : void 0;
@@ -15909,15 +16511,15 @@ init_state();
15909
16511
  init_esm_shims();
15910
16512
  init_prompts();
15911
16513
  init_debug();
15912
- import { readFile as readFile7 } from "fs/promises";
15913
- import { join as join15 } from "path";
16514
+ import { readFile as readFile8 } from "fs/promises";
16515
+ import { join as join16 } from "path";
15914
16516
  init_test_files();
15915
16517
  var ARTIFACT_FILES = ["AUTONOMA.md", "scenarios.md", "entity-audit.md"];
15916
16518
  async function readArtifacts(outputDir) {
15917
16519
  const files = await Promise.all(
15918
16520
  ARTIFACT_FILES.map(async (name) => {
15919
16521
  try {
15920
- return { name, content: await readFile7(join15(outputDir, name), "utf-8") };
16522
+ return { name, content: await readFile8(join16(outputDir, name), "utf-8") };
15921
16523
  } catch (err) {
15922
16524
  debugLog(`Artifact ${name} not on disk; skipping upload`, { err });
15923
16525
  return void 0;
@@ -15933,7 +16535,7 @@ async function readTestCases(outputDir) {
15933
16535
  const segments = testPath.split("/").slice(1);
15934
16536
  const name = segments[segments.length - 1];
15935
16537
  const folder = segments.slice(0, -1).join("/");
15936
- const content = await readFile7(join15(outputDir, testPath), "utf-8");
16538
+ const content = await readFile8(join16(outputDir, testPath), "utf-8");
15937
16539
  return { name, content, folder: folder.length > 0 ? folder : void 0 };
15938
16540
  })
15939
16541
  );
@@ -15998,11 +16600,11 @@ process.setSourceMapsEnabled(true);
15998
16600
  var PAGES_FILE = "pages.json";
15999
16601
  async function savePages(outputDir, pages) {
16000
16602
  const obj = Object.fromEntries(pages);
16001
- await writeFile16(join37(outputDir, PAGES_FILE), JSON.stringify(obj, null, 2), "utf-8");
16603
+ await writeFile17(join38(outputDir, PAGES_FILE), JSON.stringify(obj, null, 2), "utf-8");
16002
16604
  }
16003
16605
  async function loadPages(outputDir) {
16004
16606
  try {
16005
- const raw = await readFile25(join37(outputDir, PAGES_FILE), "utf-8");
16607
+ const raw = await readFile26(join38(outputDir, PAGES_FILE), "utf-8");
16006
16608
  const obj = JSON.parse(raw);
16007
16609
  return new Map(Object.entries(obj));
16008
16610
  } catch {
@@ -16371,6 +16973,23 @@ function ensureAutonomaAuth() {
16371
16973
  );
16372
16974
  return false;
16373
16975
  }
16976
+ async function runPreviewHandoffStep(frontDoor, config, nonInteractive) {
16977
+ const { runPreviewHandoff: runPreviewHandoff2, describeIncompletePreview: describeIncompletePreview2 } = await Promise.resolve().then(() => (init_front_door(), front_door_exports));
16978
+ try {
16979
+ const result = await runPreviewHandoff2({ plan: frontDoor, config, nonInteractive });
16980
+ track("cli_preview_phase_finished", { outcome: result.kind });
16981
+ const problem = describeIncompletePreview2(result);
16982
+ if (problem != null) log.warn(problem);
16983
+ } catch (err) {
16984
+ const message = err instanceof Error ? err.message : String(err);
16985
+ track("cli_preview_phase_finished", { outcome: "error" });
16986
+ trackError(err, { source: "preview_phase" });
16987
+ log.warn(`Couldn't set up your preview environment: ${message}`);
16988
+ log.info(
16989
+ "The rest of the run continues - finish the preview in the Autonoma app, or run again once it's sorted."
16990
+ );
16991
+ }
16992
+ }
16374
16993
  async function finishFrontDoorRun(frontDoor, config, nonInteractive) {
16375
16994
  try {
16376
16995
  const gitInfo = await readGitInfo(config.projectRoot);
@@ -16441,7 +17060,8 @@ async function main() {
16441
17060
  }
16442
17061
  console.log(BANNER);
16443
17062
  const projectArg = args.value("project");
16444
- const resumeCommand = `autonoma-planner --resume` + (projectArg != null ? ` --project ${projectArg}` : "");
17063
+ const self = selfInvocation();
17064
+ const resumeCommand = `${self} --resume` + (projectArg != null ? ` --project ${projectArg}` : "");
16445
17065
  let mountedUi;
16446
17066
  let stoppedAt;
16447
17067
  installInterruptHandler({
@@ -16528,11 +17148,7 @@ async function main() {
16528
17148
  });
16529
17149
  }
16530
17150
  if (frontDoor != null && previewPending) {
16531
- const { runPreviewHandoff: runPreviewHandoff2, describeIncompletePreview: describeIncompletePreview2 } = await Promise.resolve().then(() => (init_front_door(), front_door_exports));
16532
- const result = await runPreviewHandoff2({ plan: frontDoor, config, nonInteractive });
16533
- track("cli_preview_phase_finished", { outcome: result.kind });
16534
- const problem = describeIncompletePreview2(result);
16535
- if (problem != null) log.warn(problem);
17151
+ await runPreviewHandoffStep(frontDoor, config, nonInteractive);
16536
17152
  }
16537
17153
  if (args.has("fresh") && hasProgress) {
16538
17154
  await clearOutputDir(config.projectSlug);
@@ -16591,7 +17207,7 @@ or reveal hidden files (macOS: Cmd+Shift+. ) to see it.`,
16591
17207
  mountedUi?.unmount();
16592
17208
  mountedUi = void 0;
16593
17209
  if (state.steps[targetStep] === "failed") {
16594
- const retryCommand = `autonoma-planner --step ${targetStep}` + (projectArg != null ? ` --project ${projectArg}` : "");
17210
+ const retryCommand = `${self} --step ${targetStep}` + (projectArg != null ? ` --project ${projectArg}` : "");
16595
17211
  log.warn(`Your progress is saved. To retry this step, run:
16596
17212
  ${retryCommand}`);
16597
17213
  process.exitCode = 1;