@autonoma-ai/planner 0.1.28 → 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
  });
@@ -5316,6 +5524,9 @@ __export(coding_agent_exports, {
5316
5524
  parsePermissionMode: () => parsePermissionMode,
5317
5525
  selectLauncher: () => selectLauncher
5318
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";
5319
5530
  import spawn from "cross-spawn";
5320
5531
  import which from "which";
5321
5532
  function isSpawnedByPlanner2(env = process.env) {
@@ -5362,10 +5573,28 @@ function parsePermissionMode(value) {
5362
5573
  if (value === "default" || value === "acceptEdits" || value === "bypassPermissions") return value;
5363
5574
  return void 0;
5364
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
+ }
5365
5594
  function firstLine(output) {
5366
5595
  return output.split("\n").find((line) => line.trim().length > 0)?.trim() ?? "";
5367
5596
  }
5368
- 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;
5369
5598
  var init_coding_agent = __esm({
5370
5599
  "src/core/coding-agent.ts"() {
5371
5600
  "use strict";
@@ -5373,11 +5602,23 @@ var init_coding_agent = __esm({
5373
5602
  init_prompts();
5374
5603
  init_agent_env();
5375
5604
  init_debug();
5605
+ init_logs();
5376
5606
  init_preferences();
5377
5607
  init_agent_env();
5378
5608
  MCP_COMMAND_TIMEOUT_MS = 6e4;
5609
+ ATTACHED_STDERR_CAP = 4e3;
5379
5610
  CODEX_BEARER_TOKEN_ENV = "AUTONOMA_MCP_TOKEN";
5380
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";
5381
5622
  DEFAULT_PERMISSION_MODE = "bypassPermissions";
5382
5623
  PERMISSION_MODE_LABELS = {
5383
5624
  default: "Approve each command",
@@ -5464,40 +5705,107 @@ var init_coding_agent = __esm({
5464
5705
  /**
5465
5706
  * Sign this client in to a server through its own browser flow.
5466
5707
  *
5467
- * Refused outright without a terminal. The flow prints a URL, opens a browser and
5468
- * blocks on the callback, so a run with nobody at the keyboard would not fail - it
5469
- * would hang, indefinitely, on a prompt nobody can see. A run without a terminal
5470
- * is meant to have passed an API token instead, and the error says so rather than
5471
- * 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.
5472
5714
  */
5473
5715
  async signIn(serverName) {
5474
5716
  if (process.stdin.isTTY !== true) {
5475
- throw new Error(
5476
- `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.`
5477
- );
5717
+ return { ok: false, detail: " (no terminal to run a browser sign-in from)", clientUnusable: false };
5478
5718
  }
5479
5719
  log.info(`Authorizing ${this.label} with Autonoma - approve it in the browser that opens.`);
5480
5720
  const login = await this.runAttached(["mcp", "login", serverName]);
5481
- 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) {
5482
5767
  throw new Error(
5483
- `${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.`
5484
5769
  );
5485
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 };
5486
5780
  }
5487
5781
  /**
5488
5782
  * Run a subcommand that hands the terminal over - an interactive OAuth sign-in.
5489
- * The client prints a URL, opens a browser and waits on the callback, so it needs
5490
- * 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.
5491
5790
  */
5492
5791
  runAttached(args) {
5493
5792
  debugLog(`Running ${this.command} ${args.join(" ")} attached`);
5494
5793
  return new Promise((resolve6) => {
5495
- 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
+ });
5496
5804
  proc.on("error", (err) => {
5497
5805
  debugLog(`${this.command} ${args[0] ?? ""} failed to spawn`, { err });
5498
- resolve6(void 0);
5806
+ resolve6({ code: void 0, stderr: err.message });
5499
5807
  });
5500
- proc.on("close", (code) => resolve6(code ?? void 0));
5808
+ proc.on("close", (code) => resolve6({ code: code ?? void 0, stderr }));
5501
5809
  });
5502
5810
  }
5503
5811
  };
@@ -5506,36 +5814,113 @@ var init_coding_agent = __esm({
5506
5814
  label = "Claude Code";
5507
5815
  command = CLAUDE_ID;
5508
5816
  buildArgs(message, permissionMode, interactive) {
5509
- 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 };
5510
5822
  }
5511
5823
  /**
5512
- * `--scope user` and not the default (`local`): the default binds the server to the
5513
- * directory the command ran in. The planner can be invoked from anywhere in a repo,
5514
- * and a server registered against the wrong directory looks exactly like one that
5515
- * was never authorized - the agent simply has no Autonoma tools.
5516
- *
5517
- * With a token the header goes into Claude's own config and there is nothing to
5518
- * 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.
5519
5827
  */
5520
5828
  async registerMcpServer(spec) {
5521
- const add = ["mcp", "add", "--transport", "http", "--scope", "user", spec.name, spec.url];
5522
- if (spec.apiToken != null) add.push("--header", `Authorization: Bearer ${spec.apiToken}`);
5523
- const existing = await this.runCommand(["mcp", "get", spec.name]);
5524
- if (existing.code === 0 && !existing.stdout.includes(spec.url)) {
5525
- debugLog("Replacing an MCP registration that points elsewhere", { server: spec.name, url: spec.url });
5526
- 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: {} };
5527
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}`);
5528
5916
  await this.runCommand(add);
5529
5917
  const registered = await this.runCommand(["mcp", "get", spec.name]);
5530
5918
  if (registered.code !== 0) {
5531
5919
  throw new Error(
5532
- `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)}`
5533
5921
  );
5534
5922
  }
5535
- if (spec.apiToken == null && !registered.stdout.includes(CLAUDE_CONNECTED_MARKER)) {
5536
- await this.signIn(spec.name);
5537
- }
5538
- return { env: {} };
5923
+ return registered.stdout;
5539
5924
  }
5540
5925
  };
5541
5926
  CodexLauncher = class extends BaseLauncher {
@@ -5572,19 +5957,53 @@ var init_coding_agent = __esm({
5572
5957
  * server overwrites its entry, so a re-run cannot leave a stale URL behind.
5573
5958
  */
5574
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) {
5575
5999
  const add = ["mcp", "add", spec.name, "--url", spec.url];
5576
- 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);
5577
6001
  const added = await this.runCommand(add);
5578
6002
  if (added.code !== 0) {
5579
6003
  throw new Error(
5580
- `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)}`
5581
6005
  );
5582
6006
  }
5583
- if (spec.apiToken == null) {
5584
- await this.signIn(spec.name);
5585
- return { env: {} };
5586
- }
5587
- return { env: { [CODEX_BEARER_TOKEN_ENV]: spec.apiToken } };
5588
6007
  }
5589
6008
  };
5590
6009
  }
@@ -6261,7 +6680,7 @@ var init_permission_mode = __esm({
6261
6680
  // src/core/preview-phase.ts
6262
6681
  function previewPrompt(code, interactive) {
6263
6682
  const instruction = `set up my preview environments with the ${MCP_SERVER_NAME} MCP, code ${code}`;
6264
- return interactive ? instruction : `${instruction}.${HEADLESS_GUIDANCE}`;
6683
+ return interactive ? `${instruction}.${BRANCH_GUIDANCE}` : `${instruction}.${BRANCH_GUIDANCE}${HEADLESS_GUIDANCE}`;
6265
6684
  }
6266
6685
  async function runPreviewPhase(deps) {
6267
6686
  const timing = deps.timing ?? DEFAULT_PHASE_TIMING;
@@ -6269,7 +6688,8 @@ async function runPreviewPhase(deps) {
6269
6688
  const registration = await deps.launcher.registerMcpServer({
6270
6689
  name: MCP_SERVER_NAME,
6271
6690
  url: deps.mcpUrl,
6272
- apiToken: deps.apiToken
6691
+ apiToken: deps.apiToken,
6692
+ browserSignIn: deps.interactive
6273
6693
  });
6274
6694
  const code = await deps.client.createAgentPairing(deps.applicationId);
6275
6695
  captureLog("info", "Handing the preview environment to a coding agent", {
@@ -6329,11 +6749,12 @@ async function readVerifiedState(client, applicationId) {
6329
6749
  });
6330
6750
  return client.getOnboardingState(applicationId);
6331
6751
  }
6332
- 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;
6333
6753
  var init_preview_phase = __esm({
6334
6754
  "src/core/preview-phase.ts"() {
6335
6755
  "use strict";
6336
6756
  init_esm_shims();
6757
+ init_src();
6337
6758
  init_prompts();
6338
6759
  init_debug();
6339
6760
  init_logs();
@@ -6348,6 +6769,7 @@ var init_preview_phase = __esm({
6348
6769
  killMs: KILL_ESCALATION_MS
6349
6770
  };
6350
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.`;
6351
6773
  }
6352
6774
  });
6353
6775
 
@@ -6367,7 +6789,8 @@ async function runSdkRepairPhase(deps) {
6367
6789
  const registration = await deps.launcher.registerMcpServer({
6368
6790
  name: MCP_SERVER_NAME,
6369
6791
  url: deps.mcpUrl,
6370
- apiToken: deps.apiToken
6792
+ apiToken: deps.apiToken,
6793
+ browserSignIn: deps.interactive
6371
6794
  });
6372
6795
  const code = await deps.client.createAgentPairing(deps.applicationId);
6373
6796
  captureLog("info", "Handing the SDK and dry run to a coding agent", {
@@ -6489,7 +6912,7 @@ async function runPreviewHandoff(deps) {
6489
6912
  applicationId: plan.applicationId,
6490
6913
  launcher,
6491
6914
  permissionMode,
6492
- apiToken: interactive ? void 0 : config.autonomaApiToken,
6915
+ apiToken: config.autonomaApiToken,
6493
6916
  mcpUrl: resolveMcpUrl(config.autonomaApiUrl),
6494
6917
  interactive
6495
6918
  });
@@ -6533,7 +6956,7 @@ async function runSdkRepairHandoff(deps) {
6533
6956
  applicationId: plan.applicationId,
6534
6957
  launcher,
6535
6958
  permissionMode,
6536
- apiToken: interactive ? void 0 : config.autonomaApiToken,
6959
+ apiToken: config.autonomaApiToken,
6537
6960
  mcpUrl: resolveMcpUrl(config.autonomaApiUrl),
6538
6961
  interactive
6539
6962
  });
@@ -6619,16 +7042,16 @@ var init_notify = __esm({
6619
7042
  });
6620
7043
 
6621
7044
  // src/core/project-map.ts
6622
- import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
6623
- import { join as join14 } from "path";
6624
- 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";
6625
7048
  async function saveProjectMap(outputDir, map) {
6626
- 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");
6627
7050
  }
6628
7051
  async function loadProjectMap(outputDir) {
6629
- const path3 = join14(outputDir, PROJECT_MAP_FILE);
7052
+ const path3 = join15(outputDir, PROJECT_MAP_FILE);
6630
7053
  try {
6631
- const raw = await readFile6(path3, "utf-8");
7054
+ const raw = await readFile7(path3, "utf-8");
6632
7055
  const parsed = ProjectMapSchema.safeParse(JSON.parse(raw));
6633
7056
  if (parsed.success) return parsed.data;
6634
7057
  debugLog("project-map.json failed schema validation, ignoring it", { path: path3, issues: parsed.error.issues });
@@ -6730,34 +7153,34 @@ var init_project_map = __esm({
6730
7153
  "use strict";
6731
7154
  init_esm_shims();
6732
7155
  init_debug();
6733
- FrontendEntry = z35.object({
6734
- path: z35.string().min(1).describe("Repo-relative path to the frontend app/directory (the UI surface)."),
6735
- framework: z35.string().describe("Detected UI framework/stack, or 'unknown' if not obvious (e.g. next, react, vue, svelte)."),
6736
- 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(
6737
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."
6738
7161
  ),
6739
- 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.")
6740
7163
  });
6741
- BackendEntry = z35.object({
6742
- path: z35.string().min(1).describe("Repo-relative path to the backend/API/service or the package that owns the data layer."),
6743
- language: z35.string().describe("Primary language, or 'unknown' (e.g. typescript, python, go, rust)."),
6744
- framework: z35.string().describe("Web/service framework or ORM stack, or 'unknown' (e.g. express, hono, fastapi, rails)."),
6745
- dataLayer: z35.object({
6746
- kind: z35.string().describe("How models are defined (e.g. prisma, drizzle, sqlalchemy, typeorm, raw-sql, unknown)."),
6747
- 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.")
6748
7171
  }).optional().describe("Where this backend's database models live. Omit if this backend owns no data layer."),
6749
- 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.")
6750
7173
  });
6751
- IgnoreEntry = z35.object({
6752
- path: z35.string().min(1).describe("Repo-relative path to a directory that is NOT relevant to testing this app."),
6753
- 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).")
6754
7177
  });
6755
- ProjectMapSchema = z35.object({
6756
- frontends: z35.array(FrontendEntry).describe("The UI surface(s) whose pages/flows get tested. Usually 1; may be more."),
6757
- 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(
6758
7181
  "The API/service(s) and data layer(s) that own the models we seed. May be 0 (frontend-only), 1, or many."
6759
7182
  ),
6760
- 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.")
6761
7184
  });
6762
7185
  PROJECT_MAP_FILE = "project-map.json";
6763
7186
  }
@@ -6768,11 +7191,11 @@ var parse_entity_audit_exports = {};
6768
7191
  __export(parse_entity_audit_exports, {
6769
7192
  parseEntityNames: () => parseEntityNames
6770
7193
  });
6771
- import { readFile as readFile8 } from "fs/promises";
6772
- import { join as join16 } from "path";
7194
+ import { readFile as readFile9 } from "fs/promises";
7195
+ import { join as join17 } from "path";
6773
7196
  async function parseEntityNames(outputDir) {
6774
7197
  try {
6775
- const content = await readFile8(join16(outputDir, "entity-audit.md"), "utf-8");
7198
+ const content = await readFile9(join17(outputDir, "entity-audit.md"), "utf-8");
6776
7199
  const names = [];
6777
7200
  for (const line of content.split("\n")) {
6778
7201
  const match = line.match(/^\s+-\s+name:\s+(.+)$/);
@@ -6807,7 +7230,7 @@ var init_count_generated_tests = __esm({
6807
7230
  });
6808
7231
 
6809
7232
  // src/core/display.ts
6810
- import { join as join17 } from "path";
7233
+ import { join as join18 } from "path";
6811
7234
  function formatArgs(input, keys) {
6812
7235
  const parts = [];
6813
7236
  for (const key of keys) {
@@ -6899,7 +7322,7 @@ function logToStore(store, agentId, info, stats) {
6899
7322
  const folder = String(tc.input.folder ?? "");
6900
7323
  const filename = String(tc.input.filename ?? "");
6901
7324
  if (folder && filename) {
6902
- store.noteWrite(join17(TESTS_DIR, folder, normalizeTestFilename(filename)));
7325
+ store.noteWrite(join18(TESTS_DIR, folder, normalizeTestFilename(filename)));
6903
7326
  }
6904
7327
  }
6905
7328
  if (tc.name === "bash") {
@@ -7207,8 +7630,8 @@ var init_agent = __esm({
7207
7630
  });
7208
7631
 
7209
7632
  // src/core/gitignore.ts
7210
- import { readFile as readFile9 } from "fs/promises";
7211
- 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";
7212
7635
  import { glob as glob2 } from "glob";
7213
7636
  async function loadGitignorePatterns(projectRoot) {
7214
7637
  const patterns = [
@@ -7228,10 +7651,10 @@ async function loadGitignorePatterns(projectRoot) {
7228
7651
  ];
7229
7652
  const matches = await glob2("**/.gitignore", { cwd: projectRoot, dot: true });
7230
7653
  for (const match of matches) {
7231
- const fullPath = join18(projectRoot, match);
7654
+ const fullPath = join19(projectRoot, match);
7232
7655
  try {
7233
- const content = await readFile9(fullPath, "utf-8");
7234
- const prefix = relative2(projectRoot, join18(projectRoot, match, ".."));
7656
+ const content = await readFile10(fullPath, "utf-8");
7657
+ const prefix = relative2(projectRoot, join19(projectRoot, match, ".."));
7235
7658
  const parsed = parseGitignore(content, prefix);
7236
7659
  patterns.push(...parsed);
7237
7660
  } catch (err) {
@@ -7294,7 +7717,7 @@ var init_exec_error = __esm({
7294
7717
  import { execFile as execFile3 } from "child_process";
7295
7718
  import { promisify as promisify2 } from "util";
7296
7719
  import { tool } from "ai";
7297
- import { z as z36 } from "zod";
7720
+ import { z as z37 } from "zod";
7298
7721
  function validateCommand(command, allowed) {
7299
7722
  const trimmed = command.trim();
7300
7723
  if (trimmed.length === 0) return "Empty command";
@@ -7360,8 +7783,8 @@ var init_bash = __esm({
7360
7783
  DEFAULT_ALLOWED = /* @__PURE__ */ new Set(["git", "wc", "sort", "head", "tail", "cat", "ls", "find", "diff", "echo"]);
7361
7784
  TIMEOUT_MS = 3e4;
7362
7785
  MAX_OUTPUT_BYTES = 1024 * 512;
7363
- inputSchema = z36.object({
7364
- command: z36.string().describe("Shell command to execute")
7786
+ inputSchema = z37.object({
7787
+ command: z37.string().describe("Shell command to execute")
7365
7788
  });
7366
7789
  }
7367
7790
  });
@@ -7369,7 +7792,7 @@ var init_bash = __esm({
7369
7792
  // src/tools/glob.ts
7370
7793
  import { tool as tool2 } from "ai";
7371
7794
  import { glob as glob3 } from "glob";
7372
- import { z as z37 } from "zod";
7795
+ import { z as z38 } from "zod";
7373
7796
  async function executeGlob(pattern, cwd, ignorePatterns = DEFAULT_IGNORE) {
7374
7797
  try {
7375
7798
  const matches = await glob3(pattern, {
@@ -7403,9 +7826,9 @@ var init_glob = __esm({
7403
7826
  "src/tools/glob.ts"() {
7404
7827
  "use strict";
7405
7828
  init_esm_shims();
7406
- inputSchema2 = z37.object({
7407
- pattern: z37.string().describe("Glob pattern to match files (e.g. '**/*.ts', 'src/**/*.py')"),
7408
- 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.")
7409
7832
  });
7410
7833
  DEFAULT_IGNORE = [
7411
7834
  "**/node_modules/**",
@@ -7423,7 +7846,7 @@ var init_glob = __esm({
7423
7846
  import { execFile as execFile4 } from "child_process";
7424
7847
  import { promisify as promisify3 } from "util";
7425
7848
  import { tool as tool3 } from "ai";
7426
- import { z as z38 } from "zod";
7849
+ import { z as z39 } from "zod";
7427
7850
  function buildGrepTool(workingDirectory) {
7428
7851
  return tool3({
7429
7852
  description: "Search file contents with ripgrep. Returns matching lines with file paths and line numbers.",
@@ -7467,10 +7890,10 @@ var init_grep = __esm({
7467
7890
  init_esm_shims();
7468
7891
  init_exec_error();
7469
7892
  execFileAsync3 = promisify3(execFile4);
7470
- inputSchema3 = z38.object({
7471
- pattern: z38.string().describe("Regex pattern to search for in file contents"),
7472
- glob: z38.string().optional().describe("Glob to filter files (e.g. '*.ts')"),
7473
- 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")
7474
7897
  });
7475
7898
  }
7476
7899
  });
@@ -7478,10 +7901,10 @@ var init_grep = __esm({
7478
7901
  // src/tools/list-directory.ts
7479
7902
  import { readdir } from "fs/promises";
7480
7903
  import { stat } from "fs/promises";
7481
- import { join as join19, relative as relative3 } from "path";
7904
+ import { join as join20, relative as relative3 } from "path";
7482
7905
  import { tool as tool4 } from "ai";
7483
7906
  import { minimatch } from "minimatch";
7484
- import { z as z39 } from "zod";
7907
+ import { z as z40 } from "zod";
7485
7908
  function buildMatcher(patterns) {
7486
7909
  const positive = patterns.filter((p) => !p.startsWith("!"));
7487
7910
  const negative = patterns.filter((p) => p.startsWith("!")).map((p) => p.slice(1));
@@ -7503,7 +7926,7 @@ async function buildTree(dirPath, maxDepth, currentDepth, isIgnored, relativeBas
7503
7926
  const withTypes = [];
7504
7927
  for (const name of rawEntries) {
7505
7928
  try {
7506
- const s = await stat(join19(dirPath, name));
7929
+ const s = await stat(join20(dirPath, name));
7507
7930
  withTypes.push({ name, isDir: s.isDirectory() });
7508
7931
  } catch {
7509
7932
  withTypes.push({ name, isDir: false });
@@ -7523,7 +7946,7 @@ async function buildTree(dirPath, maxDepth, currentDepth, isIgnored, relativeBas
7523
7946
  }
7524
7947
  if (entry.isDir) {
7525
7948
  const children = await buildTree(
7526
- join19(dirPath, entry.name),
7949
+ join20(dirPath, entry.name),
7527
7950
  maxDepth,
7528
7951
  currentDepth + 1,
7529
7952
  isIgnored,
@@ -7561,10 +7984,10 @@ async function buildListDirectoryTool(workingDirectory) {
7561
7984
  const isIgnored = buildMatcher(patterns);
7562
7985
  return tool4({
7563
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.",
7564
- inputSchema: z39.object({
7565
- path: z39.string().default(".").describe("Directory path relative to project root. Defaults to root."),
7566
- depth: z39.number().min(1).max(15).default(10).describe("Max depth to traverse (1-15). Default 10."),
7567
- 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(
7568
7991
  "Whether to respect the gitignore or to ignore it. true will respect it. false will ignore it. Default true"
7569
7992
  ).default(true)
7570
7993
  }),
@@ -7576,7 +7999,7 @@ async function buildListDirectoryTool(workingDirectory) {
7576
7999
  };
7577
8000
  }
7578
8001
  seen.add(cacheKey);
7579
- const targetDir = input.path === "." ? workingDirectory : join19(workingDirectory, input.path);
8002
+ const targetDir = input.path === "." ? workingDirectory : join20(workingDirectory, input.path);
7580
8003
  try {
7581
8004
  const s = await stat(targetDir);
7582
8005
  if (!s.isDirectory()) {
@@ -7612,10 +8035,10 @@ var init_list_directory = __esm({
7612
8035
  });
7613
8036
 
7614
8037
  // src/tools/read-file.ts
7615
- import { readFile as readFile10 } from "fs/promises";
8038
+ import { readFile as readFile11 } from "fs/promises";
7616
8039
  import { relative as relative4, resolve as resolve2 } from "path";
7617
8040
  import { tool as tool5 } from "ai";
7618
- import { z as z40 } from "zod";
8041
+ import { z as z41 } from "zod";
7619
8042
  function resolveSandboxedPath(workingDirectory, filePath) {
7620
8043
  const absolutePath = resolve2(workingDirectory, filePath);
7621
8044
  const relativePath = relative4(workingDirectory, absolutePath);
@@ -7640,7 +8063,7 @@ async function executeReadFile(workingDirectory, filePath, offset, limit) {
7640
8063
  const resolved2 = resolveSandboxedPath(workingDirectory, filePath);
7641
8064
  if ("error" in resolved2) return resolved2;
7642
8065
  try {
7643
- const content = await readFile10(resolved2.absolutePath, "utf-8");
8066
+ const content = await readFile11(resolved2.absolutePath, "utf-8");
7644
8067
  const sliced = sliceLines(content, offset ?? 0, limit ?? MAX_LINES);
7645
8068
  if (sliced.numbered.length > MAX_OUTPUT_BYTES2) {
7646
8069
  sliced.numbered = sliced.numbered.slice(0, MAX_OUTPUT_BYTES2) + `
@@ -7673,10 +8096,10 @@ var init_read_file = __esm({
7673
8096
  init_esm_shims();
7674
8097
  MAX_LINES = 2e3;
7675
8098
  MAX_OUTPUT_BYTES2 = 256 * 1024;
7676
- inputSchema4 = z40.object({
7677
- filePath: z40.string().describe("Path to the file (absolute or relative to working directory)"),
7678
- offset: z40.number().int().min(0).optional().describe("Line number to start reading from (0-based)"),
7679
- 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")
7680
8103
  });
7681
8104
  }
7682
8105
  });
@@ -7699,10 +8122,10 @@ var init_pick_string = __esm({
7699
8122
 
7700
8123
  // src/tools/subagent.ts
7701
8124
  import { ToolLoopAgent as ToolLoopAgent2, hasToolCall as hasToolCall2, stepCountIs as stepCountIs2, tool as tool6 } from "ai";
7702
- import { z as z41 } from "zod";
8125
+ import { z as z42 } from "zod";
7703
8126
  function buildSubagentTools(workingDirectory, onFileRead) {
7704
8127
  const baseReadFile = buildReadFileTool(workingDirectory);
7705
- const readFile26 = onFileRead ? tool6({
8128
+ const readFile27 = onFileRead ? tool6({
7706
8129
  description: baseReadFile.description,
7707
8130
  inputSchema: baseReadFile.inputSchema,
7708
8131
  execute: async (input, options) => {
@@ -7715,7 +8138,7 @@ function buildSubagentTools(workingDirectory, onFileRead) {
7715
8138
  bash: buildBashTool(workingDirectory),
7716
8139
  glob: buildGlobTool(workingDirectory),
7717
8140
  grep: buildGrepTool(workingDirectory),
7718
- read_file: readFile26
8141
+ read_file: readFile27
7719
8142
  };
7720
8143
  }
7721
8144
  function buildSubagentTool(model, workingDirectory, onHeartbeat, onFileRead) {
@@ -7772,11 +8195,11 @@ var init_subagent = __esm({
7772
8195
  init_glob();
7773
8196
  init_grep();
7774
8197
  init_read_file();
7775
- inputSchema5 = z41.object({
7776
- 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.")
7777
8200
  });
7778
- resultSchema = z41.object({
7779
- findings: z41.string().describe("Summary of what was found")
8201
+ resultSchema = z42.object({
8202
+ findings: z42.string().describe("Summary of what was found")
7780
8203
  });
7781
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).
7782
8205
 
@@ -7787,10 +8210,10 @@ Be thorough but focused - only investigate what's relevant to your instruction.`
7787
8210
  });
7788
8211
 
7789
8212
  // src/tools/write-file.ts
7790
- import { writeFile as writeFile6, mkdir as mkdir3 } from "fs/promises";
8213
+ import { writeFile as writeFile7, mkdir as mkdir3 } from "fs/promises";
7791
8214
  import { dirname as dirname3, relative as relative5, resolve as resolve3 } from "path";
7792
8215
  import { tool as tool7 } from "ai";
7793
- import { z as z42 } from "zod";
8216
+ import { z as z43 } from "zod";
7794
8217
  async function executeWriteFile(outputDirectory, filePath, content) {
7795
8218
  const cleaned = filePath.replace(/^autonoma\//, "");
7796
8219
  const absolutePath = resolve3(outputDirectory, cleaned);
@@ -7800,7 +8223,7 @@ async function executeWriteFile(outputDirectory, filePath, content) {
7800
8223
  }
7801
8224
  try {
7802
8225
  await mkdir3(dirname3(absolutePath), { recursive: true });
7803
- await writeFile6(absolutePath, content, "utf-8");
8226
+ await writeFile7(absolutePath, content, "utf-8");
7804
8227
  return { path: relativePath, bytesWritten: content.length };
7805
8228
  } catch (err) {
7806
8229
  const message = err instanceof Error ? err.message : String(err);
@@ -7819,21 +8242,21 @@ var init_write_file = __esm({
7819
8242
  "src/tools/write-file.ts"() {
7820
8243
  "use strict";
7821
8244
  init_esm_shims();
7822
- inputSchema6 = z42.object({
7823
- filePath: z42.string().describe("Path to write (absolute or relative to output directory)"),
7824
- 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")
7825
8248
  });
7826
8249
  }
7827
8250
  });
7828
8251
 
7829
8252
  // src/tools/ask-user.ts
7830
8253
  import { tool as tool8 } from "ai";
7831
- import { z as z43 } from "zod";
8254
+ import { z as z44 } from "zod";
7832
8255
  function buildAskUserTool() {
7833
8256
  return tool8({
7834
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.",
7835
- inputSchema: z43.object({
7836
- question: z43.string().describe(
8258
+ inputSchema: z44.object({
8259
+ question: z44.string().describe(
7837
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?'"
7838
8261
  )
7839
8262
  }),
@@ -7893,7 +8316,7 @@ var init_tools = __esm({
7893
8316
 
7894
8317
  // src/agents/00-project-mapper/coverage.ts
7895
8318
  import { readdir as readdir2 } from "fs/promises";
7896
- import { join as join20 } from "path";
8319
+ import { join as join21 } from "path";
7897
8320
  async function findUncoveredDirs(projectRoot, map) {
7898
8321
  const entries = [...map.frontends, ...map.backends, ...map.ignore].map(
7899
8322
  (e) => e.path.replace(/^\.\//, "").replace(/\/+$/, "")
@@ -7917,7 +8340,7 @@ async function findUncoveredDirs(projectRoot, map) {
7917
8340
  const childRel = rel === "" ? child.name : `${rel}/${child.name}`;
7918
8341
  if (underEntry(childRel)) continue;
7919
8342
  if (hasEntryWithin(childRel)) {
7920
- 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);
7921
8344
  } else {
7922
8345
  out.push(childRel);
7923
8346
  }
@@ -7944,7 +8367,7 @@ __export(project_mapper_exports, {
7944
8367
  runProjectMapper: () => runProjectMapper
7945
8368
  });
7946
8369
  import { tool as tool9 } from "ai";
7947
- import { z as z44 } from "zod";
8370
+ import { z as z45 } from "zod";
7948
8371
  async function runProjectMapper(input) {
7949
8372
  const model = getModel(input.modelId);
7950
8373
  const { logger, onStepFinish } = buildDefaultStepLogger("project-map", MAX_STEPS);
@@ -7978,7 +8401,7 @@ First build the full inventory (workspace/package manifests + top-level director
7978
8401
  }),
7979
8402
  finish: tool9({
7980
8403
  description: "End this step. Call once set_project_map has recorded a complete map.",
7981
- inputSchema: z44.object({}),
8404
+ inputSchema: z45.object({}),
7982
8405
  execute: () => {
7983
8406
  if (captured == null) {
7984
8407
  return { error: "Cannot finish: no map recorded - call set_project_map first." };
@@ -8022,7 +8445,7 @@ __export(pages_finder_exports, {
8022
8445
  import { existsSync } from "fs";
8023
8446
  import * as path2 from "path";
8024
8447
  import { tool as tool10 } from "ai";
8025
- import { z as z45 } from "zod";
8448
+ import { z as z46 } from "zod";
8026
8449
  async function runPageFinder(input) {
8027
8450
  const model = getModel(input.modelId);
8028
8451
  const pageCollector = new PageCollector();
@@ -8057,12 +8480,12 @@ ${input.extraMessage}`;
8057
8480
  }),
8058
8481
  view_pages: tool10({
8059
8482
  description: "use this tool to view all the pages that you already added",
8060
- inputSchema: z45.object(),
8483
+ inputSchema: z46.object(),
8061
8484
  execute: () => pageCollector.viewPages()
8062
8485
  }),
8063
8486
  finish: tool10({
8064
8487
  description: "End this step. Call once every page in the codebase has been added via add_page.",
8065
- inputSchema: z45.object({}),
8488
+ inputSchema: z46.object({}),
8066
8489
  execute: () => {
8067
8490
  if (pageCollector.pages.size === 0) {
8068
8491
  return {
@@ -8089,10 +8512,10 @@ var init_pages_finder = __esm({
8089
8512
  init_agent();
8090
8513
  init_model();
8091
8514
  init_tools();
8092
- Page = z45.object({
8093
- route: z45.string().min(1),
8094
- path: z45.string().min(1),
8095
- 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)
8096
8519
  });
8097
8520
  PageCollector = class {
8098
8521
  // the key is the path
@@ -8288,15 +8711,15 @@ var kb_generator_exports = {};
8288
8711
  __export(kb_generator_exports, {
8289
8712
  runKBGenerator: () => runKBGenerator
8290
8713
  });
8291
- import { readFile as readFile11 } from "fs/promises";
8292
- 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";
8293
8716
  import { tool as tool11 } from "ai";
8294
- import { z as z46 } from "zod";
8717
+ import { z as z47 } from "zod";
8295
8718
  function buildRegisterPagesTool(tracker) {
8296
8719
  return tool11({
8297
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.",
8298
- inputSchema: z46.object({
8299
- 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")
8300
8723
  }),
8301
8724
  execute: async (input) => {
8302
8725
  tracker.register(input.pages);
@@ -8310,7 +8733,7 @@ function buildRegisterPagesTool(tracker) {
8310
8733
  function buildPageCoverageTool(tracker) {
8311
8734
  return tool11({
8312
8735
  description: "Check how many registered pages you've read vs how many remain.",
8313
- inputSchema: z46.object({}),
8736
+ inputSchema: z47.object({}),
8314
8737
  execute: async () => tracker.coverage()
8315
8738
  });
8316
8739
  }
@@ -8321,9 +8744,9 @@ function requiredReads(total) {
8321
8744
  function buildFinishTool(tracker, onFinish) {
8322
8745
  return tool11({
8323
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.",
8324
- inputSchema: z46.object({
8325
- summary: z46.string().describe("Summary of what was generated"),
8326
- 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")
8327
8750
  }),
8328
8751
  execute: async (input) => {
8329
8752
  const cov = tracker.coverage();
@@ -8402,8 +8825,8 @@ Output files:
8402
8825
  const agentConfig = buildKbAgentConfig(tracker, model, input, onStepFinish, setResult);
8403
8826
  await runAgent(agentConfig, prompt, () => result);
8404
8827
  logger.summary();
8405
- const autonomaPath = join21(input.outputDir, "AUTONOMA.md");
8406
- 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) => {
8407
8830
  debugLog("AUTONOMA.md not found while checking step completion", { err });
8408
8831
  return false;
8409
8832
  });
@@ -8589,17 +9012,17 @@ var entity_audit_exports = {};
8589
9012
  __export(entity_audit_exports, {
8590
9013
  runEntityAudit: () => runEntityAudit
8591
9014
  });
8592
- import { readFile as readFile12, writeFile as writeFile7 } from "fs/promises";
8593
- import { join as join22 } from "path";
9015
+ import { readFile as readFile13, writeFile as writeFile8 } from "fs/promises";
9016
+ import { join as join23 } from "path";
8594
9017
  import { tool as tool12 } from "ai";
8595
9018
  import { glob as glob4 } from "glob";
8596
- import { z as z47 } from "zod";
9019
+ import { z as z48 } from "zod";
8597
9020
  function buildRegisterModelsTool(tracker) {
8598
9021
  return tool12({
8599
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.",
8600
- inputSchema: z47.object({
8601
- models: z47.array(z47.string()).describe("All model/table names found by grep"),
8602
- 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')")
8603
9026
  }),
8604
9027
  execute: async (input) => {
8605
9028
  tracker.register(input.models);
@@ -8615,7 +9038,7 @@ function buildRegisterModelsTool(tracker) {
8615
9038
  function buildNextModelTool(tracker) {
8616
9039
  return tool12({
8617
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.",
8618
- inputSchema: z47.object({}),
9041
+ inputSchema: z48.object({}),
8619
9042
  execute: async () => {
8620
9043
  const next = tracker.nextModel();
8621
9044
  if (!next) {
@@ -8635,17 +9058,17 @@ function buildNextModelTool(tracker) {
8635
9058
  function buildMarkModelAuditedTool(tracker) {
8636
9059
  return tool12({
8637
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).",
8638
- inputSchema: z47.object({
8639
- model: z47.string().describe("Model name"),
8640
- independently_created: z47.boolean(),
8641
- creation_file: z47.string().optional().describe("File containing the creation function"),
8642
- creation_function: z47.string().optional().describe("Function/method name (e.g. 'UserService.create' or 'create_user')"),
8643
- side_effects: z47.array(z47.string()).optional().describe("Side effects of creation (e.g. 'creates default Settings row', 'hashes password')"),
8644
- created_by: z47.array(
8645
- z47.object({
8646
- owner: z47.string().describe("Owner model name"),
8647
- via: z47.string().optional().describe("Function that creates this model (e.g. 'OrganizationService.create')"),
8648
- 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")
8649
9072
  })
8650
9073
  ).describe("List of owner models that create this as a side effect, empty array if none")
8651
9074
  }),
@@ -8684,16 +9107,16 @@ function buildMarkModelAuditedTool(tracker) {
8684
9107
  function buildModelCoverageTool(tracker) {
8685
9108
  return tool12({
8686
9109
  description: "Check how many registered models you've audited vs how many remain.",
8687
- inputSchema: z47.object({}),
9110
+ inputSchema: z48.object({}),
8688
9111
  execute: async () => tracker.coverage()
8689
9112
  });
8690
9113
  }
8691
9114
  function buildFinishTool2(tracker, onFinish) {
8692
9115
  return tool12({
8693
9116
  description: "Call when entity audit is complete. BLOCKED if there are unaudited models - call model_coverage first to check.",
8694
- inputSchema: z47.object({
8695
- summary: z47.string().describe("Summary of the audit"),
8696
- 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")
8697
9120
  }),
8698
9121
  execute: async (input) => {
8699
9122
  const cov = tracker.coverage();
@@ -8721,7 +9144,7 @@ async function findPrismaSchema(projectRoot) {
8721
9144
  return candidates[0] ?? void 0;
8722
9145
  }
8723
9146
  async function extractPrismaModels(schemaPath) {
8724
- const content = await readFile12(schemaPath, "utf-8");
9147
+ const content = await readFile13(schemaPath, "utf-8");
8725
9148
  return content.split("\n").filter((line) => line.startsWith("model ")).map((line) => line.split(/\s+/)[1]).filter((name) => name != null);
8726
9149
  }
8727
9150
  async function detectFrameworkAndModels(projectRoot) {
@@ -8808,8 +9231,8 @@ ${formatException(err)}`);
8808
9231
  logger.summary();
8809
9232
  const writeCanonicalAudit = async () => {
8810
9233
  if (tracker.auditedModels.size === 0) return void 0;
8811
- const auditPath = join22(input.outputDir, "entity-audit.md");
8812
- await writeFile7(auditPath, tracker.generateAuditMarkdown(), "utf-8");
9234
+ const auditPath = join23(input.outputDir, "entity-audit.md");
9235
+ await writeFile8(auditPath, tracker.generateAuditMarkdown(), "utf-8");
8813
9236
  return auditPath;
8814
9237
  };
8815
9238
  const canonicalPath = await writeCanonicalAudit();
@@ -8823,9 +9246,9 @@ ${formatException(err)}`);
8823
9246
  }
8824
9247
  const reviewed = result;
8825
9248
  if (!reviewed) {
8826
- const auditPath = join22(input.outputDir, "entity-audit.md");
9249
+ const auditPath = join23(input.outputDir, "entity-audit.md");
8827
9250
  try {
8828
- await readFile12(auditPath, "utf-8");
9251
+ await readFile13(auditPath, "utf-8");
8829
9252
  return {
8830
9253
  success: true,
8831
9254
  artifacts: ["entity-audit.md"],
@@ -9029,15 +9452,37 @@ anything the database will refuse a second copy of - must embed a token INSIDE a
9029
9452
  otherwise real-looking value ("admin+{{${TEST_RUN_ID_TOKEN}}}@acme.test",
9030
9453
  "acme-{{${TEST_RUN_SHORT_ID_TOKEN}}}"), never replace the value entirely. Two tests
9031
9454
  run at the same time seed this scenario twice; without the token the second one fails
9032
- on a unique constraint. Everything else stays concrete and static, and no other
9033
- {{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.`;
9034
9479
  }
9035
9480
  });
9036
9481
 
9037
9482
  // src/agents/03-scenario-recipe/scenario-table.ts
9038
- import { readFile as readFile13 } from "fs/promises";
9039
- import { join as join23 } from "path";
9040
- 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";
9041
9486
  function validateScenarioIsConcrete(content) {
9042
9487
  const errors = findUnknownRecipeTokens(content).map(
9043
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}.`
@@ -9071,22 +9516,22 @@ __export(scenario_recipe_exports, {
9071
9516
  feedbackToScenario: () => feedbackToScenario,
9072
9517
  runScenarioRecipe: () => runScenarioRecipe
9073
9518
  });
9074
- import { readFile as readFile14 } from "fs/promises";
9075
- import { join as join24 } from "path";
9519
+ import { readFile as readFile15 } from "fs/promises";
9520
+ import { join as join25 } from "path";
9076
9521
  import { tool as tool13 } from "ai";
9077
- import { z as z48 } from "zod";
9522
+ import { z as z49 } from "zod";
9078
9523
  function buildFinishTool3(requiredEntities, outputDir, onFinish) {
9079
9524
  return tool13({
9080
9525
  description: "Call when scenario design is complete and scenarios.md is written. BLOCKED if any required entities are missing from the scenario.",
9081
- inputSchema: z48.object({
9082
- summary: z48.string().describe("Summary of the scenario"),
9083
- entityCount: z48.number().describe("Number of entity types in the scenario"),
9084
- 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")
9085
9530
  }),
9086
9531
  execute: async (input) => {
9087
9532
  let content;
9088
9533
  try {
9089
- content = await readFile14(join24(outputDir, "scenarios.md"), "utf-8");
9534
+ content = await readFile15(join25(outputDir, "scenarios.md"), "utf-8");
9090
9535
  } catch {
9091
9536
  return { error: "Cannot finish: scenarios.md not found. Write it first." };
9092
9537
  }
@@ -9165,9 +9610,9 @@ When done, call finish.`;
9165
9610
  logger.summary();
9166
9611
  const reviewed = result;
9167
9612
  if (!reviewed) {
9168
- const scenariosPath = join24(input.outputDir, "scenarios.md");
9613
+ const scenariosPath = join25(input.outputDir, "scenarios.md");
9169
9614
  try {
9170
- await readFile14(scenariosPath, "utf-8");
9615
+ await readFile15(scenariosPath, "utf-8");
9171
9616
  return {
9172
9617
  success: true,
9173
9618
  artifacts: ["scenarios.md"],
@@ -9226,12 +9671,12 @@ var init_scenario_recipe = __esm({
9226
9671
  });
9227
9672
 
9228
9673
  // src/agents/04-recipe-builder/entity-order.ts
9229
- import { readFile as readFile15 } from "fs/promises";
9230
- import { join as join25 } from "path";
9231
- import matter3 from "gray-matter";
9232
- 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";
9233
9678
  async function parseEntityAudit(outputDir) {
9234
- const raw = await readFile15(join25(outputDir, "entity-audit.md"), "utf-8");
9679
+ const raw = await readFile16(join26(outputDir, "entity-audit.md"), "utf-8");
9235
9680
  try {
9236
9681
  const parsed = frontmatterSchema.safeParse(matter3(raw).data);
9237
9682
  if (parsed.success && parsed.data.models.length > 0) {
@@ -9392,34 +9837,34 @@ var init_entity_order = __esm({
9392
9837
  "src/agents/04-recipe-builder/entity-order.ts"() {
9393
9838
  "use strict";
9394
9839
  init_esm_shims();
9395
- createdBySchema = z49.object({
9396
- owner: z49.string(),
9397
- via: z49.string().optional(),
9398
- why: z49.string().optional()
9840
+ createdBySchema = z50.object({
9841
+ owner: z50.string(),
9842
+ via: z50.string().optional(),
9843
+ why: z50.string().optional()
9399
9844
  });
9400
- auditedModelSchema = z49.object({
9401
- name: z49.string(),
9402
- independently_created: z49.coerce.boolean().default(false),
9403
- creation_file: z49.string().optional(),
9404
- creation_function: z49.string().optional(),
9405
- 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(),
9406
9851
  // Tolerate a stray `created_by:` with no entries (parsed as null by YAML).
9407
- created_by: z49.array(createdBySchema).nullish().transform((v) => v ?? [])
9852
+ created_by: z50.array(createdBySchema).nullish().transform((v) => v ?? [])
9408
9853
  });
9409
- frontmatterSchema = z49.object({
9410
- models: z49.array(auditedModelSchema).nullish().transform((v) => v ?? [])
9854
+ frontmatterSchema = z50.object({
9855
+ models: z50.array(auditedModelSchema).nullish().transform((v) => v ?? [])
9411
9856
  });
9412
9857
  }
9413
9858
  });
9414
9859
 
9415
9860
  // src/agents/04-recipe-builder/completion.ts
9416
- import { readFile as readFile16 } from "fs/promises";
9417
- import { join as join26 } from "path";
9418
- 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";
9419
9864
  async function readCompletion(outputDir) {
9420
9865
  let raw;
9421
9866
  try {
9422
- raw = await readFile16(join26(outputDir, COMPLETION_MARKER_FILE), "utf-8");
9867
+ raw = await readFile17(join27(outputDir, COMPLETION_MARKER_FILE), "utf-8");
9423
9868
  } catch (err) {
9424
9869
  debugLog("No completion marker yet", { err });
9425
9870
  return false;
@@ -9445,7 +9890,7 @@ var init_completion = __esm({
9445
9890
  init_esm_shims();
9446
9891
  init_debug();
9447
9892
  COMPLETION_MARKER_FILE = ".sdk-integration-complete";
9448
- completionSchema = z50.object({ complete: z50.literal(true) });
9893
+ completionSchema = z51.object({ complete: z51.literal(true) });
9449
9894
  }
9450
9895
  });
9451
9896
 
@@ -9453,9 +9898,10 @@ var init_completion = __esm({
9453
9898
  function watchForCompletion(outputDir, proc, timing = DEFAULT_WATCH_TIMING) {
9454
9899
  let graceTimer;
9455
9900
  let killTimer;
9901
+ let stopped = false;
9456
9902
  const poll = setInterval(() => {
9457
9903
  void readCompletion(outputDir).then((complete) => {
9458
- if (!complete || graceTimer != null) return;
9904
+ if (stopped || !complete || graceTimer != null) return;
9459
9905
  debugLog("Completion marker detected while the agent runs; scheduling terminal reclaim");
9460
9906
  clearInterval(poll);
9461
9907
  graceTimer = setTimeout(() => {
@@ -9469,6 +9915,7 @@ function watchForCompletion(outputDir, proc, timing = DEFAULT_WATCH_TIMING) {
9469
9915
  });
9470
9916
  }, timing.pollMs);
9471
9917
  return () => {
9918
+ stopped = true;
9472
9919
  clearInterval(poll);
9473
9920
  if (graceTimer != null) clearTimeout(graceTimer);
9474
9921
  if (killTimer != null) clearTimeout(killTimer);
@@ -9493,8 +9940,8 @@ var init_completion_watch = __esm({
9493
9940
  });
9494
9941
 
9495
9942
  // src/agents/04-recipe-builder/integration-prompt.ts
9496
- import { writeFile as writeFile8 } from "fs/promises";
9497
- import { join as join27 } from "path";
9943
+ import { writeFile as writeFile9 } from "fs/promises";
9944
+ import { join as join28 } from "path";
9498
9945
  function renderIntegrationPrompt(params) {
9499
9946
  const priorFailureSection = params.priorFailure != null ? `
9500
9947
  \u2550\u2550\u2550 A PRIOR SESSION DID NOT COMPLETE - READ THIS FIRST \u2550\u2550\u2550
@@ -9577,7 +10024,10 @@ STOP immediately and say EXACTLY what is missing and why you can't proceed.
9577
10024
  JavaScript/npm package.
9578
10025
  2. Implement ONE endpoint (prefer "${DEFAULT_ENDPOINT_PATH}" unless the repo has a
9579
10026
  clearly better convention) that handles the discover / up / down protocol through
9580
- 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
9581
10031
  in the app's environment - verify the x-signature HMAC against that env value (the
9582
10032
  SDK reads it for you). Do NOT hardcode a secret or overwrite the env value.
9583
10033
  3. Implement a real factory for EVERY entity the entity audit says needs one:
@@ -9652,6 +10102,35 @@ value still reads as real: "admin+{{${TEST_RUN_ID_TOKEN}}}@acme.test", "acme-{{$
9652
10102
  Any OTHER {{token}} is rejected on upload: there is no general variable mechanism, so
9653
10103
  never invent one.
9654
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
+
9655
10134
  WHICH fields need a token is not a judgement call and not a guess from the field name.
9656
10135
  Before you write the recipe, ENUMERATE the uniqueness rules for every entity you seed:
9657
10136
  read the schema definitions and migrations, and query the live database you are already
@@ -9715,6 +10194,11 @@ Once every entity passes independently, run the FULL recipe as one pass:
9715
10194
  \u2022 confirm all rows created (DB), then down with the refsToken -> succeeds, rows gone (DB)
9716
10195
  \u2022 confirm a WRONG signature is rejected (the SDK does this for you - do not disable it)
9717
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.
9718
10202
 
9719
10203
  \u2550\u2550\u2550 CHECK THE RECIPE FILE - THE GATE YOU CANNOT SKIP \u2550\u2550\u2550
9720
10204
  A recipe that seeds a database perfectly can still be a file Autonoma refuses, because
@@ -9783,7 +10267,7 @@ Write the completion marker once ALL of these hold:
9783
10267
  A step you documented as genuinely blocked NEVER justifies withholding the marker; a
9784
10268
  checklist item you simply have not finished always does. The marker is how the CLI knows
9785
10269
  the session is done and can upload the recipe:
9786
- ${join27(params.outputDir, COMPLETION_MARKER_FILE)}
10270
+ ${join28(params.outputDir, COMPLETION_MARKER_FILE)}
9787
10271
  Its contents MUST be exactly:
9788
10272
  { "complete": true }
9789
10273
  Writing it is not optional: the planner watches for this marker and takes the terminal
@@ -9795,27 +10279,45 @@ or the commit you left behind and what blocked the push - and then says:
9795
10279
  Nothing after that message - no further questions, summaries, or work.`;
9796
10280
  }
9797
10281
  async function writeIntegrationPrompt(params) {
9798
- const path3 = join27(params.outputDir, INTEGRATION_PROMPT_FILE);
9799
- await writeFile8(path3, renderIntegrationPrompt(params), "utf-8");
10282
+ const path3 = join28(params.outputDir, INTEGRATION_PROMPT_FILE);
10283
+ await writeFile9(path3, renderIntegrationPrompt(params), "utf-8");
9800
10284
  return path3;
9801
10285
  }
9802
- var INTEGRATION_PROMPT_VERSION, INTEGRATION_PROMPT_FILE, DEFAULT_ENDPOINT_PATH, INTEGRATION_BRANCH;
10286
+ var INTEGRATION_PROMPT_VERSION, INTEGRATION_PROMPT_FILE, DEFAULT_ENDPOINT_PATH;
9803
10287
  var init_integration_prompt = __esm({
9804
10288
  "src/agents/04-recipe-builder/integration-prompt.ts"() {
9805
10289
  "use strict";
9806
10290
  init_esm_shims();
9807
10291
  init_src();
9808
10292
  init_completion();
9809
- INTEGRATION_PROMPT_VERSION = 10;
10293
+ INTEGRATION_PROMPT_VERSION = 11;
9810
10294
  INTEGRATION_PROMPT_FILE = "integration-prompt.md";
9811
10295
  DEFAULT_ENDPOINT_PATH = "/api/autonoma";
9812
- 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;
9813
10315
  }
9814
10316
  });
9815
10317
 
9816
10318
  // src/agents/04-recipe-builder/state.ts
9817
- import { readFile as readFile17, writeFile as writeFile9 } from "fs/promises";
9818
- import { join as join28 } from "path";
10319
+ import { readFile as readFile18, writeFile as writeFile10 } from "fs/promises";
10320
+ import { join as join29 } from "path";
9819
10321
  function initialRecipeState() {
9820
10322
  return {
9821
10323
  phase: "tech-detect",
@@ -9825,7 +10327,7 @@ function initialRecipeState() {
9825
10327
  }
9826
10328
  async function loadRecipeState(outputDir) {
9827
10329
  try {
9828
- const raw = await readFile17(join28(outputDir, STATE_FILE2), "utf-8");
10330
+ const raw = await readFile18(join29(outputDir, STATE_FILE2), "utf-8");
9829
10331
  const parsed = JSON.parse(raw);
9830
10332
  return parsed;
9831
10333
  } catch {
@@ -9833,7 +10335,7 @@ async function loadRecipeState(outputDir) {
9833
10335
  }
9834
10336
  }
9835
10337
  async function saveRecipeState(outputDir, state) {
9836
- 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");
9837
10339
  }
9838
10340
  var STATE_FILE2;
9839
10341
  var init_state2 = __esm({
@@ -9846,12 +10348,12 @@ var init_state2 = __esm({
9846
10348
 
9847
10349
  // src/agents/04-recipe-builder/phases/handoff.ts
9848
10350
  import { rm as rm2 } from "fs/promises";
9849
- import { join as join29 } from "path";
10351
+ import { join as join30 } from "path";
9850
10352
  function launchMessage(promptFile) {
9851
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.`;
9852
10354
  }
9853
10355
  async function runHandoffPhase(state, deps, outputDir) {
9854
- const recipePath = state.recipePath ?? join29(outputDir, RECIPE_FILE);
10356
+ const recipePath = state.recipePath ?? join30(outputDir, RECIPE_FILE);
9855
10357
  state.recipePath = recipePath;
9856
10358
  const launcher = await selectLauncher(deps.launchers, state.agentId ?? deps.presetAgentId, deps.interactive);
9857
10359
  if (launcher == null) {
@@ -9868,7 +10370,7 @@ async function runHandoffPhase(state, deps, outputDir) {
9868
10370
  state.agentId = launcher.id;
9869
10371
  state.permissionMode = permissionMode;
9870
10372
  await saveRecipeState(outputDir, state);
9871
- await launchAgent(launcher, permissionMode, {
10373
+ state.lastLaunch = await launchAgent(launcher, permissionMode, {
9872
10374
  outputDir,
9873
10375
  recipePath,
9874
10376
  cliCommand: deps.cliCommand,
@@ -9881,7 +10383,7 @@ async function runHandoffPhase(state, deps, outputDir) {
9881
10383
  return { kind: "advance" };
9882
10384
  }
9883
10385
  async function runCompletionPhase(state, deps, outputDir) {
9884
- const recipePath = state.recipePath ?? join29(outputDir, RECIPE_FILE);
10386
+ const recipePath = state.recipePath ?? join30(outputDir, RECIPE_FILE);
9885
10387
  while (true) {
9886
10388
  const [complete, read] = await Promise.all([readCompletion(outputDir), loadRecipe(outputDir)]);
9887
10389
  const uploadProblems = read.status === "ok" ? findRecipeUploadProblems(read.recipe) : [];
@@ -9897,30 +10399,59 @@ async function runCompletionPhase(state, deps, outputDir) {
9897
10399
  return await manualFallback(outputDir, recipePath, deps.cliCommand, NO_AGENT_FOUND);
9898
10400
  }
9899
10401
  const failure = describeIncompleteRecipe(read, uploadProblems, recipePath, deps.cliCommand);
9900
- if (launcher != null && (state.launchAttempts ?? 0) < MAX_LAUNCH_ATTEMPTS) {
9901
- log.warn("The integration isn't complete yet. Launching the agent to finish it...");
9902
- state.agentId = launcher.id;
9903
- state.priorFailure = failure;
9904
- await saveRecipeState(outputDir, state);
9905
- await launchAgent(launcher, state.permissionMode ?? "bypassPermissions", {
9906
- outputDir,
9907
- recipePath,
9908
- cliCommand: deps.cliCommand,
9909
- interactive: deps.interactive,
9910
- priorFailure: failure,
9911
- userGuidance: state.userGuidance
9912
- });
9913
- state.launchAttempts = (state.launchAttempts ?? 0) + 1;
9914
- await saveRecipeState(outputDir, state);
9915
- continue;
9916
- }
9917
- 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);
10418
+ }
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
+ };
9918
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]);
9919
10450
  }
9920
10451
  function handbackSummary(failure, outputDir) {
9921
10452
  return `${failure}
9922
10453
 
9923
- 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.`;
9924
10455
  }
9925
10456
  async function launchAgent(launcher, permissionMode, target) {
9926
10457
  const promptFile = await writeIntegrationPrompt({
@@ -9930,7 +10461,7 @@ async function launchAgent(launcher, permissionMode, target) {
9930
10461
  priorFailure: target.priorFailure,
9931
10462
  userGuidance: target.userGuidance
9932
10463
  });
9933
- 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) => {
9934
10465
  debugLog("Could not clear a stale completion marker", { err });
9935
10466
  });
9936
10467
  log.info(`Launching ${launcher.label}. It will implement the integration - watch and steer it as it works.`);
@@ -9947,6 +10478,7 @@ async function launchAgent(launcher, permissionMode, target) {
9947
10478
  });
9948
10479
  }
9949
10480
  suspend();
10481
+ const startedAt = Date.now();
9950
10482
  try {
9951
10483
  const exitCode = await launcher.launch({
9952
10484
  message: launchMessage(promptFile),
@@ -9957,7 +10489,22 @@ async function launchAgent(launcher, permissionMode, target) {
9957
10489
  // own and needs no watcher.
9958
10490
  watch: target.interactive ? (proc) => watchForCompletion(target.outputDir, proc) : void 0
9959
10491
  });
9960
- 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;
9961
10508
  } finally {
9962
10509
  resume();
9963
10510
  }
@@ -10004,6 +10551,7 @@ var init_handoff = __esm({
10004
10551
  "src/agents/04-recipe-builder/phases/handoff.ts"() {
10005
10552
  "use strict";
10006
10553
  init_esm_shims();
10554
+ init_analytics();
10007
10555
  init_coding_agent();
10008
10556
  init_debug();
10009
10557
  init_interrupt();
@@ -10013,6 +10561,7 @@ var init_handoff = __esm({
10013
10561
  init_completion();
10014
10562
  init_completion_watch();
10015
10563
  init_integration_prompt();
10564
+ init_launch_outcome();
10016
10565
  init_recipe();
10017
10566
  init_state2();
10018
10567
  MAX_LAUNCH_ATTEMPTS = 2;
@@ -10129,17 +10678,17 @@ var init_recipe_builder = __esm({
10129
10678
  });
10130
10679
 
10131
10680
  // src/agents/00b-feature-discovery/index.ts
10132
- import { readFile as readFile18, writeFile as writeFile10 } from "fs/promises";
10133
- import { join as join30 } from "path";
10681
+ import { readFile as readFile19, writeFile as writeFile11 } from "fs/promises";
10682
+ import { join as join31 } from "path";
10134
10683
  import { tool as tool14 } from "ai";
10135
- import { z as z51 } from "zod";
10684
+ import { z as z52 } from "zod";
10136
10685
  async function saveFeatures(outputDir, features) {
10137
10686
  const obj = Object.fromEntries(features);
10138
- 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");
10139
10688
  }
10140
10689
  async function loadFeatures(outputDir) {
10141
10690
  try {
10142
- const raw = await readFile18(join30(outputDir, FEATURES_FILE), "utf-8");
10691
+ const raw = await readFile19(join31(outputDir, FEATURES_FILE), "utf-8");
10143
10692
  const obj = JSON.parse(raw);
10144
10693
  return new Map(Object.entries(obj));
10145
10694
  } catch {
@@ -10173,7 +10722,7 @@ Process every page. Call add_feature for each sub-feature you discover. When don
10173
10722
  add_feature: tool14({
10174
10723
  description: "Add a discovered sub-feature",
10175
10724
  inputSchema: Feature.extend({
10176
- 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')")
10177
10726
  }),
10178
10727
  execute: (featureInput) => {
10179
10728
  const { id, ...rest } = featureInput;
@@ -10187,17 +10736,17 @@ Process every page. Call add_feature for each sub-feature you discover. When don
10187
10736
  }),
10188
10737
  view_features: tool14({
10189
10738
  description: "View all discovered features so far",
10190
- inputSchema: z51.object({}),
10739
+ inputSchema: z52.object({}),
10191
10740
  execute: () => collector.viewFeatures()
10192
10741
  }),
10193
10742
  view_pages: tool14({
10194
10743
  description: "View the pages list to know what to analyze",
10195
- inputSchema: z51.object({}),
10744
+ inputSchema: z52.object({}),
10196
10745
  execute: () => pagesDescription
10197
10746
  }),
10198
10747
  finish: tool14({
10199
10748
  description: "Signal that feature discovery is complete",
10200
- inputSchema: z51.object({ summary: z51.string() }),
10749
+ inputSchema: z52.object({ summary: z52.string() }),
10201
10750
  execute: async (finishInput) => {
10202
10751
  result = {
10203
10752
  success: true,
@@ -10228,13 +10777,13 @@ var init_b_feature_discovery = __esm({
10228
10777
  init_model();
10229
10778
  init_tools();
10230
10779
  FEATURES_FILE = "features.json";
10231
- Feature = z51.object({
10232
- name: z51.string().min(1).describe("Human-readable name (e.g. 'Settings > Notifications Tab', 'Create Project Modal')"),
10233
- type: z51.enum(["tab", "modal", "form", "table", "wizard", "nested-route", "complex-component"]),
10234
- parentPagePath: z51.string().min(1).describe("The page path this feature belongs to (from the pages list)"),
10235
- sourceFiles: z51.array(z51.string()).min(1).describe("Relative paths to the source files for this sub-feature"),
10236
- interactiveElements: z51.number().int().min(0).describe("Count of interactive elements found (buttons, inputs, toggles, etc.)"),
10237
- 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")
10238
10787
  });
10239
10788
  FeatureCollector = class {
10240
10789
  features = /* @__PURE__ */ new Map();
@@ -10317,21 +10866,21 @@ Use kebab-case IDs that indicate the parent page and feature type:
10317
10866
  });
10318
10867
 
10319
10868
  // src/agents/05-test-generator/graph.ts
10320
- import { readFile as readFile19, writeFile as writeFile11 } from "fs/promises";
10321
- import { join as join31 } from "path";
10869
+ import { readFile as readFile20, writeFile as writeFile12 } from "fs/promises";
10870
+ import { join as join32 } from "path";
10322
10871
  function estimateExpectedTests(written, processed, totalNodes) {
10323
10872
  if (totalNodes <= 0) return written;
10324
10873
  const rate = written > 0 && processed >= LIVE_RATE_MIN_PROCESSED ? written / processed : TESTS_PER_NODE_PRIOR;
10325
10874
  return Math.max(written, Math.round(rate * totalNodes));
10326
10875
  }
10327
10876
  async function saveBfsState(outputDir, state) {
10328
- const path3 = join31(outputDir, state.stateFile);
10329
- 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");
10330
10879
  }
10331
10880
  async function loadBfsState(outputDir) {
10332
- const path3 = join31(outputDir, BFS_STATE_FILE);
10881
+ const path3 = join32(outputDir, BFS_STATE_FILE);
10333
10882
  try {
10334
- const raw = await readFile19(path3, "utf-8");
10883
+ const raw = await readFile20(path3, "utf-8");
10335
10884
  return CoverageState.deserialize(JSON.parse(raw));
10336
10885
  } catch {
10337
10886
  return void 0;
@@ -10931,13 +11480,13 @@ When you finish, all dimensions are reported so the user knows what's covered an
10931
11480
  });
10932
11481
 
10933
11482
  // src/agents/05-test-generator/recipe-context.ts
10934
- import { readFile as readFile20 } from "fs/promises";
10935
- import { join as join32 } from "path";
10936
- 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";
10937
11486
  async function loadRecipeContext(outputDir) {
10938
11487
  let raw;
10939
11488
  try {
10940
- raw = await readFile20(join32(outputDir, "recipe.json"), "utf-8");
11489
+ raw = await readFile21(join33(outputDir, "recipe.json"), "utf-8");
10941
11490
  } catch (err) {
10942
11491
  debugLog("recipe.json not present; test generation falls back to scenarios.md alone", { err });
10943
11492
  return "";
@@ -10995,13 +11544,13 @@ var init_recipe_context = __esm({
10995
11544
  init_debug();
10996
11545
  STRUCTURAL_KEYS = /* @__PURE__ */ new Set(["_alias", "_ref"]);
10997
11546
  TEMPLATE_TOKEN = /\{\{\s*\w+\s*\}\}/;
10998
- recipeRowSchema = z52.record(z52.string(), z52.unknown());
10999
- recipeFileSchema = z52.object({
11000
- recipes: z52.array(
11001
- z52.object({
11002
- name: z52.string(),
11003
- description: z52.string().optional(),
11004
- 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()
11005
11554
  })
11006
11555
  )
11007
11556
  });
@@ -11009,7 +11558,7 @@ var init_recipe_context = __esm({
11009
11558
  });
11010
11559
 
11011
11560
  // src/agents/05-test-generator/restore-deleted-test.ts
11012
- import { access, mkdir as mkdir4, writeFile as writeFile12 } from "fs/promises";
11561
+ import { access, mkdir as mkdir4, writeFile as writeFile13 } from "fs/promises";
11013
11562
  import { dirname as dirname4 } from "path";
11014
11563
  async function restoreDeletedTest(testPath, originalContent) {
11015
11564
  try {
@@ -11020,7 +11569,7 @@ async function restoreDeletedTest(testPath, originalContent) {
11020
11569
  }
11021
11570
  try {
11022
11571
  await mkdir4(dirname4(testPath), { recursive: true });
11023
- await writeFile12(testPath, originalContent, "utf-8");
11572
+ await writeFile13(testPath, originalContent, "utf-8");
11024
11573
  return true;
11025
11574
  } catch (err) {
11026
11575
  console.warn(` [fix] Could not restore ${testPath}: ${err instanceof Error ? err.message : String(err)}`);
@@ -11087,21 +11636,21 @@ var init_pool = __esm({
11087
11636
  });
11088
11637
 
11089
11638
  // src/agents/05-test-generator/rubrics.ts
11090
- import { z as z53 } from "zod";
11639
+ import { z as z54 } from "zod";
11091
11640
  function reviewResultSchema(shape) {
11092
- return z53.object(shape);
11641
+ return z54.object(shape);
11093
11642
  }
11094
11643
  var dimensionResultSchema, reviewResultRecordSchema, structuralIntentRubric, flowCompletenessRubric, uiTextRubric, dataAccuracyRubric, ALL_RUBRICS;
11095
11644
  var init_rubrics = __esm({
11096
11645
  "src/agents/05-test-generator/rubrics.ts"() {
11097
11646
  "use strict";
11098
11647
  init_esm_shims();
11099
- dimensionResultSchema = z53.object({
11100
- pass: z53.boolean(),
11101
- evidence: z53.string().describe("What you checked and found - cite file paths, line content, or specific strings"),
11102
- 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")
11103
11652
  });
11104
- reviewResultRecordSchema = z53.record(z53.string(), dimensionResultSchema);
11653
+ reviewResultRecordSchema = z54.record(z54.string(), dimensionResultSchema);
11105
11654
  structuralIntentRubric = {
11106
11655
  name: "structural-intent",
11107
11656
  maxSteps: 8,
@@ -11347,12 +11896,12 @@ var init_review_pass = __esm({
11347
11896
  });
11348
11897
 
11349
11898
  // src/agents/05-test-generator/review.ts
11350
- import { readFile as readFile21 } from "fs/promises";
11351
- import { join as join33, relative as relative7, basename as basename6 } from "path";
11899
+ import { readFile as readFile22 } from "fs/promises";
11900
+ import { join as join34, relative as relative7, basename as basename6 } from "path";
11352
11901
  import "ai";
11353
11902
  import { glob as glob5 } from "glob";
11354
11903
  function markReview(relativePath, status) {
11355
- getActiveStore()?.setArtifactReview(join33(TESTS_DIR, relativePath), status);
11904
+ getActiveStore()?.setArtifactReview(join34(TESTS_DIR, relativePath), status);
11356
11905
  }
11357
11906
  function mergeRubricResults(reported) {
11358
11907
  const merged = {};
@@ -11407,24 +11956,24 @@ async function readDataContract(outputDir) {
11407
11956
  const recipe = await loadRecipeContext(outputDir);
11408
11957
  if (recipe !== "") return recipe;
11409
11958
  try {
11410
- return await readFile21(join33(outputDir, "scenarios.md"), "utf-8");
11959
+ return await readFile22(join34(outputDir, "scenarios.md"), "utf-8");
11411
11960
  } catch (err) {
11412
11961
  debugLog("No data contract available for review", { err });
11413
11962
  return void 0;
11414
11963
  }
11415
11964
  }
11416
11965
  async function runConsolidatedReview(outputDir, projectRoot, model, deadline, settled = /* @__PURE__ */ new Set(), precomputed = [], onProgress) {
11417
- const testsDir = join33(outputDir, TESTS_DIR);
11966
+ const testsDir = join34(outputDir, TESTS_DIR);
11418
11967
  const logger = createStepLogger("review", 5);
11419
11968
  const scenarioData = await readDataContract(outputDir);
11420
- const testFiles = await glob5(join33(testsDir, TEST_FILE_GLOB));
11969
+ const testFiles = await glob5(join34(testsDir, TEST_FILE_GLOB));
11421
11970
  const tests = [];
11422
11971
  for (const testPath of testFiles) {
11423
11972
  if (!isTestFile(testPath)) continue;
11424
11973
  if (testPath.includes("/_invalid/")) continue;
11425
11974
  const relativePath = relative7(testsDir, testPath);
11426
11975
  if (settled.has(relativePath)) continue;
11427
- const content = await readFile21(testPath, "utf-8");
11976
+ const content = await readFile22(testPath, "utf-8");
11428
11977
  const flowMatch = content.match(/^---\n[\s\S]*?flow:\s*["']?([^"'\n]+)["']?\s*\n[\s\S]*?---/m);
11429
11978
  tests.push({ path: testPath, relativePath, content, flow: flowMatch?.[1]?.trim() ?? "unknown" });
11430
11979
  }
@@ -11619,7 +12168,7 @@ var init_review_pipeline = __esm({
11619
12168
  });
11620
12169
 
11621
12170
  // src/agents/05-test-generator/validation.ts
11622
- import matter4 from "gray-matter";
12171
+ import matter4 from "@11ty/gray-matter";
11623
12172
  function isValidVerb(verb) {
11624
12173
  return VALID_VERBS.has(verb);
11625
12174
  }
@@ -11683,7 +12232,7 @@ var init_validation = __esm({
11683
12232
  });
11684
12233
 
11685
12234
  // src/agents/05-test-generator/test-spec.ts
11686
- import { z as z54 } from "zod";
12235
+ import { z as z55 } from "zod";
11687
12236
  function hasPlaceholder(text2) {
11688
12237
  if (text2 == null) return false;
11689
12238
  return PLACEHOLDER_PATTERNS.some(({ pattern }) => pattern.test(text2));
@@ -11734,12 +12283,12 @@ var init_test_spec = __esm({
11734
12283
  { pattern: /(?<!\{)\{[a-z][a-zA-Z]*\}(?!\})/, name: "bare {variable}" },
11735
12284
  { pattern: /\be\.g\./i, name: '"e.g." example' }
11736
12285
  ];
11737
- stepSchema = z54.object({
11738
- verb: z54.enum(STEP_VERBS).describe("The action. Only these verbs exist."),
11739
- 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(
11740
12289
  `What to do or check, naming the exact visible text. For assert, the thing expected on screen - e.g. 'text "Transfer Successful"'.`
11741
12290
  ),
11742
- location: z54.string().optional().describe(
12291
+ location: z55.string().optional().describe(
11743
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.'
11744
12293
  )
11745
12294
  }).refine((step) => !requiresLocation(step.verb) || (step.location?.trim() ?? "") !== "", {
@@ -11749,27 +12298,27 @@ var init_test_spec = __esm({
11749
12298
  message: "steps carry no variables - use the exact value from the test data, not a placeholder or example",
11750
12299
  path: ["description"]
11751
12300
  });
11752
- testSpecSchema = z54.object({
11753
- title: z54.string().min(1).describe("Short, descriptive test name."),
11754
- description: z54.string().min(1).describe("One sentence explaining what the test verifies."),
11755
- 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(
11756
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'."
11757
12306
  ),
11758
- criticality: z54.enum(CRITICALITY_LEVELS),
11759
- scenario: z54.string().min(1).describe('Which scenario this test uses (usually "standard").'),
11760
- flow: z54.string().min(1).describe("Which feature/flow this belongs to (must match a flow from AUTONOMA.md)."),
11761
- 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(
11762
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."
11763
12312
  ),
11764
- setup: z54.string().min(1).describe(
12313
+ setup: z55.string().min(1).describe(
11765
12314
  "Which page the user starts on and how they got there. Never authentication - the user is already signed in."
11766
12315
  ),
11767
- steps: z54.array(stepSchema).min(1).describe("The action sequence, in order."),
11768
- verificationSteps: z54.array(stepSchema).describe(
12316
+ steps: z55.array(stepSchema).min(1).describe("The action sequence, in order."),
12317
+ verificationSteps: z55.array(stepSchema).describe(
11769
12318
  "Steps that navigate to the source of truth and assert the mutation landed. Implements the `verification` field above."
11770
12319
  ),
11771
- expectedResult: z54.string().min(1).describe("What should be true when the test passes."),
11772
- 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(
11773
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."
11774
12323
  )
11775
12324
  }).refine((spec) => spec.steps.filter((step) => isInteractionVerb(step.verb)).length >= MIN_INTERACTIONS, {
@@ -11780,25 +12329,25 @@ var init_test_spec = __esm({
11780
12329
  });
11781
12330
 
11782
12331
  // src/agents/05-test-generator/tools.ts
11783
- import { mkdir as mkdir5, writeFile as writeFile13 } from "fs/promises";
11784
- 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";
11785
12334
  import { hasToolCall as hasToolCall3, stepCountIs as stepCountIs3, tool as tool16, ToolLoopAgent as ToolLoopAgent3 } from "ai";
11786
- import { z as z55 } from "zod";
12335
+ import { z as z56 } from "zod";
11787
12336
  function buildWriteTestTool(state, outputDir, onWritten) {
11788
12337
  return tool16({
11789
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.",
11790
- inputSchema: z55.object({
11791
- folder: z55.string().describe("Subfolder name under qa-tests/"),
11792
- filename: z55.string().describe(`File name ending in ${TEST_FILE_EXT} (e.g. login-valid-credentials${TEST_FILE_EXT})`),
11793
- 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(
11794
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."
11795
12344
  ),
11796
12345
  test: testSpecSchema
11797
12346
  }),
11798
12347
  execute: async (input) => {
11799
12348
  const content = renderTestMarkdown(input.test);
11800
- const relPath = join34(TESTS_DIR, input.folder, normalizeTestFilename(input.filename));
11801
- const absPath = join34(outputDir, relPath);
12349
+ const relPath = join35(TESTS_DIR, input.folder, normalizeTestFilename(input.filename));
12350
+ const absPath = join35(outputDir, relPath);
11802
12351
  const nodeId = state.resolveNodeId(input.nodeId, relPath);
11803
12352
  if (nodeId == null) {
11804
12353
  const stats = state.summary();
@@ -11817,7 +12366,7 @@ function buildWriteTestTool(state, outputDir, onWritten) {
11817
12366
  }
11818
12367
  try {
11819
12368
  await mkdir5(dirname5(absPath), { recursive: true });
11820
- await writeFile13(absPath, content, "utf-8");
12369
+ await writeFile14(absPath, content, "utf-8");
11821
12370
  state.markTested(nodeId, [relPath]);
11822
12371
  await saveBfsState(outputDir, state);
11823
12372
  const notes = input.test.notes?.trim();
@@ -11830,7 +12379,7 @@ function buildWriteTestTool(state, outputDir, onWritten) {
11830
12379
  });
11831
12380
  }
11832
12381
  onWritten?.({
11833
- relativePath: join34(input.folder, normalizeTestFilename(input.filename)),
12382
+ relativePath: join35(input.folder, normalizeTestFilename(input.filename)),
11834
12383
  content,
11835
12384
  flow: input.test.flow
11836
12385
  });
@@ -11868,14 +12417,14 @@ function buildWriteTestTool(state, outputDir, onWritten) {
11868
12417
  function buildCreateFolderTool(outputDir) {
11869
12418
  return tool16({
11870
12419
  description: "Create a folder under qa-tests/ for organizing tests.",
11871
- inputSchema: z55.object({
11872
- folder: z55.string().describe("Folder name (kebab-case)")
12420
+ inputSchema: z56.object({
12421
+ folder: z56.string().describe("Folder name (kebab-case)")
11873
12422
  }),
11874
12423
  execute: async (input) => {
11875
- const absPath = join34(outputDir, TESTS_DIR, input.folder);
12424
+ const absPath = join35(outputDir, TESTS_DIR, input.folder);
11876
12425
  try {
11877
12426
  await mkdir5(absPath, { recursive: true });
11878
- return { path: join34(TESTS_DIR, input.folder) };
12427
+ return { path: join35(TESTS_DIR, input.folder) };
11879
12428
  } catch (err) {
11880
12429
  const message = err instanceof Error ? err.message : String(err);
11881
12430
  return { error: `Failed to create folder: ${message}` };
@@ -11886,7 +12435,7 @@ function buildCreateFolderTool(outputDir) {
11886
12435
  function buildNextNodeTool(state, outputDir) {
11887
12436
  return tool16({
11888
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.",
11889
- inputSchema: z55.object({}),
12438
+ inputSchema: z56.object({}),
11890
12439
  execute: async () => {
11891
12440
  const next = state.nextNode();
11892
12441
  await saveBfsState(outputDir, state);
@@ -11920,7 +12469,7 @@ function buildNextNodeTool(state, outputDir) {
11920
12469
  function buildGetProgressTool(state) {
11921
12470
  return tool16({
11922
12471
  description: "Check how many nodes have been tested vs how many remain.",
11923
- inputSchema: z55.object({}),
12472
+ inputSchema: z56.object({}),
11924
12473
  execute: async () => {
11925
12474
  const stats = state.summary();
11926
12475
  const nodes = [...state.nodes.values()].map((n) => ({
@@ -11936,12 +12485,12 @@ function buildGetProgressTool(state) {
11936
12485
  function buildSpawnResearcherTool(model, workingDirectory, onHeartbeat) {
11937
12486
  return tool16({
11938
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.",
11939
- inputSchema: z55.object({
11940
- 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")
11941
12490
  }),
11942
12491
  execute: async (input) => {
11943
- const resultSchema2 = z55.object({
11944
- findings: z55.string().describe("Summary of what was found")
12492
+ const resultSchema2 = z56.object({
12493
+ findings: z56.string().describe("Summary of what was found")
11945
12494
  });
11946
12495
  let result;
11947
12496
  const subagent = new ToolLoopAgent3({
@@ -11994,11 +12543,11 @@ var init_tools2 = __esm({
11994
12543
  });
11995
12544
 
11996
12545
  // src/agents/05-test-generator/write-index.ts
11997
- import { readFile as readFile22, writeFile as writeFile14 } from "fs/promises";
11998
- import { join as join35 } from "path";
12546
+ import { readFile as readFile23, writeFile as writeFile15 } from "fs/promises";
12547
+ import { join as join36 } from "path";
11999
12548
  async function scanTest(outputDir, path3) {
12000
12549
  try {
12001
- const content = await readFile22(join35(outputDir, path3), "utf-8");
12550
+ const content = await readFile23(join36(outputDir, path3), "utf-8");
12002
12551
  return {
12003
12552
  criticality: content.match(/criticality:\s*(\w+)/)?.[1] ?? "",
12004
12553
  steps: content.match(STEP_VERBS2)?.length ?? 0,
@@ -12069,7 +12618,7 @@ ${folders.map((f) => `| ${f.name} | ${f.test_count} |`).join("\n")}
12069
12618
 
12070
12619
  ${[...testsByFolder.entries()].flatMap(([_folder, tests]) => tests.map((t) => `- \`${t}\``)).join("\n")}
12071
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)}`;
12072
- 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");
12073
12622
  }
12074
12623
  function untestedFeatures(state) {
12075
12624
  const withTests = new Set(state.testsWritten.keys());
@@ -12104,11 +12653,11 @@ __export(test_generator_exports, {
12104
12653
  runTestGenerator: () => runTestGenerator
12105
12654
  });
12106
12655
  import { existsSync as existsSync2 } from "fs";
12107
- import { mkdir as mkdir6, readFile as readFile23, rmdir, unlink, writeFile as writeFile15 } from "fs/promises";
12108
- import { basename as basename7, 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";
12109
12658
  import { tool as tool17 } from "ai";
12110
12659
  import { glob as glob6 } from "glob";
12111
- import { z as z56 } from "zod";
12660
+ import { z as z57 } from "zod";
12112
12661
  async function preseedQueue(state, projectRoot, pages, features) {
12113
12662
  let seeded = 0;
12114
12663
  const pageIdByPath = /* @__PURE__ */ new Map();
@@ -12160,8 +12709,8 @@ async function runTestGenerator(input) {
12160
12709
  let result;
12161
12710
  const finishTool = tool17({
12162
12711
  description: "Call when the BFS queue is empty and all routes have been explored.",
12163
- inputSchema: z56.object({
12164
- summary: z56.string().describe("Coverage summary")
12712
+ inputSchema: z57.object({
12713
+ summary: z57.string().describe("Coverage summary")
12165
12714
  }),
12166
12715
  execute: async (finishInput) => {
12167
12716
  const stats = state.summary();
@@ -12189,7 +12738,7 @@ async function runTestGenerator(input) {
12189
12738
  });
12190
12739
  let kbContext = "";
12191
12740
  try {
12192
- const autonomaMd = await readFile23(join36(input.outputDir, "AUTONOMA.md"), "utf-8");
12741
+ const autonomaMd = await readFile24(join37(input.outputDir, "AUTONOMA.md"), "utf-8");
12193
12742
  kbContext += `
12194
12743
  ## Knowledge Base (AUTONOMA.md)
12195
12744
 
@@ -12202,7 +12751,7 @@ ${autonomaMd}
12202
12751
  kbContext += recipeContext;
12203
12752
  } else {
12204
12753
  try {
12205
- const scenariosMd = await readFile23(join36(input.outputDir, "scenarios.md"), "utf-8");
12754
+ const scenariosMd = await readFile24(join37(input.outputDir, "scenarios.md"), "utf-8");
12206
12755
  kbContext += `
12207
12756
  ## Scenarios
12208
12757
 
@@ -12500,20 +13049,20 @@ IMPORTANT: Do NOT try to finish early. Process every node via next_node until it
12500
13049
  }
12501
13050
  state.clearReviewProgress();
12502
13051
  state.setPhase("checking every test");
12503
- 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));
12504
13053
  let markedInvalid = 0;
12505
13054
  for (const testPath of allTestFiles) {
12506
13055
  if (!isTestFile(testPath)) continue;
12507
13056
  if (testPath.includes(`/${INVALID_DIR}/`)) continue;
12508
- const content = await readFile23(testPath, "utf-8");
13057
+ const content = await readFile24(testPath, "utf-8");
12509
13058
  const validation = validateTestContent(content);
12510
13059
  if (!validation.valid) {
12511
- const invalidDir = join36(input.outputDir, TESTS_DIR, INVALID_DIR);
13060
+ const invalidDir = join37(input.outputDir, TESTS_DIR, INVALID_DIR);
12512
13061
  await mkdir6(invalidDir, { recursive: true });
12513
- const dest = join36(invalidDir, basename7(testPath));
13062
+ const dest = join37(invalidDir, basename7(testPath));
12514
13063
  const annotated = `<!-- VALIDATION ERRORS: ${validation.errors.join("; ")} -->
12515
13064
  ${content}`;
12516
- await writeFile15(dest, annotated, "utf-8");
13065
+ await writeFile16(dest, annotated, "utf-8");
12517
13066
  await unlink(testPath);
12518
13067
  markedInvalid++;
12519
13068
  }
@@ -12521,7 +13070,7 @@ ${content}`;
12521
13070
  if (markedInvalid > 0) {
12522
13071
  console.log(` ${markedInvalid} tests still invalid after review cycles - moved to _invalid/`);
12523
13072
  }
12524
- const dirs = await glob6(join36(input.outputDir, TESTS_DIR, "**/"), {
13073
+ const dirs = await glob6(join37(input.outputDir, TESTS_DIR, "**/"), {
12525
13074
  dot: false
12526
13075
  });
12527
13076
  for (const dir of dirs.sort((a, b) => b.length - a.length)) {
@@ -12574,21 +13123,21 @@ async function generateJourneyTests(outputDir, model, projectRoot) {
12574
13123
  let autonomaMd = "";
12575
13124
  let scenariosMd = "";
12576
13125
  try {
12577
- autonomaMd = await readFile23(join36(outputDir, "AUTONOMA.md"), "utf-8");
13126
+ autonomaMd = await readFile24(join37(outputDir, "AUTONOMA.md"), "utf-8");
12578
13127
  } catch (err) {
12579
13128
  debugLog("AUTONOMA.md not present for journey generation", { err });
12580
13129
  }
12581
13130
  try {
12582
- scenariosMd = await readFile23(join36(outputDir, "scenarios.md"), "utf-8");
13131
+ scenariosMd = await readFile24(join37(outputDir, "scenarios.md"), "utf-8");
12583
13132
  } catch (err) {
12584
13133
  debugLog("scenarios.md not present for journey generation", { err });
12585
13134
  }
12586
13135
  if (!autonomaMd) return 0;
12587
- const existingTests = await glob6(join36(outputDir, TESTS_DIR, TEST_FILE_GLOB));
13136
+ const existingTests = await glob6(join37(outputDir, TESTS_DIR, TEST_FILE_GLOB));
12588
13137
  const existingTitles = [];
12589
13138
  for (const t of existingTests) {
12590
13139
  if (!isTestFile(t)) continue;
12591
- const content = await readFile23(t, "utf-8");
13140
+ const content = await readFile24(t, "utf-8");
12592
13141
  const titleMatch = content.match(/title:\s*"([^"]+)"/);
12593
13142
  if (titleMatch) existingTitles.push(titleMatch[1]);
12594
13143
  }
@@ -12634,7 +13183,7 @@ Write 5-8 journey tests using the write_test tool with folder "${JOURNEY_NODE_ID
12634
13183
  let journeyResult;
12635
13184
  const journeyFinish = tool17({
12636
13185
  description: "Signal journey generation is complete.",
12637
- inputSchema: z56.object({ summary: z56.string() }),
13186
+ inputSchema: z57.object({ summary: z57.string() }),
12638
13187
  execute: async (finishInput) => {
12639
13188
  journeyResult = {
12640
13189
  success: true,
@@ -14481,14 +15030,14 @@ var init_session_recorder = __esm({
14481
15030
  });
14482
15031
 
14483
15032
  // src/ui/artifacts/reader.ts
14484
- import { open, readFile as readFile24, stat as stat2 } from "fs/promises";
15033
+ import { open, readFile as readFile25, stat as stat2 } from "fs/promises";
14485
15034
  async function readForLive(absPath) {
14486
15035
  try {
14487
15036
  const info = await stat2(absPath);
14488
15037
  if (!info.isFile()) return void 0;
14489
15038
  const kind = kindOf(absPath);
14490
15039
  if (info.size <= LARGE_BYTES) {
14491
- const text2 = await readFile24(absPath, "utf-8");
15040
+ const text2 = await readFile25(absPath, "utf-8");
14492
15041
  return { text: text2, kind, truncated: false };
14493
15042
  }
14494
15043
  const fh = await open(absPath, "r");
@@ -14782,9 +15331,9 @@ ensureSupportedNode();
14782
15331
 
14783
15332
  // src/index.ts
14784
15333
  init_submit();
14785
- import { readFile as readFile25, writeFile as writeFile16 } from "fs/promises";
15334
+ import { readFile as readFile26, writeFile as writeFile17 } from "fs/promises";
14786
15335
  import { freemem } from "os";
14787
- import { delimiter, join as join37 } from "path";
15336
+ import { delimiter, join as join38 } from "path";
14788
15337
 
14789
15338
  // src/agents/04-recipe-builder/sdk-command.ts
14790
15339
  init_esm_shims();
@@ -14973,7 +15522,7 @@ function shortHash(seed) {
14973
15522
  }
14974
15523
 
14975
15524
  // src/agents/04-recipe-builder/sdk-command.ts
14976
- import { z as z33 } from "zod";
15525
+ import { z as z34 } from "zod";
14977
15526
 
14978
15527
  // src/core/cli-args.ts
14979
15528
  init_esm_shims();
@@ -15132,16 +15681,16 @@ async function down(config, refsToken) {
15132
15681
  init_recipe();
15133
15682
  var DEFAULT_REQUEST_TIMEOUT_MS = 12e4;
15134
15683
  var MIN_REPEAT_INSTANCES = 2;
15135
- var createSchema = z33.record(z33.string(), z33.array(z33.unknown()));
15136
- var recipeSliceSchema = z33.object({ create: createSchema, variables: ScenarioRecipeVariablesSchema.optional() });
15137
- var envelopeSchema = z33.object({ recipes: z33.array(recipeSliceSchema).min(1) });
15138
- var flagsSchema = z33.object({
15139
- url: z33.string().min(1).optional(),
15140
- recipe: z33.string().min(1).optional(),
15141
- "refs-token": z33.string().min(1).optional(),
15142
- "test-run-id": z33.string().min(1).optional(),
15143
- timeout: z33.coerce.number().int().positive().optional(),
15144
- 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()
15145
15694
  });
15146
15695
  var SDK_FLAGS = new Set(Object.keys(flagsSchema.shape));
15147
15696
  async function runSdkCommand(argv, io) {
@@ -15911,8 +16460,8 @@ init_prompts();
15911
16460
  // src/core/git.ts
15912
16461
  init_esm_shims();
15913
16462
  import { execFile } from "child_process";
15914
- import { readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
15915
- import { join as join13 } from "path";
16463
+ import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
16464
+ import { join as join14 } from "path";
15916
16465
  import { promisify } from "util";
15917
16466
  var execFileAsync = promisify(execFile);
15918
16467
  var GIT_INFO_FILE = ".git-info.json";
@@ -15936,11 +16485,11 @@ async function readGitInfo(projectRoot) {
15936
16485
  };
15937
16486
  }
15938
16487
  async function saveGitInfo(outputDir, info) {
15939
- 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");
15940
16489
  }
15941
16490
  async function loadGitInfo(outputDir) {
15942
16491
  try {
15943
- const raw = await readFile5(join13(outputDir, GIT_INFO_FILE), "utf-8");
16492
+ const raw = await readFile6(join14(outputDir, GIT_INFO_FILE), "utf-8");
15944
16493
  const parsed = JSON.parse(raw);
15945
16494
  if (typeof parsed === "object" && parsed != null && "sha" in parsed && typeof parsed.sha === "string") {
15946
16495
  const branch = "branch" in parsed && typeof parsed.branch === "string" ? parsed.branch : void 0;
@@ -15962,15 +16511,15 @@ init_state();
15962
16511
  init_esm_shims();
15963
16512
  init_prompts();
15964
16513
  init_debug();
15965
- import { readFile as readFile7 } from "fs/promises";
15966
- import { join as join15 } from "path";
16514
+ import { readFile as readFile8 } from "fs/promises";
16515
+ import { join as join16 } from "path";
15967
16516
  init_test_files();
15968
16517
  var ARTIFACT_FILES = ["AUTONOMA.md", "scenarios.md", "entity-audit.md"];
15969
16518
  async function readArtifacts(outputDir) {
15970
16519
  const files = await Promise.all(
15971
16520
  ARTIFACT_FILES.map(async (name) => {
15972
16521
  try {
15973
- return { name, content: await readFile7(join15(outputDir, name), "utf-8") };
16522
+ return { name, content: await readFile8(join16(outputDir, name), "utf-8") };
15974
16523
  } catch (err) {
15975
16524
  debugLog(`Artifact ${name} not on disk; skipping upload`, { err });
15976
16525
  return void 0;
@@ -15986,7 +16535,7 @@ async function readTestCases(outputDir) {
15986
16535
  const segments = testPath.split("/").slice(1);
15987
16536
  const name = segments[segments.length - 1];
15988
16537
  const folder = segments.slice(0, -1).join("/");
15989
- const content = await readFile7(join15(outputDir, testPath), "utf-8");
16538
+ const content = await readFile8(join16(outputDir, testPath), "utf-8");
15990
16539
  return { name, content, folder: folder.length > 0 ? folder : void 0 };
15991
16540
  })
15992
16541
  );
@@ -16051,11 +16600,11 @@ process.setSourceMapsEnabled(true);
16051
16600
  var PAGES_FILE = "pages.json";
16052
16601
  async function savePages(outputDir, pages) {
16053
16602
  const obj = Object.fromEntries(pages);
16054
- 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");
16055
16604
  }
16056
16605
  async function loadPages(outputDir) {
16057
16606
  try {
16058
- const raw = await readFile25(join37(outputDir, PAGES_FILE), "utf-8");
16607
+ const raw = await readFile26(join38(outputDir, PAGES_FILE), "utf-8");
16059
16608
  const obj = JSON.parse(raw);
16060
16609
  return new Map(Object.entries(obj));
16061
16610
  } catch {
@@ -16424,6 +16973,23 @@ function ensureAutonomaAuth() {
16424
16973
  );
16425
16974
  return false;
16426
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
+ }
16427
16993
  async function finishFrontDoorRun(frontDoor, config, nonInteractive) {
16428
16994
  try {
16429
16995
  const gitInfo = await readGitInfo(config.projectRoot);
@@ -16582,11 +17148,7 @@ async function main() {
16582
17148
  });
16583
17149
  }
16584
17150
  if (frontDoor != null && previewPending) {
16585
- const { runPreviewHandoff: runPreviewHandoff2, describeIncompletePreview: describeIncompletePreview2 } = await Promise.resolve().then(() => (init_front_door(), front_door_exports));
16586
- const result = await runPreviewHandoff2({ plan: frontDoor, config, nonInteractive });
16587
- track("cli_preview_phase_finished", { outcome: result.kind });
16588
- const problem = describeIncompletePreview2(result);
16589
- if (problem != null) log.warn(problem);
17151
+ await runPreviewHandoffStep(frontDoor, config, nonInteractive);
16590
17152
  }
16591
17153
  if (args.has("fresh") && hasProgress) {
16592
17154
  await clearOutputDir(config.projectSlug);