@runa-ai/runa-cli 0.5.51 → 0.5.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/commands/db/apply/helpers/pg-schema-diff-helpers.d.ts +14 -0
  2. package/dist/commands/db/apply/helpers/pg-schema-diff-helpers.d.ts.map +1 -1
  3. package/dist/commands/db/apply/helpers/retry-logic.d.ts.map +1 -1
  4. package/dist/commands/db/constants.d.ts +3 -3
  5. package/dist/commands/db/constants.d.ts.map +1 -1
  6. package/dist/commands/db/utils/db-target.d.ts.map +1 -1
  7. package/dist/commands/db/utils/preflight-check.d.ts.map +1 -1
  8. package/dist/commands/env/commands/env-pull.d.ts.map +1 -1
  9. package/dist/commands/env/constants/local-supabase.d.ts +30 -62
  10. package/dist/commands/env/constants/local-supabase.d.ts.map +1 -1
  11. package/dist/commands/inject-test-attrs/action.d.ts.map +1 -1
  12. package/dist/commands/inject-test-attrs/commands/inject-test-attrs.d.ts.map +1 -1
  13. package/dist/commands/inject-test-attrs/contract.d.ts +118 -0
  14. package/dist/commands/inject-test-attrs/contract.d.ts.map +1 -1
  15. package/dist/commands/inject-test-attrs/detection-diagnostics.d.ts +67 -0
  16. package/dist/commands/inject-test-attrs/detection-diagnostics.d.ts.map +1 -0
  17. package/dist/commands/inject-test-attrs/manifest-generator.d.ts +7 -1
  18. package/dist/commands/inject-test-attrs/manifest-generator.d.ts.map +1 -1
  19. package/dist/commands/inject-test-attrs/processor-utils.d.ts.map +1 -1
  20. package/dist/commands/inject-test-attrs/processor.d.ts.map +1 -1
  21. package/dist/commands/inject-test-attrs/types.d.ts +57 -0
  22. package/dist/commands/inject-test-attrs/types.d.ts.map +1 -1
  23. package/dist/commands/manifest/index.d.ts.map +1 -1
  24. package/dist/commands/test/commands/test-e2e.d.ts.map +1 -1
  25. package/dist/commands/test/commands/test-integration.d.ts.map +1 -1
  26. package/dist/commands/test/commands/test-layer.d.ts.map +1 -1
  27. package/dist/commands/test/commands/test.d.ts.map +1 -1
  28. package/dist/index.js +1162 -559
  29. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module';
3
- import * as path10 from 'path';
4
- import path10__default, { join, dirname, resolve, relative, basename, sep, isAbsolute, normalize } from 'path';
3
+ import * as path11 from 'path';
4
+ import path11__default, { join, dirname, resolve, relative, basename, sep, isAbsolute, normalize } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
- import { execSync, spawnSync, execFileSync, exec, spawn } from 'child_process';
7
6
  import * as fs5 from 'fs';
8
7
  import fs5__default, { existsSync, readFileSync, readdirSync, mkdtempSync, writeFileSync, mkdirSync, copyFileSync, createWriteStream, statSync, rmSync, realpathSync, renameSync, promises, lstatSync, accessSync, constants, chmodSync, unlinkSync } from 'fs';
8
+ import { execSync, spawnSync, execFileSync, exec, spawn } from 'child_process';
9
9
  import { createCLILogger, cacheClear, CacheClearOutputSchema, CLIError, cachePrune, CachePruneOutputSchema, cacheStats, CacheStatsOutputSchema, cacheList, CacheListOutputSchema, cacheInvalidate, CacheInvalidateOutputSchema, syncFromProduction, dbGenerateDiagram, DbDiagramGenerateOutputSchema, createDbSnapshot, syncDatabase, emitDbPushFailureCapsule, emitDbAnnotations, writeDbPushStepSummary, exportDbReportJson, DbSyncOutputSchema, databasePaths, detectRequiredServices, formatDetectionResults, dbStart, DbLifecycleStartOutputSchema, dbStop, DbLifecycleStopOutputSchema, dbReset, DbLifecycleResetOutputSchema, dbValidateSchemas, DbSchemaValidateOutputSchema, DbSchemaRisksOutputSchema, dbDetectSchemaRisks, dbApplySchemas, DbSchemaApplyOutputSchema, dbGenerateTypes, DbSchemaGenerateOutputSchema, extractSchemaFilter, dbSeedInit, DbSeedInitOutputSchema, dbSeedValidate, DbSeedValidateOutputSchema, dbSeedGenerate, DbSeedGenerateOutputSchema, dbVerifySeeds, DbSeedVerifyOutputSchema, DbSnapshotCreateOutputSchema, restoreDbSnapshot, DbSnapshotRestoreOutputSchema, listDbSnapshots, DbSnapshotListOutputSchema, dbGeneratePgTapTests, DbTestGenOutputSchema, dbUpdateGoldenRecord, DbTestUpdateGoldenOutputSchema, repairRunaConfig, detectExistingInitConfig, initProject, validateInitResult, linkCliGlobally, LinkCliOutputSchema, unlinkCliGlobally, UnlinkCliOutputSchema, checkRepoStatus, CheckRepoStatusOutputSchema, enableTelemetry, disableTelemetry, getTelemetryStatus, uploadTelemetry, TelemetryUploadOutputSchema, runTest, TestRunOutputSchema, runTestService, TestServiceOutputSchema, runTestIntegration, TestIntegrationOutputSchema, runTestStatic, TestStaticOutputSchema, generateOwaspTop10Tests, TestOwaspGenerateOutputSchema, updateGoldenRecord, generateE2ETests, generateSecurityTests, generateUnitTests, generateApiTests, generateComponentTests, generateE2EScaffold, validateConfig, ValidateConfigOutputSchema, deploySchemaToProduction, WorkflowNotifyOutputSchema, devopsSync, workflowSync, validateInfrastructure, emitWorkflowValidateFailureCapsule, emitWorkflowAnnotations, writeWorkflowValidateStepSummary, exportWorkflowReportJson, WorkflowValidateInfrastructureOutputSchema, createSuccessEnvelopeSchema, CLI_CONTRACT_VERSION, runChecks, RunCheckOutputSchema, formatDuration as formatDuration$1, GITHUB_API, loadRunaConfig, getClassificationForProfile, loadRunaConfigOrThrow, recordSchemaAudit, RecordSchemaAuditOutputSchema, createBackup, CreateBackupOutputSchema, listBackups, ListBackupsOutputSchema, getBackupMetadata, restoreBackup, RestoreBackupOutputSchema, deleteBackup, DeleteBackupOutputSchema, detectSchemaNames, SUPABASE_SYSTEM_SCHEMAS, dbSeedApply, writeDbSeedStepSummary, DbSeedApplyOutputSchema, emitDbSeedFailureCapsule, syncEnvironment, EnvSyncOutputSchema, detectDatabasePackage, findProjectRoot as findProjectRoot$1, TelemetryEnableOutputSchema, TelemetryDisableOutputSchema, TelemetryStatusOutputSchema, workflowNotify, DevOpsSyncOutputSchema, WorkflowSyncOutputSchema, formatCLIError, getStatusIcon as getStatusIcon$1, findWorkspaceRoot as findWorkspaceRoot$1, checkExtensionConfig, UpgradeTransaction, readRunaVersion, syncTemplates, SyncOutputSchema, DATABASE_PACKAGE_CANDIDATES, ErrorEnvelopeSchema, preCheckSync, findConflictFiles, TestUnitGenOutputSchema, TestE2EGenerateOutputSchema, TestSecurityGenOutputSchema, TestApiGenOutputSchema, TestComponentGenOutputSchema } from '@runa-ai/runa';
10
10
  import { z } from 'zod';
11
11
  import fs9, { mkdir, writeFile, appendFile, readFile, rm, stat, realpath, cp, readdir, lstat } from 'fs/promises';
@@ -33,7 +33,7 @@ import { createJiti } from 'jiti';
33
33
  import ora from 'ora';
34
34
  import { stdout, stdin } from 'process';
35
35
  import * as readline from 'readline/promises';
36
- import { clearInjectionRegistry, clearUnifiedRegistry, postProcessRegistries, isPageFile, collectPageInfo, isLayoutFile, collectLayoutInfo, isApiRouteFile, collectApiRouteInfo, isMiddlewareFile, collectAuthBoundaries, hasMachineDefinition, collectMachineDefinition, getInjectionRegistry, buildManifest, getAllMachineDefinitions, generateSelectorTypeScript, getUnifiedRegistry, buildMachineLinks, createReadAndParseFile, createResolveImportPath, transformSync, registerInjection } from '@runa-ai/runa-xstate-test-plugin/standalone';
36
+ import { clearInjectionRegistry, clearUnifiedRegistry, postProcessRegistries, isPageFile, collectPageInfo, isLayoutFile, collectLayoutInfo, isApiRouteFile, collectApiRouteInfo, isMiddlewareFile, collectAuthBoundaries, hasMachineDefinition, collectMachineDefinition, createReadAndParseFile, createResolveImportPath, transformSync, getInjectionRegistry, buildManifest, getAllMachineDefinitions, generateSelectorTypeScript, getUnifiedRegistry, buildMachineLinks, registerInjection } from '@runa-ai/runa-xstate-test-plugin/standalone';
37
37
  import { listSessions, formatDuration as formatDuration$2, cleanupStaleSessions, removeSession, isSessionCheckDisabled, getCurrentSessionId, checkActiveSessions, createSession, addActivity, checkConflicts, formatConflictDetails } from '@runa-ai/runa/session';
38
38
  import { render, Box, Text } from 'ink';
39
39
  import Spinner from 'ink-spinner';
@@ -73,10 +73,230 @@ var getFilename, getDirname, __dirname$1;
73
73
  var init_esm_shims = __esm({
74
74
  "../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/esm_shims.js"() {
75
75
  getFilename = () => fileURLToPath(import.meta.url);
76
- getDirname = () => path10__default.dirname(getFilename());
76
+ getDirname = () => path11__default.dirname(getFilename());
77
77
  __dirname$1 = /* @__PURE__ */ getDirname();
78
78
  }
79
79
  });
80
+ function isValidPort(value) {
81
+ if (typeof value !== "number") {
82
+ return false;
83
+ }
84
+ return Number.isInteger(value) && value > 0 && value < 65536;
85
+ }
86
+ function asPort(value, fallback) {
87
+ const parsed = typeof value === "number" ? value : typeof value === "string" ? Number.parseInt(value, 10) : NaN;
88
+ return isValidPort(parsed) ? parsed : fallback;
89
+ }
90
+ function asHost(value) {
91
+ if (!value) return null;
92
+ const trimmed = value.trim();
93
+ return trimmed.length > 0 ? trimmed : null;
94
+ }
95
+ function getStatusValue(status, keys) {
96
+ for (const key of keys) {
97
+ const value = status[key];
98
+ if (typeof value === "string" && value.trim()) {
99
+ return value.trim();
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+ function extractHost(rawUrl) {
105
+ if (!rawUrl) return null;
106
+ try {
107
+ return new URL(rawUrl).hostname;
108
+ } catch {
109
+ return null;
110
+ }
111
+ }
112
+ function extractPort(rawUrl) {
113
+ if (!rawUrl) return null;
114
+ try {
115
+ const port = new URL(rawUrl).port;
116
+ if (!port) return null;
117
+ const parsed = Number.parseInt(port, 10);
118
+ return isValidPort(parsed) ? parsed : null;
119
+ } catch {
120
+ const match = rawUrl.match(/:(\d+)\//);
121
+ if (!match) return null;
122
+ const parsed = Number.parseInt(match[1], 10);
123
+ return isValidPort(parsed) ? parsed : null;
124
+ }
125
+ }
126
+ function parseTomlPort(content, section, key) {
127
+ const sectionRegex = new RegExp(`\\[${section}\\]([\\s\\S]*?)(?=\\n\\[|$)`, "m");
128
+ const sectionMatch = sectionRegex.exec(content);
129
+ if (!sectionMatch) return null;
130
+ const sectionContent = sectionMatch[1];
131
+ const keyRegex = new RegExp(`^\\s*${key}\\s*=\\s*(\\d+)`, "m");
132
+ const keyMatch = keyRegex.exec(sectionContent);
133
+ if (!keyMatch) return null;
134
+ const parsed = Number.parseInt(keyMatch[1], 10);
135
+ return isValidPort(parsed) ? parsed : null;
136
+ }
137
+ function parseTomlPorts(configRoot) {
138
+ const configPath = path11__default.join(configRoot, "supabase", "config.toml");
139
+ if (!existsSync(configPath)) return null;
140
+ try {
141
+ const content = readFileSync(configPath, "utf-8");
142
+ return {
143
+ api: parseTomlPort(content, "api", "port"),
144
+ db: parseTomlPort(content, "db", "port")
145
+ };
146
+ } catch {
147
+ return null;
148
+ }
149
+ }
150
+ function detectStatus(projectRoot) {
151
+ try {
152
+ const result = spawnSync("supabase", ["status", "--output", "json"], {
153
+ cwd: projectRoot,
154
+ encoding: "utf-8",
155
+ stdio: ["pipe", "pipe", "pipe"],
156
+ timeout: 5e3
157
+ });
158
+ if (result.status !== 0 || !result.stdout) return null;
159
+ const jsonMatch = result.stdout.match(/\{[\s\S]*\}/);
160
+ if (!jsonMatch) return null;
161
+ return JSON.parse(jsonMatch[0]);
162
+ } catch {
163
+ return null;
164
+ }
165
+ }
166
+ function resolveSupabaseRoot(projectRoot) {
167
+ const start = path11__default.resolve(projectRoot);
168
+ let current = start;
169
+ while (true) {
170
+ if (existsSync(path11__default.join(current, "supabase", "config.toml"))) {
171
+ return current;
172
+ }
173
+ const parent = path11__default.dirname(current);
174
+ if (parent === current) {
175
+ return start;
176
+ }
177
+ current = parent;
178
+ }
179
+ }
180
+ function isAllowedLocalhostHost(host) {
181
+ return host === "127.0.0.1" || host === "localhost" || host === "host.docker.internal";
182
+ }
183
+ function readSupabaseOverrides() {
184
+ return {
185
+ host: asHost(process.env.LOCAL_SUPABASE_HOST),
186
+ api: asPort(process.env.LOCAL_SUPABASE_API_PORT, DEFAULT_API_PORT),
187
+ db: asPort(process.env.LOCAL_SUPABASE_DB_PORT, DEFAULT_DB_PORT),
188
+ studio: asPort(process.env.LOCAL_SUPABASE_STUDIO_PORT, DEFAULT_STUDIO_PORT)
189
+ };
190
+ }
191
+ function detectLocalSupabasePorts(projectRoot = process.cwd()) {
192
+ const resolvedRoot = resolveSupabaseRoot(projectRoot);
193
+ const overrides = readSupabaseOverrides();
194
+ const status = detectStatus(resolvedRoot);
195
+ const tomlPorts = parseTomlPorts(resolvedRoot);
196
+ const statusApiUrl = status ? getStatusValue(status, ["API_URL", "API URL", "api_url"]) : null;
197
+ const statusDbUrl = status ? getStatusValue(status, ["DB_URL", "DB URL", "db_url"]) : null;
198
+ const statusStudioUrl = status ? getStatusValue(status, ["STUDIO_URL", "Studio URL", "studio_url"]) : null;
199
+ const detectedHost = asHost(
200
+ overrides.host ?? extractHost(statusApiUrl) ?? extractHost(statusDbUrl) ?? extractHost(statusStudioUrl)
201
+ );
202
+ const detectedApiPort = asPort(
203
+ overrides.api !== DEFAULT_API_PORT ? overrides.api : void 0,
204
+ extractPort(statusApiUrl) ?? tomlPorts?.api ?? DEFAULT_API_PORT
205
+ );
206
+ const detectedDbPort = asPort(
207
+ overrides.db !== DEFAULT_DB_PORT ? overrides.db : void 0,
208
+ extractPort(statusDbUrl) ?? tomlPorts?.db ?? DEFAULT_DB_PORT
209
+ );
210
+ const detectedStudioPort = asPort(
211
+ overrides.studio !== DEFAULT_STUDIO_PORT ? overrides.studio : void 0,
212
+ extractPort(statusStudioUrl) ?? detectedApiPort + 2
213
+ );
214
+ return {
215
+ host: detectedHost ?? DEFAULT_HOST,
216
+ api: detectedApiPort,
217
+ db: detectedDbPort,
218
+ studio: detectedStudioPort
219
+ };
220
+ }
221
+ function buildLocalSupabaseUrl(projectRoot = process.cwd()) {
222
+ const config = detectLocalSupabasePorts(projectRoot);
223
+ return `http://${config.host}:${config.api}`;
224
+ }
225
+ function buildLocalDatabaseUrl(projectRoot = process.cwd()) {
226
+ const config = detectLocalSupabasePorts(projectRoot);
227
+ return `postgresql://postgres:postgres@${config.host}:${config.db}/postgres`;
228
+ }
229
+ function getLocalSupabaseEnvValues(projectRoot = process.cwd()) {
230
+ const config = detectLocalSupabasePorts(projectRoot);
231
+ const supabaseUrl = buildLocalSupabaseUrl(projectRoot);
232
+ const databaseUrl = buildLocalDatabaseUrl(projectRoot);
233
+ return {
234
+ LOCAL_SUPABASE_HOST: config.host,
235
+ LOCAL_SUPABASE_API_PORT: String(config.api),
236
+ LOCAL_SUPABASE_DB_PORT: String(config.db),
237
+ DATABASE_URL: databaseUrl,
238
+ DATABASE_URL_ADMIN: databaseUrl,
239
+ DATABASE_URL_SERVICE: databaseUrl,
240
+ NEXT_PUBLIC_SUPABASE_URL: supabaseUrl,
241
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: LOCAL_SUPABASE_ANON_KEY,
242
+ SUPABASE_SERVICE_ROLE_KEY: LOCAL_SUPABASE_SERVICE_ROLE_KEY
243
+ };
244
+ }
245
+ function getLocalValueDescriptions(projectRoot = process.cwd()) {
246
+ const config = detectLocalSupabasePorts(projectRoot);
247
+ return {
248
+ LOCAL_SUPABASE_HOST: `supabase local host ${config.host}`,
249
+ LOCAL_SUPABASE_API_PORT: `supabase local api port ${config.api}`,
250
+ LOCAL_SUPABASE_DB_PORT: `supabase local db port ${config.db}`,
251
+ DATABASE_URL: `supabase local DB ${config.host}:${config.db}`,
252
+ DATABASE_URL_ADMIN: `supabase local DB ${config.host}:${config.db}`,
253
+ DATABASE_URL_SERVICE: `supabase local DB ${config.host}:${config.db}`,
254
+ NEXT_PUBLIC_SUPABASE_URL: `supabase local API ${config.host}:${config.api}`,
255
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: "local anon key (supabase-demo)",
256
+ SUPABASE_SERVICE_ROLE_KEY: "local service key (supabase-demo)"
257
+ };
258
+ }
259
+ function validateLocalhostValues(envValues) {
260
+ const urlKeys = [
261
+ "DATABASE_URL",
262
+ "DATABASE_URL_ADMIN",
263
+ "DATABASE_URL_SERVICE",
264
+ "NEXT_PUBLIC_SUPABASE_URL"
265
+ ];
266
+ const invalidEntries = [];
267
+ for (const key of urlKeys) {
268
+ const value = envValues[key];
269
+ if (!value) continue;
270
+ try {
271
+ const hostname = new URL(value).hostname;
272
+ if (!isAllowedLocalhostHost(hostname)) {
273
+ invalidEntries.push(key);
274
+ }
275
+ } catch {
276
+ invalidEntries.push(key);
277
+ }
278
+ }
279
+ if (invalidEntries.length > 0) {
280
+ throw new Error(
281
+ `Local Supabase replacement aborted: not a local endpoint. The following keys are not local: ${invalidEntries.join(", ")}`
282
+ );
283
+ }
284
+ }
285
+ var DEFAULT_HOST, DEFAULT_API_PORT, DEFAULT_DB_PORT, DEFAULT_STUDIO_PORT, LOCAL_SUPABASE_ANON_KEY, LOCAL_SUPABASE_SERVICE_ROLE_KEY, LOCAL_SUPABASE_ENV_VALUES;
286
+ var init_local_supabase = __esm({
287
+ "src/commands/env/constants/local-supabase.ts"() {
288
+ init_esm_shims();
289
+ DEFAULT_HOST = "127.0.0.1";
290
+ DEFAULT_API_PORT = 54321;
291
+ DEFAULT_DB_PORT = 54322;
292
+ DEFAULT_STUDIO_PORT = 54323;
293
+ LOCAL_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
294
+ LOCAL_SUPABASE_SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU";
295
+ LOCAL_SUPABASE_ENV_VALUES = getLocalSupabaseEnvValues();
296
+ getLocalValueDescriptions();
297
+ validateLocalhostValues(LOCAL_SUPABASE_ENV_VALUES);
298
+ }
299
+ });
80
300
 
81
301
  // src/commands/db/constants.ts
82
302
  var constants_exports = {};
@@ -113,7 +333,7 @@ function detectSupabasePorts(projectRoot) {
113
333
  const apiUrl = status.API_URL || status["API URL"] || status.api_url;
114
334
  const dbUrl = status.DB_URL || status["DB URL"] || status.db_url;
115
335
  const studioUrl = status.STUDIO_URL || status["Studio URL"] || status.studio_url;
116
- const extractPort = (url) => {
336
+ const extractPort2 = (url) => {
117
337
  try {
118
338
  const parsed = new URL(url);
119
339
  return parsed.port ? Number.parseInt(parsed.port, 10) : null;
@@ -122,28 +342,38 @@ function detectSupabasePorts(projectRoot) {
122
342
  return match ? Number.parseInt(match[1], 10) : null;
123
343
  }
124
344
  };
125
- const apiPort = apiUrl ? extractPort(apiUrl) : null;
126
- const dbPort = dbUrl ? extractPort(dbUrl) : null;
127
- const studioPort = studioUrl ? extractPort(studioUrl) : null;
345
+ const apiPort = apiUrl ? extractPort2(apiUrl) : null;
346
+ const dbPort = dbUrl ? extractPort2(dbUrl) : null;
347
+ const studioPort = studioUrl ? extractPort2(studioUrl) : null;
128
348
  if (!apiPort || !dbPort) {
129
349
  throw new Error(
130
350
  "Could not detect Supabase ports from status output.\n\nTry restarting Supabase: supabase stop && supabase start"
131
351
  );
132
352
  }
133
- return { api: apiPort, db: dbPort, studio: studioPort ?? apiPort + 2 };
353
+ return {
354
+ api: apiPort,
355
+ db: dbPort,
356
+ studio: studioPort ?? apiPort + 2
357
+ };
134
358
  }
135
359
  function getSupabaseAccessPoints(projectRoot) {
136
- const ports = detectSupabasePorts(projectRoot);
360
+ const ports = detectLocalSupabasePorts(projectRoot);
361
+ const buildSupabaseUrl = (port) => {
362
+ const url = new URL(buildLocalSupabaseUrl(projectRoot));
363
+ url.port = String(port);
364
+ return url.toString().replace(/\/$/, "");
365
+ };
137
366
  return {
138
- studio: `http://127.0.0.1:${ports.studio}`,
139
- api: `http://127.0.0.1:${ports.api}`,
140
- db: `postgresql://postgres:postgres@127.0.0.1:${ports.db}/postgres`
367
+ studio: buildSupabaseUrl(ports.studio),
368
+ api: buildLocalSupabaseUrl(projectRoot),
369
+ db: buildLocalDatabaseUrl(projectRoot)
141
370
  };
142
371
  }
143
372
  var DATABASE_DEFAULTS, SEED_DEFAULTS, SCRIPT_LOCATIONS, ERROR_MESSAGES;
144
373
  var init_constants = __esm({
145
374
  "src/commands/db/constants.ts"() {
146
375
  init_esm_shims();
376
+ init_local_supabase();
147
377
  DATABASE_DEFAULTS = {
148
378
  // Supabase Local defaults (for development)
149
379
  // Note: PORT is detected from running Supabase instance
@@ -152,7 +382,9 @@ var init_constants = __esm({
152
382
  // This is a documented public value, not a secret.
153
383
  // Production uses environment variables via .env.production.
154
384
  SUPABASE_LOCAL: {
155
- HOST: "127.0.0.1",
385
+ get HOST() {
386
+ return detectLocalSupabasePorts().host;
387
+ },
156
388
  get PORT() {
157
389
  return detectSupabasePorts().db;
158
390
  },
@@ -186,15 +418,15 @@ var init_constants = __esm({
186
418
  if (databaseUrl) {
187
419
  try {
188
420
  const url2 = new URL(databaseUrl);
189
- const isLocalhost = url2.hostname === "127.0.0.1" || url2.hostname === "localhost";
421
+ const isLocalhost = url2.hostname === "127.0.0.1" || url2.hostname === "localhost" || url2.hostname === "host.docker.internal";
190
422
  if (isLocalhost) {
191
423
  return databaseUrl;
192
424
  }
193
425
  } catch {
194
426
  }
195
427
  }
196
- const host = process.env.LOCAL_DB_HOST || process.env.DB_HOST || this.SUPABASE_LOCAL.HOST;
197
- const port = process.env.LOCAL_DB_PORT || process.env.DB_PORT || String(this.SUPABASE_LOCAL.PORT);
428
+ const host = process.env.LOCAL_DB_HOST || process.env.DB_HOST || process.env.LOCAL_SUPABASE_HOST || this.SUPABASE_LOCAL.HOST;
429
+ const port = process.env.LOCAL_DB_PORT || process.env.DB_PORT || process.env.LOCAL_SUPABASE_DB_PORT || String(this.SUPABASE_LOCAL.PORT);
198
430
  const user = process.env.LOCAL_DB_USER || process.env.DB_USER || this.SUPABASE_LOCAL.USER;
199
431
  const password = process.env.LOCAL_DB_PASSWORD || process.env.DB_PASSWORD || this.SUPABASE_LOCAL.PASSWORD;
200
432
  const database = process.env.LOCAL_DB_NAME || process.env.DB_NAME || this.SUPABASE_LOCAL.DATABASE;
@@ -748,11 +980,11 @@ function validateRunaConfig(config) {
748
980
  };
749
981
  }
750
982
  function hasValidDatabaseIndicators(dir) {
751
- const hasPrimaryIndicator = existsSync(path10__default.join(dir, "drizzle.config.ts")) || existsSync(path10__default.join(dir, "supabase", "schemas")) || existsSync(path10__default.join(dir, "src", "schema")) || existsSync(path10__default.join(dir, "scripts", "db-sync.ts"));
983
+ const hasPrimaryIndicator = existsSync(path11__default.join(dir, "drizzle.config.ts")) || existsSync(path11__default.join(dir, "supabase", "schemas")) || existsSync(path11__default.join(dir, "src", "schema")) || existsSync(path11__default.join(dir, "scripts", "db-sync.ts"));
752
984
  if (hasPrimaryIndicator) {
753
985
  return true;
754
986
  }
755
- const pkgJsonPath = path10__default.join(dir, "package.json");
987
+ const pkgJsonPath = path11__default.join(dir, "package.json");
756
988
  if (existsSync(pkgJsonPath)) {
757
989
  try {
758
990
  const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
@@ -768,15 +1000,15 @@ function hasValidDatabaseIndicators(dir) {
768
1000
  function tryResolveFromConfig(cwd) {
769
1001
  try {
770
1002
  const loaded = loadRunaConfigOrThrow(cwd);
771
- const configDir = path10__default.dirname(loaded.configPath);
1003
+ const configDir = path11__default.dirname(loaded.configPath);
772
1004
  const config = loaded.config;
773
1005
  if (config.project.monorepo === false && hasValidDatabaseIndicators(configDir)) {
774
1006
  return configDir;
775
1007
  }
776
1008
  const dbConfig = getDatabaseConfig(config);
777
1009
  const schemaPath = dbConfig.schemaPath;
778
- const dbPath = schemaPath.includes("/src/") ? schemaPath.split("/src/")[0] : schemaPath.startsWith("src/") ? "." : path10__default.dirname(schemaPath);
779
- const fullPath = dbPath === "." ? configDir : path10__default.join(configDir, dbPath);
1010
+ const dbPath = schemaPath.includes("/src/") ? schemaPath.split("/src/")[0] : schemaPath.startsWith("src/") ? "." : path11__default.dirname(schemaPath);
1011
+ const fullPath = dbPath === "." ? configDir : path11__default.join(configDir, dbPath);
780
1012
  return existsSync(fullPath) ? fullPath : null;
781
1013
  } catch {
782
1014
  return null;
@@ -789,9 +1021,9 @@ async function getDatabasePackagePath(cwd = process.cwd()) {
789
1021
  if (dbPackage) return dbPackage;
790
1022
  const baseDir = findWorkspaceRoot(cwd) || cwd;
791
1023
  const conventionalPaths = [
792
- path10__default.join(baseDir, "packages", "database"),
793
- path10__default.join(baseDir, "packages", "db"),
794
- path10__default.join(baseDir, "db"),
1024
+ path11__default.join(baseDir, "packages", "database"),
1025
+ path11__default.join(baseDir, "packages", "db"),
1026
+ path11__default.join(baseDir, "db"),
795
1027
  baseDir
796
1028
  ];
797
1029
  for (const candidate of conventionalPaths) {
@@ -822,14 +1054,14 @@ Solutions:
822
1054
  async function getSDKScriptsPath(cwd = process.cwd()) {
823
1055
  const sdkPackage = findPackage("sdk", cwd);
824
1056
  if (sdkPackage) {
825
- const scriptsPath = path10__default.join(sdkPackage, "scripts");
1057
+ const scriptsPath = path11__default.join(sdkPackage, "scripts");
826
1058
  if (existsSync(scriptsPath)) {
827
1059
  return scriptsPath;
828
1060
  }
829
1061
  }
830
1062
  const workspaceRoot = findWorkspaceRoot(cwd);
831
1063
  const baseDir = workspaceRoot || cwd;
832
- const installedPath = path10__default.join(baseDir, "node_modules", "@runa-ai", "runa", "scripts");
1064
+ const installedPath = path11__default.join(baseDir, "node_modules", "@runa-ai", "runa", "scripts");
833
1065
  if (existsSync(installedPath)) {
834
1066
  return installedPath;
835
1067
  }
@@ -840,14 +1072,14 @@ async function getSDKScriptsPath(cwd = process.cwd()) {
840
1072
  async function getSDKTemplatesPath(cwd = process.cwd()) {
841
1073
  const sdkPackage = findPackage("sdk", cwd);
842
1074
  if (sdkPackage) {
843
- const templatesPath = path10__default.join(sdkPackage, "templates");
1075
+ const templatesPath = path11__default.join(sdkPackage, "templates");
844
1076
  if (existsSync(templatesPath)) {
845
1077
  return templatesPath;
846
1078
  }
847
1079
  }
848
1080
  const workspaceRoot = findWorkspaceRoot(cwd);
849
1081
  const baseDir = workspaceRoot || cwd;
850
- const installedPath = path10__default.join(baseDir, "node_modules", "@runa-ai", "runa", "templates");
1082
+ const installedPath = path11__default.join(baseDir, "node_modules", "@runa-ai", "runa", "templates");
851
1083
  if (existsSync(installedPath)) {
852
1084
  return installedPath;
853
1085
  }
@@ -929,7 +1161,7 @@ var CLI_VERSION, HAS_ADMIN_COMMAND;
929
1161
  var init_version = __esm({
930
1162
  "src/version.ts"() {
931
1163
  init_esm_shims();
932
- CLI_VERSION = "0.5.51";
1164
+ CLI_VERSION = "0.5.52";
933
1165
  HAS_ADMIN_COMMAND = false;
934
1166
  }
935
1167
  });
@@ -1325,7 +1557,7 @@ var init_dependency_analyzer = __esm({
1325
1557
  name = "DependencyAnalyzer";
1326
1558
  categories = ["dependency"];
1327
1559
  async analyze(options) {
1328
- const packageJsonPath = path10__default.join(options.rootDir, "package.json");
1560
+ const packageJsonPath = path11__default.join(options.rootDir, "package.json");
1329
1561
  try {
1330
1562
  await fs9.access(packageJsonPath);
1331
1563
  } catch {
@@ -3079,17 +3311,17 @@ var init_typescript_analyzer = __esm({
3079
3311
  }
3080
3312
  });
3081
3313
  function containsPathTraversal4(inputPath) {
3082
- const normalized = path10__default.normalize(inputPath);
3314
+ const normalized = path11__default.normalize(inputPath);
3083
3315
  if (normalized.includes("..")) return true;
3084
3316
  if (inputPath.includes("\0")) return true;
3085
3317
  return false;
3086
3318
  }
3087
3319
  function isPathWithinBoundary(filePath, boundaryDir) {
3088
3320
  try {
3089
- const resolvedFile = path10__default.resolve(filePath);
3090
- const resolvedBoundary = path10__default.resolve(boundaryDir);
3091
- const relative9 = path10__default.relative(resolvedBoundary, resolvedFile);
3092
- return !relative9.startsWith("..") && !path10__default.isAbsolute(relative9);
3321
+ const resolvedFile = path11__default.resolve(filePath);
3322
+ const resolvedBoundary = path11__default.resolve(boundaryDir);
3323
+ const relative9 = path11__default.relative(resolvedBoundary, resolvedFile);
3324
+ return !relative9.startsWith("..") && !path11__default.isAbsolute(relative9);
3093
3325
  } catch {
3094
3326
  return false;
3095
3327
  }
@@ -3098,14 +3330,14 @@ function resolvePathWithinBoundary(inputPath, boundaryDir) {
3098
3330
  if (containsPathTraversal4(inputPath)) {
3099
3331
  throw new Error(`Path contains traversal patterns: ${inputPath}`);
3100
3332
  }
3101
- const resolvedPath = path10__default.isAbsolute(inputPath) ? inputPath : path10__default.resolve(boundaryDir, inputPath);
3333
+ const resolvedPath = path11__default.isAbsolute(inputPath) ? inputPath : path11__default.resolve(boundaryDir, inputPath);
3102
3334
  if (!isPathWithinBoundary(resolvedPath, boundaryDir)) {
3103
3335
  throw new Error(`Path is outside allowed boundary: ${inputPath}`);
3104
3336
  }
3105
3337
  return resolvedPath;
3106
3338
  }
3107
3339
  function filterPathsWithinBoundary(files, boundaryDir) {
3108
- const resolvedBoundary = path10__default.resolve(boundaryDir);
3340
+ const resolvedBoundary = path11__default.resolve(boundaryDir);
3109
3341
  return files.filter((file) => isPathWithinBoundary(file, resolvedBoundary));
3110
3342
  }
3111
3343
  function validateGlobPatterns(patterns) {
@@ -3166,7 +3398,7 @@ var init_loader = __esm({
3166
3398
  }
3167
3399
  });
3168
3400
  function normalizePath(filePath) {
3169
- const normalized = path10__default.normalize(filePath);
3401
+ const normalized = path11__default.normalize(filePath);
3170
3402
  return normalized.replace(/\\/g, "/");
3171
3403
  }
3172
3404
  function normalizeRuleId(ruleId) {
@@ -5329,7 +5561,7 @@ function pipeToSharedLog(params) {
5329
5561
  }
5330
5562
  async function ensureRunaTmpDir(cwd) {
5331
5563
  const root = cwd ?? process.cwd();
5332
- const dir = path10__default.join(root, ".runa", "tmp");
5564
+ const dir = path11__default.join(root, ".runa", "tmp");
5333
5565
  await mkdir(dir, { recursive: true });
5334
5566
  return dir;
5335
5567
  }
@@ -5354,7 +5586,7 @@ var buildActor = fromPromise(
5354
5586
  const { repoRoot, tmpDir, hasTurbo, e2e, env: env2 = process.env } = input3;
5355
5587
  const startTime = Date.now();
5356
5588
  try {
5357
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
5589
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
5358
5590
  await mkdir(fullTmpDir, { recursive: true });
5359
5591
  const buildEnv = { ...env2 };
5360
5592
  if (e2e) {
@@ -5363,7 +5595,7 @@ var buildActor = fromPromise(
5363
5595
  buildEnv.TURBO_FORCE = "true";
5364
5596
  console.log(" E2E mode enabled: NEXT_PUBLIC_E2E_TEST=true, TURBO_FORCE=true");
5365
5597
  }
5366
- const hasApps = existsSync(path10__default.join(repoRoot, "apps"));
5598
+ const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
5367
5599
  let args;
5368
5600
  if (hasTurbo) {
5369
5601
  args = hasApps ? ["turbo", "run", "build", "--filter=./apps/*", "--filter=./packages/*"] : ["turbo", "run", "build"];
@@ -5376,7 +5608,7 @@ var buildActor = fromPromise(
5376
5608
  label: "build",
5377
5609
  command: "pnpm",
5378
5610
  args,
5379
- logFile: path10__default.join(fullTmpDir, "build.log")
5611
+ logFile: path11__default.join(fullTmpDir, "build.log")
5380
5612
  });
5381
5613
  return {
5382
5614
  passed: true,
@@ -5615,7 +5847,7 @@ function deleteIfExists(fullPath, displayPath, verbose) {
5615
5847
  function deleteRootDirectories(repoRoot, dirs, verbose) {
5616
5848
  const deleted = [];
5617
5849
  for (const dir of dirs) {
5618
- const fullPath = path10__default.join(repoRoot, dir);
5850
+ const fullPath = path11__default.join(repoRoot, dir);
5619
5851
  if (deleteIfExists(fullPath, dir, verbose)) {
5620
5852
  deleted.push(dir);
5621
5853
  }
@@ -5626,13 +5858,13 @@ function cleanMonorepoPackages(repoRoot, dirs, verbose) {
5626
5858
  const deleted = [];
5627
5859
  const subdirs = ["apps", "packages"];
5628
5860
  for (const subdir of subdirs) {
5629
- const subdirPath = path10__default.join(repoRoot, subdir);
5861
+ const subdirPath = path11__default.join(repoRoot, subdir);
5630
5862
  if (!existsSync(subdirPath)) continue;
5631
5863
  const entries = __require("fs").readdirSync(subdirPath, { withFileTypes: true });
5632
5864
  for (const entry of entries) {
5633
5865
  if (!entry.isDirectory()) continue;
5634
5866
  for (const dir of dirs) {
5635
- const targetPath = path10__default.join(subdirPath, entry.name, dir);
5867
+ const targetPath = path11__default.join(subdirPath, entry.name, dir);
5636
5868
  const displayPath = `${subdir}/${entry.name}/${dir}`;
5637
5869
  if (deleteIfExists(targetPath, displayPath, verbose)) {
5638
5870
  deleted.push(displayPath);
@@ -5651,7 +5883,7 @@ var cleanActor = fromPromise(
5651
5883
  async ({ input: input3 }) => {
5652
5884
  const { repoRoot, tmpDir, verbose = false } = input3;
5653
5885
  try {
5654
- await mkdir(path10__default.join(repoRoot, tmpDir), { recursive: true });
5886
+ await mkdir(path11__default.join(repoRoot, tmpDir), { recursive: true });
5655
5887
  if (verbose) {
5656
5888
  console.log("Cleaning build caches...");
5657
5889
  }
@@ -5673,7 +5905,7 @@ var freshActor = fromPromise(
5673
5905
  async ({ input: input3 }) => {
5674
5906
  const { repoRoot, tmpDir, verbose = false } = input3;
5675
5907
  try {
5676
- await mkdir(path10__default.join(repoRoot, tmpDir), { recursive: true });
5908
+ await mkdir(path11__default.join(repoRoot, tmpDir), { recursive: true });
5677
5909
  if (verbose) {
5678
5910
  console.log("Fresh install: cleaning all caches and node_modules...");
5679
5911
  }
@@ -5745,7 +5977,7 @@ var dbSyncActor = fromPromise(
5745
5977
  const { repoRoot, tmpDir, env: env2 = process.env } = input3;
5746
5978
  const startTime = Date.now();
5747
5979
  try {
5748
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
5980
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
5749
5981
  await mkdir(fullTmpDir, { recursive: true });
5750
5982
  await runLogged({
5751
5983
  cwd: repoRoot,
@@ -5753,7 +5985,7 @@ var dbSyncActor = fromPromise(
5753
5985
  label: "db-sync",
5754
5986
  command: "pnpm",
5755
5987
  args: ["exec", "runa", "db", "sync", "--auto-approve"],
5756
- logFile: path10__default.join(fullTmpDir, "db-sync.log")
5988
+ logFile: path11__default.join(fullTmpDir, "db-sync.log")
5757
5989
  });
5758
5990
  return {
5759
5991
  passed: true,
@@ -5789,7 +6021,7 @@ var manifestActor = fromPromise(
5789
6021
  const { repoRoot, tmpDir, env: env2 = process.env } = input3;
5790
6022
  const startTime = Date.now();
5791
6023
  try {
5792
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
6024
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
5793
6025
  await mkdir(fullTmpDir, { recursive: true });
5794
6026
  await runLogged({
5795
6027
  cwd: repoRoot,
@@ -5797,7 +6029,7 @@ var manifestActor = fromPromise(
5797
6029
  label: "manifest",
5798
6030
  command: "pnpm",
5799
6031
  args: ["exec", "runa", "manifest"],
5800
- logFile: path10__default.join(fullTmpDir, "manifest.log")
6032
+ logFile: path11__default.join(fullTmpDir, "manifest.log")
5801
6033
  });
5802
6034
  return {
5803
6035
  passed: true,
@@ -6061,7 +6293,7 @@ function buildOutput(typeCheckPassed, lintPassed, typeCheckDurationMs, lintDurat
6061
6293
  var staticChecksActor = fromPromise(
6062
6294
  async ({ input: input3 }) => {
6063
6295
  const { repoRoot, tmpDir, hasTurbo, env: env2 = process.env, skipTypes, skipLint } = input3;
6064
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
6296
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
6065
6297
  await mkdir(fullTmpDir, { recursive: true });
6066
6298
  const startTime = Date.now();
6067
6299
  const checksToRun = [];
@@ -6075,7 +6307,7 @@ var staticChecksActor = fromPromise(
6075
6307
  label: "type-check",
6076
6308
  command: cmd.command,
6077
6309
  args: cmd.args,
6078
- logFile: path10__default.join(fullTmpDir, "type-check.log")
6310
+ logFile: path11__default.join(fullTmpDir, "type-check.log")
6079
6311
  })
6080
6312
  );
6081
6313
  checkOrder.push("type-check");
@@ -6089,7 +6321,7 @@ var staticChecksActor = fromPromise(
6089
6321
  label: "lint",
6090
6322
  command: cmd.command,
6091
6323
  args: cmd.args,
6092
- logFile: path10__default.join(fullTmpDir, "lint.log")
6324
+ logFile: path11__default.join(fullTmpDir, "lint.log")
6093
6325
  })
6094
6326
  );
6095
6327
  checkOrder.push("lint");
@@ -6133,14 +6365,14 @@ var validateActor = fromPromise(
6133
6365
  let manifestsExist = true;
6134
6366
  const buildOutputPaths = [
6135
6367
  // Single app
6136
- path10__default.join(repoRoot, ".next"),
6137
- path10__default.join(repoRoot, "dist"),
6368
+ path11__default.join(repoRoot, ".next"),
6369
+ path11__default.join(repoRoot, "dist"),
6138
6370
  // Monorepo apps
6139
- path10__default.join(repoRoot, "apps", "web", ".next"),
6140
- path10__default.join(repoRoot, "apps", "dashboard", ".next"),
6371
+ path11__default.join(repoRoot, "apps", "web", ".next"),
6372
+ path11__default.join(repoRoot, "apps", "dashboard", ".next"),
6141
6373
  // Packages
6142
- path10__default.join(repoRoot, "packages", "cli", "dist"),
6143
- path10__default.join(repoRoot, "packages", "sdk", "dist")
6374
+ path11__default.join(repoRoot, "packages", "cli", "dist"),
6375
+ path11__default.join(repoRoot, "packages", "sdk", "dist")
6144
6376
  ];
6145
6377
  for (const outputPath of buildOutputPaths) {
6146
6378
  if (existsSync(outputPath)) {
@@ -6154,7 +6386,7 @@ var validateActor = fromPromise(
6154
6386
  );
6155
6387
  }
6156
6388
  if (!skipManifest) {
6157
- const manifestPath = path10__default.join(repoRoot, ".runa", "manifests", "manifest.json");
6389
+ const manifestPath = path11__default.join(repoRoot, ".runa", "manifests", "manifest.json");
6158
6390
  if (!existsSync(manifestPath)) {
6159
6391
  manifestsExist = false;
6160
6392
  warnings.push("No manifest.json found. E2E test generation may be affected.");
@@ -6213,35 +6445,35 @@ function isE2EMode({ context }) {
6213
6445
  return context.input.e2e;
6214
6446
  }
6215
6447
  function detectDatabase(repoRoot) {
6216
- const configPath = path10__default.join(repoRoot, "runa.config.ts");
6448
+ const configPath = path11__default.join(repoRoot, "runa.config.ts");
6217
6449
  if (!existsSync(configPath)) {
6218
- const jsConfigPath = path10__default.join(repoRoot, "runa.config.js");
6450
+ const jsConfigPath = path11__default.join(repoRoot, "runa.config.js");
6219
6451
  if (!existsSync(jsConfigPath)) {
6220
6452
  return false;
6221
6453
  }
6222
6454
  }
6223
- const supabaseDir = path10__default.join(repoRoot, "supabase");
6455
+ const supabaseDir = path11__default.join(repoRoot, "supabase");
6224
6456
  if (existsSync(supabaseDir)) {
6225
6457
  return true;
6226
6458
  }
6227
- const databasePkg = path10__default.join(repoRoot, "packages", "database");
6459
+ const databasePkg = path11__default.join(repoRoot, "packages", "database");
6228
6460
  if (existsSync(databasePkg)) {
6229
6461
  return true;
6230
6462
  }
6231
6463
  return false;
6232
6464
  }
6233
6465
  function detectManifestTask(repoRoot) {
6234
- const runaConfigPath = path10__default.join(repoRoot, "runa.config.ts");
6466
+ const runaConfigPath = path11__default.join(repoRoot, "runa.config.ts");
6235
6467
  if (existsSync(runaConfigPath)) {
6236
6468
  return true;
6237
6469
  }
6238
- const rootPkgPath = path10__default.join(repoRoot, "package.json");
6470
+ const rootPkgPath = path11__default.join(repoRoot, "package.json");
6239
6471
  if (hasXStateDependency(rootPkgPath)) {
6240
6472
  return true;
6241
6473
  }
6242
6474
  const appDirs = ["apps/web", "apps/app", "apps/dashboard", "app"];
6243
6475
  for (const appDir of appDirs) {
6244
- const appPkgPath = path10__default.join(repoRoot, appDir, "package.json");
6476
+ const appPkgPath = path11__default.join(repoRoot, appDir, "package.json");
6245
6477
  if (hasXStateDependency(appPkgPath)) {
6246
6478
  return true;
6247
6479
  }
@@ -6268,7 +6500,7 @@ function hasXStateDependency(pkgPath) {
6268
6500
  }
6269
6501
  }
6270
6502
  function detectTurbo(repoRoot) {
6271
- const turboJsonPath = path10__default.join(repoRoot, "turbo.json");
6503
+ const turboJsonPath = path11__default.join(repoRoot, "turbo.json");
6272
6504
  return existsSync(turboJsonPath);
6273
6505
  }
6274
6506
  var guards = {
@@ -7276,15 +7508,15 @@ function printSummary(logger16, output3) {
7276
7508
  }
7277
7509
  }
7278
7510
  function findRepoRoot(startDir) {
7279
- const { existsSync: existsSync51, readFileSync: readFileSync29 } = __require("fs");
7511
+ const { existsSync: existsSync52, readFileSync: readFileSync29 } = __require("fs");
7280
7512
  const { join: join23, dirname: dirname5 } = __require("path");
7281
7513
  let current = startDir;
7282
7514
  while (current !== dirname5(current)) {
7283
- if (existsSync51(join23(current, "turbo.json"))) {
7515
+ if (existsSync52(join23(current, "turbo.json"))) {
7284
7516
  return current;
7285
7517
  }
7286
7518
  const pkgPath = join23(current, "package.json");
7287
- if (existsSync51(pkgPath)) {
7519
+ if (existsSync52(pkgPath)) {
7288
7520
  try {
7289
7521
  const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
7290
7522
  if (pkg.workspaces) {
@@ -7527,42 +7759,42 @@ function resolvePolicy(_config, _repoKind) {
7527
7759
  };
7528
7760
  }
7529
7761
  function detectRepoKind(repoRoot) {
7530
- const hasApps = existsSync(path10__default.join(repoRoot, "apps"));
7531
- const hasPackages = existsSync(path10__default.join(repoRoot, "packages"));
7532
- const hasTurbo = existsSync(path10__default.join(repoRoot, "turbo.json"));
7762
+ const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
7763
+ const hasPackages = existsSync(path11__default.join(repoRoot, "packages"));
7764
+ const hasTurbo = existsSync(path11__default.join(repoRoot, "turbo.json"));
7533
7765
  if (hasApps || hasPackages || hasTurbo) {
7534
7766
  return "monorepo";
7535
7767
  }
7536
- const hasSrc = existsSync(path10__default.join(repoRoot, "src"));
7537
- const hasApp = existsSync(path10__default.join(repoRoot, "app"));
7768
+ const hasSrc = existsSync(path11__default.join(repoRoot, "src"));
7769
+ const hasApp = existsSync(path11__default.join(repoRoot, "app"));
7538
7770
  if (hasSrc || hasApp) {
7539
7771
  return "pj-repo";
7540
7772
  }
7541
7773
  return "unknown";
7542
7774
  }
7543
7775
  function hasKnownFrameworkConfig(dir) {
7544
- if (existsSync(path10__default.join(dir, "next.config.js")) || existsSync(path10__default.join(dir, "next.config.mjs")) || existsSync(path10__default.join(dir, "next.config.ts"))) {
7776
+ if (existsSync(path11__default.join(dir, "next.config.js")) || existsSync(path11__default.join(dir, "next.config.mjs")) || existsSync(path11__default.join(dir, "next.config.ts"))) {
7545
7777
  return true;
7546
7778
  }
7547
- if (existsSync(path10__default.join(dir, "vite.config.js")) || existsSync(path10__default.join(dir, "vite.config.ts"))) {
7779
+ if (existsSync(path11__default.join(dir, "vite.config.js")) || existsSync(path11__default.join(dir, "vite.config.ts"))) {
7548
7780
  return true;
7549
7781
  }
7550
- if (existsSync(path10__default.join(dir, "remix.config.js"))) {
7782
+ if (existsSync(path11__default.join(dir, "remix.config.js"))) {
7551
7783
  return true;
7552
7784
  }
7553
- if (existsSync(path10__default.join(dir, "astro.config.mjs")) || existsSync(path10__default.join(dir, "astro.config.ts"))) {
7785
+ if (existsSync(path11__default.join(dir, "astro.config.mjs")) || existsSync(path11__default.join(dir, "astro.config.ts"))) {
7554
7786
  return true;
7555
7787
  }
7556
- if (existsSync(path10__default.join(dir, "nuxt.config.js")) || existsSync(path10__default.join(dir, "nuxt.config.ts"))) {
7788
+ if (existsSync(path11__default.join(dir, "nuxt.config.js")) || existsSync(path11__default.join(dir, "nuxt.config.ts"))) {
7557
7789
  return true;
7558
7790
  }
7559
- if (existsSync(path10__default.join(dir, "svelte.config.js"))) {
7791
+ if (existsSync(path11__default.join(dir, "svelte.config.js"))) {
7560
7792
  return true;
7561
7793
  }
7562
7794
  return false;
7563
7795
  }
7564
7796
  function hasPackageJson(dir) {
7565
- return existsSync(path10__default.join(dir, "package.json"));
7797
+ return existsSync(path11__default.join(dir, "package.json"));
7566
7798
  }
7567
7799
  var PORT_PATTERNS = [
7568
7800
  /-p\s*([0-9]+)/i,
@@ -7582,7 +7814,7 @@ function extractPortFromScript(script) {
7582
7814
  return null;
7583
7815
  }
7584
7816
  function readPortFromScripts(appDir) {
7585
- const pkgPath = path10__default.join(appDir, "package.json");
7817
+ const pkgPath = path11__default.join(appDir, "package.json");
7586
7818
  if (!existsSync(pkgPath)) return 3e3;
7587
7819
  try {
7588
7820
  const { readFileSync: readFileSync29 } = __require("fs");
@@ -7601,30 +7833,30 @@ function readPortFromScripts(appDir) {
7601
7833
  return 3e3;
7602
7834
  }
7603
7835
  function findWebAppUnderApps(repoRoot) {
7604
- const appsDir = path10__default.join(repoRoot, "apps");
7836
+ const appsDir = path11__default.join(repoRoot, "apps");
7605
7837
  if (!existsSync(appsDir)) return null;
7606
7838
  try {
7607
7839
  const { readdirSync: readdirSync12 } = __require("fs");
7608
7840
  const entries = readdirSync12(appsDir, { withFileTypes: true });
7609
7841
  const priority = ["web", "dashboard", "app", "frontend", "client"];
7610
7842
  for (const name of priority) {
7611
- const candidate = path10__default.join(appsDir, name);
7843
+ const candidate = path11__default.join(appsDir, name);
7612
7844
  if (hasKnownFrameworkConfig(candidate)) return candidate;
7613
7845
  }
7614
7846
  for (const entry of entries) {
7615
7847
  if (!entry.isDirectory()) continue;
7616
7848
  if (priority.includes(entry.name)) continue;
7617
- const candidate = path10__default.join(appsDir, entry.name);
7849
+ const candidate = path11__default.join(appsDir, entry.name);
7618
7850
  if (hasKnownFrameworkConfig(candidate)) return candidate;
7619
7851
  }
7620
7852
  for (const name of priority) {
7621
- const candidate = path10__default.join(appsDir, name);
7853
+ const candidate = path11__default.join(appsDir, name);
7622
7854
  if (hasPackageJson(candidate)) return candidate;
7623
7855
  }
7624
7856
  for (const entry of entries) {
7625
7857
  if (!entry.isDirectory()) continue;
7626
7858
  if (priority.includes(entry.name)) continue;
7627
- const candidate = path10__default.join(appsDir, entry.name);
7859
+ const candidate = path11__default.join(appsDir, entry.name);
7628
7860
  if (hasPackageJson(candidate)) return candidate;
7629
7861
  }
7630
7862
  } catch {
@@ -7633,7 +7865,7 @@ function findWebAppUnderApps(repoRoot) {
7633
7865
  }
7634
7866
  function detectApp(repoRoot, configOverride) {
7635
7867
  if (configOverride?.directory && configOverride.directory !== ".") {
7636
- const configuredDir = path10__default.join(repoRoot, configOverride.directory);
7868
+ const configuredDir = path11__default.join(repoRoot, configOverride.directory);
7637
7869
  if (existsSync(configuredDir) && hasPackageJson(configuredDir)) {
7638
7870
  return {
7639
7871
  appDir: configuredDir,
@@ -7768,7 +8000,7 @@ function pipeChildOutputToLog(params) {
7768
8000
  return { cleanup };
7769
8001
  }
7770
8002
  async function writeEnvLocal(params) {
7771
- const filePath = path10__default.join(params.appDir, ".env.local");
8003
+ const filePath = path11__default.join(params.appDir, ".env.local");
7772
8004
  const content = `${Object.entries(params.values).map(([k, v]) => `${k}=${v}`).join("\n")}
7773
8005
  `;
7774
8006
  await writeFile(filePath, content, "utf-8");
@@ -7858,10 +8090,10 @@ function determineAppCommand(mode, isMonorepo2, rootScripts, appScripts, repoRoo
7858
8090
  }
7859
8091
  if (appHasCiScript || appHasDefaultScript) {
7860
8092
  const scriptName = appHasCiScript ? ciScriptName : "start";
7861
- const dirArgs2 = isMonorepo2 ? ["-C", path10__default.relative(repoRoot, appDir)] : [];
8093
+ const dirArgs2 = isMonorepo2 ? ["-C", path11__default.relative(repoRoot, appDir)] : [];
7862
8094
  return { command: ["pnpm", ...dirArgs2, scriptName], useRootScript: false };
7863
8095
  }
7864
- const dirArgs = isMonorepo2 ? ["-C", path10__default.relative(repoRoot, appDir)] : [];
8096
+ const dirArgs = isMonorepo2 ? ["-C", path11__default.relative(repoRoot, appDir)] : [];
7865
8097
  return {
7866
8098
  command: ["pnpm", ...dirArgs, "exec", "next", nextCommand, "-p", String(port)],
7867
8099
  useRootScript: false
@@ -7869,17 +8101,17 @@ function determineAppCommand(mode, isMonorepo2, rootScripts, appScripts, repoRoo
7869
8101
  }
7870
8102
  var NEXT_CRITICAL_FILES = ["routes-manifest.json", "build-manifest.json"];
7871
8103
  function cleanStaleNextDevState(appDir) {
7872
- const nextDir = path10__default.join(appDir, ".next");
8104
+ const nextDir = path11__default.join(appDir, ".next");
7873
8105
  if (!existsSync(nextDir)) {
7874
8106
  return { cleaned: false };
7875
8107
  }
7876
8108
  for (const file of NEXT_CRITICAL_FILES) {
7877
- if (!existsSync(path10__default.join(nextDir, file))) {
8109
+ if (!existsSync(path11__default.join(nextDir, file))) {
7878
8110
  cleanNextDir(nextDir, `Missing ${file}`);
7879
8111
  return { cleaned: true, reason: `Missing ${file}` };
7880
8112
  }
7881
8113
  }
7882
- const serverDir = path10__default.join(nextDir, "server");
8114
+ const serverDir = path11__default.join(nextDir, "server");
7883
8115
  if (!existsSync(serverDir)) {
7884
8116
  try {
7885
8117
  const nextStat = statSync(nextDir);
@@ -7901,7 +8133,7 @@ function cleanNextDir(nextDir, reason) {
7901
8133
  console.log("[runa] Cleanup complete");
7902
8134
  } catch {
7903
8135
  const staleDir = `${nextDir}-stale-${Date.now()}`;
7904
- console.log(`[runa] Could not remove .next, quarantining to ${path10__default.basename(staleDir)}`);
8136
+ console.log(`[runa] Could not remove .next, quarantining to ${path11__default.basename(staleDir)}`);
7905
8137
  try {
7906
8138
  renameSync(nextDir, staleDir);
7907
8139
  } catch {
@@ -7912,8 +8144,8 @@ function cleanNextDir(nextDir, reason) {
7912
8144
  async function startAppBackground(params) {
7913
8145
  const mode = params.mode ?? "start";
7914
8146
  const isMonorepo2 = params.appDir !== params.repoRoot;
7915
- const rootPkgPath = path10__default.join(params.repoRoot, "package.json");
7916
- const appPkgPath = path10__default.join(params.appDir, "package.json");
8147
+ const rootPkgPath = path11__default.join(params.repoRoot, "package.json");
8148
+ const appPkgPath = path11__default.join(params.appDir, "package.json");
7917
8149
  const rootScripts = await readPackageScripts(rootPkgPath);
7918
8150
  const appScripts = isMonorepo2 ? await readPackageScripts(appPkgPath) : rootScripts;
7919
8151
  const { command, useRootScript } = determineAppCommand(
@@ -7925,7 +8157,7 @@ async function startAppBackground(params) {
7925
8157
  params.appDir,
7926
8158
  params.port
7927
8159
  );
7928
- const appLog = path10__default.join(params.tmpDir, "app.log");
8160
+ const appLog = path11__default.join(params.tmpDir, "app.log");
7929
8161
  const out = createWriteStream(appLog, { flags: "a" });
7930
8162
  const commandStr = command.join(" ");
7931
8163
  const modeLabel = mode === "dev" ? "development (hot reload)" : "production";
@@ -7934,7 +8166,7 @@ async function startAppBackground(params) {
7934
8166
  `[runa] Mode: ${modeLabel}`,
7935
8167
  `[runa] Command: ${commandStr}`,
7936
8168
  `[runa] Working directory: ${params.repoRoot}`,
7937
- `[runa] App directory: ${path10__default.relative(params.repoRoot, params.appDir) || "."}`,
8169
+ `[runa] App directory: ${path11__default.relative(params.repoRoot, params.appDir) || "."}`,
7938
8170
  useRootScript ? "[runa] Using root package.json script" : "[runa] Using app package.json script",
7939
8171
  "---",
7940
8172
  ""
@@ -7955,12 +8187,12 @@ async function startAppBackground(params) {
7955
8187
  streamToTerminal: params.stream
7956
8188
  });
7957
8189
  const pid = child.pid ?? -1;
7958
- await writeFile(path10__default.join(params.tmpDir, "app.pid"), `${pid}
8190
+ await writeFile(path11__default.join(params.tmpDir, "app.pid"), `${pid}
7959
8191
  `, "utf-8");
7960
8192
  return { pid, cleanupStreams };
7961
8193
  }
7962
8194
  async function waitForAppReady(params) {
7963
- const logFilePath = params.tmpDir ? path10__default.join(params.tmpDir, "app.log") : void 0;
8195
+ const logFilePath = params.tmpDir ? path11__default.join(params.tmpDir, "app.log") : void 0;
7964
8196
  await waitHttpOk({
7965
8197
  url: `http://127.0.0.1:${params.port}/`,
7966
8198
  timeoutSeconds: params.timeoutSeconds,
@@ -8100,7 +8332,7 @@ var e2eMeta2 = {
8100
8332
  var appStartActor = fromPromise(
8101
8333
  async ({ input: input3 }) => {
8102
8334
  const { repoRoot, appDir, port, tmpDir, stream } = input3;
8103
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
8335
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
8104
8336
  await mkdir(fullTmpDir, { recursive: true });
8105
8337
  cleanStaleNextDevState(appDir);
8106
8338
  const result = await startAppBackground({
@@ -8368,11 +8600,11 @@ function printSummary2(logger16, output3) {
8368
8600
  }
8369
8601
  function findRepoRoot2(startDir) {
8370
8602
  let current = startDir;
8371
- while (current !== path10__default.dirname(current)) {
8372
- if (existsSync(path10__default.join(current, "turbo.json"))) {
8603
+ while (current !== path11__default.dirname(current)) {
8604
+ if (existsSync(path11__default.join(current, "turbo.json"))) {
8373
8605
  return current;
8374
8606
  }
8375
- const pkgPath = path10__default.join(current, "package.json");
8607
+ const pkgPath = path11__default.join(current, "package.json");
8376
8608
  if (existsSync(pkgPath)) {
8377
8609
  try {
8378
8610
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
@@ -8382,7 +8614,7 @@ function findRepoRoot2(startDir) {
8382
8614
  } catch {
8383
8615
  }
8384
8616
  }
8385
- current = path10__default.dirname(current);
8617
+ current = path11__default.dirname(current);
8386
8618
  }
8387
8619
  return startDir;
8388
8620
  }
@@ -8569,19 +8801,19 @@ function isSupportedNodeEnv(value) {
8569
8801
  function findProjectRoot(from) {
8570
8802
  const workspaceRoot = findWorkspaceRoot(from);
8571
8803
  if (workspaceRoot) return workspaceRoot;
8572
- let current = path10__default.resolve(from);
8573
- const root = path10__default.parse(current).root;
8804
+ let current = path11__default.resolve(from);
8805
+ const root = path11__default.parse(current).root;
8574
8806
  let depth = 0;
8575
8807
  while (current !== root && depth < MAX_DIRECTORY_TRAVERSAL_DEPTH) {
8576
- const hasGit = existsSync(path10__default.join(current, ".git"));
8577
- const hasPackageJson2 = existsSync(path10__default.join(current, "package.json"));
8808
+ const hasGit = existsSync(path11__default.join(current, ".git"));
8809
+ const hasPackageJson2 = existsSync(path11__default.join(current, "package.json"));
8578
8810
  if (hasGit || hasPackageJson2) return current;
8579
- const parent = path10__default.dirname(current);
8811
+ const parent = path11__default.dirname(current);
8580
8812
  if (parent === current) break;
8581
8813
  current = parent;
8582
8814
  depth++;
8583
8815
  }
8584
- return path10__default.resolve(from);
8816
+ return path11__default.resolve(from);
8585
8817
  }
8586
8818
  function mapRunaEnvToVercelEnv(runaEnv) {
8587
8819
  if (runaEnv === "preview") return "preview";
@@ -8622,7 +8854,7 @@ function loadEnvFiles(options = {}) {
8622
8854
  const nodeEnv = resolveNodeEnv(options.nodeEnv);
8623
8855
  const projectRoot = findProjectRoot(cwd);
8624
8856
  const vercelEnv = options.vercelEnv ?? inferVercelEnv({ nodeEnv, runaEnv: options.runaEnv });
8625
- const keysFile = path10__default.join(projectRoot, ".env.keys");
8857
+ const keysFile = path11__default.join(projectRoot, ".env.keys");
8626
8858
  const baseFilePaths = buildBaseEnvFilePaths({ nodeEnv, vercelEnv });
8627
8859
  const runaFilePaths = options.runaEnv ? buildRunaEnvFilePaths(options.runaEnv) : [];
8628
8860
  const allRelPaths = [...baseFilePaths, ...runaFilePaths];
@@ -8632,7 +8864,7 @@ function loadEnvFiles(options = {}) {
8632
8864
  const filePaths = [
8633
8865
  keysFile,
8634
8866
  // Load keys first
8635
- ...allRelPaths.map((rel) => path10__default.join(projectRoot, rel)).filter(existsSync)
8867
+ ...allRelPaths.map((rel) => path11__default.join(projectRoot, rel)).filter(existsSync)
8636
8868
  ];
8637
8869
  config({
8638
8870
  path: filePaths,
@@ -8641,7 +8873,7 @@ function loadEnvFiles(options = {}) {
8641
8873
  quiet: true
8642
8874
  // Suppress dotenvx verbose output
8643
8875
  });
8644
- loadedFiles = allRelPaths.filter((rel) => existsSync(path10__default.join(projectRoot, rel)));
8876
+ loadedFiles = allRelPaths.filter((rel) => existsSync(path11__default.join(projectRoot, rel)));
8645
8877
  } else {
8646
8878
  const targetEnv = { ...process.env };
8647
8879
  loadedFiles = [
@@ -8716,8 +8948,8 @@ function buildRunaEnvFilePaths(runaEnv) {
8716
8948
  function loadEnvFilesIntoTarget(params) {
8717
8949
  const loadedFiles = [];
8718
8950
  for (const relPath of params.relPaths) {
8719
- const fullPath = path10__default.join(params.projectRoot, relPath);
8720
- const resolvedPath = path10__default.resolve(fullPath);
8951
+ const fullPath = path11__default.join(params.projectRoot, relPath);
8952
+ const resolvedPath = path11__default.resolve(fullPath);
8721
8953
  if (!isPathContained(params.projectRoot, resolvedPath)) {
8722
8954
  continue;
8723
8955
  }
@@ -8985,7 +9217,7 @@ async function runTool(params) {
8985
9217
  exitCode,
8986
9218
  issueCount,
8987
9219
  durationMs,
8988
- outputPath: path10__default.relative(process.cwd(), params.outputPath)
9220
+ outputPath: path11__default.relative(process.cwd(), params.outputPath)
8989
9221
  });
8990
9222
  });
8991
9223
  proc.on("error", async () => {
@@ -9004,7 +9236,7 @@ async function runTool(params) {
9004
9236
  exitCode: -1,
9005
9237
  issueCount: 0,
9006
9238
  durationMs,
9007
- outputPath: path10__default.relative(process.cwd(), params.outputPath)
9239
+ outputPath: path11__default.relative(process.cwd(), params.outputPath)
9008
9240
  });
9009
9241
  });
9010
9242
  });
@@ -9036,7 +9268,7 @@ async function executeWorkflowCheck(params) {
9036
9268
  label: params.label,
9037
9269
  command: params.command,
9038
9270
  args: params.args,
9039
- outputPath: path10__default.join(params.logDir, `${params.name}-output.txt`),
9271
+ outputPath: path11__default.join(params.logDir, `${params.name}-output.txt`),
9040
9272
  parseIssueCount: params.parseIssueCount
9041
9273
  });
9042
9274
  logCheckResult(result, params.isWarningOnly ?? false);
@@ -9108,7 +9340,7 @@ async function runCiChecks(options) {
9108
9340
  const mode = options.mode === "github-actions" ? "github-actions" : "local";
9109
9341
  const isCI3 = mode === "github-actions";
9110
9342
  const workflowsChanged = options.workflowsChanged;
9111
- const logDir = path10__default.join(process.cwd(), ".runa", "tmp", "workflow");
9343
+ const logDir = path11__default.join(process.cwd(), ".runa", "tmp", "workflow");
9112
9344
  await mkdir(logDir, { recursive: true });
9113
9345
  console.log("");
9114
9346
  console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
@@ -9117,7 +9349,7 @@ async function runCiChecks(options) {
9117
9349
  console.log("");
9118
9350
  const results = await executeChecks(workflowsChanged, logDir);
9119
9351
  const summary = buildChecksSummary(startedAt, workflowsChanged, results);
9120
- const summaryPath = path10__default.join(logDir, "checks-summary.json");
9352
+ const summaryPath = path11__default.join(logDir, "checks-summary.json");
9121
9353
  await writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
9122
9354
  if (isCI3) {
9123
9355
  await appendGithubStepSummary(buildStepSummaryMarkdown(summary));
@@ -9184,7 +9416,7 @@ function printFinalOutput(summary, summaryPath) {
9184
9416
  console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
9185
9417
  console.log(`${summary.status === "failure" ? "\u274C" : "\u2705"} Workflow Checks: ${summary.status}`);
9186
9418
  console.log(` Duration: ${formatDuration$1(summary.durationMs)}`);
9187
- console.log(` Summary: ${path10__default.relative(process.cwd(), summaryPath)}`);
9419
+ console.log(` Summary: ${path11__default.relative(process.cwd(), summaryPath)}`);
9188
9420
  console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
9189
9421
  }
9190
9422
  var ciChecksCommand = new Command("checks").description("Run workflow checks (actionlint, zizmor)").option("--mode <mode>", "Execution mode (github-actions | local)", "local").option("--workflows-changed", "Indicate workflows have changed", false).action(runCiChecks);
@@ -9197,10 +9429,10 @@ init_esm_shims();
9197
9429
  var CiConfigSchema = z.record(z.string(), z.unknown());
9198
9430
  async function loadCiConfig(params) {
9199
9431
  const override = typeof params.overridePath === "string" && params.overridePath.trim().length > 0 ? params.overridePath.trim() : null;
9200
- const defaultPath = path10__default.join(params.repoRoot, ".runa", "ci.config.json");
9432
+ const defaultPath = path11__default.join(params.repoRoot, ".runa", "ci.config.json");
9201
9433
  const resolvedPath = override ?? (existsSync(defaultPath) ? defaultPath : null);
9202
9434
  if (!resolvedPath) return { configPath: null, config: null };
9203
- const abs = path10__default.isAbsolute(resolvedPath) ? resolvedPath : path10__default.join(params.repoRoot, resolvedPath);
9435
+ const abs = path11__default.isAbsolute(resolvedPath) ? resolvedPath : path11__default.join(params.repoRoot, resolvedPath);
9204
9436
  if (!existsSync(abs)) return { configPath: abs, config: null };
9205
9437
  const raw = await readFile(abs, "utf-8");
9206
9438
  const parsed = JSON.parse(raw);
@@ -9302,9 +9534,9 @@ var CiSummarySchema = z.object({
9302
9534
  async function writeCiSummary(params) {
9303
9535
  const cwd = params.cwd ?? process.cwd();
9304
9536
  const parsed = CiSummarySchema.parse(params.summary);
9305
- const dir = path10__default.join(cwd, ".runa", "tmp");
9537
+ const dir = path11__default.join(cwd, ".runa", "tmp");
9306
9538
  await mkdir(dir, { recursive: true });
9307
- const filePath = path10__default.join(dir, "ci-summary.json");
9539
+ const filePath = path11__default.join(dir, "ci-summary.json");
9308
9540
  await writeFile(filePath, `${JSON.stringify(parsed, null, 2)}
9309
9541
  `, "utf-8");
9310
9542
  return filePath;
@@ -9553,12 +9785,12 @@ async function detectStack(repoRoot, tmpDir, productionDbUrlAdmin) {
9553
9785
  label: "detect-stack",
9554
9786
  command: "pnpm",
9555
9787
  args: ["exec", "runa", "db", "detect-stack", "--quiet"],
9556
- logFile: path10__default.join(tmpDir, "detect-stack.log")
9788
+ logFile: path11__default.join(tmpDir, "detect-stack.log")
9557
9789
  });
9558
9790
  return String(res.stdout ?? "").trim();
9559
9791
  }
9560
9792
  function checkIfInitialDeployment(repoRoot, productionDbUrl) {
9561
- const schemasDir = path10__default.join(repoRoot, "supabase", "schemas", "declarative");
9793
+ const schemasDir = path11__default.join(repoRoot, "supabase", "schemas", "declarative");
9562
9794
  let schemas;
9563
9795
  try {
9564
9796
  schemas = detectAppSchemas(schemasDir, false);
@@ -9624,9 +9856,9 @@ function checkIfInitialDeployment(repoRoot, productionDbUrl) {
9624
9856
  }
9625
9857
  }
9626
9858
  async function showSchemaDiff(repoRoot, tmpDir) {
9627
- const diffLog = path10__default.join(tmpDir, "schema-diff.log");
9859
+ const diffLog = path11__default.join(tmpDir, "schema-diff.log");
9628
9860
  const safeEnv = getSafeEnv();
9629
- const declarativeSqlPath = path10__default.join(repoRoot, "supabase/schemas/declarative");
9861
+ const declarativeSqlPath = path11__default.join(repoRoot, "supabase/schemas/declarative");
9630
9862
  if (existsSync(declarativeSqlPath)) {
9631
9863
  await runLogged({
9632
9864
  cwd: repoRoot,
@@ -9640,8 +9872,8 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9640
9872
  }
9641
9873
  const detected = detectDatabasePackage(repoRoot);
9642
9874
  if (detected) {
9643
- const schemaPath = path10__default.join(detected, "src", "schema");
9644
- if (existsSync(path10__default.join(repoRoot, schemaPath))) {
9875
+ const schemaPath = path11__default.join(detected, "src", "schema");
9876
+ if (existsSync(path11__default.join(repoRoot, schemaPath))) {
9645
9877
  await runLogged({
9646
9878
  cwd: repoRoot,
9647
9879
  env: safeEnv,
@@ -9654,8 +9886,8 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9654
9886
  }
9655
9887
  }
9656
9888
  for (const candidate of DATABASE_PACKAGE_CANDIDATES) {
9657
- const candidatePath = path10__default.join("packages", candidate, "src", "schema");
9658
- if (existsSync(path10__default.join(repoRoot, candidatePath))) {
9889
+ const candidatePath = path11__default.join("packages", candidate, "src", "schema");
9890
+ if (existsSync(path11__default.join(repoRoot, candidatePath))) {
9659
9891
  await runLogged({
9660
9892
  cwd: repoRoot,
9661
9893
  env: safeEnv,
@@ -9667,7 +9899,7 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9667
9899
  return;
9668
9900
  }
9669
9901
  }
9670
- if (existsSync(path10__default.join(repoRoot, "src", "schema"))) {
9902
+ if (existsSync(path11__default.join(repoRoot, "src", "schema"))) {
9671
9903
  await runLogged({
9672
9904
  cwd: repoRoot,
9673
9905
  env: safeEnv,
@@ -9679,7 +9911,7 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9679
9911
  }
9680
9912
  }
9681
9913
  async function detectRisks(repoRoot, tmpDir) {
9682
- const logFile = path10__default.join(tmpDir, "db-risks.log");
9914
+ const logFile = path11__default.join(tmpDir, "db-risks.log");
9683
9915
  try {
9684
9916
  const env2 = getFilteredEnv();
9685
9917
  await runLogged({
@@ -9725,7 +9957,7 @@ async function snapshotCreate(repoRoot, tmpDir, productionDbUrlAdmin, commit) {
9725
9957
  label: "snapshot create production",
9726
9958
  command: "pnpm",
9727
9959
  args: ["exec", "runa", "db", "snapshot", "create", "production", "--commit", commit],
9728
- logFile: path10__default.join(tmpDir, "snapshot-create.log")
9960
+ logFile: path11__default.join(tmpDir, "snapshot-create.log")
9729
9961
  });
9730
9962
  }
9731
9963
  async function snapshotRestoreLatest(repoRoot, tmpDir, productionDbUrlAdmin) {
@@ -9738,7 +9970,7 @@ async function snapshotRestoreLatest(repoRoot, tmpDir, productionDbUrlAdmin) {
9738
9970
  label: "snapshot restore production (latest)",
9739
9971
  command: "pnpm",
9740
9972
  args: ["exec", "runa", "db", "snapshot", "restore", "production", "--latest", "--auto-approve"],
9741
- logFile: path10__default.join(tmpDir, "snapshot-restore.log")
9973
+ logFile: path11__default.join(tmpDir, "snapshot-restore.log")
9742
9974
  });
9743
9975
  }
9744
9976
  function parseApplyLog(logContent) {
@@ -9802,7 +10034,7 @@ async function applyProductionSchema(repoRoot, tmpDir, productionDbUrlAdmin, pro
9802
10034
  if (options?.maxLockWaitMs !== void 0) {
9803
10035
  args.push("--max-lock-wait-ms", String(options.maxLockWaitMs));
9804
10036
  }
9805
- const logPath = path10__default.join(tmpDir, "db-apply-production.log");
10037
+ const logPath = path11__default.join(tmpDir, "db-apply-production.log");
9806
10038
  const startTime = Date.now();
9807
10039
  await runLogged({
9808
10040
  cwd: repoRoot,
@@ -9847,11 +10079,11 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
9847
10079
  label: "git log (commit message)",
9848
10080
  command: "git",
9849
10081
  args: ["log", "-1", "--pretty=format:%s"],
9850
- logFile: path10__default.join(tmpDir, "git-commit-message.log")
10082
+ logFile: path11__default.join(tmpDir, "git-commit-message.log")
9851
10083
  });
9852
10084
  const commitMsg = String(msg.stdout ?? "").trim();
9853
10085
  const schemaPaths = [];
9854
- const declarativeSqlPath = path10__default.join(repoRoot, "supabase/schemas/declarative");
10086
+ const declarativeSqlPath = path11__default.join(repoRoot, "supabase/schemas/declarative");
9855
10087
  if (existsSync(declarativeSqlPath)) {
9856
10088
  schemaPaths.push("supabase/schemas/declarative/");
9857
10089
  } else {
@@ -9871,7 +10103,7 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
9871
10103
  label: "git diff (schema)",
9872
10104
  command: "git",
9873
10105
  args: ["diff", "origin/main", "HEAD", "--", ...schemaPaths],
9874
- logFile: path10__default.join(tmpDir, "git-schema-diff.log")
10106
+ logFile: path11__default.join(tmpDir, "git-schema-diff.log")
9875
10107
  });
9876
10108
  const diffRaw = String(diff.stdout ?? "");
9877
10109
  const diffLimited = diffRaw.length > 1e4 ? diffRaw.slice(0, 1e4) : diffRaw;
@@ -9900,7 +10132,7 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
9900
10132
  "--environment",
9901
10133
  "production"
9902
10134
  ],
9903
- logFile: path10__default.join(tmpDir, "db-audit-record.log")
10135
+ logFile: path11__default.join(tmpDir, "db-audit-record.log")
9904
10136
  });
9905
10137
  }
9906
10138
  async function notifyDeployment(repoRoot, tmpDir, params) {
@@ -9928,7 +10160,7 @@ async function notifyDeployment(repoRoot, tmpDir, params) {
9928
10160
  "--type",
9929
10161
  "production-schema"
9930
10162
  ],
9931
- logFile: path10__default.join(tmpDir, "notify-deployment.log")
10163
+ logFile: path11__default.join(tmpDir, "notify-deployment.log")
9932
10164
  });
9933
10165
  }
9934
10166
 
@@ -10290,7 +10522,7 @@ $$;
10290
10522
  label: `repair timestamps (${params.labelPrefix})`,
10291
10523
  command: "psql",
10292
10524
  args: [...psql.args, "-v", "ON_ERROR_STOP=1", "-c", sql],
10293
- logFile: path10__default.join(params.tmpDir, `timestamp-repair-${params.labelPrefix}.log`)
10525
+ logFile: path11__default.join(params.tmpDir, `timestamp-repair-${params.labelPrefix}.log`)
10294
10526
  });
10295
10527
  }
10296
10528
 
@@ -10722,7 +10954,7 @@ async function runCiProdApply(params) {
10722
10954
  overridePath: params.options.config
10723
10955
  });
10724
10956
  if (cfg.configPath)
10725
- params.summary.detected.configPath = path10__default.relative(params.repoRoot, cfg.configPath);
10957
+ params.summary.detected.configPath = path11__default.relative(params.repoRoot, cfg.configPath);
10726
10958
  if (cfg.config) params.summary.detected.config = cfg.config;
10727
10959
  requireCiAutoApprove({ mode: params.summary.mode, autoApprove: params.options.autoApprove });
10728
10960
  const inputs = resolveProdApplyInputs();
@@ -10815,7 +11047,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
10815
11047
  await appendGithubStepSummary(
10816
11048
  buildCiProdApplyStepSummaryMarkdown({
10817
11049
  summary,
10818
- summaryPath: path10__default.relative(repoRoot, summaryPath)
11050
+ summaryPath: path11__default.relative(repoRoot, summaryPath)
10819
11051
  })
10820
11052
  );
10821
11053
  if (summary.mode === "github-actions") {
@@ -10831,7 +11063,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
10831
11063
  const summaryPath = await writeCiSummary({ summary });
10832
11064
  logSection("Result");
10833
11065
  console.log(`status: ${summary.status}`);
10834
- console.log(`summary: ${path10__default.relative(repoRoot, summaryPath)}`);
11066
+ console.log(`summary: ${path11__default.relative(repoRoot, summaryPath)}`);
10835
11067
  logNextActions([
10836
11068
  "Inspect .runa/tmp logs (db-apply-production.log, snapshot-*.log)",
10837
11069
  "If rollback succeeded, database should be restored to pre-deploy snapshot"
@@ -10839,7 +11071,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
10839
11071
  await appendGithubStepSummary(
10840
11072
  buildCiProdApplyStepSummaryMarkdown({
10841
11073
  summary,
10842
- summaryPath: path10__default.relative(repoRoot, summaryPath)
11074
+ summaryPath: path11__default.relative(repoRoot, summaryPath)
10843
11075
  })
10844
11076
  );
10845
11077
  await maybePostFailureComment({
@@ -10910,7 +11142,7 @@ function getChecks() {
10910
11142
  }
10911
11143
  async function runCheck(check, logDir) {
10912
11144
  const startTime = Date.now();
10913
- const logPath = path10__default.join(logDir, `${check.name}.log`);
11145
+ const logPath = path11__default.join(logDir, `${check.name}.log`);
10914
11146
  return new Promise((resolve12) => {
10915
11147
  const proc = spawn(check.command, check.args, {
10916
11148
  cwd: process.cwd(),
@@ -10940,7 +11172,7 @@ async function runCheck(check, logDir) {
10940
11172
  status: exitCode === 0 ? "passed" : "failed",
10941
11173
  exitCode,
10942
11174
  durationMs,
10943
- logPath: path10__default.relative(process.cwd(), logPath)
11175
+ logPath: path11__default.relative(process.cwd(), logPath)
10944
11176
  });
10945
11177
  });
10946
11178
  proc.on("error", async () => {
@@ -10955,7 +11187,7 @@ async function runCheck(check, logDir) {
10955
11187
  status: "failed",
10956
11188
  exitCode: 1,
10957
11189
  durationMs,
10958
- logPath: path10__default.relative(process.cwd(), logPath)
11190
+ logPath: path11__default.relative(process.cwd(), logPath)
10959
11191
  });
10960
11192
  });
10961
11193
  });
@@ -11083,19 +11315,19 @@ function printFinalStaticOutput(summary, summaryPath) {
11083
11315
  console.log(`${summary.status === "success" ? "\u2705" : "\u274C"} Static Analysis: ${summary.status}`);
11084
11316
  console.log(` Duration: ${formatDuration$1(summary.durationMs)}`);
11085
11317
  console.log(` Passed: ${summary.passedCount}/${summary.checks.length}`);
11086
- console.log(` Summary: ${path10__default.relative(process.cwd(), summaryPath)}`);
11318
+ console.log(` Summary: ${path11__default.relative(process.cwd(), summaryPath)}`);
11087
11319
  console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
11088
11320
  }
11089
11321
  async function runCiStatic(options) {
11090
11322
  const startedAt = /* @__PURE__ */ new Date();
11091
11323
  const isCI3 = options.mode === "github-actions";
11092
- const logDir = path10__default.join(process.cwd(), ".runa", "tmp", "workflow");
11324
+ const logDir = path11__default.join(process.cwd(), ".runa", "tmp", "workflow");
11093
11325
  await mkdir(logDir, { recursive: true });
11094
11326
  const checksToRun = getChecksToRun(options);
11095
11327
  printStaticHeader(options);
11096
11328
  const results = options.parallel ? await runChecksParallel(checksToRun, logDir) : await runChecksSequential(checksToRun, logDir);
11097
11329
  const summary = buildStaticSummary(startedAt, results);
11098
- const summaryPath = path10__default.join(logDir, "static-summary.json");
11330
+ const summaryPath = path11__default.join(logDir, "static-summary.json");
11099
11331
  await writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
11100
11332
  if (isCI3) {
11101
11333
  await appendGithubStepSummary(buildStepSummaryMarkdown2(summary));
@@ -11125,9 +11357,9 @@ var appBuildActor = fromPromise(
11125
11357
  async ({ input: input3 }) => {
11126
11358
  const { repoRoot, tmpDir, env: env2 = process.env } = input3;
11127
11359
  try {
11128
- const hasTurbo = existsSync(path10__default.join(repoRoot, "turbo.json"));
11129
- const hasApps = existsSync(path10__default.join(repoRoot, "apps"));
11130
- const hasAppsWeb = existsSync(path10__default.join(repoRoot, "apps", "web"));
11360
+ const hasTurbo = existsSync(path11__default.join(repoRoot, "turbo.json"));
11361
+ const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
11362
+ const hasAppsWeb = existsSync(path11__default.join(repoRoot, "apps", "web"));
11131
11363
  const args = hasTurbo ? hasApps && !hasAppsWeb ? ["turbo", "run", "build", "--filter=./apps/*"] : ["turbo", "run", "build"] : ["build"];
11132
11364
  await runLogged({
11133
11365
  cwd: repoRoot,
@@ -11135,7 +11367,7 @@ var appBuildActor = fromPromise(
11135
11367
  label: "build",
11136
11368
  command: "pnpm",
11137
11369
  args,
11138
- logFile: path10__default.join(tmpDir, "build.log")
11370
+ logFile: path11__default.join(tmpDir, "build.log")
11139
11371
  });
11140
11372
  return { passed: true };
11141
11373
  } catch (error) {
@@ -11151,14 +11383,14 @@ var appBuildActor = fromPromise(
11151
11383
  init_esm_shims();
11152
11384
  var APP_CANDIDATES = ["web", "dashboard", "app", "frontend", "client"];
11153
11385
  function findExistingAppDirs(repoRoot) {
11154
- const appsDir = path10__default.join(repoRoot, "apps");
11386
+ const appsDir = path11__default.join(repoRoot, "apps");
11155
11387
  if (!existsSync(appsDir)) return [];
11156
11388
  try {
11157
11389
  const entries = readdirSync(appsDir, { withFileTypes: true });
11158
11390
  const found = [];
11159
11391
  for (const entry of entries) {
11160
11392
  if (!entry.isDirectory()) continue;
11161
- const pkgJson = path10__default.join(appsDir, entry.name, "package.json");
11393
+ const pkgJson = path11__default.join(appsDir, entry.name, "package.json");
11162
11394
  if (existsSync(pkgJson)) {
11163
11395
  found.push(`apps/${entry.name}`);
11164
11396
  }
@@ -11178,9 +11410,9 @@ function findExistingAppDirs(repoRoot) {
11178
11410
  }
11179
11411
  }
11180
11412
  function validateAppDir(repoRoot, appDir) {
11181
- const pkgJsonPath = path10__default.join(appDir, "package.json");
11413
+ const pkgJsonPath = path11__default.join(appDir, "package.json");
11182
11414
  if (!existsSync(appDir)) {
11183
- const relPath = path10__default.relative(repoRoot, appDir) || ".";
11415
+ const relPath = path11__default.relative(repoRoot, appDir) || ".";
11184
11416
  const suggestions = findExistingAppDirs(repoRoot);
11185
11417
  const errorParts = [`App directory not found: ${relPath}`];
11186
11418
  if (suggestions.length > 0) {
@@ -11202,7 +11434,7 @@ function validateAppDir(repoRoot, appDir) {
11202
11434
  return errorParts.join("\n");
11203
11435
  }
11204
11436
  if (!existsSync(pkgJsonPath)) {
11205
- const relPath = path10__default.relative(repoRoot, appDir) || ".";
11437
+ const relPath = path11__default.relative(repoRoot, appDir) || ".";
11206
11438
  return `No package.json found in app directory: ${relPath}`;
11207
11439
  }
11208
11440
  return null;
@@ -11259,9 +11491,9 @@ init_esm_shims();
11259
11491
  async function runAppBuild(params) {
11260
11492
  const { repoRoot, tmpDir, env: env2 } = params;
11261
11493
  try {
11262
- const hasTurbo = existsSync(path10__default.join(repoRoot, "turbo.json"));
11263
- const hasApps = existsSync(path10__default.join(repoRoot, "apps"));
11264
- const hasAppsWeb = existsSync(path10__default.join(repoRoot, "apps", "web"));
11494
+ const hasTurbo = existsSync(path11__default.join(repoRoot, "turbo.json"));
11495
+ const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
11496
+ const hasAppsWeb = existsSync(path11__default.join(repoRoot, "apps", "web"));
11265
11497
  const args = hasTurbo ? hasApps && !hasAppsWeb ? ["turbo", "run", "build", "--filter=./apps/*"] : ["turbo", "run", "build"] : ["build"];
11266
11498
  await runLogged({
11267
11499
  cwd: repoRoot,
@@ -11269,7 +11501,7 @@ async function runAppBuild(params) {
11269
11501
  label: "build",
11270
11502
  command: "pnpm",
11271
11503
  args,
11272
- logFile: path10__default.join(tmpDir, "build.log")
11504
+ logFile: path11__default.join(tmpDir, "build.log")
11273
11505
  });
11274
11506
  return { passed: true };
11275
11507
  } catch (error) {
@@ -11288,7 +11520,7 @@ async function runManifestGenerate(params) {
11288
11520
  label: "manifest:generate",
11289
11521
  command: "pnpm",
11290
11522
  args: ["manifest:generate"],
11291
- logFile: path10__default.join(tmpDir, "manifest-generate.log")
11523
+ logFile: path11__default.join(tmpDir, "manifest-generate.log")
11292
11524
  });
11293
11525
  return { generated: true };
11294
11526
  } catch (error) {
@@ -11308,7 +11540,7 @@ async function runPlaywrightInstall(params) {
11308
11540
  label: "playwright install",
11309
11541
  command: "pnpm",
11310
11542
  args,
11311
- logFile: path10__default.join(tmpDir, "playwright-install.log")
11543
+ logFile: path11__default.join(tmpDir, "playwright-install.log")
11312
11544
  });
11313
11545
  return { installed: true };
11314
11546
  } catch (error) {
@@ -11381,7 +11613,7 @@ var playwrightInstallActor = fromPromise(
11381
11613
  label: "playwright install",
11382
11614
  command: "pnpm",
11383
11615
  args,
11384
- logFile: path10__default.join(tmpDir, "playwright-install.log")
11616
+ logFile: path11__default.join(tmpDir, "playwright-install.log")
11385
11617
  });
11386
11618
  return { installed: true };
11387
11619
  } catch (error) {
@@ -11405,7 +11637,7 @@ var staticChecksActor2 = fromPromise(
11405
11637
  label: "type-check",
11406
11638
  command: "pnpm",
11407
11639
  args: ["type-check"],
11408
- logFile: path10__default.join(tmpDir, "type-check.log")
11640
+ logFile: path11__default.join(tmpDir, "type-check.log")
11409
11641
  }),
11410
11642
  runLogged({
11411
11643
  cwd: repoRoot,
@@ -11413,7 +11645,7 @@ var staticChecksActor2 = fromPromise(
11413
11645
  label: "lint",
11414
11646
  command: "pnpm",
11415
11647
  args: ["lint"],
11416
- logFile: path10__default.join(tmpDir, "lint.log")
11648
+ logFile: path11__default.join(tmpDir, "lint.log")
11417
11649
  })
11418
11650
  ]);
11419
11651
  const typeCheckPassed = typeCheckResult.status === "fulfilled";
@@ -11564,7 +11796,7 @@ var applySeedsActor = fromPromise(
11564
11796
  label: `db seed (${envArg})`,
11565
11797
  command: "pnpm",
11566
11798
  args: ["exec", "runa", "db", "seed", envArg, "--auto-approve"],
11567
- logFile: path10__default.join(tmpDir, `ci-db-seed-${envArg}.log`)
11799
+ logFile: path11__default.join(tmpDir, `ci-db-seed-${envArg}.log`)
11568
11800
  });
11569
11801
  return { applied: true };
11570
11802
  } catch (error) {
@@ -11942,7 +12174,7 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
11942
12174
  label: `probe pgtap (best-effort, ${params.label})`,
11943
12175
  command: "psql",
11944
12176
  args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", probeSql],
11945
- logFile: path10__default.join(params.tmpDir, `pgtap-probe-${params.label}.log`)
12177
+ logFile: path11__default.join(params.tmpDir, `pgtap-probe-${params.label}.log`)
11946
12178
  }).catch(() => null);
11947
12179
  const raw = String(probe?.stdout ?? "").trim();
11948
12180
  const [availableRaw, installedRaw] = raw.split(",");
@@ -11957,11 +12189,11 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
11957
12189
  label: `ensure pgtap (best-effort, ${params.label})`,
11958
12190
  command: "psql",
11959
12191
  args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-c", installSql],
11960
- logFile: path10__default.join(params.tmpDir, `pgtap-ensure-${params.label}.log`)
12192
+ logFile: path11__default.join(params.tmpDir, `pgtap-ensure-${params.label}.log`)
11961
12193
  }).catch(async (error) => {
11962
12194
  try {
11963
12195
  await writeFile(
11964
- path10__default.join(params.tmpDir, `pgtap-ensure-${params.label}.failed`),
12196
+ path11__default.join(params.tmpDir, `pgtap-ensure-${params.label}.failed`),
11965
12197
  `${error instanceof Error ? error.message : String(error)}
11966
12198
  `,
11967
12199
  "utf-8"
@@ -11975,7 +12207,7 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
11975
12207
  label: `probe pgtap (best-effort, ${params.label}, after)`,
11976
12208
  command: "psql",
11977
12209
  args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", probeSql],
11978
- logFile: path10__default.join(params.tmpDir, `pgtap-probe-${params.label}-after.log`)
12210
+ logFile: path11__default.join(params.tmpDir, `pgtap-probe-${params.label}-after.log`)
11979
12211
  }).catch(() => null);
11980
12212
  const afterRaw = String(probeAfter?.stdout ?? "").trim();
11981
12213
  const [availableAfterRaw, installedAfterRaw] = afterRaw.split(",");
@@ -12096,14 +12328,14 @@ function extractSqlFromSchemaChanges(fullOutput) {
12096
12328
  return null;
12097
12329
  }
12098
12330
  function getIdempotentRoleNames(repoRoot) {
12099
- const idempotentDir = path10__default.join(repoRoot, "supabase", "schemas", "idempotent");
12331
+ const idempotentDir = path11__default.join(repoRoot, "supabase", "schemas", "idempotent");
12100
12332
  const roles = [];
12101
12333
  try {
12102
12334
  const fs14 = __require("fs");
12103
12335
  if (!fs14.existsSync(idempotentDir)) return [];
12104
12336
  const files = fs14.readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
12105
12337
  for (const file of files) {
12106
- const content = fs14.readFileSync(path10__default.join(idempotentDir, file), "utf-8");
12338
+ const content = fs14.readFileSync(path11__default.join(idempotentDir, file), "utf-8");
12107
12339
  const roleMatches = content.matchAll(/CREATE\s+ROLE\s+(\w+)\s+WITH/gi);
12108
12340
  for (const match of roleMatches) {
12109
12341
  if (match[1]) roles.push(match[1].toLowerCase());
@@ -12244,7 +12476,7 @@ var productionPreviewActor = fromPromise(
12244
12476
  );
12245
12477
  return buildSkipResult(!!productionUrl);
12246
12478
  }
12247
- const logFile = path10__default.join(tmpDir, "ci-production-preview.log");
12479
+ const logFile = path11__default.join(tmpDir, "ci-production-preview.log");
12248
12480
  console.log("\u25B6 production preview (dry-run): runa db apply production --check");
12249
12481
  try {
12250
12482
  const result = await execa(
@@ -12334,7 +12566,7 @@ var resetDbActor = fromPromise(
12334
12566
  label: "db reset (local)",
12335
12567
  command: "npx",
12336
12568
  args: ["supabase", "db", "reset", "--local"],
12337
- logFile: path10__default.join(tmpDir, "ci-db-reset.log")
12569
+ logFile: path11__default.join(tmpDir, "ci-db-reset.log")
12338
12570
  });
12339
12571
  return { reset: true };
12340
12572
  } catch (error) {
@@ -12350,8 +12582,8 @@ var resetDbActor = fromPromise(
12350
12582
  init_esm_shims();
12351
12583
  async function hasSetupRolesScript(repoRoot) {
12352
12584
  const candidates = [
12353
- path10__default.join(repoRoot, "packages", "database", "package.json"),
12354
- path10__default.join(repoRoot, "package.json")
12585
+ path11__default.join(repoRoot, "packages", "database", "package.json"),
12586
+ path11__default.join(repoRoot, "package.json")
12355
12587
  ];
12356
12588
  for (const pkgPath of candidates) {
12357
12589
  if (!existsSync(pkgPath)) continue;
@@ -12389,7 +12621,7 @@ var setupRolesActor = fromPromise(
12389
12621
  label: "db roles setup",
12390
12622
  command: "pnpm",
12391
12623
  args: ["db:setup-roles"],
12392
- logFile: path10__default.join(tmpDir, "ci-db-roles-setup.log")
12624
+ logFile: path11__default.join(tmpDir, "ci-db-roles-setup.log")
12393
12625
  });
12394
12626
  const stdout = String(result.stdout ?? "");
12395
12627
  const appUrlMatch = stdout.match(/APP_DATABASE_URL=["']?([^"'\n]+)["']?/);
@@ -12502,14 +12734,14 @@ function getSchemaGitDiff(repoRoot) {
12502
12734
  }
12503
12735
  }
12504
12736
  function getIdempotentRoleNames2(repoRoot) {
12505
- const idempotentDir = path10__default.join(repoRoot, "supabase", "schemas", "idempotent");
12737
+ const idempotentDir = path11__default.join(repoRoot, "supabase", "schemas", "idempotent");
12506
12738
  const roles = [];
12507
12739
  try {
12508
12740
  const fs14 = __require("fs");
12509
12741
  if (!fs14.existsSync(idempotentDir)) return [];
12510
12742
  const files = fs14.readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
12511
12743
  for (const file of files) {
12512
- const content = fs14.readFileSync(path10__default.join(idempotentDir, file), "utf-8");
12744
+ const content = fs14.readFileSync(path11__default.join(idempotentDir, file), "utf-8");
12513
12745
  const roleMatches = content.matchAll(/CREATE\s+ROLE\s+(\w+)\s+WITH/gi);
12514
12746
  for (const match of roleMatches) {
12515
12747
  if (match[1]) roles.push(match[1].toLowerCase());
@@ -12606,7 +12838,7 @@ var syncSchemaActor = fromPromise(
12606
12838
  // Always verbose for full traceability
12607
12839
  ...skipCodegen ? ["--skip-codegen"] : []
12608
12840
  ];
12609
- const logFile = path10__default.join(tmpDir, `ci-db-${useDbApply ? "apply" : "sync"}-${envArg}.log`);
12841
+ const logFile = path11__default.join(tmpDir, `ci-db-${useDbApply ? "apply" : "sync"}-${envArg}.log`);
12610
12842
  await runLogged({
12611
12843
  cwd: repoRoot,
12612
12844
  env: baseEnv,
@@ -12746,7 +12978,7 @@ async function startSupabaseLocal(params) {
12746
12978
  label: "supabase start (local)",
12747
12979
  command: "supabase",
12748
12980
  args: ["start", "--exclude", exclude],
12749
- logFile: path10__default.join(params.tmpDir, "supabase-start-local.log")
12981
+ logFile: path11__default.join(params.tmpDir, "supabase-start-local.log")
12750
12982
  });
12751
12983
  }
12752
12984
  function getDefaultLocalSupabaseUrl(repoRoot) {
@@ -12774,7 +13006,7 @@ async function resolveLocalSupabaseEnv(params) {
12774
13006
  label: "supabase status (json)",
12775
13007
  command: "supabase",
12776
13008
  args: ["status", "--output", "json"],
12777
- logFile: path10__default.join(params.tmpDir, `supabase-status-${i + 1}.log`)
13009
+ logFile: path11__default.join(params.tmpDir, `supabase-status-${i + 1}.log`)
12778
13010
  });
12779
13011
  const parsed = JSON.parse(String(res.stdout ?? "{}"));
12780
13012
  const out = z.object({
@@ -12894,7 +13126,7 @@ async function findFilesRecursive(params) {
12894
13126
  continue;
12895
13127
  }
12896
13128
  for (const e of entries) {
12897
- const p = path10__default.join(dir, e.name);
13129
+ const p = path11__default.join(dir, e.name);
12898
13130
  if (e.isDirectory()) stack.push(p);
12899
13131
  else if (e.isFile() && params.suffixes.some((s) => p.endsWith(s))) out.push(p);
12900
13132
  }
@@ -12908,7 +13140,7 @@ async function queryScalar(params) {
12908
13140
  label: `psql scalar (${params.logName})`,
12909
13141
  command: "psql",
12910
13142
  args: [params.databaseUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", params.sql],
12911
- logFile: path10__default.join(params.tmpDir, `psql-${params.logName}.log`)
13143
+ logFile: path11__default.join(params.tmpDir, `psql-${params.logName}.log`)
12912
13144
  });
12913
13145
  return String(res.stdout ?? "").trim();
12914
13146
  }
@@ -13036,8 +13268,8 @@ function isPlaywrightIgnored(filePath) {
13036
13268
  async function detectGeneratedE2eCapabilities(params) {
13037
13269
  const caps = /* @__PURE__ */ new Set();
13038
13270
  const diagnostics = {};
13039
- const layer4Dir = path10__default.join(params.repoRoot, ".runa", "tests", "layer4");
13040
- const tmpDir = path10__default.join(params.repoRoot, ".runa", "tmp");
13271
+ const layer4Dir = path11__default.join(params.repoRoot, ".runa", "tests", "layer4");
13272
+ const tmpDir = path11__default.join(params.repoRoot, ".runa", "tmp");
13041
13273
  const hasLayer4Dir = await pathExists(layer4Dir);
13042
13274
  const hasTmpDir = await pathExists(tmpDir);
13043
13275
  if (!hasLayer4Dir && !hasTmpDir) {
@@ -13547,7 +13779,7 @@ init_esm_shims();
13547
13779
  // src/commands/ci/utils/test-parallel.ts
13548
13780
  init_esm_shims();
13549
13781
  async function readLayerResult(tmpDir, layer) {
13550
- const resultFile = path10__default.join(tmpDir, `vitest-layer${layer}-result.json`);
13782
+ const resultFile = path11__default.join(tmpDir, `vitest-layer${layer}-result.json`);
13551
13783
  try {
13552
13784
  const content = await readFile(resultFile, "utf-8");
13553
13785
  return JSON.parse(content);
@@ -13665,8 +13897,8 @@ async function waitUntilAllFinished(params) {
13665
13897
  async function runLayersInParallel(params) {
13666
13898
  const spawned = [];
13667
13899
  for (const layer of params.layers) {
13668
- const logFile = path10__default.join(params.tmpDir, `layer${layer}.log`);
13669
- const exitFile = path10__default.join(params.tmpDir, `layer${layer}.exit`);
13900
+ const logFile = path11__default.join(params.tmpDir, `layer${layer}.log`);
13901
+ const exitFile = path11__default.join(params.tmpDir, `layer${layer}.exit`);
13670
13902
  const proc = runLogged({
13671
13903
  cwd: params.repoRoot,
13672
13904
  env: {
@@ -13709,7 +13941,7 @@ async function runLayersInParallel(params) {
13709
13941
  for (const p of spawned) {
13710
13942
  const codeRaw = p.exitCode ?? await p.procPromise;
13711
13943
  const code = Number.isNaN(codeRaw) ? 1 : codeRaw;
13712
- const resultFile = path10__default.join(params.tmpDir, `vitest-layer${p.layer}-result.json`);
13944
+ const resultFile = path11__default.join(params.tmpDir, `vitest-layer${p.layer}-result.json`);
13713
13945
  const wasKilled = killedLayerSet.has(p.layer);
13714
13946
  const actualResult = waitResult.successMap.get(p.layer) ?? {
13715
13947
  success: code === 0,
@@ -13724,9 +13956,9 @@ async function runLayersInParallel(params) {
13724
13956
  skippedReason: actualResult.skippedReason,
13725
13957
  killed: wasKilled,
13726
13958
  killedBy: wasKilled ? failFastSource : void 0,
13727
- logPath: path10__default.relative(params.repoRoot, p.logFile),
13728
- exitPath: path10__default.relative(params.repoRoot, p.exitFile),
13729
- resultPath: path10__default.relative(params.repoRoot, resultFile),
13959
+ logPath: path11__default.relative(params.repoRoot, p.logFile),
13960
+ exitPath: path11__default.relative(params.repoRoot, p.exitFile),
13961
+ resultPath: path11__default.relative(params.repoRoot, resultFile),
13730
13962
  // Test count information
13731
13963
  totalTests: actualResult.totalTests,
13732
13964
  passedTests: actualResult.passedTests,
@@ -17022,13 +17254,20 @@ init_esm_shims();
17022
17254
  // src/commands/db/utils/db-target.ts
17023
17255
  init_esm_shims();
17024
17256
  init_env();
17025
- init_constants();
17257
+ init_local_supabase();
17026
17258
  function getLocalDatabaseUrl() {
17027
- const ports = detectSupabasePorts(process.cwd());
17028
- return `postgresql://postgres:postgres@localhost:${ports.db}/postgres`;
17259
+ return buildLocalDatabaseUrl(process.cwd());
17260
+ }
17261
+ function isLocalHostname(hostname) {
17262
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "host.docker.internal";
17029
17263
  }
17030
17264
  function isLocalDatabaseUrl(url) {
17031
- return url.includes("localhost") || url.includes("127.0.0.1") || url.includes("host.docker.internal");
17265
+ try {
17266
+ const parsed = new URL(url);
17267
+ return isLocalHostname(parsed.hostname);
17268
+ } catch {
17269
+ return false;
17270
+ }
17032
17271
  }
17033
17272
  function resolveDatabaseUrl(environment) {
17034
17273
  switch (environment) {
@@ -18329,6 +18568,60 @@ function handleHazards(hazards, input3) {
18329
18568
  );
18330
18569
  }
18331
18570
  }
18571
+ var TYPE_TO_EXTENSION = {
18572
+ geometry: "postgis",
18573
+ geography: "postgis",
18574
+ box2d: "postgis",
18575
+ box3d: "postgis",
18576
+ raster: "postgis_raster",
18577
+ vector: "vector",
18578
+ halfvec: "vector",
18579
+ sparsevec: "vector",
18580
+ cube: "cube",
18581
+ hstore: "hstore",
18582
+ ltree: "ltree",
18583
+ citext: "citext"
18584
+ };
18585
+ function detectMissingExtensionType(errorOutput) {
18586
+ const typePattern = /type ["']?(\w+)["']? does not exist/gi;
18587
+ const matches = [...errorOutput.matchAll(typePattern)];
18588
+ const missingTypes = [...new Set(matches.map((m) => m[1].toLowerCase()))];
18589
+ if (missingTypes.length === 0) {
18590
+ return { detected: false, missingTypes: [], suggestedExtensions: [] };
18591
+ }
18592
+ const extensions = /* @__PURE__ */ new Set();
18593
+ for (const type of missingTypes) {
18594
+ const ext = TYPE_TO_EXTENSION[type];
18595
+ if (ext) extensions.add(ext);
18596
+ }
18597
+ return {
18598
+ detected: true,
18599
+ missingTypes,
18600
+ suggestedExtensions: [...extensions]
18601
+ };
18602
+ }
18603
+ function formatExtensionErrorHint(detection) {
18604
+ if (!detection.detected) return "";
18605
+ const lines = [];
18606
+ lines.push("");
18607
+ lines.push("Missing extension type(s) detected:");
18608
+ for (const type of detection.missingTypes) {
18609
+ const ext = TYPE_TO_EXTENSION[type];
18610
+ lines.push(` type "${type}" \u2192 extension: ${ext ?? "unknown"}`);
18611
+ }
18612
+ if (detection.suggestedExtensions.length > 0) {
18613
+ lines.push("");
18614
+ lines.push("Fix 1: Add to supabase/schemas/idempotent/00_extensions.sql:");
18615
+ for (const ext of detection.suggestedExtensions) {
18616
+ lines.push(` CREATE EXTENSION IF NOT EXISTS ${ext};`);
18617
+ }
18618
+ const extList = detection.suggestedExtensions.map((e) => `'${e}'`).join(", ");
18619
+ lines.push("");
18620
+ lines.push("Fix 2: Configure shadow DB in runa.config.ts:");
18621
+ lines.push(` database: { pgSchemaDiff: { shadowDbExtensions: [${extList}] } }`);
18622
+ }
18623
+ return lines.join("\n");
18624
+ }
18332
18625
  function executePgSchemaDiffPlan(dbUrl, schemasDir, includeSchemas, verbose, options) {
18333
18626
  const planArgs = [
18334
18627
  "plan",
@@ -18364,6 +18657,10 @@ function executePgSchemaDiffPlan(dbUrl, schemasDir, includeSchemas, verbose, opt
18364
18657
  logger4.error(`Exit code: ${planResult.status}`);
18365
18658
  logger4.error(`Signal: ${planResult.signal || "none"}`);
18366
18659
  logger4.error(`Stderr: ${planStderr || "(empty)"}`);
18660
+ const extDetection = detectMissingExtensionType(planStderr || planOutput);
18661
+ if (extDetection.detected) {
18662
+ logger4.error(formatExtensionErrorHint(extDetection));
18663
+ }
18367
18664
  throw new Error(
18368
18665
  `pg-schema-diff plan failed (exit ${planResult.status}): ${planStderr || "(no output)"}`
18369
18666
  );
@@ -18421,6 +18718,10 @@ async function executeApplyWithRetry(applyArgs, verbose, config) {
18421
18718
  }
18422
18719
  logger5.error("pg-schema-diff apply failed:");
18423
18720
  logger5.error(errorOutput);
18721
+ const extDetection = detectMissingExtensionType(errorOutput);
18722
+ if (extDetection.detected) {
18723
+ logger5.error(formatExtensionErrorHint(extDetection));
18724
+ }
18424
18725
  return {
18425
18726
  success: false,
18426
18727
  error: new Error(`pg-schema-diff apply failed: ${errorOutput}`),
@@ -19887,16 +20188,16 @@ var ERROR_MESSAGES2 = {
19887
20188
  SCHEMA_NOT_FOUND: "Schema file not found"
19888
20189
  };
19889
20190
  function containsPathTraversal2(inputPath) {
19890
- const normalized = path10__default.normalize(inputPath);
20191
+ const normalized = path11__default.normalize(inputPath);
19891
20192
  return normalized.includes("..") || inputPath.includes("\0");
19892
20193
  }
19893
20194
  function isPathWithinBase(filePath, baseDir) {
19894
20195
  try {
19895
- const resolvedFile = path10__default.resolve(filePath);
19896
- const resolvedBase = path10__default.resolve(baseDir);
19897
- const normalizedFile = path10__default.normalize(resolvedFile);
19898
- const normalizedBase = path10__default.normalize(resolvedBase);
19899
- return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase + path10__default.sep);
20196
+ const resolvedFile = path11__default.resolve(filePath);
20197
+ const resolvedBase = path11__default.resolve(baseDir);
20198
+ const normalizedFile = path11__default.normalize(resolvedFile);
20199
+ const normalizedBase = path11__default.normalize(resolvedBase);
20200
+ return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase + path11__default.sep);
19900
20201
  } catch {
19901
20202
  return false;
19902
20203
  }
@@ -19905,13 +20206,13 @@ function validateSchemaPath(dbPackagePath, projectRoot = process.cwd()) {
19905
20206
  if (containsPathTraversal2(dbPackagePath)) {
19906
20207
  throw new Error(ERROR_MESSAGES2.PATH_TRAVERSAL);
19907
20208
  }
19908
- const schemaEntry = path10__default.join(dbPackagePath, "src", "schema", "index.ts");
19909
- const absoluteSchemaPath = path10__default.resolve(projectRoot, schemaEntry);
20209
+ const schemaEntry = path11__default.join(dbPackagePath, "src", "schema", "index.ts");
20210
+ const absoluteSchemaPath = path11__default.resolve(projectRoot, schemaEntry);
19910
20211
  let resolvedProjectRoot;
19911
20212
  try {
19912
20213
  resolvedProjectRoot = realpathSync(projectRoot);
19913
20214
  } catch {
19914
- resolvedProjectRoot = path10__default.resolve(projectRoot);
20215
+ resolvedProjectRoot = path11__default.resolve(projectRoot);
19915
20216
  }
19916
20217
  if (!isPathWithinBase(absoluteSchemaPath, resolvedProjectRoot)) {
19917
20218
  throw new Error(ERROR_MESSAGES2.PATH_TRAVERSAL);
@@ -20043,7 +20344,7 @@ function diffSchema(params) {
20043
20344
  };
20044
20345
  }
20045
20346
  function extractTablesFromIdempotentSql(idempotentDir, projectRoot = process.cwd()) {
20046
- const fullPath = path10__default.resolve(projectRoot, idempotentDir);
20347
+ const fullPath = path11__default.resolve(projectRoot, idempotentDir);
20047
20348
  if (!existsSync(fullPath)) {
20048
20349
  return [];
20049
20350
  }
@@ -20052,7 +20353,7 @@ function extractTablesFromIdempotentSql(idempotentDir, projectRoot = process.cwd
20052
20353
  try {
20053
20354
  const files = readdirSync(fullPath).filter((f) => f.endsWith(".sql"));
20054
20355
  for (const file of files) {
20055
- const filePath = path10__default.join(fullPath, file);
20356
+ const filePath = path11__default.join(fullPath, file);
20056
20357
  const content = readFileSync(filePath, "utf-8");
20057
20358
  const contentWithoutComments = content.replace(/--.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
20058
20359
  for (const match of contentWithoutComments.matchAll(createTablePattern)) {
@@ -20275,7 +20576,7 @@ async function validateGitHubOutputPath(filePath) {
20275
20576
  if (!filePath || filePath.trim().length === 0) {
20276
20577
  return { valid: false, resolvedPath: null, error: "Empty file path" };
20277
20578
  }
20278
- const normalizedPath = path10__default.normalize(filePath);
20579
+ const normalizedPath = path11__default.normalize(filePath);
20279
20580
  if (normalizedPath.includes("..")) {
20280
20581
  return {
20281
20582
  valid: false,
@@ -20283,7 +20584,7 @@ async function validateGitHubOutputPath(filePath) {
20283
20584
  error: "Path traversal detected (..) in file path"
20284
20585
  };
20285
20586
  }
20286
- const absolutePath = path10__default.resolve(normalizedPath);
20587
+ const absolutePath = path11__default.resolve(normalizedPath);
20287
20588
  for (const forbidden of FORBIDDEN_PATHS) {
20288
20589
  if (absolutePath.startsWith(forbidden) || absolutePath.includes(forbidden)) {
20289
20590
  return {
@@ -20762,7 +21063,7 @@ async function analyzeSchemaChanges() {
20762
21063
  try {
20763
21064
  const { getDatabasePackagePath: getDatabasePackagePath2 } = await Promise.resolve().then(() => (init_config_loader(), config_loader_exports));
20764
21065
  const dbPath = await getDatabasePackagePath2();
20765
- const schemaPath = path10__default.join(dbPath, "src/schema/");
21066
+ const schemaPath = path11__default.join(dbPath, "src/schema/");
20766
21067
  const { stdout } = await execa("git", ["diff", "--cached", "--", schemaPath]);
20767
21068
  const lines = stdout.split("\n");
20768
21069
  return parseDiffLines(lines);
@@ -21041,7 +21342,7 @@ function categorizeRisks(risks) {
21041
21342
  }
21042
21343
 
21043
21344
  // src/commands/db/utils/preflight-check.ts
21044
- init_constants();
21345
+ init_local_supabase();
21045
21346
  init_config_loader();
21046
21347
  function createInitialResult() {
21047
21348
  return {
@@ -21095,7 +21396,7 @@ function runDatabasePackageChecks(result, logger16, step) {
21095
21396
  logger16.error("Database package path is missing");
21096
21397
  return null;
21097
21398
  }
21098
- logger16.success(`Found database package: ${path10__default.basename(dbPackagePath)}`);
21399
+ logger16.success(`Found database package: ${path11__default.basename(dbPackagePath)}`);
21099
21400
  logger16.step("Checking schema files", step.next());
21100
21401
  const schemaCheck = checkSchemaFiles(dbPackagePath);
21101
21402
  if (!schemaCheck.exists) {
@@ -21219,9 +21520,9 @@ ${stderr}`.toLowerCase();
21219
21520
  }
21220
21521
  }
21221
21522
  async function testDatabaseConnection(projectRoot) {
21222
- const ports = detectSupabasePorts(projectRoot);
21223
- const dbPort = ports.db;
21224
- const connectionUrl = `postgresql://postgres:postgres@127.0.0.1:${dbPort}/postgres`;
21523
+ const resolvedRoot = process.cwd();
21524
+ const connectionUrl = buildLocalDatabaseUrl(resolvedRoot);
21525
+ const dbPort = detectLocalSupabasePorts(resolvedRoot).db;
21225
21526
  let sql = null;
21226
21527
  try {
21227
21528
  sql = postgres(connectionUrl, {
@@ -21243,12 +21544,12 @@ async function testDatabaseConnection(projectRoot) {
21243
21544
  function checkDatabasePackage() {
21244
21545
  const cwd = process.cwd();
21245
21546
  const locations = [
21246
- path10__default.join(cwd, "packages", "database"),
21247
- path10__default.join(cwd, "packages", "db"),
21248
- path10__default.join(cwd, "db")
21547
+ path11__default.join(cwd, "packages", "database"),
21548
+ path11__default.join(cwd, "packages", "db"),
21549
+ path11__default.join(cwd, "db")
21249
21550
  ];
21250
21551
  for (const location of locations) {
21251
- const configPath = path10__default.join(location, "drizzle.config.ts");
21552
+ const configPath = path11__default.join(location, "drizzle.config.ts");
21252
21553
  if (existsSync(configPath)) {
21253
21554
  return { exists: true, path: location };
21254
21555
  }
@@ -21293,7 +21594,7 @@ function countTsFilesRecursive(dir) {
21293
21594
  try {
21294
21595
  const entries = readdirSync(dir, { withFileTypes: true });
21295
21596
  for (const entry of entries) {
21296
- const fullPath = path10__default.join(dir, entry.name);
21597
+ const fullPath = path11__default.join(dir, entry.name);
21297
21598
  if (entry.isDirectory()) {
21298
21599
  count += countTsFilesRecursive(fullPath);
21299
21600
  } else if (entry.isFile() && entry.name.endsWith(".ts")) {
@@ -21305,7 +21606,7 @@ function countTsFilesRecursive(dir) {
21305
21606
  return count;
21306
21607
  }
21307
21608
  function checkSchemaFiles(dbPackagePath) {
21308
- const schemaDir = path10__default.join(dbPackagePath, "src", "schema");
21609
+ const schemaDir = path11__default.join(dbPackagePath, "src", "schema");
21309
21610
  if (!existsSync(schemaDir)) {
21310
21611
  return { exists: false, count: 0 };
21311
21612
  }
@@ -21342,9 +21643,9 @@ async function runOrphanCheck(env2, dbPackagePath, result, logger16, step) {
21342
21643
  logger16.step("Checking for orphaned database objects", step.next());
21343
21644
  try {
21344
21645
  const { expectedTables, expectedEnums } = await extractSchemaTablesAndEnums(dbPackagePath);
21345
- const databaseUrl = tryResolveDatabaseUrl("local") || "postgresql://postgres:postgres@localhost:54322/postgres";
21646
+ const databaseUrl = tryResolveDatabaseUrl("local") || buildLocalDatabaseUrl(process.cwd());
21346
21647
  const { dbTables, dbEnums } = await fetchDbTablesAndEnums(databaseUrl, {
21347
- schemaDir: path10__default.join(dbPackagePath, "src", "schema")
21648
+ schemaDir: path11__default.join(dbPackagePath, "src", "schema")
21348
21649
  });
21349
21650
  let excludeFromOrphanDetection = [];
21350
21651
  let idempotentSqlDir = "supabase/schemas/idempotent";
@@ -21386,31 +21687,39 @@ function runExtensionConfigCheck(_result, logger16, step) {
21386
21687
  logger16.step("Checking PostgreSQL extension configuration", step.next());
21387
21688
  try {
21388
21689
  const extensionResult = checkExtensionConfig(process.cwd());
21389
- if (extensionResult.usedExtensions.length === 0) {
21690
+ if (!extensionResult || typeof extensionResult !== "object") {
21691
+ logger16.warn("Extension config check returned invalid result");
21692
+ return;
21693
+ }
21694
+ const usedExtensions = extensionResult.usedExtensions ?? [];
21695
+ if (usedExtensions.length === 0) {
21390
21696
  logger16.success("No extensions detected in SQL files");
21391
21697
  return;
21392
21698
  }
21699
+ const sqlManaged = extensionResult.sqlManagedExtensions ?? [];
21700
+ const supabaseManaged = extensionResult.supabaseManagedExtensions ?? [];
21393
21701
  const parts = [];
21394
- if (extensionResult.sqlManagedExtensions.length > 0) {
21395
- parts.push(`${extensionResult.sqlManagedExtensions.length} SQL-managed`);
21702
+ if (sqlManaged.length > 0) {
21703
+ parts.push(`${sqlManaged.length} SQL-managed`);
21396
21704
  }
21397
- if (extensionResult.supabaseManagedExtensions.length > 0) {
21398
- parts.push(`${extensionResult.supabaseManagedExtensions.length} Supabase-managed`);
21705
+ if (supabaseManaged.length > 0) {
21706
+ parts.push(`${supabaseManaged.length} Supabase-managed`);
21399
21707
  }
21400
21708
  const summary = parts.join(", ");
21401
- logger16.success(`${extensionResult.usedExtensions.length} extension(s) found (${summary})`);
21402
- for (const note of extensionResult.notes) {
21709
+ logger16.success(`${usedExtensions.length} extension(s) found (${summary})`);
21710
+ const notes = extensionResult.notes ?? [];
21711
+ for (const note of notes) {
21403
21712
  logger16.info(` ${note}`);
21404
21713
  }
21405
21714
  } catch (error) {
21406
21715
  const message = error instanceof Error ? error.message : "Unknown error";
21407
- logger16.warn(`Extension config check skipped: ${message}`);
21716
+ logger16.warn(`Extension config check failed: ${message}`);
21408
21717
  }
21409
21718
  }
21410
21719
  async function runSqlSchemaRiskCheck(result, logger16, step) {
21411
21720
  logger16.step("Checking SQL schema for risky patterns", step.next());
21412
21721
  const cwd = process.cwd();
21413
- const sqlDir = path10__default.join(cwd, "supabase", "schemas", "declarative");
21722
+ const sqlDir = path11__default.join(cwd, "supabase", "schemas", "declarative");
21414
21723
  if (!existsSync(sqlDir)) {
21415
21724
  logger16.success("No SQL schema directory found (supabase/schemas/declarative/)");
21416
21725
  return;
@@ -21423,7 +21732,7 @@ async function runSqlSchemaRiskCheck(result, logger16, step) {
21423
21732
  }
21424
21733
  const allRisks = [];
21425
21734
  for (const sqlFile of sqlFiles) {
21426
- const filePath = path10__default.join(sqlDir, sqlFile);
21735
+ const filePath = path11__default.join(sqlDir, sqlFile);
21427
21736
  const risks = await detectSchemaRisks(filePath);
21428
21737
  for (const risk of risks) {
21429
21738
  allRisks.push({ ...risk, file: sqlFile });
@@ -23175,7 +23484,7 @@ async function checkPort(port) {
23175
23484
  };
23176
23485
  }
23177
23486
  function detectSupabasePortsFromConfig() {
23178
- const configPath = path10__default.join(process.cwd(), "supabase", "config.toml");
23487
+ const configPath = path11__default.join(process.cwd(), "supabase", "config.toml");
23179
23488
  const BASE_PORTS = { api: 54321, db: 54322, studio: 54323, inbucket: 54324 };
23180
23489
  if (!existsSync(configPath)) {
23181
23490
  return Object.values(BASE_PORTS);
@@ -23264,7 +23573,7 @@ var BASE_PORT = 54321;
23264
23573
  var PORTS_PER_SLOT = 10;
23265
23574
  var TOTAL_SLOTS = 100;
23266
23575
  function calculatePortOffset(projectPath) {
23267
- const normalizedPath = path10__default.resolve(projectPath);
23576
+ const normalizedPath = path11__default.resolve(projectPath);
23268
23577
  const hash = createHash("md5").update(normalizedPath).digest("hex");
23269
23578
  return parseInt(hash.slice(0, 8), 16) % TOTAL_SLOTS;
23270
23579
  }
@@ -23285,7 +23594,7 @@ function getSupabasePorts(projectPath) {
23285
23594
  }
23286
23595
  function updateSupabaseConfigPorts(projectPath) {
23287
23596
  const ports = getSupabasePorts(projectPath);
23288
- const configPath = path10__default.join(projectPath, "supabase", "config.toml");
23597
+ const configPath = path11__default.join(projectPath, "supabase", "config.toml");
23289
23598
  if (!existsSync(configPath)) {
23290
23599
  return { updated: false, ports, configPath };
23291
23600
  }
@@ -23320,7 +23629,7 @@ function getPortAllocationSummary(projectPath) {
23320
23629
  const ports = getSupabasePorts(projectPath);
23321
23630
  const offset = calculatePortOffset(projectPath);
23322
23631
  return [
23323
- `Port allocation for: ${path10__default.basename(projectPath)}`,
23632
+ `Port allocation for: ${path11__default.basename(projectPath)}`,
23324
23633
  ` Slot: ${offset} (hash-based)`,
23325
23634
  ` API: ${ports.api}`,
23326
23635
  ` DB: ${ports.db}`,
@@ -23354,7 +23663,7 @@ function parseSeedPaths(configPath) {
23354
23663
  }
23355
23664
  }
23356
23665
  async function applySeedFile(seedPath, dbUrl) {
23357
- const supabaseDir = path10__default.join(process.cwd(), "supabase");
23666
+ const supabaseDir = path11__default.join(process.cwd(), "supabase");
23358
23667
  const absolutePath = resolveSafePath(supabaseDir, seedPath);
23359
23668
  if (!existsSync(absolutePath)) {
23360
23669
  return;
@@ -23365,12 +23674,12 @@ async function applySeedFile(seedPath, dbUrl) {
23365
23674
  });
23366
23675
  }
23367
23676
  async function applySeeds2(configPath) {
23368
- const configFile = path10__default.join(process.cwd(), "supabase", "config.toml");
23677
+ const configFile = path11__default.join(process.cwd(), "supabase", "config.toml");
23369
23678
  const seedPaths = parseSeedPaths(configFile);
23370
23679
  if (seedPaths.length === 0) {
23371
23680
  return;
23372
23681
  }
23373
- const supabaseDir = path10__default.join(process.cwd(), "supabase");
23682
+ const supabaseDir = path11__default.join(process.cwd(), "supabase");
23374
23683
  const safePaths = filterSafePaths(seedPaths, supabaseDir);
23375
23684
  if (safePaths.length === 0) {
23376
23685
  return;
@@ -23788,7 +24097,7 @@ var validateCommand = new Command("validate").description("Validate schema files
23788
24097
  const logger16 = createCLILogger("db:validate");
23789
24098
  try {
23790
24099
  logger16.section("Schema Validation");
23791
- const schemasPath = path10__default.join(process.cwd(), "packages", "database", "src", "schema");
24100
+ const schemasPath = path11__default.join(process.cwd(), "packages", "database", "src", "schema");
23792
24101
  if (!existsSync(schemasPath)) {
23793
24102
  throw new CLIError("Schema directory not found", "SCHEMA_DIR_NOT_FOUND", [
23794
24103
  `Expected location: ${schemasPath}`,
@@ -23953,8 +24262,8 @@ var generateCommand = new Command("generate").description("Generate TypeScript t
23953
24262
  var listCommand = new Command("list").description("List managed schemas from drizzle.config.ts").option("--sql", "Output as SQL-compatible string for IN clauses").option("--json", "Output as JSON array").action(async (options) => {
23954
24263
  const logger16 = createCLILogger("db:schema:list");
23955
24264
  try {
23956
- const dbPackagePath = path10__default.join(process.cwd(), "packages", "database");
23957
- if (!existsSync(path10__default.join(dbPackagePath, "drizzle.config.ts"))) {
24265
+ const dbPackagePath = path11__default.join(process.cwd(), "packages", "database");
24266
+ if (!existsSync(path11__default.join(dbPackagePath, "drizzle.config.ts"))) {
23958
24267
  throw new CLIError("drizzle.config.ts not found", "CONFIG_NOT_FOUND", [
23959
24268
  `Expected location: ${dbPackagePath}/drizzle.config.ts`,
23960
24269
  "Ensure you are in the project root",
@@ -25193,7 +25502,7 @@ var testGenCommand = new Command("test:gen").description("Generate pgTAP behavio
25193
25502
  const databaseUrl = options.db || process.env.DATABASE_URL || getLocalDbUrl();
25194
25503
  const schemas = options.schemas ? options.schemas.split(",") : void 0;
25195
25504
  const dbPackage = databasePaths.package();
25196
- const defaultOutputPath = path10__default.join(dbPackage, "tests/00_behavior.generated.test.sql");
25505
+ const defaultOutputPath = path11__default.join(dbPackage, "tests/00_behavior.generated.test.sql");
25197
25506
  const outputPath = options.output || defaultOutputPath;
25198
25507
  spinner.text = "Generating pgTAP behavior tests...";
25199
25508
  const result = await dbGeneratePgTapTests({
@@ -26205,108 +26514,8 @@ async function getVercelRootDirectory() {
26205
26514
  return info?.rootDirectory ?? null;
26206
26515
  }
26207
26516
 
26208
- // src/commands/env/constants/local-supabase.ts
26209
- init_esm_shims();
26210
- var DEFAULT_API_PORT = 54321;
26211
- var DEFAULT_DB_PORT = 54322;
26212
- function parsePortFromToml(content, section, key) {
26213
- const sectionRegex = new RegExp(`\\[${section}\\]([\\s\\S]*?)(?=\\n\\[|$)`, "g");
26214
- const sectionMatch = sectionRegex.exec(content);
26215
- if (!sectionMatch) return null;
26216
- const sectionContent = sectionMatch[1];
26217
- const keyRegex = new RegExp(`^\\s*${key}\\s*=\\s*(\\d+)`, "m");
26218
- const keyMatch = keyRegex.exec(sectionContent);
26219
- if (!keyMatch) return null;
26220
- const port = Number.parseInt(keyMatch[1], 10);
26221
- return Number.isFinite(port) && port > 0 && port < 65536 ? port : null;
26222
- }
26223
- function readPortsFromConfigToml(projectRoot) {
26224
- const configPath = path10__default.join(projectRoot, "supabase", "config.toml");
26225
- try {
26226
- const content = readFileSync(configPath, "utf-8");
26227
- const apiPort = parsePortFromToml(content, "api", "port");
26228
- const dbPort = parsePortFromToml(content, "db", "port");
26229
- if (apiPort !== null || dbPort !== null) {
26230
- return {
26231
- api: apiPort ?? DEFAULT_API_PORT,
26232
- db: dbPort ?? DEFAULT_DB_PORT
26233
- };
26234
- }
26235
- return null;
26236
- } catch {
26237
- return null;
26238
- }
26239
- }
26240
- function detectLocalSupabasePorts(projectRoot = process.cwd()) {
26241
- const configPorts = readPortsFromConfigToml(projectRoot);
26242
- if (configPorts) {
26243
- return configPorts;
26244
- }
26245
- return {
26246
- api: DEFAULT_API_PORT,
26247
- db: DEFAULT_DB_PORT
26248
- };
26249
- }
26250
- var LOCAL_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
26251
- var LOCAL_SUPABASE_SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU";
26252
- function buildLocalSupabaseUrl(projectRoot = process.cwd()) {
26253
- const ports = detectLocalSupabasePorts(projectRoot);
26254
- return `http://127.0.0.1:${ports.api}`;
26255
- }
26256
- function buildLocalDatabaseUrl(projectRoot = process.cwd()) {
26257
- const ports = detectLocalSupabasePorts(projectRoot);
26258
- return `postgresql://postgres:postgres@127.0.0.1:${ports.db}/postgres`;
26259
- }
26260
- function getLocalSupabaseEnvValues(projectRoot = process.cwd()) {
26261
- const supabaseUrl = buildLocalSupabaseUrl(projectRoot);
26262
- const databaseUrl = buildLocalDatabaseUrl(projectRoot);
26263
- return {
26264
- // Database URLs
26265
- DATABASE_URL: databaseUrl,
26266
- DATABASE_URL_ADMIN: databaseUrl,
26267
- DATABASE_URL_SERVICE: databaseUrl,
26268
- // Supabase URLs and keys
26269
- NEXT_PUBLIC_SUPABASE_URL: supabaseUrl,
26270
- NEXT_PUBLIC_SUPABASE_ANON_KEY: LOCAL_SUPABASE_ANON_KEY,
26271
- SUPABASE_SERVICE_ROLE_KEY: LOCAL_SUPABASE_SERVICE_ROLE_KEY
26272
- };
26273
- }
26274
- function getLocalValueDescriptions(projectRoot = process.cwd()) {
26275
- const ports = detectLocalSupabasePorts(projectRoot);
26276
- return {
26277
- DATABASE_URL: `localhost:${ports.db} (PostgreSQL)`,
26278
- DATABASE_URL_ADMIN: `localhost:${ports.db} (PostgreSQL)`,
26279
- DATABASE_URL_SERVICE: `localhost:${ports.db} (PostgreSQL)`,
26280
- NEXT_PUBLIC_SUPABASE_URL: `localhost:${ports.api} (Supabase API)`,
26281
- NEXT_PUBLIC_SUPABASE_ANON_KEY: "local anon key (supabase-demo)",
26282
- SUPABASE_SERVICE_ROLE_KEY: "local service key (supabase-demo)"
26283
- };
26284
- }
26285
- var LOCAL_SUPABASE_ENV_VALUES = getLocalSupabaseEnvValues();
26286
- getLocalValueDescriptions();
26287
- function validateLocalhostValues(envValues) {
26288
- const urlKeys = [
26289
- "DATABASE_URL",
26290
- "DATABASE_URL_ADMIN",
26291
- "DATABASE_URL_SERVICE",
26292
- "NEXT_PUBLIC_SUPABASE_URL"
26293
- ];
26294
- const invalidEntries = [];
26295
- for (const key of urlKeys) {
26296
- const value = envValues[key];
26297
- if (value && !value.includes("127.0.0.1") && !value.includes("localhost")) {
26298
- invalidEntries.push(key);
26299
- }
26300
- }
26301
- if (invalidEntries.length > 0) {
26302
- throw new Error(
26303
- `LOCAL_SUPABASE_ENV_VALUES safety check failed: The following keys do not point to localhost: ${invalidEntries.join(", ")}. This is a safety feature to prevent accidental production database connections during local development.`
26304
- );
26305
- }
26306
- }
26307
- validateLocalhostValues(LOCAL_SUPABASE_ENV_VALUES);
26308
-
26309
26517
  // src/commands/env/commands/env-pull.ts
26518
+ init_local_supabase();
26310
26519
  var ERROR_MESSAGES3 = {
26311
26520
  INVALID_PATH: "Invalid working directory path",
26312
26521
  PATH_TRAVERSAL: "Working directory path validation failed",
@@ -26338,16 +26547,16 @@ function sanitizeErrorMessage(message) {
26338
26547
  return sanitized;
26339
26548
  }
26340
26549
  function containsPathTraversal3(inputPath) {
26341
- const normalized = path10__default.normalize(inputPath);
26550
+ const normalized = path11__default.normalize(inputPath);
26342
26551
  return normalized.includes("..") || inputPath.includes("\0");
26343
26552
  }
26344
26553
  function isPathWithinBase2(filePath, baseDir) {
26345
26554
  try {
26346
- const resolvedFile = path10__default.resolve(filePath);
26347
- const resolvedBase = path10__default.resolve(baseDir);
26348
- const normalizedFile = path10__default.normalize(resolvedFile);
26349
- const normalizedBase = path10__default.normalize(resolvedBase);
26350
- return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase + path10__default.sep);
26555
+ const resolvedFile = path11__default.resolve(filePath);
26556
+ const resolvedBase = path11__default.resolve(baseDir);
26557
+ const normalizedFile = path11__default.normalize(resolvedFile);
26558
+ const normalizedBase = path11__default.normalize(resolvedBase);
26559
+ return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase + path11__default.sep);
26351
26560
  } catch {
26352
26561
  return false;
26353
26562
  }
@@ -26356,12 +26565,12 @@ function validateCustomWorkingDir(cwdPath, projectRoot) {
26356
26565
  if (containsPathTraversal3(cwdPath)) {
26357
26566
  throw new CLIError(ERROR_MESSAGES3.PATH_TRAVERSAL, "ENV_PULL_PATH_TRAVERSAL");
26358
26567
  }
26359
- const absolutePath = path10__default.isAbsolute(cwdPath) ? cwdPath : path10__default.resolve(projectRoot, cwdPath);
26568
+ const absolutePath = path11__default.isAbsolute(cwdPath) ? cwdPath : path11__default.resolve(projectRoot, cwdPath);
26360
26569
  let resolvedProjectRoot;
26361
26570
  try {
26362
26571
  resolvedProjectRoot = realpathSync(projectRoot);
26363
26572
  } catch {
26364
- resolvedProjectRoot = path10__default.resolve(projectRoot);
26573
+ resolvedProjectRoot = path11__default.resolve(projectRoot);
26365
26574
  }
26366
26575
  if (!isPathWithinBase2(absolutePath, resolvedProjectRoot)) {
26367
26576
  throw new CLIError(ERROR_MESSAGES3.PATH_TRAVERSAL, "ENV_PULL_PATH_TRAVERSAL");
@@ -26388,6 +26597,27 @@ function validateAppDirectory2(appName, projectRoot) {
26388
26597
  }
26389
26598
  return appDir;
26390
26599
  }
26600
+ var LOCAL_BOOTSTRAP_REQUIRED_KEYS = [
26601
+ "LOCAL_SUPABASE_HOST",
26602
+ "LOCAL_SUPABASE_API_PORT",
26603
+ "LOCAL_SUPABASE_DB_PORT"
26604
+ ];
26605
+ function getMissingLocalBootstrapKeys(parsed) {
26606
+ return LOCAL_BOOTSTRAP_REQUIRED_KEYS.filter((key) => !(key in parsed));
26607
+ }
26608
+ function getLocalBootstrapStatusFromParsed(parsed) {
26609
+ const missing = getMissingLocalBootstrapKeys(parsed);
26610
+ return {
26611
+ status: missing.length === 0 ? "ok" : "partial",
26612
+ missing
26613
+ };
26614
+ }
26615
+ function missingLocalBootstrapReport() {
26616
+ return {
26617
+ status: "missing",
26618
+ missing: [...LOCAL_BOOTSTRAP_REQUIRED_KEYS]
26619
+ };
26620
+ }
26391
26621
  var EnvPullOutputSchema = z.object({
26392
26622
  results: z.array(
26393
26623
  z.object({
@@ -26401,6 +26631,10 @@ var EnvPullOutputSchema = z.object({
26401
26631
  totalPulled: z.number(),
26402
26632
  totalFailed: z.number(),
26403
26633
  totalEncrypted: z.number().optional(),
26634
+ localBootstrap: z.object({
26635
+ status: z.enum(["ok", "partial", "missing"]),
26636
+ missing: z.array(z.string())
26637
+ }).optional(),
26404
26638
  /** Vercel Root Directory sync result */
26405
26639
  vercelSync: z.object({
26406
26640
  detected: z.boolean(),
@@ -26533,60 +26767,74 @@ function removePrivateKeysFromEnvFile(filePath) {
26533
26767
  writeFileSync(filePath, `${newContent}
26534
26768
  `, "utf-8");
26535
26769
  }
26536
- function replaceWithLocalValues(filePath, logger16, dryRun = false) {
26770
+ function replaceWithLocalValues(filePath, workDir, logger16, dryRun = false) {
26537
26771
  if (!existsSync(filePath)) {
26538
26772
  logger16.warn(" \u26A0\uFE0F .env.development not found (was pull successful?)");
26539
- return;
26773
+ return missingLocalBootstrapReport();
26540
26774
  }
26541
26775
  const content = readFileSync(filePath, "utf-8");
26542
26776
  if (!content.trim()) {
26543
26777
  logger16.warn(" \u26A0\uFE0F .env.development is empty (no env vars in Vercel?)");
26544
- return;
26778
+ return missingLocalBootstrapReport();
26545
26779
  }
26546
26780
  const parsed = parse(content);
26547
26781
  if (Object.keys(parsed).length === 0) {
26548
26782
  logger16.warn(" \u26A0\uFE0F No valid env vars found in .env.development (check syntax)");
26549
- return;
26783
+ return missingLocalBootstrapReport();
26550
26784
  }
26551
- const projectRoot = process.cwd();
26552
- const localEnvValues = getLocalSupabaseEnvValues(projectRoot);
26553
- const localDescriptions = getLocalValueDescriptions(projectRoot);
26785
+ const localEnvValues = getLocalSupabaseEnvValues(workDir);
26786
+ const localDescriptions = getLocalValueDescriptions(workDir);
26554
26787
  const replacementKeys = Object.keys(localEnvValues);
26555
26788
  const replacedKeys = [];
26789
+ const hasAnySupabaseKey = Object.keys(parsed).some((key) => key.includes("SUPABASE") || key.includes("DATABASE_URL")) || replacementKeys.some((key) => key in parsed);
26556
26790
  for (const key of replacementKeys) {
26557
- if (key in parsed && localEnvValues[key]) {
26791
+ if (key in parsed || hasAnySupabaseKey) {
26558
26792
  parsed[key] = localEnvValues[key];
26559
26793
  replacedKeys.push(key);
26560
26794
  }
26561
26795
  }
26562
26796
  if (replacedKeys.length === 0) {
26563
- const hasAnySupabaseKey = Object.keys(parsed).some(
26797
+ const hasAnySupabaseKey2 = Object.keys(parsed).some(
26564
26798
  (k) => k.includes("SUPABASE") || k.includes("DATABASE_URL")
26565
26799
  );
26566
- if (hasAnySupabaseKey) {
26800
+ if (hasAnySupabaseKey2) {
26567
26801
  logger16.warn(" \u26A0\uFE0F Found Supabase keys but none matched local replacement patterns");
26568
26802
  } else {
26569
26803
  logger16.info(" No Supabase variables found (may be expected for new projects)");
26570
26804
  }
26571
- return;
26805
+ return getLocalBootstrapStatusFromParsed(parsed);
26806
+ }
26807
+ const bootstrapStatus = getLocalBootstrapStatusFromParsed(parsed);
26808
+ if (bootstrapStatus.missing.length > 0) {
26809
+ logger16.warn(
26810
+ ` \u26A0\uFE0F Some local bootstrap keys were not updated: ${bootstrapStatus.missing.join(", ")}`
26811
+ );
26572
26812
  }
26813
+ const ensureRequired = bootstrapStatus.status === "ok";
26573
26814
  const newContent = Object.entries(parsed).map(([key, value]) => `${key}=${formatEnvValue(value)}`).join("\n");
26574
26815
  if (dryRun) {
26575
- logger16.info(` \u{1F3E0} Would replace ${replacedKeys.length} variables with localhost values:`);
26816
+ logger16.info(` \u{1F3E0} Would replace ${replacedKeys.length} variables with local values:`);
26576
26817
  for (const key of replacedKeys) {
26577
26818
  const description = localDescriptions[key] || "localhost";
26578
26819
  logger16.info(` ${key} \u2192 ${description}`);
26579
26820
  }
26821
+ logger16.info(
26822
+ ` ${ensureRequired ? "\u2705" : "\u26A0\uFE0F"} Local bootstrap keys ready: ${ensureRequired ? "yes" : "partial"}`
26823
+ );
26580
26824
  logger16.info(" (dry-run: no files modified)");
26581
- return;
26825
+ return bootstrapStatus;
26582
26826
  }
26583
26827
  writeFileSync(filePath, `${newContent}
26584
26828
  `, "utf-8");
26585
- logger16.success(` \u{1F3E0} Replaced ${replacedKeys.length} variables with localhost values:`);
26829
+ logger16.success(` \u{1F3E0} Replaced ${replacedKeys.length} variables with local values:`);
26586
26830
  for (const key of replacedKeys) {
26587
26831
  const description = localDescriptions[key] || "localhost";
26588
26832
  logger16.info(` ${key} \u2192 ${description}`);
26589
26833
  }
26834
+ logger16.info(
26835
+ ` ${ensureRequired ? "\u2705" : "\u26A0\uFE0F"} Local bootstrap keys ready: ${ensureRequired ? "yes" : "partial"}`
26836
+ );
26837
+ return bootstrapStatus;
26590
26838
  }
26591
26839
  async function encryptFile2(workDir, filePath, logger16) {
26592
26840
  if (!existsSync(filePath)) {
@@ -26818,13 +27066,20 @@ async function runEnvPullAction(options) {
26818
27066
  }
26819
27067
  logger16.info("");
26820
27068
  const results = await pullAllEnvironments(workDir, environments, auth, logger16);
26821
- if (!options.productionAll) {
27069
+ const shouldEvaluateLocalBootstrap = !options.productionAll && (!options.environment || options.environment === "development");
27070
+ let localBootstrap;
27071
+ if (shouldEvaluateLocalBootstrap) {
26822
27072
  const devResult = results.find((r) => r.environment === "development" && r.success);
26823
27073
  if (devResult) {
26824
27074
  logger16.info("");
26825
27075
  logger16.info("Applying local Supabase values to .env.development...");
26826
- replaceWithLocalValues(devResult.outputPath, logger16, options.check);
27076
+ localBootstrap = replaceWithLocalValues(devResult.outputPath, workDir, logger16, options.check);
27077
+ } else {
27078
+ localBootstrap = missingLocalBootstrapReport();
27079
+ logger16.warn(" LOCAL_BOOTSTRAP: skipped (development env pull failed or missing)");
26827
27080
  }
27081
+ } else {
27082
+ localBootstrap = void 0;
26828
27083
  }
26829
27084
  if (options.encrypt && !options.check) {
26830
27085
  await encryptPulledFiles(workDir, results, logger16);
@@ -26845,6 +27100,7 @@ async function runEnvPullAction(options) {
26845
27100
  totalPulled,
26846
27101
  totalFailed,
26847
27102
  totalEncrypted: options.encrypt ? totalEncrypted : void 0,
27103
+ localBootstrap,
26848
27104
  vercelSync: vercelSyncResult
26849
27105
  });
26850
27106
  if (totalFailed > 0) {
@@ -28584,13 +28840,13 @@ z.object({
28584
28840
 
28585
28841
  // src/commands/hotfix/metadata.ts
28586
28842
  function getHotfixDir(targetDir) {
28587
- return path10__default.join(targetDir, ".runa", "hotfix");
28843
+ return path11__default.join(targetDir, ".runa", "hotfix");
28588
28844
  }
28589
28845
  function getCurrentFile(targetDir) {
28590
- return path10__default.join(getHotfixDir(targetDir), "current.json");
28846
+ return path11__default.join(getHotfixDir(targetDir), "current.json");
28591
28847
  }
28592
28848
  function getArchiveDir(targetDir) {
28593
- return path10__default.join(getHotfixDir(targetDir), "archive");
28849
+ return path11__default.join(getHotfixDir(targetDir), "archive");
28594
28850
  }
28595
28851
  async function ensureHotfixDir(targetDir) {
28596
28852
  await mkdir(getHotfixDir(targetDir), { recursive: true });
@@ -28600,7 +28856,7 @@ async function ensureArchiveDir(targetDir) {
28600
28856
  }
28601
28857
  async function getHotfixMetadata(input3 = {}) {
28602
28858
  const parsed = GetHotfixInputSchema.parse(input3);
28603
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
28859
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28604
28860
  const currentFile = getCurrentFile(targetDir);
28605
28861
  if (!existsSync(currentFile)) {
28606
28862
  return null;
@@ -28610,7 +28866,7 @@ async function getHotfixMetadata(input3 = {}) {
28610
28866
  }
28611
28867
  async function createHotfixMetadata(input3) {
28612
28868
  const parsed = CreateHotfixMetadataInputSchema.parse(input3);
28613
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
28869
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28614
28870
  await ensureHotfixDir(targetDir);
28615
28871
  const metadata = {
28616
28872
  branch: parsed.branch,
@@ -28627,7 +28883,7 @@ async function createHotfixMetadata(input3) {
28627
28883
  }
28628
28884
  async function updateHotfixStatus(input3) {
28629
28885
  const parsed = UpdateHotfixInputSchema.parse(input3);
28630
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
28886
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28631
28887
  const current = await getHotfixMetadata({ targetDir });
28632
28888
  if (!current) {
28633
28889
  throw createError("HOTFIX_NOT_FOUND");
@@ -28644,13 +28900,13 @@ async function updateHotfixStatus(input3) {
28644
28900
  return updated;
28645
28901
  }
28646
28902
  async function archiveHotfix(targetDir) {
28647
- const dir = targetDir ? path10__default.resolve(targetDir) : process.cwd();
28903
+ const dir = targetDir ? path11__default.resolve(targetDir) : process.cwd();
28648
28904
  const current = await getHotfixMetadata({ targetDir: dir });
28649
28905
  if (!current) {
28650
28906
  throw createError("HOTFIX_NOT_FOUND");
28651
28907
  }
28652
28908
  await ensureArchiveDir(dir);
28653
- const archiveFile = path10__default.join(
28909
+ const archiveFile = path11__default.join(
28654
28910
  getArchiveDir(dir),
28655
28911
  `${current.branch.replace(/\//g, "-")}-${Date.now()}.json`
28656
28912
  );
@@ -28666,7 +28922,7 @@ async function archiveHotfix(targetDir) {
28666
28922
  return archived;
28667
28923
  }
28668
28924
  async function cancelHotfix(targetDir) {
28669
- const dir = targetDir ? path10__default.resolve(targetDir) : process.cwd();
28925
+ const dir = targetDir ? path11__default.resolve(targetDir) : process.cwd();
28670
28926
  await updateHotfixStatus({
28671
28927
  status: "cancelled",
28672
28928
  completedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -28676,7 +28932,7 @@ async function cancelHotfix(targetDir) {
28676
28932
  }
28677
28933
  async function listArchivedHotfixes(input3 = {}) {
28678
28934
  const parsed = ListArchivedHotfixesInputSchema.parse(input3);
28679
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
28935
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28680
28936
  const archiveDir = getArchiveDir(targetDir);
28681
28937
  if (!existsSync(archiveDir)) {
28682
28938
  return { hotfixes: [] };
@@ -28685,7 +28941,7 @@ async function listArchivedHotfixes(input3 = {}) {
28685
28941
  const hotfixes = [];
28686
28942
  for (const file of files.filter((f) => f.endsWith(".json"))) {
28687
28943
  try {
28688
- const content = await readFile(path10__default.join(archiveDir, file), "utf-8");
28944
+ const content = await readFile(path11__default.join(archiveDir, file), "utf-8");
28689
28945
  hotfixes.push(HotfixMetadataSchema.parse(JSON.parse(content)));
28690
28946
  } catch {
28691
28947
  }
@@ -30185,13 +30441,13 @@ function validateVersion(version) {
30185
30441
  }
30186
30442
  }
30187
30443
  function getCacheBase() {
30188
- return path10__default.join(os.homedir(), ".cache", "runa", "templates");
30444
+ return path11__default.join(os.homedir(), ".cache", "runa", "templates");
30189
30445
  }
30190
30446
  function getCacheDir(version) {
30191
30447
  validateVersion(version);
30192
30448
  const cacheBase = getCacheBase();
30193
- const cacheDir = path10__default.join(cacheBase, version);
30194
- const resolvedCacheDir = path10__default.resolve(cacheDir);
30449
+ const cacheDir = path11__default.join(cacheBase, version);
30450
+ const resolvedCacheDir = path11__default.resolve(cacheDir);
30195
30451
  if (!isPathContained(cacheBase, resolvedCacheDir)) {
30196
30452
  throw new CLIError(
30197
30453
  "Security: cache directory would escape allowed location.",
@@ -30203,7 +30459,7 @@ function getCacheDir(version) {
30203
30459
  }
30204
30460
  function isCached(version) {
30205
30461
  const cacheDir = getCacheDir(version);
30206
- const templatesDir = path10__default.join(cacheDir, "templates");
30462
+ const templatesDir = path11__default.join(cacheDir, "templates");
30207
30463
  return fs5__default.existsSync(templatesDir);
30208
30464
  }
30209
30465
  var scopedAuthToken = null;
@@ -30254,13 +30510,13 @@ async function createTempPackageJson(tempDir, version) {
30254
30510
  [TEMPLATES_PACKAGE_NAME]: version
30255
30511
  }
30256
30512
  };
30257
- await writeFile(path10__default.join(tempDir, "package.json"), JSON.stringify(packageJson, null, 2));
30513
+ await writeFile(path11__default.join(tempDir, "package.json"), JSON.stringify(packageJson, null, 2));
30258
30514
  }
30259
30515
  async function createTempNpmrc(tempDir) {
30260
30516
  const npmrc = `@r06-dev:registry=${GITHUB_PACKAGES_REGISTRY}
30261
30517
  //npm.pkg.github.com/:_authToken=\${NODE_AUTH_TOKEN}
30262
30518
  `;
30263
- await writeFile(path10__default.join(tempDir, ".npmrc"), npmrc);
30519
+ await writeFile(path11__default.join(tempDir, ".npmrc"), npmrc);
30264
30520
  }
30265
30521
  async function installTemplates(tempDir, authToken, verbose) {
30266
30522
  try {
@@ -30318,10 +30574,10 @@ async function installTemplates(tempDir, authToken, verbose) {
30318
30574
  async function verifyNoSymlinks(dir, baseDir) {
30319
30575
  const entries = await readdir(dir, { withFileTypes: true });
30320
30576
  for (const entry of entries) {
30321
- const fullPath = path10__default.join(dir, entry.name);
30577
+ const fullPath = path11__default.join(dir, entry.name);
30322
30578
  const stats = await lstat(fullPath);
30323
30579
  if (stats.isSymbolicLink()) {
30324
- const relativePath = path10__default.relative(baseDir, fullPath);
30580
+ const relativePath = path11__default.relative(baseDir, fullPath);
30325
30581
  throw new CLIError(
30326
30582
  "Security: Symlink detected in template package.",
30327
30583
  "SYMLINK_ATTACK_DETECTED",
@@ -30339,7 +30595,7 @@ async function verifyNoSymlinks(dir, baseDir) {
30339
30595
  }
30340
30596
  }
30341
30597
  async function copyToCache(tempDir, cacheDir) {
30342
- const sourceTemplates = path10__default.join(tempDir, "node_modules", TEMPLATES_PACKAGE_NAME, "templates");
30598
+ const sourceTemplates = path11__default.join(tempDir, "node_modules", TEMPLATES_PACKAGE_NAME, "templates");
30343
30599
  if (!fs5__default.existsSync(sourceTemplates)) {
30344
30600
  throw new CLIError("Templates directory not found in package.", "TEMPLATES_DIR_NOT_FOUND", [
30345
30601
  `Expected: ${sourceTemplates}`,
@@ -30349,7 +30605,7 @@ async function copyToCache(tempDir, cacheDir) {
30349
30605
  }
30350
30606
  await verifyNoSymlinks(sourceTemplates, sourceTemplates);
30351
30607
  await mkdir(cacheDir, { recursive: true });
30352
- const targetTemplates = path10__default.join(cacheDir, "templates");
30608
+ const targetTemplates = path11__default.join(cacheDir, "templates");
30353
30609
  await cp(sourceTemplates, targetTemplates, {
30354
30610
  recursive: true,
30355
30611
  dereference: false
@@ -30371,7 +30627,7 @@ async function fetchTemplates(options = {}) {
30371
30627
  };
30372
30628
  }
30373
30629
  const cacheDir = getCacheDir(version);
30374
- const templatesDir = path10__default.join(cacheDir, "templates");
30630
+ const templatesDir = path11__default.join(cacheDir, "templates");
30375
30631
  if (!fresh && isCached(version)) {
30376
30632
  if (verbose) {
30377
30633
  console.log(`Using cached templates v${version}: ${templatesDir}`);
@@ -30387,7 +30643,7 @@ async function fetchTemplates(options = {}) {
30387
30643
  if (fresh && fs5__default.existsSync(cacheDir)) {
30388
30644
  await rm(cacheDir, { recursive: true, force: true });
30389
30645
  }
30390
- const tempDir = path10__default.join(os.tmpdir(), `runa-templates-${Date.now()}`);
30646
+ const tempDir = path11__default.join(os.tmpdir(), `runa-templates-${Date.now()}`);
30391
30647
  await mkdir(tempDir, { recursive: true });
30392
30648
  try {
30393
30649
  if (verbose) {
@@ -30415,11 +30671,11 @@ async function fetchTemplates(options = {}) {
30415
30671
  }
30416
30672
  var MAX_WORKSPACE_TRAVERSAL_DEPTH = 10;
30417
30673
  function isLegitimateWorkspaceRoot(workspaceRoot) {
30418
- const pnpmWorkspaceFile = path10__default.join(workspaceRoot, "pnpm-workspace.yaml");
30674
+ const pnpmWorkspaceFile = path11__default.join(workspaceRoot, "pnpm-workspace.yaml");
30419
30675
  if (!fs5__default.existsSync(pnpmWorkspaceFile)) {
30420
30676
  return false;
30421
30677
  }
30422
- const rootPackageFile = path10__default.join(workspaceRoot, "package.json");
30678
+ const rootPackageFile = path11__default.join(workspaceRoot, "package.json");
30423
30679
  if (!fs5__default.existsSync(rootPackageFile)) {
30424
30680
  return false;
30425
30681
  }
@@ -30433,24 +30689,24 @@ function isLegitimateWorkspaceRoot(workspaceRoot) {
30433
30689
  }
30434
30690
  }
30435
30691
  function resolveWorkspaceTemplates() {
30436
- let current = path10__default.resolve(process.cwd());
30437
- const root = path10__default.parse(current).root;
30692
+ let current = path11__default.resolve(process.cwd());
30693
+ const root = path11__default.parse(current).root;
30438
30694
  let depth = 0;
30439
30695
  while (current !== root && depth < MAX_WORKSPACE_TRAVERSAL_DEPTH) {
30440
30696
  if (!isLegitimateWorkspaceRoot(current)) {
30441
- current = path10__default.dirname(current);
30697
+ current = path11__default.dirname(current);
30442
30698
  depth++;
30443
30699
  continue;
30444
30700
  }
30445
- const packagesTemplates = path10__default.join(current, "packages", "runa-templates", "templates");
30446
- const normalizedTemplatesPath = path10__default.resolve(packagesTemplates);
30447
- if (!normalizedTemplatesPath.startsWith(current + path10__default.sep)) {
30448
- current = path10__default.dirname(current);
30701
+ const packagesTemplates = path11__default.join(current, "packages", "runa-templates", "templates");
30702
+ const normalizedTemplatesPath = path11__default.resolve(packagesTemplates);
30703
+ if (!normalizedTemplatesPath.startsWith(current + path11__default.sep)) {
30704
+ current = path11__default.dirname(current);
30449
30705
  depth++;
30450
30706
  continue;
30451
30707
  }
30452
30708
  if (fs5__default.existsSync(normalizedTemplatesPath)) {
30453
- const markerFile = path10__default.join(current, "packages", "runa-templates", "package.json");
30709
+ const markerFile = path11__default.join(current, "packages", "runa-templates", "package.json");
30454
30710
  if (fs5__default.existsSync(markerFile)) {
30455
30711
  try {
30456
30712
  const pkg = JSON.parse(fs5__default.readFileSync(markerFile, "utf-8"));
@@ -30461,7 +30717,7 @@ function resolveWorkspaceTemplates() {
30461
30717
  }
30462
30718
  }
30463
30719
  }
30464
- current = path10__default.dirname(current);
30720
+ current = path11__default.dirname(current);
30465
30721
  depth++;
30466
30722
  }
30467
30723
  return void 0;
@@ -30470,9 +30726,9 @@ function resolveWorkspaceTemplates() {
30470
30726
  // src/commands/init.ts
30471
30727
  function checkZodVersion(_logger) {
30472
30728
  const zodPaths = [
30473
- path10__default.join(process.cwd(), "node_modules", "zod", "package.json"),
30729
+ path11__default.join(process.cwd(), "node_modules", "zod", "package.json"),
30474
30730
  // Check home directory node_modules (common source of conflicts)
30475
- path10__default.join(process.env.HOME ?? "", "node_modules", "zod", "package.json")
30731
+ path11__default.join(process.env.HOME ?? "", "node_modules", "zod", "package.json")
30476
30732
  ];
30477
30733
  for (const zodPath of zodPaths) {
30478
30734
  if (!fs5__default.existsSync(zodPath)) continue;
@@ -30486,7 +30742,7 @@ function checkZodVersion(_logger) {
30486
30742
  "ZOD_VERSION_INCOMPATIBLE",
30487
30743
  [
30488
30744
  "runa SDK requires zod v4.x, but found zod v3.x",
30489
- `Conflicting zod found at: ${path10__default.dirname(zodPath)}`,
30745
+ `Conflicting zod found at: ${path11__default.dirname(zodPath)}`,
30490
30746
  "",
30491
30747
  "Solutions:",
30492
30748
  "1. Run from a clean project directory without existing node_modules",
@@ -30738,7 +30994,7 @@ var initCommand = new Command("init").description("Initialize pj-repo with runa
30738
30994
  try {
30739
30995
  if (options.repairConfig) {
30740
30996
  logger16.section("Repairing runa.config.ts");
30741
- const projectName2 = path10__default.basename(process.cwd());
30997
+ const projectName2 = path11__default.basename(process.cwd());
30742
30998
  const repairResult = repairRunaConfig(process.cwd(), projectName2);
30743
30999
  if (repairResult.success) {
30744
31000
  logger16.success("\u2705 Config file repaired successfully");
@@ -30789,7 +31045,7 @@ var initCommand = new Command("init").description("Initialize pj-repo with runa
30789
31045
  existingConfig,
30790
31046
  force: options.force === true
30791
31047
  });
30792
- const projectName = path10__default.basename(process.cwd());
31048
+ const projectName = path11__default.basename(process.cwd());
30793
31049
  logger16.info(`Project: ${projectName}`);
30794
31050
  logger16.step("Applying templates (SDK)", 1);
30795
31051
  const result = await initProject({
@@ -30886,7 +31142,9 @@ var InjectTestAttrsInputSchema = z.object({
30886
31142
  /** Manifest output directory */
30887
31143
  manifestDir: z.string().default(".runa"),
30888
31144
  /** Resolve Zod schemas to JSON Schema (v7+) for API contracts */
30889
- resolveSchemas: z.boolean().default(false)
31145
+ resolveSchemas: z.boolean().default(false),
31146
+ /** Fail when heuristic fallback detection is used */
31147
+ strictDetect: z.boolean().default(false)
30890
31148
  }).strict();
30891
31149
  var FileChangeSchema = z.object({
30892
31150
  filePath: z.string(),
@@ -30898,6 +31156,51 @@ var MachineWithoutE2EMetaSchema = z.object({
30898
31156
  id: z.string(),
30899
31157
  sourceFile: z.string()
30900
31158
  });
31159
+ var DetectionScanSummarySchema = z.object({
31160
+ totalFiles: z.number().int().nonnegative(),
31161
+ filesWithMachineDefinitions: z.number().int().nonnegative(),
31162
+ filesWithMachineHooks: z.number().int().nonnegative(),
31163
+ filesWithJsxOnly: z.number().int().nonnegative()
31164
+ }).strict();
31165
+ var MachineResolutionDetailSchema = z.object({
31166
+ filePath: z.string(),
31167
+ machineRef: z.string(),
31168
+ resolvedId: z.string(),
31169
+ source: z.enum(["explicit", "import", "inline", "fallback"])
31170
+ }).strict();
31171
+ var DetectionDiagnosticsSchema = z.object({
31172
+ schemaVersion: z.literal(1),
31173
+ scan: DetectionScanSummarySchema,
31174
+ resolution: z.object({
31175
+ totalMachineUsages: z.number().int().nonnegative(),
31176
+ bySource: z.object({
31177
+ explicit: z.number().int().nonnegative(),
31178
+ import: z.number().int().nonnegative(),
31179
+ inline: z.number().int().nonnegative(),
31180
+ fallback: z.number().int().nonnegative()
31181
+ }).strict(),
31182
+ fallbackRate: z.number().min(0).max(1),
31183
+ fallbackExamples: z.array(MachineResolutionDetailSchema)
31184
+ }).strict(),
31185
+ coverage: z.object({
31186
+ totalManifestMachines: z.number().int().nonnegative(),
31187
+ linkedManifestMachines: z.number().int().nonnegative(),
31188
+ unlinkedManifestMachines: z.number().int().nonnegative(),
31189
+ machineLinkCoverage: z.number().min(0).max(1),
31190
+ unlinkedManifestMachineIds: z.array(z.string())
31191
+ }).strict(),
31192
+ warnings: z.array(
31193
+ z.object({
31194
+ severity: z.enum(["warning", "info", "hint"]),
31195
+ message: z.string()
31196
+ }).strict()
31197
+ )
31198
+ }).strict();
31199
+ var StrictDetectStatusSchema = z.object({
31200
+ enabled: z.literal(true),
31201
+ passed: z.boolean(),
31202
+ reasons: z.array(z.string())
31203
+ }).strict();
30901
31204
  var InjectTestAttrsOutputSchema = z.object({
30902
31205
  totalFiles: z.number(),
30903
31206
  changedFiles: z.number(),
@@ -30909,17 +31212,98 @@ var InjectTestAttrsOutputSchema = z.object({
30909
31212
  /** Number of machines in manifest */
30910
31213
  manifestMachineCount: z.number().optional(),
30911
31214
  /** Machines without meta.e2e annotation (opt-in warning) */
30912
- machinesWithoutE2EMeta: z.array(MachineWithoutE2EMetaSchema).optional()
31215
+ machinesWithoutE2EMeta: z.array(MachineWithoutE2EMetaSchema).optional(),
31216
+ /** Structured diagnostics for detection quality */
31217
+ detectionDiagnostics: DetectionDiagnosticsSchema.optional(),
31218
+ /** Strict detection mode result */
31219
+ strictDetect: StrictDetectStatusSchema.optional()
30913
31220
  }).strict();
30914
31221
 
30915
31222
  // src/commands/inject-test-attrs/processor.ts
30916
31223
  init_esm_shims();
30917
31224
 
31225
+ // src/commands/inject-test-attrs/detection-diagnostics.ts
31226
+ init_esm_shims();
31227
+ var MAX_EXAMPLES = 20;
31228
+ function normalizeMachineId(id) {
31229
+ return id.replace(/-([a-z])/g, (_, char) => char.toUpperCase()).replace(/Machine$/i, "").toLowerCase();
31230
+ }
31231
+ function buildDetectionDiagnostics(params) {
31232
+ const bySource = {
31233
+ explicit: 0,
31234
+ import: 0,
31235
+ inline: 0,
31236
+ fallback: 0
31237
+ };
31238
+ const fallbackExamples = [];
31239
+ for (const detail of params.resolutionDetails) {
31240
+ bySource[detail.source] += 1;
31241
+ if (detail.source === "fallback" && fallbackExamples.length < MAX_EXAMPLES) {
31242
+ fallbackExamples.push(detail);
31243
+ }
31244
+ }
31245
+ const linkedMachineIds = new Set(
31246
+ params.machineLinks.filter((link) => link.usedIn.length > 0).map((link) => normalizeMachineId(link.machineName))
31247
+ );
31248
+ const linkedManifestMachineIds = [];
31249
+ const unlinkedManifestMachineIds = [];
31250
+ for (const machineId of params.manifestMachineIds) {
31251
+ if (linkedMachineIds.has(normalizeMachineId(machineId))) {
31252
+ linkedManifestMachineIds.push(machineId);
31253
+ continue;
31254
+ }
31255
+ unlinkedManifestMachineIds.push(machineId);
31256
+ }
31257
+ const totalMachineUsages = params.resolutionDetails.length;
31258
+ const fallbackRate = totalMachineUsages > 0 ? bySource.fallback / totalMachineUsages : 0;
31259
+ const totalManifestMachines = params.manifestMachineIds.length;
31260
+ const linkedManifestMachines = linkedManifestMachineIds.length;
31261
+ const machineLinkCoverage = totalManifestMachines > 0 ? linkedManifestMachines / totalManifestMachines : 1;
31262
+ return {
31263
+ schemaVersion: 1,
31264
+ scan: params.scanSummary,
31265
+ resolution: {
31266
+ totalMachineUsages,
31267
+ bySource,
31268
+ fallbackRate,
31269
+ fallbackExamples
31270
+ },
31271
+ coverage: {
31272
+ totalManifestMachines,
31273
+ linkedManifestMachines,
31274
+ unlinkedManifestMachines: totalManifestMachines - linkedManifestMachines,
31275
+ machineLinkCoverage,
31276
+ unlinkedManifestMachineIds: unlinkedManifestMachineIds.slice(0, MAX_EXAMPLES)
31277
+ },
31278
+ warnings: params.warnings
31279
+ };
31280
+ }
31281
+ function evaluateStrictDetect(diagnostics) {
31282
+ const reasons = [];
31283
+ const fallbackCount = diagnostics.resolution.bySource.fallback;
31284
+ if (fallbackCount > 0) {
31285
+ reasons.push(`fallback machine resolution detected (${fallbackCount})`);
31286
+ }
31287
+ if (diagnostics.scan.filesWithMachineHooks > 0 && diagnostics.resolution.totalMachineUsages === 0) {
31288
+ reasons.push(
31289
+ `machine hooks were detected in ${diagnostics.scan.filesWithMachineHooks} files, but no machine usages were resolved`
31290
+ );
31291
+ }
31292
+ if (diagnostics.resolution.totalMachineUsages > 0 && diagnostics.coverage.totalManifestMachines > 0 && diagnostics.coverage.linkedManifestMachines === 0) {
31293
+ reasons.push("machine usages were detected, but no machines were linked to routes/pages");
31294
+ }
31295
+ return {
31296
+ enabled: true,
31297
+ passed: reasons.length === 0,
31298
+ reasons
31299
+ };
31300
+ }
31301
+
30918
31302
  // src/commands/inject-test-attrs/formatter.ts
30919
31303
  init_esm_shims();
30920
31304
  async function formatFilesWithBiome(files, cwd) {
30921
31305
  if (files.length === 0) return;
30922
- const relativePaths = files.map((f) => path10.relative(cwd, f));
31306
+ const relativePaths = files.map((f) => path11.relative(cwd, f));
30923
31307
  try {
30924
31308
  await execa("pnpm", ["exec", "biome", "format", "--write", ...relativePaths], {
30925
31309
  cwd,
@@ -31011,7 +31395,8 @@ function emptyResult(filePath) {
31011
31395
  changed: false,
31012
31396
  actions: [],
31013
31397
  fields: [],
31014
- testIds: []
31398
+ testIds: [],
31399
+ resolutionDetails: []
31015
31400
  };
31016
31401
  }
31017
31402
  function ensureDirectoryExists(dirPath) {
@@ -31021,7 +31406,7 @@ function ensureDirectoryExists(dirPath) {
31021
31406
  }
31022
31407
  function getGeneratorVersion() {
31023
31408
  try {
31024
- const pkgPath = path10.resolve(__dirname$1, "../../../package.json");
31409
+ const pkgPath = path11.resolve(__dirname$1, "../../../package.json");
31025
31410
  if (fs5.existsSync(pkgPath)) {
31026
31411
  const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
31027
31412
  return pkg.version ?? "unknown";
@@ -31036,15 +31421,15 @@ function detectPlatform(repoRoot) {
31036
31421
  const nextConfigPatterns = ["next.config.ts", "next.config.js", "next.config.mjs"];
31037
31422
  for (const pattern of nextConfigPatterns) {
31038
31423
  const paths = [
31039
- path10.join(repoRoot, pattern),
31040
- path10.join(repoRoot, "apps", "web", pattern),
31041
- path10.join(repoRoot, "apps", "dashboard", pattern)
31424
+ path11.join(repoRoot, pattern),
31425
+ path11.join(repoRoot, "apps", "web", pattern),
31426
+ path11.join(repoRoot, "apps", "dashboard", pattern)
31042
31427
  ];
31043
31428
  if (paths.some((p) => fs5.existsSync(p))) {
31044
31429
  return "nextjs";
31045
31430
  }
31046
31431
  }
31047
- const appJsonPath = path10.join(repoRoot, "app.json");
31432
+ const appJsonPath = path11.join(repoRoot, "app.json");
31048
31433
  if (fs5.existsSync(appJsonPath)) {
31049
31434
  try {
31050
31435
  const appJson = JSON.parse(fs5.readFileSync(appJsonPath, "utf-8"));
@@ -31054,7 +31439,7 @@ function detectPlatform(repoRoot) {
31054
31439
  } catch {
31055
31440
  }
31056
31441
  }
31057
- if (fs5.existsSync(path10.join(repoRoot, "expo.json"))) {
31442
+ if (fs5.existsSync(path11.join(repoRoot, "expo.json"))) {
31058
31443
  return "expo";
31059
31444
  }
31060
31445
  const electronPatterns = [
@@ -31063,56 +31448,38 @@ function detectPlatform(repoRoot) {
31063
31448
  "electron.vite.config.ts",
31064
31449
  "electron.vite.config.js"
31065
31450
  ];
31066
- if (electronPatterns.some((p) => fs5.existsSync(path10.join(repoRoot, p)))) {
31451
+ if (electronPatterns.some((p) => fs5.existsSync(path11.join(repoRoot, p)))) {
31067
31452
  return "electron";
31068
31453
  }
31069
31454
  return "unknown";
31070
31455
  }
31071
- function findPossibleHonoDirs(repoRoot) {
31072
- const possibleDirs = [];
31073
- const appsDir = path10.join(repoRoot, "apps");
31074
- if (fs5.existsSync(appsDir)) {
31075
- try {
31076
- const apps = fs5.readdirSync(appsDir, { withFileTypes: true });
31077
- for (const app of apps) {
31078
- if (app.isDirectory()) {
31079
- const routesDir = path10.join(appsDir, app.name, "routes");
31080
- if (fs5.existsSync(routesDir)) {
31081
- const files = fs5.readdirSync(routesDir);
31082
- const hasRouteFiles = files.some(
31083
- (f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.endsWith(".spec.ts")
31084
- );
31085
- if (hasRouteFiles) {
31086
- possibleDirs.push(`apps/${app.name}/routes`);
31087
- }
31088
- }
31089
- }
31090
- }
31091
- } catch {
31092
- }
31456
+ function hasHonoRouteFiles(dir) {
31457
+ try {
31458
+ const files = fs5.readdirSync(dir);
31459
+ return files.some(
31460
+ (file) => file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".spec.ts")
31461
+ );
31462
+ } catch {
31463
+ return false;
31093
31464
  }
31094
- const packagesDir = path10.join(repoRoot, "packages");
31095
- if (fs5.existsSync(packagesDir)) {
31096
- try {
31097
- const packages = fs5.readdirSync(packagesDir, { withFileTypes: true });
31098
- for (const pkg of packages) {
31099
- if (pkg.isDirectory()) {
31100
- const routesDir = path10.join(packagesDir, pkg.name, "routes");
31101
- if (fs5.existsSync(routesDir)) {
31102
- const files = fs5.readdirSync(routesDir);
31103
- const hasRouteFiles = files.some(
31104
- (f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.endsWith(".spec.ts")
31105
- );
31106
- if (hasRouteFiles) {
31107
- possibleDirs.push(`packages/${pkg.name}/routes`);
31108
- }
31109
- }
31110
- }
31111
- }
31112
- } catch {
31113
- }
31465
+ }
31466
+ function collectRouteDirsInScope(repoRoot, scope) {
31467
+ const scopeDir = path11.join(repoRoot, scope);
31468
+ if (!fs5.existsSync(scopeDir)) {
31469
+ return [];
31470
+ }
31471
+ try {
31472
+ const entries = fs5.readdirSync(scopeDir, { withFileTypes: true });
31473
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((entryName) => hasHonoRouteFiles(path11.join(scopeDir, entryName, "routes"))).map((entryName) => `${scope}/${entryName}/routes`);
31474
+ } catch {
31475
+ return [];
31114
31476
  }
31115
- return possibleDirs;
31477
+ }
31478
+ function findPossibleHonoDirs(repoRoot) {
31479
+ return [
31480
+ ...collectRouteDirsInScope(repoRoot, "apps"),
31481
+ ...collectRouteDirsInScope(repoRoot, "packages")
31482
+ ];
31116
31483
  }
31117
31484
  function collectManifestWarnings(repoRoot, platform, apiContracts, machinesWithoutE2EMeta, totalMachines) {
31118
31485
  const warnings = [];
@@ -31163,15 +31530,18 @@ function printManifestWarnings(warnings, verbose) {
31163
31530
  for (const detail of warning.details) {
31164
31531
  console.log(detail);
31165
31532
  }
31166
- if (warning.details.length < warning._totalCount) {
31167
- console.log(` ... and more`);
31168
- }
31169
31533
  }
31170
31534
  if (warning.fix) {
31171
31535
  console.log(` \u2192 ${warning.fix}`);
31172
31536
  }
31173
31537
  }
31174
31538
  }
31539
+ function toDetectionWarnings(warnings) {
31540
+ return warnings.map((warning) => ({
31541
+ severity: warning.severity,
31542
+ message: warning.message
31543
+ }));
31544
+ }
31175
31545
  function normalizeToCanonicalId(id) {
31176
31546
  return id.replace(/-([a-z])/g, (_, c) => c.toUpperCase()).replace(/Machine$/i, "");
31177
31547
  }
@@ -31259,7 +31629,7 @@ async function analyzeHonoRoutes(repoRoot, verbose, resolveSchemas = false) {
31259
31629
  return { apiContracts: [], schemasResolved: false };
31260
31630
  }
31261
31631
  if (verbose) {
31262
- console.log(` Analyzing Hono routes in: ${path10.relative(repoRoot, routesPath)}`);
31632
+ console.log(` Analyzing Hono routes in: ${path11.relative(repoRoot, routesPath)}`);
31263
31633
  if (resolveSchemas) {
31264
31634
  console.log(" Schema resolution enabled (--resolve-schemas)");
31265
31635
  }
@@ -31305,7 +31675,7 @@ async function analyzeHonoRoutes(repoRoot, verbose, resolveSchemas = false) {
31305
31675
  return { apiContracts: [], schemasResolved: false };
31306
31676
  }
31307
31677
  }
31308
- async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSchemas = false) {
31678
+ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSchemas = false, diagnosticsInput) {
31309
31679
  const registry = getInjectionRegistry();
31310
31680
  const generatorVersion = getGeneratorVersion();
31311
31681
  const e2eManifest = buildManifest(registry, generatorVersion);
@@ -31319,18 +31689,18 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31319
31689
  }
31320
31690
  const definitionMap = buildDefinitionMap(machineDefinitions);
31321
31691
  const enhancedMachines = buildEnhancedMachines(e2eManifest, definitionMap, machineDefinitions);
31322
- const absoluteManifestDir = path10.isAbsolute(manifestDir) ? manifestDir : path10.join(repoRoot, manifestDir);
31692
+ const absoluteManifestDir = path11.isAbsolute(manifestDir) ? manifestDir : path11.join(repoRoot, manifestDir);
31323
31693
  if (!isPathContained(repoRoot, absoluteManifestDir)) {
31324
31694
  throw new Error(
31325
31695
  `Security error: Manifest directory '${manifestDir}' would escape the project root. The --manifest-dir must be a relative path within the project directory.`
31326
31696
  );
31327
31697
  }
31328
31698
  ensureDirectoryExists(absoluteManifestDir);
31329
- const generatedDir = path10.join(absoluteManifestDir, "generated");
31699
+ const generatedDir = path11.join(absoluteManifestDir, "generated");
31330
31700
  ensureDirectoryExists(generatedDir);
31331
- const manifestsDir = path10.join(absoluteManifestDir, "manifests");
31701
+ const manifestsDir = path11.join(absoluteManifestDir, "manifests");
31332
31702
  ensureDirectoryExists(manifestsDir);
31333
- const tsPath = path10.join(generatedDir, "selectors.ts");
31703
+ const tsPath = path11.join(generatedDir, "selectors.ts");
31334
31704
  await fs5.promises.writeFile(tsPath, generateSelectorTypeScript(e2eManifest), "utf-8");
31335
31705
  const unifiedRegistry = getUnifiedRegistry();
31336
31706
  const machineLinks = buildMachineLinks();
@@ -31345,6 +31715,29 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31345
31715
  const jstOffset = 9 * 60 * 60 * 1e3;
31346
31716
  const jst = new Date(now.getTime() + jstOffset);
31347
31717
  const generatedAtJST = `${jst.getUTCFullYear()}-${String(jst.getUTCMonth() + 1).padStart(2, "0")}-${String(jst.getUTCDate()).padStart(2, "0")}T${String(jst.getUTCHours()).padStart(2, "0")}:${String(jst.getUTCMinutes()).padStart(2, "0")}:${String(jst.getUTCSeconds()).padStart(2, "0")}+09:00`;
31718
+ const machinesWithoutE2EMeta = machineDefinitions.filter(
31719
+ (def) => !def.hasE2EMeta && typeof def.id === "string"
31720
+ ).map((def) => ({ id: def.id, sourceFile: def.sourceFile }));
31721
+ const warnings = collectManifestWarnings(
31722
+ repoRoot,
31723
+ platform,
31724
+ apiContracts,
31725
+ machinesWithoutE2EMeta,
31726
+ machineDefinitions.length
31727
+ );
31728
+ printManifestWarnings(warnings, verbose);
31729
+ const detectionDiagnostics = buildDetectionDiagnostics({
31730
+ scanSummary: diagnosticsInput?.scanSummary ?? {
31731
+ totalFiles: 0,
31732
+ filesWithMachineDefinitions: 0,
31733
+ filesWithMachineHooks: 0,
31734
+ filesWithJsxOnly: 0
31735
+ },
31736
+ resolutionDetails: diagnosticsInput?.resolutionDetails ?? [],
31737
+ manifestMachineIds: Object.keys(enhancedMachines),
31738
+ machineLinks,
31739
+ warnings: toDetectionWarnings(warnings)
31740
+ });
31348
31741
  const unifiedManifest = {
31349
31742
  version: manifestVersion,
31350
31743
  generatedAt: generatedAtJST,
@@ -31357,17 +31750,15 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31357
31750
  authBoundaries: unifiedRegistry.authBoundaries,
31358
31751
  machineDefinitions: unifiedRegistry.machineDefinitions,
31359
31752
  machineLinks,
31360
- apiContracts
31753
+ apiContracts,
31754
+ detectionDiagnostics
31361
31755
  };
31362
- const manifestPath = path10.join(manifestsDir, "manifest.json");
31756
+ const manifestPath = path11.join(manifestsDir, "manifest.json");
31363
31757
  await fs5.promises.writeFile(manifestPath, JSON.stringify(unifiedManifest, null, 2), "utf-8");
31364
- const machinesWithoutE2EMeta = machineDefinitions.filter(
31365
- (def) => !def.hasE2EMeta && typeof def.id === "string"
31366
- ).map((def) => ({ id: def.id, sourceFile: def.sourceFile }));
31367
31758
  if (verbose) {
31368
- console.log(`Generated selectors: ${path10.relative(repoRoot, tsPath)}`);
31759
+ console.log(`Generated selectors: ${path11.relative(repoRoot, tsPath)}`);
31369
31760
  console.log(
31370
- `Generated manifest: ${path10.relative(repoRoot, manifestPath)} (v${manifestVersion})`
31761
+ `Generated manifest: ${path11.relative(repoRoot, manifestPath)} (v${manifestVersion})`
31371
31762
  );
31372
31763
  console.log(` Platform: ${platform}`);
31373
31764
  console.log(` Machine definitions: ${machineDefinitions.length}`);
@@ -31381,19 +31772,15 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31381
31772
  ` API contracts: ${apiContracts.length}${schemasResolved ? " (with schemas)" : ""}`
31382
31773
  );
31383
31774
  console.log(` Machine links: ${machineLinks.length}`);
31775
+ console.log(
31776
+ ` Detection: fallback=${detectionDiagnostics.resolution.bySource.fallback}, linkCoverage=${(detectionDiagnostics.coverage.machineLinkCoverage * 100).toFixed(1)}%`
31777
+ );
31384
31778
  }
31385
- const warnings = collectManifestWarnings(
31386
- repoRoot,
31387
- platform,
31388
- apiContracts,
31389
- machinesWithoutE2EMeta,
31390
- machineDefinitions.length
31391
- );
31392
- printManifestWarnings(warnings, verbose);
31393
31779
  return {
31394
- manifestPath: path10.relative(repoRoot, tsPath),
31780
+ manifestPath: path11.relative(repoRoot, tsPath),
31395
31781
  machineCount: Object.keys(enhancedMachines).length,
31396
- machinesWithoutE2EMeta
31782
+ machinesWithoutE2EMeta,
31783
+ detectionDiagnostics
31397
31784
  };
31398
31785
  }
31399
31786
 
@@ -31425,7 +31812,7 @@ function registerExistingInjections(machineIds, attrs, sourceFile) {
31425
31812
  }
31426
31813
  async function preprocessFile(filePath, repoRoot, options) {
31427
31814
  let code = await fs5.promises.readFile(filePath, "utf-8");
31428
- const relativePath = path10.relative(repoRoot, filePath);
31815
+ const relativePath = path11.relative(repoRoot, filePath);
31429
31816
  collectRouteInfo(relativePath, code, options.verbose);
31430
31817
  const hasMarker = code.includes(CLI_INJECTION_MARKER);
31431
31818
  if (hasMarker && options.force) {
@@ -31456,14 +31843,15 @@ async function preprocessFile(filePath, repoRoot, options) {
31456
31843
  injectedCount: 0,
31457
31844
  machineIds,
31458
31845
  changed: false,
31459
- ...attrs
31846
+ ...attrs,
31847
+ resolutionDetails: []
31460
31848
  }
31461
31849
  };
31462
31850
  }
31463
31851
  return { code, hasMarker: false, skipped: false };
31464
31852
  }
31465
31853
  function transformAndRegister(filePath, code, repoRoot, options) {
31466
- const relativePath = path10.relative(repoRoot, filePath);
31854
+ const relativePath = path11.relative(repoRoot, filePath);
31467
31855
  const readAndParseFile = createReadAndParseFile(options.verbose);
31468
31856
  const resolveImportPath = createResolveImportPath();
31469
31857
  try {
@@ -31479,6 +31867,14 @@ function transformAndRegister(filePath, code, repoRoot, options) {
31479
31867
  const transformedCode = markerComment + result.code;
31480
31868
  const { actions, fields, testIds } = extractInjectedAttributes(transformedCode);
31481
31869
  const machineIds = [...result.resolvedIds.values()];
31870
+ const resultWithResolution = result;
31871
+ const rawResolutionDetails = Array.isArray(resultWithResolution.resolutionDetails) ? resultWithResolution.resolutionDetails : [];
31872
+ const resolutionDetails = rawResolutionDetails.map((detail) => ({
31873
+ filePath: relativePath,
31874
+ machineRef: detail.machineRef,
31875
+ resolvedId: detail.resolvedId,
31876
+ source: detail.source
31877
+ }));
31482
31878
  registerExistingInjections(machineIds, { actions, fields, testIds }, relativePath);
31483
31879
  return {
31484
31880
  filePath,
@@ -31488,7 +31884,8 @@ function transformAndRegister(filePath, code, repoRoot, options) {
31488
31884
  transformedCode,
31489
31885
  actions,
31490
31886
  fields,
31491
- testIds
31887
+ testIds,
31888
+ resolutionDetails
31492
31889
  };
31493
31890
  } catch (error) {
31494
31891
  if (options.verbose) {
@@ -31509,7 +31906,7 @@ async function processFileForChildInjection(filePath, repoRoot, options) {
31509
31906
  if (prep.skipped && prep.skipResult) return prep.skipResult;
31510
31907
  const result = transformAndRegister(filePath, prep.code, repoRoot, options);
31511
31908
  if (options.verbose && result.changed && result.injectedCount > 0) {
31512
- const relativePath = path10.relative(repoRoot, filePath);
31909
+ const relativePath = path11.relative(repoRoot, filePath);
31513
31910
  console.log(
31514
31911
  ` [child] Injected ${result.injectedCount} attrs in ${relativePath} (actions: ${result.actions.join(", ")})`
31515
31912
  );
@@ -31529,7 +31926,7 @@ async function handleChangedFile(result, check, repoRoot, verbose, state2) {
31529
31926
  await fs5.promises.writeFile(result.filePath, result.transformedCode, "utf-8");
31530
31927
  state2.filesToFormat.push(result.filePath);
31531
31928
  if (verbose) {
31532
- const relativePath = path10.relative(repoRoot, result.filePath);
31929
+ const relativePath = path11.relative(repoRoot, result.filePath);
31533
31930
  console.log(` Injected ${result.injectedCount} attrs in ${relativePath}`);
31534
31931
  }
31535
31932
  }
@@ -31540,6 +31937,60 @@ async function formatChangedFiles(filesToFormat, repoRoot, verbose) {
31540
31937
  }
31541
31938
  await formatFilesWithBiome(filesToFormat, repoRoot);
31542
31939
  }
31940
+ function createScanSummary(params) {
31941
+ return {
31942
+ totalFiles: params.files.length,
31943
+ filesWithMachineDefinitions: params.withMachineDefinitions.length,
31944
+ filesWithMachineHooks: params.withMachineHooks.length,
31945
+ filesWithJsxOnly: params.withJsxOnly.length
31946
+ };
31947
+ }
31948
+ async function resolveManifestArtifacts(params) {
31949
+ let manifestPath;
31950
+ let manifestMachineCount;
31951
+ let machinesWithoutE2EMeta;
31952
+ let detectionDiagnostics;
31953
+ if (params.manifest && !params.check) {
31954
+ const diagnosticsInput = {
31955
+ scanSummary: params.scanSummary,
31956
+ resolutionDetails: params.resolutionDetails
31957
+ };
31958
+ const manifestResult = await generateManifestFiles(
31959
+ params.manifestDir,
31960
+ params.repoRoot,
31961
+ params.verbose,
31962
+ params.resolveSchemas,
31963
+ diagnosticsInput
31964
+ );
31965
+ manifestPath = manifestResult.manifestPath;
31966
+ manifestMachineCount = manifestResult.machineCount;
31967
+ machinesWithoutE2EMeta = manifestResult.machinesWithoutE2EMeta;
31968
+ detectionDiagnostics = manifestResult.detectionDiagnostics;
31969
+ } else if (params.manifest && params.check) {
31970
+ const warnings = [];
31971
+ detectionDiagnostics = buildDetectionDiagnostics({
31972
+ scanSummary: params.scanSummary,
31973
+ resolutionDetails: params.resolutionDetails,
31974
+ manifestMachineIds: [],
31975
+ machineLinks: [],
31976
+ warnings
31977
+ });
31978
+ }
31979
+ const strictDetectStatus = params.strictDetect ? detectionDiagnostics ? evaluateStrictDetect(detectionDiagnostics) : {
31980
+ enabled: true,
31981
+ passed: false,
31982
+ reasons: [
31983
+ "strict detect requires manifest diagnostics, but diagnostics were unavailable"
31984
+ ]
31985
+ } : void 0;
31986
+ return {
31987
+ manifestPath,
31988
+ manifestMachineCount,
31989
+ machinesWithoutE2EMeta,
31990
+ detectionDiagnostics,
31991
+ strictDetectStatus
31992
+ };
31993
+ }
31543
31994
  function mightContainMachineDefinition(code) {
31544
31995
  return code.includes("createMachine");
31545
31996
  }
@@ -31563,13 +32014,34 @@ async function categorizeFiles(files) {
31563
32014
  return { withMachineDefinitions, withMachineHooks, withJsxOnly };
31564
32015
  }
31565
32016
  async function processFiles(options) {
31566
- const { repoRoot, check, verbose, include, exclude, manifest, manifestDir, resolveSchemas } = options;
32017
+ const {
32018
+ repoRoot,
32019
+ check,
32020
+ verbose,
32021
+ include,
32022
+ exclude,
32023
+ manifest,
32024
+ manifestDir,
32025
+ resolveSchemas,
32026
+ strictDetect
32027
+ } = options;
31567
32028
  clearInjectionRegistry();
31568
32029
  clearUnifiedRegistry();
31569
32030
  const files = await discoverFiles(repoRoot, include, exclude);
31570
32031
  if (verbose) console.log(`Found ${files.length} files to process`);
31571
- const state2 = { changes: [], filesToFormat: [], totalInjections: 0 };
32032
+ const state2 = {
32033
+ changes: [],
32034
+ filesToFormat: [],
32035
+ totalInjections: 0,
32036
+ resolutionDetails: []
32037
+ };
31572
32038
  const { withMachineDefinitions, withMachineHooks, withJsxOnly } = await categorizeFiles(files);
32039
+ const scanSummary = createScanSummary({
32040
+ files,
32041
+ withMachineDefinitions,
32042
+ withMachineHooks,
32043
+ withJsxOnly
32044
+ });
31573
32045
  if (verbose) {
31574
32046
  console.log(` Files with machine definitions: ${withMachineDefinitions.length}`);
31575
32047
  console.log(` Files with machine hooks: ${withMachineHooks.length}`);
@@ -31579,46 +32051,50 @@ async function processFiles(options) {
31579
32051
  for (const filePath of withMachineDefinitions) {
31580
32052
  try {
31581
32053
  const code = await fs5.promises.readFile(filePath, "utf-8");
31582
- const relativePath = path10.relative(repoRoot, filePath);
32054
+ const relativePath = path11.relative(repoRoot, filePath);
31583
32055
  collectRouteInfo(relativePath, code, verbose);
31584
32056
  } catch {
31585
32057
  }
31586
32058
  }
31587
32059
  for (const filePath of withMachineHooks) {
31588
32060
  const result = await processFile(filePath, repoRoot, processOpts);
32061
+ state2.resolutionDetails.push(...result.resolutionDetails);
31589
32062
  await handleChangedFile(result, check, repoRoot, verbose, state2);
31590
32063
  }
31591
32064
  for (const filePath of withJsxOnly) {
31592
32065
  const result = await processFileForChildInjection(filePath, repoRoot, processOpts);
32066
+ state2.resolutionDetails.push(...result.resolutionDetails);
31593
32067
  await handleChangedFile(result, check, repoRoot, verbose, state2);
31594
32068
  }
31595
32069
  if (!check) {
31596
32070
  await formatChangedFiles(state2.filesToFormat, repoRoot, verbose);
31597
32071
  }
31598
32072
  postProcessRegistries();
31599
- let manifestPath;
31600
- let manifestMachineCount;
31601
- let machinesWithoutE2EMeta;
31602
- if (manifest && !check) {
31603
- const manifestResult = await generateManifestFiles(
31604
- manifestDir,
31605
- repoRoot,
31606
- verbose,
31607
- resolveSchemas ?? false
31608
- );
31609
- manifestPath = manifestResult.manifestPath;
31610
- manifestMachineCount = manifestResult.machineCount;
31611
- machinesWithoutE2EMeta = manifestResult.machinesWithoutE2EMeta;
31612
- }
32073
+ const manifestArtifacts = await resolveManifestArtifacts({
32074
+ manifest,
32075
+ check,
32076
+ manifestDir,
32077
+ repoRoot,
32078
+ verbose,
32079
+ resolveSchemas: resolveSchemas ?? false,
32080
+ strictDetect: strictDetect ?? false,
32081
+ scanSummary,
32082
+ resolutionDetails: state2.resolutionDetails
32083
+ });
32084
+ const hasCheckFailure = check && state2.changes.length > 0;
32085
+ const hasStrictDetectFailure = manifestArtifacts.strictDetectStatus?.passed === false;
32086
+ const exitCode = hasCheckFailure || hasStrictDetectFailure ? 1 : 0;
31613
32087
  return {
31614
32088
  totalFiles: files.length,
31615
32089
  changedFiles: state2.changes.length,
31616
32090
  totalInjections: state2.totalInjections,
31617
32091
  changes: state2.changes,
31618
- exitCode: check && state2.changes.length > 0 ? 1 : 0,
31619
- manifestPath,
31620
- manifestMachineCount,
31621
- machinesWithoutE2EMeta
32092
+ exitCode,
32093
+ manifestPath: manifestArtifacts.manifestPath,
32094
+ manifestMachineCount: manifestArtifacts.manifestMachineCount,
32095
+ machinesWithoutE2EMeta: manifestArtifacts.machinesWithoutE2EMeta,
32096
+ detectionDiagnostics: manifestArtifacts.detectionDiagnostics,
32097
+ strictDetect: manifestArtifacts.strictDetectStatus
31622
32098
  };
31623
32099
  }
31624
32100
 
@@ -31678,6 +32154,35 @@ function logMachinesWithoutE2EMeta(result, logger16) {
31678
32154
  logger16.info(" }");
31679
32155
  logger16.info(" See: .claude/rules/xstate-design.md#meta.e2e");
31680
32156
  }
32157
+ function logDetectionDiagnostics(result, logger16) {
32158
+ if (!result.detectionDiagnostics) return;
32159
+ const diagnostics = result.detectionDiagnostics;
32160
+ const fallbackCount = diagnostics.resolution.bySource.fallback;
32161
+ const fallbackRate = (diagnostics.resolution.fallbackRate * 100).toFixed(1);
32162
+ const coverage = (diagnostics.coverage.machineLinkCoverage * 100).toFixed(1);
32163
+ logger16.info("");
32164
+ logger16.info(
32165
+ `Detection diagnostics: usages=${diagnostics.resolution.totalMachineUsages}, fallback=${fallbackCount} (${fallbackRate}%), linkCoverage=${coverage}%`
32166
+ );
32167
+ if (fallbackCount > 0) {
32168
+ for (const item of diagnostics.resolution.fallbackExamples.slice(0, 5)) {
32169
+ logger16.warn(
32170
+ ` fallback: ${item.filePath} :: ${item.machineRef} -> ${item.resolvedId} (${item.source})`
32171
+ );
32172
+ }
32173
+ }
32174
+ }
32175
+ function logStrictDetect(result, logger16) {
32176
+ if (!result.strictDetect) return;
32177
+ if (result.strictDetect.passed) {
32178
+ logger16.success("Strict detect passed (no fallback resolution)");
32179
+ return;
32180
+ }
32181
+ logger16.error("Strict detect failed");
32182
+ for (const reason of result.strictDetect.reasons) {
32183
+ logger16.error(` - ${reason}`);
32184
+ }
32185
+ }
31681
32186
  async function injectTestAttrsAction(rawOptions, command) {
31682
32187
  const logger16 = createCLILogger("manifest");
31683
32188
  const parseResult = InjectTestAttrsInputSchema.safeParse(rawOptions);
@@ -31688,6 +32193,20 @@ async function injectTestAttrsAction(rawOptions, command) {
31688
32193
  ]);
31689
32194
  }
31690
32195
  const options = parseResult.data;
32196
+ if (options.strictDetect && options.check) {
32197
+ throw new CLIError(
32198
+ "--strict-detect cannot be used with --check",
32199
+ "STRICT_DETECT_CHECK_UNSUPPORTED",
32200
+ ["Run without --check to evaluate strict detection against manifest diagnostics"]
32201
+ );
32202
+ }
32203
+ if (options.strictDetect && !options.manifest) {
32204
+ throw new CLIError(
32205
+ "--strict-detect requires manifest generation",
32206
+ "STRICT_DETECT_MANIFEST_REQUIRED",
32207
+ ["Remove --no-manifest, or disable --strict-detect"]
32208
+ );
32209
+ }
31691
32210
  const repoRoot = findProjectRoot$1() ?? process.cwd();
31692
32211
  if (!options.check) {
31693
32212
  logger16.section("Generating manifest (manifest.json)");
@@ -31706,6 +32225,8 @@ async function injectTestAttrsAction(rawOptions, command) {
31706
32225
  logResultSummary(result, options, logger16);
31707
32226
  logManifestInfo(result, logger16);
31708
32227
  logMachinesWithoutE2EMeta(result, logger16);
32228
+ logDetectionDiagnostics(result, logger16);
32229
+ logStrictDetect(result, logger16);
31709
32230
  emitJsonSuccess(command, InjectTestAttrsOutputSchema, result);
31710
32231
  if (result.exitCode !== 0) {
31711
32232
  process.exit(result.exitCode);
@@ -31725,7 +32246,7 @@ var injectTestAttrsCommand = new Command("inject-test-attrs").description("Injec
31725
32246
  "**/*.test.*",
31726
32247
  "**/*.spec.*",
31727
32248
  "**/*.stories.*"
31728
- ]).option("--no-manifest", "Skip E2E selector manifest generation").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").action(async (rawOptions) => {
32249
+ ]).option("--no-manifest", "Skip E2E selector manifest generation").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").option("--strict-detect", "Fail when fallback machine detection is used (for deterministic CI)").action(async (rawOptions) => {
31729
32250
  await injectTestAttrsAction(rawOptions, injectTestAttrsCommand);
31730
32251
  });
31731
32252
 
@@ -31789,7 +32310,7 @@ var manifestCommand = new Command("manifest").description("Generate E2E manifest
31789
32310
  "**/*.test.*",
31790
32311
  "**/*.spec.*",
31791
32312
  "**/*.stories.*"
31792
- ]).option("--no-manifest", "Skip manifest file generation (attributes only)").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").action(async (options) => {
32313
+ ]).option("--no-manifest", "Skip manifest file generation (attributes only)").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").option("--strict-detect", "Fail when fallback machine detection is used (for deterministic CI)").action(async (options) => {
31793
32314
  await injectTestAttrsAction(options, manifestCommand);
31794
32315
  });
31795
32316
 
@@ -31848,7 +32369,7 @@ function assertNodeAuthToken(options) {
31848
32369
  }
31849
32370
  }
31850
32371
  function getPackageVersion(packagePath) {
31851
- const packageJsonPath = path10__default.join(packagePath, "package.json");
32372
+ const packageJsonPath = path11__default.join(packagePath, "package.json");
31852
32373
  if (!existsSync(packageJsonPath)) {
31853
32374
  throw new CLIError(`package.json not found at ${packagePath}`, "PACKAGE_NOT_FOUND");
31854
32375
  }
@@ -31867,7 +32388,7 @@ function resolveWorkspaceDependencies(workspaceRoot, packages, logger16) {
31867
32388
  const sdkPackage = packages.find((p) => p.name === "SDK");
31868
32389
  const xstatePluginPackage = packages.find((p) => p.name === "xstate-test-plugin");
31869
32390
  if (!sdkPackage) return;
31870
- const cliPackagePath = path10__default.join(workspaceRoot, "packages", "cli", "package.json");
32391
+ const cliPackagePath = path11__default.join(workspaceRoot, "packages", "cli", "package.json");
31871
32392
  if (!existsSync(cliPackagePath)) return;
31872
32393
  let content = readFileSync(cliPackagePath, "utf-8");
31873
32394
  let updated = false;
@@ -31896,7 +32417,7 @@ function resolveWorkspaceDependencies(workspaceRoot, packages, logger16) {
31896
32417
  }
31897
32418
  }
31898
32419
  function restoreWorkspaceDependencies(workspaceRoot) {
31899
- const cliPackagePath = path10__default.join(workspaceRoot, "packages", "cli", "package.json");
32420
+ const cliPackagePath = path11__default.join(workspaceRoot, "packages", "cli", "package.json");
31900
32421
  if (!existsSync(cliPackagePath)) return;
31901
32422
  let content = readFileSync(cliPackagePath, "utf-8");
31902
32423
  content = content.replace(/"@runa-ai\/runa": "\^[\d.]+"/, '"@runa-ai/runa": "workspace:*"');
@@ -32008,7 +32529,7 @@ function collectPackageInfo(workspaceRoot, logger16, stepNum) {
32008
32529
  logger16.step("Collecting package info", stepNum);
32009
32530
  const packages = [];
32010
32531
  for (const pkgConfig of PUBLISHABLE_PACKAGES) {
32011
- const pkgPath = path10__default.join(workspaceRoot, "packages", pkgConfig.dir);
32532
+ const pkgPath = path11__default.join(workspaceRoot, "packages", pkgConfig.dir);
32012
32533
  const version = getPackageVersion(pkgPath);
32013
32534
  const exists = checkVersionExists(pkgConfig.publishName, version);
32014
32535
  packages.push({
@@ -33397,8 +33918,8 @@ var compareActor = fromPromise(async ({ input: input3 }) => {
33397
33918
  const result = compareBothFiles(
33398
33919
  runaRelPath,
33399
33920
  templateRelPath,
33400
- path10.join(repoRoot, runaRelPath),
33401
- path10.join(templateDir, templateRelPath),
33921
+ path11.join(repoRoot, runaRelPath),
33922
+ path11.join(templateDir, templateRelPath),
33402
33923
  runaFile.category,
33403
33924
  options.diff ?? false
33404
33925
  );
@@ -33849,7 +34370,7 @@ var discoverActor = fromPromise(async ({ input: input3 }) => {
33849
34370
  const runaPattern = rule.runa;
33850
34371
  const runaFiles = await globFiles(repoRoot, runaPattern);
33851
34372
  for (const file of runaFiles) {
33852
- const relativePath = path10.relative(repoRoot, file.absolutePath);
34373
+ const relativePath = path11.relative(repoRoot, file.absolutePath);
33853
34374
  const key = generateComparisonKey(relativePath, false);
33854
34375
  inventory.runaFiles.set(relativePath, {
33855
34376
  ...file,
@@ -33863,7 +34384,7 @@ var discoverActor = fromPromise(async ({ input: input3 }) => {
33863
34384
  const templatePattern = rule.template;
33864
34385
  const templateFiles = await globFiles(templateDir, templatePattern);
33865
34386
  for (const file of templateFiles) {
33866
- const relativePath = path10.relative(templateDir, file.absolutePath);
34387
+ const relativePath = path11.relative(templateDir, file.absolutePath);
33867
34388
  const key = generateComparisonKey(relativePath, true);
33868
34389
  inventory.templateFiles.set(relativePath, {
33869
34390
  ...file,
@@ -33912,7 +34433,7 @@ async function matchDoubleWildcard(ctx, entries) {
33912
34433
  await walkAndMatch({ ...ctx, partIndex: ctx.partIndex + 1 });
33913
34434
  for (const entry of entries) {
33914
34435
  if (entry.isDirectory()) {
33915
- const subDir = path10.join(ctx.currentDir, entry.name);
34436
+ const subDir = path11.join(ctx.currentDir, entry.name);
33916
34437
  await walkAndMatch({ ...ctx, currentDir: subDir });
33917
34438
  }
33918
34439
  }
@@ -33921,7 +34442,7 @@ async function matchSingleWildcard(ctx, entries, pattern, isLastPart) {
33921
34442
  const regex = patternToRegex(pattern);
33922
34443
  for (const entry of entries) {
33923
34444
  if (regex.test(entry.name)) {
33924
- const entryPath = path10.join(ctx.currentDir, entry.name);
34445
+ const entryPath = path11.join(ctx.currentDir, entry.name);
33925
34446
  await processEntry(ctx, entryPath, entry.isFile(), entry.isDirectory(), isLastPart);
33926
34447
  }
33927
34448
  }
@@ -33931,14 +34452,14 @@ async function matchBraceExpansion(ctx, entries, pattern, isLastPart) {
33931
34452
  for (const option of options) {
33932
34453
  for (const entry of entries) {
33933
34454
  if (entry.name === option) {
33934
- const entryPath = path10.join(ctx.currentDir, entry.name);
34455
+ const entryPath = path11.join(ctx.currentDir, entry.name);
33935
34456
  await processEntry(ctx, entryPath, entry.isFile(), entry.isDirectory(), isLastPart);
33936
34457
  }
33937
34458
  }
33938
34459
  }
33939
34460
  }
33940
34461
  async function matchLiteral(ctx, pattern, isLastPart) {
33941
- const entryPath = path10.join(ctx.currentDir, pattern);
34462
+ const entryPath = path11.join(ctx.currentDir, pattern);
33942
34463
  if (!fs5.existsSync(entryPath)) return;
33943
34464
  const stats = fs5.statSync(entryPath);
33944
34465
  await processEntry(ctx, entryPath, stats.isFile(), stats.isDirectory(), isLastPart);
@@ -34463,15 +34984,15 @@ function printActionsNeeded(logger16, actions) {
34463
34984
  );
34464
34985
  }
34465
34986
  function findRepoRoot3(startDir) {
34466
- const { existsSync: existsSync51, readFileSync: readFileSync29 } = __require("fs");
34987
+ const { existsSync: existsSync52, readFileSync: readFileSync29 } = __require("fs");
34467
34988
  const { join: join23, dirname: dirname5 } = __require("path");
34468
34989
  let current = startDir;
34469
34990
  while (current !== dirname5(current)) {
34470
- if (existsSync51(join23(current, "turbo.json"))) {
34991
+ if (existsSync52(join23(current, "turbo.json"))) {
34471
34992
  return current;
34472
34993
  }
34473
34994
  const pkgPath = join23(current, "package.json");
34474
- if (existsSync51(pkgPath)) {
34995
+ if (existsSync52(pkgPath)) {
34475
34996
  try {
34476
34997
  const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
34477
34998
  if (pkg.workspaces) {
@@ -34539,10 +35060,10 @@ function generateReportOutput(output3, isJsonMode) {
34539
35060
  };
34540
35061
  }
34541
35062
  function validateRunaRepo(repoRoot) {
34542
- const { existsSync: existsSync51 } = __require("fs");
35063
+ const { existsSync: existsSync52 } = __require("fs");
34543
35064
  const { join: join23 } = __require("path");
34544
35065
  const templateDir = join23(repoRoot, "packages/runa-templates/templates");
34545
- if (!existsSync51(templateDir)) {
35066
+ if (!existsSync52(templateDir)) {
34546
35067
  throw new CLIError("template-check is a runa-repo only command", "NOT_RUNA_REPO", [
34547
35068
  "This command compares runa-repo with pj-repo templates",
34548
35069
  "It should only be run in the runa repository",
@@ -34644,11 +35165,29 @@ init_esm_shims();
34644
35165
 
34645
35166
  // src/commands/test/commands/test.ts
34646
35167
  init_esm_shims();
35168
+ function resolveEffectiveRequireManifest(options) {
35169
+ if (options.requireManifest && options.allowManifestFallback) {
35170
+ throw new CLIError(
35171
+ "--require-manifest and --allow-manifest-fallback are mutually exclusive",
35172
+ "TEST_MANIFEST_FLAGS_EXCLUSIVE",
35173
+ ["Use strict mode (default) OR explicitly allow fallback, but not both"]
35174
+ );
35175
+ }
35176
+ if (options.allowManifestFallback) return false;
35177
+ return options.requireManifest;
35178
+ }
34647
35179
  var testCommand = new Command("test").description("Run tests (compat). Prefer: test:layer0..4 or test:static/service/integration.").option("--layer <number>", "Run specific layer (0-4)").option("--from <number>", "Run from layer N to 4").option("--to <number>", "Run from layer 0 to N").option("--ci", "CI mode (fail fast, no interactive)").option("--verbose", "Verbose output").option("--record", "Record test results to database", true).option(
34648
35180
  "--report-json <path>",
34649
35181
  "Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
34650
- ).option("--generate", "Generate tests from XState before running (integration)").option("--advanced", "Generate advanced tests (integration)").option("--auto", "Zero-config auto-generation (integration)").option("--base-url <url>", "Override base URL (integration)").option("--changed", "Run only impacted layers based on git diff (service)").option("--base <ref>", "Base ref for --changed (service)").option("--skip-missing", "Skip layers with missing dependencies instead of failing").action(async (options) => {
35182
+ ).option("--generate", "Generate tests from XState before running (integration)").option("--advanced", "Generate advanced tests (integration)").option("--auto", "Zero-config auto-generation (integration)").option("--base-url <url>", "Override base URL (integration)").option("--changed", "Run only impacted layers based on git diff (service)").option("--base <ref>", "Base ref for --changed (service)").option("--skip-missing", "Skip layers with missing dependencies instead of failing").option(
35183
+ "--require-manifest",
35184
+ "Require manifest to be present and valid for Layer 3/4 tests (strict behavior)"
35185
+ ).option(
35186
+ "--allow-manifest-fallback",
35187
+ "Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
35188
+ ).action(async (options) => {
34651
35189
  try {
35190
+ const effectiveRequireManifest = resolveEffectiveRequireManifest(options);
34652
35191
  const output3 = await runTest({
34653
35192
  layer: options.layer !== void 0 ? Number.parseInt(options.layer, 10) : void 0,
34654
35193
  from: options.from !== void 0 ? Number.parseInt(options.from, 10) : void 0,
@@ -34663,7 +35202,8 @@ var testCommand = new Command("test").description("Run tests (compat). Prefer: t
34663
35202
  baseUrl: options.baseUrl,
34664
35203
  changed: options.changed,
34665
35204
  base: options.base,
34666
- skipMissing: options.skipMissing
35205
+ skipMissing: options.skipMissing,
35206
+ requireManifest: effectiveRequireManifest
34667
35207
  });
34668
35208
  emitJsonSuccess(testCommand, TestRunOutputSchema, output3);
34669
35209
  } catch (error) {
@@ -34761,11 +35301,29 @@ var testApiCommand = new Command("test:api").description("Run Layer 3: API tests
34761
35301
 
34762
35302
  // src/commands/test/commands/test-e2e.ts
34763
35303
  init_esm_shims();
35304
+ function resolveEffectiveRequireManifest2(options) {
35305
+ if (options.requireManifest && options.allowManifestFallback) {
35306
+ throw new CLIError(
35307
+ "--require-manifest and --allow-manifest-fallback are mutually exclusive",
35308
+ "TEST_E2E_MANIFEST_FLAGS_EXCLUSIVE",
35309
+ ["Use strict mode (default) OR explicitly allow fallback, but not both"]
35310
+ );
35311
+ }
35312
+ if (options.allowManifestFallback) return false;
35313
+ return options.requireManifest;
35314
+ }
34764
35315
  var testE2ECommand = new Command("test:e2e").description("Run Layer 4: E2E tests (Playwright) - Requires browser").option("--generate", "Generate tests from XState before running").option("--advanced", "Generate advanced tests (context-aware, guards, invariants, etc.)").option("--auto", "Zero-config auto-generation (implementation-driven)").option("--ci", "CI mode (fail fast, no interactive)").option("--record", "Record test results to database", true).option("--base-url <url>", "Explicit base URL for E2E (disables auto dev server start)").option(
35316
+ "--require-manifest",
35317
+ "Require manifest to be present and valid (strict behavior; enabled by default for Layer 4)"
35318
+ ).option(
35319
+ "--allow-manifest-fallback",
35320
+ "Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
35321
+ ).option(
34765
35322
  "--report-json <path>",
34766
35323
  "Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
34767
35324
  ).option("--verbose", "Verbose output (full error details, environment info)").action(async (options) => {
34768
35325
  try {
35326
+ const effectiveRequireManifest = resolveEffectiveRequireManifest2(options);
34769
35327
  const output3 = await runTestIntegration({
34770
35328
  ci: options.ci ?? false,
34771
35329
  record: options.record,
@@ -34775,6 +35333,7 @@ var testE2ECommand = new Command("test:e2e").description("Run Layer 4: E2E tests
34775
35333
  advanced: options.advanced,
34776
35334
  auto: options.auto,
34777
35335
  baseUrl: options.baseUrl,
35336
+ requireManifest: effectiveRequireManifest,
34778
35337
  invokedAs: "runa test:e2e"
34779
35338
  });
34780
35339
  emitJsonSuccess(testE2ECommand, TestIntegrationOutputSchema, output3);
@@ -34795,8 +35354,15 @@ var testE2ECommand = new Command("test:e2e").description("Run Layer 4: E2E tests
34795
35354
  );
34796
35355
  }
34797
35356
  });
34798
- var testBrowserCommand = new Command("test:browser").description("Run Layer 4: Browser tests (Playwright E2E) - Alias for test:e2e").option("--generate", "Generate tests from XState before running").option("--advanced", "Generate advanced tests").option("--auto", "Zero-config auto-generation").option("--ci", "CI mode (fail fast, no interactive)").option("--record", "Record test results to database", true).option("--base-url <url>", "Explicit base URL for E2E").option("--report-json <path>", "Export test report as JSON").option("--verbose", "Verbose output").action(async (options) => {
35357
+ var testBrowserCommand = new Command("test:browser").description("Run Layer 4: Browser tests (Playwright E2E) - Alias for test:e2e").option("--generate", "Generate tests from XState before running").option("--advanced", "Generate advanced tests").option("--auto", "Zero-config auto-generation").option("--ci", "CI mode (fail fast, no interactive)").option("--record", "Record test results to database", true).option("--base-url <url>", "Explicit base URL for E2E").option(
35358
+ "--require-manifest",
35359
+ "Require manifest to be present and valid (strict behavior; enabled by default for Layer 4)"
35360
+ ).option(
35361
+ "--allow-manifest-fallback",
35362
+ "Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
35363
+ ).option("--report-json <path>", "Export test report as JSON").option("--verbose", "Verbose output").action(async (options) => {
34799
35364
  try {
35365
+ const effectiveRequireManifest = resolveEffectiveRequireManifest2(options);
34800
35366
  const output3 = await runTestIntegration({
34801
35367
  ci: options.ci ?? false,
34802
35368
  record: options.record,
@@ -34806,6 +35372,7 @@ var testBrowserCommand = new Command("test:browser").description("Run Layer 4: B
34806
35372
  advanced: options.advanced,
34807
35373
  auto: options.auto,
34808
35374
  baseUrl: options.baseUrl,
35375
+ requireManifest: effectiveRequireManifest,
34809
35376
  invokedAs: "runa test:browser"
34810
35377
  });
34811
35378
  emitJsonSuccess(testBrowserCommand, TestIntegrationOutputSchema, output3);
@@ -34878,11 +35445,29 @@ var testLintCommand = new Command("test:lint").description("Run Layer 0: Lint (t
34878
35445
 
34879
35446
  // src/commands/test/commands/test-integration.ts
34880
35447
  init_esm_shims();
35448
+ function resolveEffectiveRequireManifest3(options) {
35449
+ if (options.requireManifest && options.allowManifestFallback) {
35450
+ throw new CLIError(
35451
+ "--require-manifest and --allow-manifest-fallback are mutually exclusive",
35452
+ "TEST_INTEGRATION_MANIFEST_FLAGS_EXCLUSIVE",
35453
+ ["Use strict mode (default) OR explicitly allow fallback, but not both"]
35454
+ );
35455
+ }
35456
+ if (options.allowManifestFallback) return false;
35457
+ return options.requireManifest;
35458
+ }
34881
35459
  var testIntegrationCommand = new Command("test:integration").description("Run Layer 4: Integration tests (E2E) with auto-generation").option("--generate", "Generate tests from XState before running").option("--advanced", "Generate advanced tests (context-aware, guards, invariants, etc.)").option("--auto", "Zero-config auto-generation (implementation-driven)").option("--ci", "CI mode (fail fast, no interactive)").option("--record", "Record test results to database", true).option("--base-url <url>", "Explicit base URL for E2E/Security (disables auto dev server start)").option(
35460
+ "--require-manifest",
35461
+ "Require manifest to be present and valid (strict behavior; enabled by default for Layer 4)"
35462
+ ).option(
35463
+ "--allow-manifest-fallback",
35464
+ "Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
35465
+ ).option(
34882
35466
  "--report-json <path>",
34883
35467
  "Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
34884
35468
  ).option("--verbose", "Verbose output (full error details, environment info)").action(async (options) => {
34885
35469
  try {
35470
+ const effectiveRequireManifest = resolveEffectiveRequireManifest3(options);
34886
35471
  const output3 = await runTestIntegration({
34887
35472
  ci: options.ci ?? false,
34888
35473
  record: options.record,
@@ -34892,6 +35477,7 @@ var testIntegrationCommand = new Command("test:integration").description("Run La
34892
35477
  advanced: options.advanced,
34893
35478
  auto: options.auto,
34894
35479
  baseUrl: options.baseUrl,
35480
+ requireManifest: effectiveRequireManifest,
34895
35481
  invokedAs: "runa test:integration"
34896
35482
  });
34897
35483
  emitJsonSuccess(testIntegrationCommand, TestIntegrationOutputSchema, output3);
@@ -34937,7 +35523,7 @@ function injectTestAttrsIfLayer4(layer, options) {
34937
35523
  "Run `runa inject-test-attrs` manually to see detailed errors",
34938
35524
  "Ensure XState machines exist in your project",
34939
35525
  "Check that machines have valid meta.e2e definitions",
34940
- "Or remove --require-manifest flag to continue with fallback behavior"
35526
+ "Or pass --allow-manifest-fallback to continue with fallback behavior"
34941
35527
  ],
34942
35528
  error instanceof Error ? error : void 0
34943
35529
  );
@@ -34947,10 +35533,17 @@ function injectTestAttrsIfLayer4(layer, options) {
34947
35533
  }
34948
35534
  }
34949
35535
  }
35536
+ function resolveEffectiveRequireManifest4(layer, options) {
35537
+ if (options.allowManifestFallback) return false;
35538
+ if (options.requireManifest !== void 0) return options.requireManifest;
35539
+ if (layer === 4 && process.env.RUNA_LAYER4_ALLOW_MANIFEST_FALLBACK !== "true") return true;
35540
+ return void 0;
35541
+ }
34950
35542
  async function runSingleLayer(params) {
35543
+ const effectiveRequireManifest = resolveEffectiveRequireManifest4(params.layer, params.options);
34951
35544
  injectTestAttrsIfLayer4(params.layer, {
34952
35545
  verbose: params.options.verbose,
34953
- requireManifest: params.options.requireManifest
35546
+ requireManifest: effectiveRequireManifest
34954
35547
  });
34955
35548
  try {
34956
35549
  const output3 = await runTest({
@@ -34967,7 +35560,7 @@ async function runSingleLayer(params) {
34967
35560
  reviewSnapshots: params.options.reviewSnapshots,
34968
35561
  forceRegenerate: params.options.force,
34969
35562
  skipGeneration: params.options.skipGeneration,
34970
- requireManifest: params.options.requireManifest,
35563
+ requireManifest: effectiveRequireManifest,
34971
35564
  invokedAs: `runa test:layer${params.layer}`
34972
35565
  });
34973
35566
  emitJsonSuccess(params.cmd, TestRunOutputSchema, output3);
@@ -35001,6 +35594,13 @@ function validateGenerationFlags(layer, opts) {
35001
35594
  ["Use --auto (implementation-driven) OR --generate/--advanced (XState-driven)"]
35002
35595
  );
35003
35596
  }
35597
+ if (layer === 4 && opts.requireManifest && opts.allowManifestFallback) {
35598
+ throw new CLIError(
35599
+ "--require-manifest and --allow-manifest-fallback are mutually exclusive",
35600
+ "TEST_LAYER_MANIFEST_FLAGS_EXCLUSIVE",
35601
+ ["Use strict mode (default) OR explicitly allow fallback, but not both"]
35602
+ );
35603
+ }
35004
35604
  }
35005
35605
  function validateSnapshotFlags(opts) {
35006
35606
  if (opts.reviewSnapshots && opts.ci) {
@@ -35039,6 +35639,9 @@ function createLayerCommand(layer) {
35039
35639
  cmd.option("--generate", "Generate tests from XState before running (Layer 4)").option("--advanced", "Generate advanced tests (requires --generate)").option("--auto", "Zero-config auto-generation (implementation-driven)").option("--update-snapshots", "Update visual baselines (Layer 4)").option("--filter <pattern>", 'Filter tests by pattern (e.g., "checkout-*")').option("--review-snapshots", "Interactive review of changed visual snapshots (Layer 4)").option("--force", "Force regenerate all tests, bypassing cache").option(
35040
35640
  "--require-manifest",
35041
35641
  "Require manifest to be present and valid (fail if missing or stale)"
35642
+ ).option(
35643
+ "--allow-manifest-fallback",
35644
+ "Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
35042
35645
  );
35043
35646
  }
35044
35647
  return cmd;
@@ -36887,8 +37490,8 @@ var logger13 = createCLILogger("watch");
36887
37490
  function addFallbackSchemaPatterns(patterns) {
36888
37491
  const detected = detectDatabasePackage(process.cwd());
36889
37492
  if (detected) {
36890
- patterns.push(path10__default.join(detected, "src/schema/**/*.ts"));
36891
- patterns.push(path10__default.join(detected, "sql/**/*.sql"));
37493
+ patterns.push(path11__default.join(detected, "src/schema/**/*.ts"));
37494
+ patterns.push(path11__default.join(detected, "sql/**/*.sql"));
36892
37495
  return;
36893
37496
  }
36894
37497
  for (const candidate of DATABASE_PACKAGE_CANDIDATES) {
@@ -36902,8 +37505,8 @@ async function buildSchemaPatterns() {
36902
37505
  const patterns = ["supabase/schemas/**/*.sql"];
36903
37506
  try {
36904
37507
  const dbPackagePath = await getDatabasePackagePath();
36905
- patterns.push(path10__default.join(dbPackagePath, "src/schema/**/*.ts"));
36906
- patterns.push(path10__default.join(dbPackagePath, "sql/**/*.sql"));
37508
+ patterns.push(path11__default.join(dbPackagePath, "src/schema/**/*.ts"));
37509
+ patterns.push(path11__default.join(dbPackagePath, "sql/**/*.sql"));
36907
37510
  } catch {
36908
37511
  addFallbackSchemaPatterns(patterns);
36909
37512
  }