@runa-ai/runa-cli 0.5.50 → 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 (32) hide show
  1. package/dist/commands/ci/utils/app-runtime.d.ts +16 -1
  2. package/dist/commands/ci/utils/app-runtime.d.ts.map +1 -1
  3. package/dist/commands/db/apply/helpers/pg-schema-diff-helpers.d.ts +14 -0
  4. package/dist/commands/db/apply/helpers/pg-schema-diff-helpers.d.ts.map +1 -1
  5. package/dist/commands/db/apply/helpers/retry-logic.d.ts.map +1 -1
  6. package/dist/commands/db/constants.d.ts +3 -3
  7. package/dist/commands/db/constants.d.ts.map +1 -1
  8. package/dist/commands/db/utils/db-target.d.ts.map +1 -1
  9. package/dist/commands/db/utils/preflight-check.d.ts.map +1 -1
  10. package/dist/commands/dev/machine.d.ts.map +1 -1
  11. package/dist/commands/env/commands/env-pull.d.ts.map +1 -1
  12. package/dist/commands/env/constants/local-supabase.d.ts +30 -62
  13. package/dist/commands/env/constants/local-supabase.d.ts.map +1 -1
  14. package/dist/commands/inject-test-attrs/action.d.ts.map +1 -1
  15. package/dist/commands/inject-test-attrs/commands/inject-test-attrs.d.ts.map +1 -1
  16. package/dist/commands/inject-test-attrs/contract.d.ts +118 -0
  17. package/dist/commands/inject-test-attrs/contract.d.ts.map +1 -1
  18. package/dist/commands/inject-test-attrs/detection-diagnostics.d.ts +67 -0
  19. package/dist/commands/inject-test-attrs/detection-diagnostics.d.ts.map +1 -0
  20. package/dist/commands/inject-test-attrs/manifest-generator.d.ts +7 -1
  21. package/dist/commands/inject-test-attrs/manifest-generator.d.ts.map +1 -1
  22. package/dist/commands/inject-test-attrs/processor-utils.d.ts.map +1 -1
  23. package/dist/commands/inject-test-attrs/processor.d.ts.map +1 -1
  24. package/dist/commands/inject-test-attrs/types.d.ts +57 -0
  25. package/dist/commands/inject-test-attrs/types.d.ts.map +1 -1
  26. package/dist/commands/manifest/index.d.ts.map +1 -1
  27. package/dist/commands/test/commands/test-e2e.d.ts.map +1 -1
  28. package/dist/commands/test/commands/test-integration.d.ts.map +1 -1
  29. package/dist/commands/test/commands/test-layer.d.ts.map +1 -1
  30. package/dist/commands/test/commands/test.d.ts.map +1 -1
  31. package/dist/index.js +1205 -585
  32. 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
- import fs5__default, { existsSync, readFileSync, readdirSync, mkdtempSync, writeFileSync, mkdirSync, copyFileSync, createWriteStream, statSync, rmSync, realpathSync, promises, lstatSync, accessSync, constants, chmodSync, unlinkSync } from 'fs';
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.50";
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,20 +8090,62 @@ 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
7868
8100
  };
7869
8101
  }
8102
+ var NEXT_CRITICAL_FILES = ["routes-manifest.json", "build-manifest.json"];
8103
+ function cleanStaleNextDevState(appDir) {
8104
+ const nextDir = path11__default.join(appDir, ".next");
8105
+ if (!existsSync(nextDir)) {
8106
+ return { cleaned: false };
8107
+ }
8108
+ for (const file of NEXT_CRITICAL_FILES) {
8109
+ if (!existsSync(path11__default.join(nextDir, file))) {
8110
+ cleanNextDir(nextDir, `Missing ${file}`);
8111
+ return { cleaned: true, reason: `Missing ${file}` };
8112
+ }
8113
+ }
8114
+ const serverDir = path11__default.join(nextDir, "server");
8115
+ if (!existsSync(serverDir)) {
8116
+ try {
8117
+ const nextStat = statSync(nextDir);
8118
+ const ageHours = (Date.now() - nextStat.mtimeMs) / (1e3 * 60 * 60);
8119
+ if (ageHours > 1) {
8120
+ cleanNextDir(nextDir, "Stale .next without server directory");
8121
+ return { cleaned: true, reason: "Stale .next without server directory" };
8122
+ }
8123
+ } catch {
8124
+ }
8125
+ }
8126
+ return { cleaned: false };
8127
+ }
8128
+ function cleanNextDir(nextDir, reason) {
8129
+ console.log(`[runa] Stale .next detected: ${reason}`);
8130
+ console.log("[runa] Cleaning up .next directory...");
8131
+ try {
8132
+ rmSync(nextDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
8133
+ console.log("[runa] Cleanup complete");
8134
+ } catch {
8135
+ const staleDir = `${nextDir}-stale-${Date.now()}`;
8136
+ console.log(`[runa] Could not remove .next, quarantining to ${path11__default.basename(staleDir)}`);
8137
+ try {
8138
+ renameSync(nextDir, staleDir);
8139
+ } catch {
8140
+ console.warn("[runa] Failed to quarantine .next. Run: rm -rf .next");
8141
+ }
8142
+ }
8143
+ }
7870
8144
  async function startAppBackground(params) {
7871
8145
  const mode = params.mode ?? "start";
7872
8146
  const isMonorepo2 = params.appDir !== params.repoRoot;
7873
- const rootPkgPath = path10__default.join(params.repoRoot, "package.json");
7874
- 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");
7875
8149
  const rootScripts = await readPackageScripts(rootPkgPath);
7876
8150
  const appScripts = isMonorepo2 ? await readPackageScripts(appPkgPath) : rootScripts;
7877
8151
  const { command, useRootScript } = determineAppCommand(
@@ -7883,7 +8157,7 @@ async function startAppBackground(params) {
7883
8157
  params.appDir,
7884
8158
  params.port
7885
8159
  );
7886
- const appLog = path10__default.join(params.tmpDir, "app.log");
8160
+ const appLog = path11__default.join(params.tmpDir, "app.log");
7887
8161
  const out = createWriteStream(appLog, { flags: "a" });
7888
8162
  const commandStr = command.join(" ");
7889
8163
  const modeLabel = mode === "dev" ? "development (hot reload)" : "production";
@@ -7892,7 +8166,7 @@ async function startAppBackground(params) {
7892
8166
  `[runa] Mode: ${modeLabel}`,
7893
8167
  `[runa] Command: ${commandStr}`,
7894
8168
  `[runa] Working directory: ${params.repoRoot}`,
7895
- `[runa] App directory: ${path10__default.relative(params.repoRoot, params.appDir) || "."}`,
8169
+ `[runa] App directory: ${path11__default.relative(params.repoRoot, params.appDir) || "."}`,
7896
8170
  useRootScript ? "[runa] Using root package.json script" : "[runa] Using app package.json script",
7897
8171
  "---",
7898
8172
  ""
@@ -7913,12 +8187,12 @@ async function startAppBackground(params) {
7913
8187
  streamToTerminal: params.stream
7914
8188
  });
7915
8189
  const pid = child.pid ?? -1;
7916
- await writeFile(path10__default.join(params.tmpDir, "app.pid"), `${pid}
8190
+ await writeFile(path11__default.join(params.tmpDir, "app.pid"), `${pid}
7917
8191
  `, "utf-8");
7918
8192
  return { pid, cleanupStreams };
7919
8193
  }
7920
8194
  async function waitForAppReady(params) {
7921
- 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;
7922
8196
  await waitHttpOk({
7923
8197
  url: `http://127.0.0.1:${params.port}/`,
7924
8198
  timeoutSeconds: params.timeoutSeconds,
@@ -8058,8 +8332,9 @@ var e2eMeta2 = {
8058
8332
  var appStartActor = fromPromise(
8059
8333
  async ({ input: input3 }) => {
8060
8334
  const { repoRoot, appDir, port, tmpDir, stream } = input3;
8061
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
8335
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
8062
8336
  await mkdir(fullTmpDir, { recursive: true });
8337
+ cleanStaleNextDevState(appDir);
8063
8338
  const result = await startAppBackground({
8064
8339
  repoRoot,
8065
8340
  appDir,
@@ -8325,11 +8600,11 @@ function printSummary2(logger16, output3) {
8325
8600
  }
8326
8601
  function findRepoRoot2(startDir) {
8327
8602
  let current = startDir;
8328
- while (current !== path10__default.dirname(current)) {
8329
- if (existsSync(path10__default.join(current, "turbo.json"))) {
8603
+ while (current !== path11__default.dirname(current)) {
8604
+ if (existsSync(path11__default.join(current, "turbo.json"))) {
8330
8605
  return current;
8331
8606
  }
8332
- const pkgPath = path10__default.join(current, "package.json");
8607
+ const pkgPath = path11__default.join(current, "package.json");
8333
8608
  if (existsSync(pkgPath)) {
8334
8609
  try {
8335
8610
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
@@ -8339,7 +8614,7 @@ function findRepoRoot2(startDir) {
8339
8614
  } catch {
8340
8615
  }
8341
8616
  }
8342
- current = path10__default.dirname(current);
8617
+ current = path11__default.dirname(current);
8343
8618
  }
8344
8619
  return startDir;
8345
8620
  }
@@ -8526,19 +8801,19 @@ function isSupportedNodeEnv(value) {
8526
8801
  function findProjectRoot(from) {
8527
8802
  const workspaceRoot = findWorkspaceRoot(from);
8528
8803
  if (workspaceRoot) return workspaceRoot;
8529
- let current = path10__default.resolve(from);
8530
- const root = path10__default.parse(current).root;
8804
+ let current = path11__default.resolve(from);
8805
+ const root = path11__default.parse(current).root;
8531
8806
  let depth = 0;
8532
8807
  while (current !== root && depth < MAX_DIRECTORY_TRAVERSAL_DEPTH) {
8533
- const hasGit = existsSync(path10__default.join(current, ".git"));
8534
- 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"));
8535
8810
  if (hasGit || hasPackageJson2) return current;
8536
- const parent = path10__default.dirname(current);
8811
+ const parent = path11__default.dirname(current);
8537
8812
  if (parent === current) break;
8538
8813
  current = parent;
8539
8814
  depth++;
8540
8815
  }
8541
- return path10__default.resolve(from);
8816
+ return path11__default.resolve(from);
8542
8817
  }
8543
8818
  function mapRunaEnvToVercelEnv(runaEnv) {
8544
8819
  if (runaEnv === "preview") return "preview";
@@ -8579,7 +8854,7 @@ function loadEnvFiles(options = {}) {
8579
8854
  const nodeEnv = resolveNodeEnv(options.nodeEnv);
8580
8855
  const projectRoot = findProjectRoot(cwd);
8581
8856
  const vercelEnv = options.vercelEnv ?? inferVercelEnv({ nodeEnv, runaEnv: options.runaEnv });
8582
- const keysFile = path10__default.join(projectRoot, ".env.keys");
8857
+ const keysFile = path11__default.join(projectRoot, ".env.keys");
8583
8858
  const baseFilePaths = buildBaseEnvFilePaths({ nodeEnv, vercelEnv });
8584
8859
  const runaFilePaths = options.runaEnv ? buildRunaEnvFilePaths(options.runaEnv) : [];
8585
8860
  const allRelPaths = [...baseFilePaths, ...runaFilePaths];
@@ -8589,7 +8864,7 @@ function loadEnvFiles(options = {}) {
8589
8864
  const filePaths = [
8590
8865
  keysFile,
8591
8866
  // Load keys first
8592
- ...allRelPaths.map((rel) => path10__default.join(projectRoot, rel)).filter(existsSync)
8867
+ ...allRelPaths.map((rel) => path11__default.join(projectRoot, rel)).filter(existsSync)
8593
8868
  ];
8594
8869
  config({
8595
8870
  path: filePaths,
@@ -8598,7 +8873,7 @@ function loadEnvFiles(options = {}) {
8598
8873
  quiet: true
8599
8874
  // Suppress dotenvx verbose output
8600
8875
  });
8601
- loadedFiles = allRelPaths.filter((rel) => existsSync(path10__default.join(projectRoot, rel)));
8876
+ loadedFiles = allRelPaths.filter((rel) => existsSync(path11__default.join(projectRoot, rel)));
8602
8877
  } else {
8603
8878
  const targetEnv = { ...process.env };
8604
8879
  loadedFiles = [
@@ -8673,8 +8948,8 @@ function buildRunaEnvFilePaths(runaEnv) {
8673
8948
  function loadEnvFilesIntoTarget(params) {
8674
8949
  const loadedFiles = [];
8675
8950
  for (const relPath of params.relPaths) {
8676
- const fullPath = path10__default.join(params.projectRoot, relPath);
8677
- const resolvedPath = path10__default.resolve(fullPath);
8951
+ const fullPath = path11__default.join(params.projectRoot, relPath);
8952
+ const resolvedPath = path11__default.resolve(fullPath);
8678
8953
  if (!isPathContained(params.projectRoot, resolvedPath)) {
8679
8954
  continue;
8680
8955
  }
@@ -8942,7 +9217,7 @@ async function runTool(params) {
8942
9217
  exitCode,
8943
9218
  issueCount,
8944
9219
  durationMs,
8945
- outputPath: path10__default.relative(process.cwd(), params.outputPath)
9220
+ outputPath: path11__default.relative(process.cwd(), params.outputPath)
8946
9221
  });
8947
9222
  });
8948
9223
  proc.on("error", async () => {
@@ -8961,7 +9236,7 @@ async function runTool(params) {
8961
9236
  exitCode: -1,
8962
9237
  issueCount: 0,
8963
9238
  durationMs,
8964
- outputPath: path10__default.relative(process.cwd(), params.outputPath)
9239
+ outputPath: path11__default.relative(process.cwd(), params.outputPath)
8965
9240
  });
8966
9241
  });
8967
9242
  });
@@ -8993,7 +9268,7 @@ async function executeWorkflowCheck(params) {
8993
9268
  label: params.label,
8994
9269
  command: params.command,
8995
9270
  args: params.args,
8996
- outputPath: path10__default.join(params.logDir, `${params.name}-output.txt`),
9271
+ outputPath: path11__default.join(params.logDir, `${params.name}-output.txt`),
8997
9272
  parseIssueCount: params.parseIssueCount
8998
9273
  });
8999
9274
  logCheckResult(result, params.isWarningOnly ?? false);
@@ -9065,7 +9340,7 @@ async function runCiChecks(options) {
9065
9340
  const mode = options.mode === "github-actions" ? "github-actions" : "local";
9066
9341
  const isCI3 = mode === "github-actions";
9067
9342
  const workflowsChanged = options.workflowsChanged;
9068
- const logDir = path10__default.join(process.cwd(), ".runa", "tmp", "workflow");
9343
+ const logDir = path11__default.join(process.cwd(), ".runa", "tmp", "workflow");
9069
9344
  await mkdir(logDir, { recursive: true });
9070
9345
  console.log("");
9071
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");
@@ -9074,7 +9349,7 @@ async function runCiChecks(options) {
9074
9349
  console.log("");
9075
9350
  const results = await executeChecks(workflowsChanged, logDir);
9076
9351
  const summary = buildChecksSummary(startedAt, workflowsChanged, results);
9077
- const summaryPath = path10__default.join(logDir, "checks-summary.json");
9352
+ const summaryPath = path11__default.join(logDir, "checks-summary.json");
9078
9353
  await writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
9079
9354
  if (isCI3) {
9080
9355
  await appendGithubStepSummary(buildStepSummaryMarkdown(summary));
@@ -9141,7 +9416,7 @@ function printFinalOutput(summary, summaryPath) {
9141
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");
9142
9417
  console.log(`${summary.status === "failure" ? "\u274C" : "\u2705"} Workflow Checks: ${summary.status}`);
9143
9418
  console.log(` Duration: ${formatDuration$1(summary.durationMs)}`);
9144
- console.log(` Summary: ${path10__default.relative(process.cwd(), summaryPath)}`);
9419
+ console.log(` Summary: ${path11__default.relative(process.cwd(), summaryPath)}`);
9145
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");
9146
9421
  }
9147
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);
@@ -9154,10 +9429,10 @@ init_esm_shims();
9154
9429
  var CiConfigSchema = z.record(z.string(), z.unknown());
9155
9430
  async function loadCiConfig(params) {
9156
9431
  const override = typeof params.overridePath === "string" && params.overridePath.trim().length > 0 ? params.overridePath.trim() : null;
9157
- const defaultPath = path10__default.join(params.repoRoot, ".runa", "ci.config.json");
9432
+ const defaultPath = path11__default.join(params.repoRoot, ".runa", "ci.config.json");
9158
9433
  const resolvedPath = override ?? (existsSync(defaultPath) ? defaultPath : null);
9159
9434
  if (!resolvedPath) return { configPath: null, config: null };
9160
- 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);
9161
9436
  if (!existsSync(abs)) return { configPath: abs, config: null };
9162
9437
  const raw = await readFile(abs, "utf-8");
9163
9438
  const parsed = JSON.parse(raw);
@@ -9259,9 +9534,9 @@ var CiSummarySchema = z.object({
9259
9534
  async function writeCiSummary(params) {
9260
9535
  const cwd = params.cwd ?? process.cwd();
9261
9536
  const parsed = CiSummarySchema.parse(params.summary);
9262
- const dir = path10__default.join(cwd, ".runa", "tmp");
9537
+ const dir = path11__default.join(cwd, ".runa", "tmp");
9263
9538
  await mkdir(dir, { recursive: true });
9264
- const filePath = path10__default.join(dir, "ci-summary.json");
9539
+ const filePath = path11__default.join(dir, "ci-summary.json");
9265
9540
  await writeFile(filePath, `${JSON.stringify(parsed, null, 2)}
9266
9541
  `, "utf-8");
9267
9542
  return filePath;
@@ -9510,12 +9785,12 @@ async function detectStack(repoRoot, tmpDir, productionDbUrlAdmin) {
9510
9785
  label: "detect-stack",
9511
9786
  command: "pnpm",
9512
9787
  args: ["exec", "runa", "db", "detect-stack", "--quiet"],
9513
- logFile: path10__default.join(tmpDir, "detect-stack.log")
9788
+ logFile: path11__default.join(tmpDir, "detect-stack.log")
9514
9789
  });
9515
9790
  return String(res.stdout ?? "").trim();
9516
9791
  }
9517
9792
  function checkIfInitialDeployment(repoRoot, productionDbUrl) {
9518
- const schemasDir = path10__default.join(repoRoot, "supabase", "schemas", "declarative");
9793
+ const schemasDir = path11__default.join(repoRoot, "supabase", "schemas", "declarative");
9519
9794
  let schemas;
9520
9795
  try {
9521
9796
  schemas = detectAppSchemas(schemasDir, false);
@@ -9581,9 +9856,9 @@ function checkIfInitialDeployment(repoRoot, productionDbUrl) {
9581
9856
  }
9582
9857
  }
9583
9858
  async function showSchemaDiff(repoRoot, tmpDir) {
9584
- const diffLog = path10__default.join(tmpDir, "schema-diff.log");
9859
+ const diffLog = path11__default.join(tmpDir, "schema-diff.log");
9585
9860
  const safeEnv = getSafeEnv();
9586
- const declarativeSqlPath = path10__default.join(repoRoot, "supabase/schemas/declarative");
9861
+ const declarativeSqlPath = path11__default.join(repoRoot, "supabase/schemas/declarative");
9587
9862
  if (existsSync(declarativeSqlPath)) {
9588
9863
  await runLogged({
9589
9864
  cwd: repoRoot,
@@ -9597,8 +9872,8 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9597
9872
  }
9598
9873
  const detected = detectDatabasePackage(repoRoot);
9599
9874
  if (detected) {
9600
- const schemaPath = path10__default.join(detected, "src", "schema");
9601
- if (existsSync(path10__default.join(repoRoot, schemaPath))) {
9875
+ const schemaPath = path11__default.join(detected, "src", "schema");
9876
+ if (existsSync(path11__default.join(repoRoot, schemaPath))) {
9602
9877
  await runLogged({
9603
9878
  cwd: repoRoot,
9604
9879
  env: safeEnv,
@@ -9611,8 +9886,8 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9611
9886
  }
9612
9887
  }
9613
9888
  for (const candidate of DATABASE_PACKAGE_CANDIDATES) {
9614
- const candidatePath = path10__default.join("packages", candidate, "src", "schema");
9615
- 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))) {
9616
9891
  await runLogged({
9617
9892
  cwd: repoRoot,
9618
9893
  env: safeEnv,
@@ -9624,7 +9899,7 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9624
9899
  return;
9625
9900
  }
9626
9901
  }
9627
- if (existsSync(path10__default.join(repoRoot, "src", "schema"))) {
9902
+ if (existsSync(path11__default.join(repoRoot, "src", "schema"))) {
9628
9903
  await runLogged({
9629
9904
  cwd: repoRoot,
9630
9905
  env: safeEnv,
@@ -9636,7 +9911,7 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9636
9911
  }
9637
9912
  }
9638
9913
  async function detectRisks(repoRoot, tmpDir) {
9639
- const logFile = path10__default.join(tmpDir, "db-risks.log");
9914
+ const logFile = path11__default.join(tmpDir, "db-risks.log");
9640
9915
  try {
9641
9916
  const env2 = getFilteredEnv();
9642
9917
  await runLogged({
@@ -9682,7 +9957,7 @@ async function snapshotCreate(repoRoot, tmpDir, productionDbUrlAdmin, commit) {
9682
9957
  label: "snapshot create production",
9683
9958
  command: "pnpm",
9684
9959
  args: ["exec", "runa", "db", "snapshot", "create", "production", "--commit", commit],
9685
- logFile: path10__default.join(tmpDir, "snapshot-create.log")
9960
+ logFile: path11__default.join(tmpDir, "snapshot-create.log")
9686
9961
  });
9687
9962
  }
9688
9963
  async function snapshotRestoreLatest(repoRoot, tmpDir, productionDbUrlAdmin) {
@@ -9695,7 +9970,7 @@ async function snapshotRestoreLatest(repoRoot, tmpDir, productionDbUrlAdmin) {
9695
9970
  label: "snapshot restore production (latest)",
9696
9971
  command: "pnpm",
9697
9972
  args: ["exec", "runa", "db", "snapshot", "restore", "production", "--latest", "--auto-approve"],
9698
- logFile: path10__default.join(tmpDir, "snapshot-restore.log")
9973
+ logFile: path11__default.join(tmpDir, "snapshot-restore.log")
9699
9974
  });
9700
9975
  }
9701
9976
  function parseApplyLog(logContent) {
@@ -9759,7 +10034,7 @@ async function applyProductionSchema(repoRoot, tmpDir, productionDbUrlAdmin, pro
9759
10034
  if (options?.maxLockWaitMs !== void 0) {
9760
10035
  args.push("--max-lock-wait-ms", String(options.maxLockWaitMs));
9761
10036
  }
9762
- const logPath = path10__default.join(tmpDir, "db-apply-production.log");
10037
+ const logPath = path11__default.join(tmpDir, "db-apply-production.log");
9763
10038
  const startTime = Date.now();
9764
10039
  await runLogged({
9765
10040
  cwd: repoRoot,
@@ -9804,11 +10079,11 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
9804
10079
  label: "git log (commit message)",
9805
10080
  command: "git",
9806
10081
  args: ["log", "-1", "--pretty=format:%s"],
9807
- logFile: path10__default.join(tmpDir, "git-commit-message.log")
10082
+ logFile: path11__default.join(tmpDir, "git-commit-message.log")
9808
10083
  });
9809
10084
  const commitMsg = String(msg.stdout ?? "").trim();
9810
10085
  const schemaPaths = [];
9811
- const declarativeSqlPath = path10__default.join(repoRoot, "supabase/schemas/declarative");
10086
+ const declarativeSqlPath = path11__default.join(repoRoot, "supabase/schemas/declarative");
9812
10087
  if (existsSync(declarativeSqlPath)) {
9813
10088
  schemaPaths.push("supabase/schemas/declarative/");
9814
10089
  } else {
@@ -9828,7 +10103,7 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
9828
10103
  label: "git diff (schema)",
9829
10104
  command: "git",
9830
10105
  args: ["diff", "origin/main", "HEAD", "--", ...schemaPaths],
9831
- logFile: path10__default.join(tmpDir, "git-schema-diff.log")
10106
+ logFile: path11__default.join(tmpDir, "git-schema-diff.log")
9832
10107
  });
9833
10108
  const diffRaw = String(diff.stdout ?? "");
9834
10109
  const diffLimited = diffRaw.length > 1e4 ? diffRaw.slice(0, 1e4) : diffRaw;
@@ -9857,7 +10132,7 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
9857
10132
  "--environment",
9858
10133
  "production"
9859
10134
  ],
9860
- logFile: path10__default.join(tmpDir, "db-audit-record.log")
10135
+ logFile: path11__default.join(tmpDir, "db-audit-record.log")
9861
10136
  });
9862
10137
  }
9863
10138
  async function notifyDeployment(repoRoot, tmpDir, params) {
@@ -9885,7 +10160,7 @@ async function notifyDeployment(repoRoot, tmpDir, params) {
9885
10160
  "--type",
9886
10161
  "production-schema"
9887
10162
  ],
9888
- logFile: path10__default.join(tmpDir, "notify-deployment.log")
10163
+ logFile: path11__default.join(tmpDir, "notify-deployment.log")
9889
10164
  });
9890
10165
  }
9891
10166
 
@@ -10247,7 +10522,7 @@ $$;
10247
10522
  label: `repair timestamps (${params.labelPrefix})`,
10248
10523
  command: "psql",
10249
10524
  args: [...psql.args, "-v", "ON_ERROR_STOP=1", "-c", sql],
10250
- logFile: path10__default.join(params.tmpDir, `timestamp-repair-${params.labelPrefix}.log`)
10525
+ logFile: path11__default.join(params.tmpDir, `timestamp-repair-${params.labelPrefix}.log`)
10251
10526
  });
10252
10527
  }
10253
10528
 
@@ -10679,7 +10954,7 @@ async function runCiProdApply(params) {
10679
10954
  overridePath: params.options.config
10680
10955
  });
10681
10956
  if (cfg.configPath)
10682
- params.summary.detected.configPath = path10__default.relative(params.repoRoot, cfg.configPath);
10957
+ params.summary.detected.configPath = path11__default.relative(params.repoRoot, cfg.configPath);
10683
10958
  if (cfg.config) params.summary.detected.config = cfg.config;
10684
10959
  requireCiAutoApprove({ mode: params.summary.mode, autoApprove: params.options.autoApprove });
10685
10960
  const inputs = resolveProdApplyInputs();
@@ -10772,7 +11047,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
10772
11047
  await appendGithubStepSummary(
10773
11048
  buildCiProdApplyStepSummaryMarkdown({
10774
11049
  summary,
10775
- summaryPath: path10__default.relative(repoRoot, summaryPath)
11050
+ summaryPath: path11__default.relative(repoRoot, summaryPath)
10776
11051
  })
10777
11052
  );
10778
11053
  if (summary.mode === "github-actions") {
@@ -10788,7 +11063,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
10788
11063
  const summaryPath = await writeCiSummary({ summary });
10789
11064
  logSection("Result");
10790
11065
  console.log(`status: ${summary.status}`);
10791
- console.log(`summary: ${path10__default.relative(repoRoot, summaryPath)}`);
11066
+ console.log(`summary: ${path11__default.relative(repoRoot, summaryPath)}`);
10792
11067
  logNextActions([
10793
11068
  "Inspect .runa/tmp logs (db-apply-production.log, snapshot-*.log)",
10794
11069
  "If rollback succeeded, database should be restored to pre-deploy snapshot"
@@ -10796,7 +11071,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
10796
11071
  await appendGithubStepSummary(
10797
11072
  buildCiProdApplyStepSummaryMarkdown({
10798
11073
  summary,
10799
- summaryPath: path10__default.relative(repoRoot, summaryPath)
11074
+ summaryPath: path11__default.relative(repoRoot, summaryPath)
10800
11075
  })
10801
11076
  );
10802
11077
  await maybePostFailureComment({
@@ -10867,7 +11142,7 @@ function getChecks() {
10867
11142
  }
10868
11143
  async function runCheck(check, logDir) {
10869
11144
  const startTime = Date.now();
10870
- const logPath = path10__default.join(logDir, `${check.name}.log`);
11145
+ const logPath = path11__default.join(logDir, `${check.name}.log`);
10871
11146
  return new Promise((resolve12) => {
10872
11147
  const proc = spawn(check.command, check.args, {
10873
11148
  cwd: process.cwd(),
@@ -10897,7 +11172,7 @@ async function runCheck(check, logDir) {
10897
11172
  status: exitCode === 0 ? "passed" : "failed",
10898
11173
  exitCode,
10899
11174
  durationMs,
10900
- logPath: path10__default.relative(process.cwd(), logPath)
11175
+ logPath: path11__default.relative(process.cwd(), logPath)
10901
11176
  });
10902
11177
  });
10903
11178
  proc.on("error", async () => {
@@ -10912,7 +11187,7 @@ async function runCheck(check, logDir) {
10912
11187
  status: "failed",
10913
11188
  exitCode: 1,
10914
11189
  durationMs,
10915
- logPath: path10__default.relative(process.cwd(), logPath)
11190
+ logPath: path11__default.relative(process.cwd(), logPath)
10916
11191
  });
10917
11192
  });
10918
11193
  });
@@ -11040,19 +11315,19 @@ function printFinalStaticOutput(summary, summaryPath) {
11040
11315
  console.log(`${summary.status === "success" ? "\u2705" : "\u274C"} Static Analysis: ${summary.status}`);
11041
11316
  console.log(` Duration: ${formatDuration$1(summary.durationMs)}`);
11042
11317
  console.log(` Passed: ${summary.passedCount}/${summary.checks.length}`);
11043
- console.log(` Summary: ${path10__default.relative(process.cwd(), summaryPath)}`);
11318
+ console.log(` Summary: ${path11__default.relative(process.cwd(), summaryPath)}`);
11044
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");
11045
11320
  }
11046
11321
  async function runCiStatic(options) {
11047
11322
  const startedAt = /* @__PURE__ */ new Date();
11048
11323
  const isCI3 = options.mode === "github-actions";
11049
- const logDir = path10__default.join(process.cwd(), ".runa", "tmp", "workflow");
11324
+ const logDir = path11__default.join(process.cwd(), ".runa", "tmp", "workflow");
11050
11325
  await mkdir(logDir, { recursive: true });
11051
11326
  const checksToRun = getChecksToRun(options);
11052
11327
  printStaticHeader(options);
11053
11328
  const results = options.parallel ? await runChecksParallel(checksToRun, logDir) : await runChecksSequential(checksToRun, logDir);
11054
11329
  const summary = buildStaticSummary(startedAt, results);
11055
- const summaryPath = path10__default.join(logDir, "static-summary.json");
11330
+ const summaryPath = path11__default.join(logDir, "static-summary.json");
11056
11331
  await writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
11057
11332
  if (isCI3) {
11058
11333
  await appendGithubStepSummary(buildStepSummaryMarkdown2(summary));
@@ -11082,9 +11357,9 @@ var appBuildActor = fromPromise(
11082
11357
  async ({ input: input3 }) => {
11083
11358
  const { repoRoot, tmpDir, env: env2 = process.env } = input3;
11084
11359
  try {
11085
- const hasTurbo = existsSync(path10__default.join(repoRoot, "turbo.json"));
11086
- const hasApps = existsSync(path10__default.join(repoRoot, "apps"));
11087
- 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"));
11088
11363
  const args = hasTurbo ? hasApps && !hasAppsWeb ? ["turbo", "run", "build", "--filter=./apps/*"] : ["turbo", "run", "build"] : ["build"];
11089
11364
  await runLogged({
11090
11365
  cwd: repoRoot,
@@ -11092,7 +11367,7 @@ var appBuildActor = fromPromise(
11092
11367
  label: "build",
11093
11368
  command: "pnpm",
11094
11369
  args,
11095
- logFile: path10__default.join(tmpDir, "build.log")
11370
+ logFile: path11__default.join(tmpDir, "build.log")
11096
11371
  });
11097
11372
  return { passed: true };
11098
11373
  } catch (error) {
@@ -11108,14 +11383,14 @@ var appBuildActor = fromPromise(
11108
11383
  init_esm_shims();
11109
11384
  var APP_CANDIDATES = ["web", "dashboard", "app", "frontend", "client"];
11110
11385
  function findExistingAppDirs(repoRoot) {
11111
- const appsDir = path10__default.join(repoRoot, "apps");
11386
+ const appsDir = path11__default.join(repoRoot, "apps");
11112
11387
  if (!existsSync(appsDir)) return [];
11113
11388
  try {
11114
11389
  const entries = readdirSync(appsDir, { withFileTypes: true });
11115
11390
  const found = [];
11116
11391
  for (const entry of entries) {
11117
11392
  if (!entry.isDirectory()) continue;
11118
- const pkgJson = path10__default.join(appsDir, entry.name, "package.json");
11393
+ const pkgJson = path11__default.join(appsDir, entry.name, "package.json");
11119
11394
  if (existsSync(pkgJson)) {
11120
11395
  found.push(`apps/${entry.name}`);
11121
11396
  }
@@ -11135,9 +11410,9 @@ function findExistingAppDirs(repoRoot) {
11135
11410
  }
11136
11411
  }
11137
11412
  function validateAppDir(repoRoot, appDir) {
11138
- const pkgJsonPath = path10__default.join(appDir, "package.json");
11413
+ const pkgJsonPath = path11__default.join(appDir, "package.json");
11139
11414
  if (!existsSync(appDir)) {
11140
- const relPath = path10__default.relative(repoRoot, appDir) || ".";
11415
+ const relPath = path11__default.relative(repoRoot, appDir) || ".";
11141
11416
  const suggestions = findExistingAppDirs(repoRoot);
11142
11417
  const errorParts = [`App directory not found: ${relPath}`];
11143
11418
  if (suggestions.length > 0) {
@@ -11159,7 +11434,7 @@ function validateAppDir(repoRoot, appDir) {
11159
11434
  return errorParts.join("\n");
11160
11435
  }
11161
11436
  if (!existsSync(pkgJsonPath)) {
11162
- const relPath = path10__default.relative(repoRoot, appDir) || ".";
11437
+ const relPath = path11__default.relative(repoRoot, appDir) || ".";
11163
11438
  return `No package.json found in app directory: ${relPath}`;
11164
11439
  }
11165
11440
  return null;
@@ -11216,9 +11491,9 @@ init_esm_shims();
11216
11491
  async function runAppBuild(params) {
11217
11492
  const { repoRoot, tmpDir, env: env2 } = params;
11218
11493
  try {
11219
- const hasTurbo = existsSync(path10__default.join(repoRoot, "turbo.json"));
11220
- const hasApps = existsSync(path10__default.join(repoRoot, "apps"));
11221
- 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"));
11222
11497
  const args = hasTurbo ? hasApps && !hasAppsWeb ? ["turbo", "run", "build", "--filter=./apps/*"] : ["turbo", "run", "build"] : ["build"];
11223
11498
  await runLogged({
11224
11499
  cwd: repoRoot,
@@ -11226,7 +11501,7 @@ async function runAppBuild(params) {
11226
11501
  label: "build",
11227
11502
  command: "pnpm",
11228
11503
  args,
11229
- logFile: path10__default.join(tmpDir, "build.log")
11504
+ logFile: path11__default.join(tmpDir, "build.log")
11230
11505
  });
11231
11506
  return { passed: true };
11232
11507
  } catch (error) {
@@ -11245,7 +11520,7 @@ async function runManifestGenerate(params) {
11245
11520
  label: "manifest:generate",
11246
11521
  command: "pnpm",
11247
11522
  args: ["manifest:generate"],
11248
- logFile: path10__default.join(tmpDir, "manifest-generate.log")
11523
+ logFile: path11__default.join(tmpDir, "manifest-generate.log")
11249
11524
  });
11250
11525
  return { generated: true };
11251
11526
  } catch (error) {
@@ -11265,7 +11540,7 @@ async function runPlaywrightInstall(params) {
11265
11540
  label: "playwright install",
11266
11541
  command: "pnpm",
11267
11542
  args,
11268
- logFile: path10__default.join(tmpDir, "playwright-install.log")
11543
+ logFile: path11__default.join(tmpDir, "playwright-install.log")
11269
11544
  });
11270
11545
  return { installed: true };
11271
11546
  } catch (error) {
@@ -11338,7 +11613,7 @@ var playwrightInstallActor = fromPromise(
11338
11613
  label: "playwright install",
11339
11614
  command: "pnpm",
11340
11615
  args,
11341
- logFile: path10__default.join(tmpDir, "playwright-install.log")
11616
+ logFile: path11__default.join(tmpDir, "playwright-install.log")
11342
11617
  });
11343
11618
  return { installed: true };
11344
11619
  } catch (error) {
@@ -11362,7 +11637,7 @@ var staticChecksActor2 = fromPromise(
11362
11637
  label: "type-check",
11363
11638
  command: "pnpm",
11364
11639
  args: ["type-check"],
11365
- logFile: path10__default.join(tmpDir, "type-check.log")
11640
+ logFile: path11__default.join(tmpDir, "type-check.log")
11366
11641
  }),
11367
11642
  runLogged({
11368
11643
  cwd: repoRoot,
@@ -11370,7 +11645,7 @@ var staticChecksActor2 = fromPromise(
11370
11645
  label: "lint",
11371
11646
  command: "pnpm",
11372
11647
  args: ["lint"],
11373
- logFile: path10__default.join(tmpDir, "lint.log")
11648
+ logFile: path11__default.join(tmpDir, "lint.log")
11374
11649
  })
11375
11650
  ]);
11376
11651
  const typeCheckPassed = typeCheckResult.status === "fulfilled";
@@ -11521,7 +11796,7 @@ var applySeedsActor = fromPromise(
11521
11796
  label: `db seed (${envArg})`,
11522
11797
  command: "pnpm",
11523
11798
  args: ["exec", "runa", "db", "seed", envArg, "--auto-approve"],
11524
- logFile: path10__default.join(tmpDir, `ci-db-seed-${envArg}.log`)
11799
+ logFile: path11__default.join(tmpDir, `ci-db-seed-${envArg}.log`)
11525
11800
  });
11526
11801
  return { applied: true };
11527
11802
  } catch (error) {
@@ -11899,7 +12174,7 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
11899
12174
  label: `probe pgtap (best-effort, ${params.label})`,
11900
12175
  command: "psql",
11901
12176
  args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", probeSql],
11902
- logFile: path10__default.join(params.tmpDir, `pgtap-probe-${params.label}.log`)
12177
+ logFile: path11__default.join(params.tmpDir, `pgtap-probe-${params.label}.log`)
11903
12178
  }).catch(() => null);
11904
12179
  const raw = String(probe?.stdout ?? "").trim();
11905
12180
  const [availableRaw, installedRaw] = raw.split(",");
@@ -11914,11 +12189,11 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
11914
12189
  label: `ensure pgtap (best-effort, ${params.label})`,
11915
12190
  command: "psql",
11916
12191
  args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-c", installSql],
11917
- logFile: path10__default.join(params.tmpDir, `pgtap-ensure-${params.label}.log`)
12192
+ logFile: path11__default.join(params.tmpDir, `pgtap-ensure-${params.label}.log`)
11918
12193
  }).catch(async (error) => {
11919
12194
  try {
11920
12195
  await writeFile(
11921
- path10__default.join(params.tmpDir, `pgtap-ensure-${params.label}.failed`),
12196
+ path11__default.join(params.tmpDir, `pgtap-ensure-${params.label}.failed`),
11922
12197
  `${error instanceof Error ? error.message : String(error)}
11923
12198
  `,
11924
12199
  "utf-8"
@@ -11932,7 +12207,7 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
11932
12207
  label: `probe pgtap (best-effort, ${params.label}, after)`,
11933
12208
  command: "psql",
11934
12209
  args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", probeSql],
11935
- 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`)
11936
12211
  }).catch(() => null);
11937
12212
  const afterRaw = String(probeAfter?.stdout ?? "").trim();
11938
12213
  const [availableAfterRaw, installedAfterRaw] = afterRaw.split(",");
@@ -12053,14 +12328,14 @@ function extractSqlFromSchemaChanges(fullOutput) {
12053
12328
  return null;
12054
12329
  }
12055
12330
  function getIdempotentRoleNames(repoRoot) {
12056
- const idempotentDir = path10__default.join(repoRoot, "supabase", "schemas", "idempotent");
12331
+ const idempotentDir = path11__default.join(repoRoot, "supabase", "schemas", "idempotent");
12057
12332
  const roles = [];
12058
12333
  try {
12059
12334
  const fs14 = __require("fs");
12060
12335
  if (!fs14.existsSync(idempotentDir)) return [];
12061
12336
  const files = fs14.readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
12062
12337
  for (const file of files) {
12063
- const content = fs14.readFileSync(path10__default.join(idempotentDir, file), "utf-8");
12338
+ const content = fs14.readFileSync(path11__default.join(idempotentDir, file), "utf-8");
12064
12339
  const roleMatches = content.matchAll(/CREATE\s+ROLE\s+(\w+)\s+WITH/gi);
12065
12340
  for (const match of roleMatches) {
12066
12341
  if (match[1]) roles.push(match[1].toLowerCase());
@@ -12201,7 +12476,7 @@ var productionPreviewActor = fromPromise(
12201
12476
  );
12202
12477
  return buildSkipResult(!!productionUrl);
12203
12478
  }
12204
- const logFile = path10__default.join(tmpDir, "ci-production-preview.log");
12479
+ const logFile = path11__default.join(tmpDir, "ci-production-preview.log");
12205
12480
  console.log("\u25B6 production preview (dry-run): runa db apply production --check");
12206
12481
  try {
12207
12482
  const result = await execa(
@@ -12291,7 +12566,7 @@ var resetDbActor = fromPromise(
12291
12566
  label: "db reset (local)",
12292
12567
  command: "npx",
12293
12568
  args: ["supabase", "db", "reset", "--local"],
12294
- logFile: path10__default.join(tmpDir, "ci-db-reset.log")
12569
+ logFile: path11__default.join(tmpDir, "ci-db-reset.log")
12295
12570
  });
12296
12571
  return { reset: true };
12297
12572
  } catch (error) {
@@ -12307,8 +12582,8 @@ var resetDbActor = fromPromise(
12307
12582
  init_esm_shims();
12308
12583
  async function hasSetupRolesScript(repoRoot) {
12309
12584
  const candidates = [
12310
- path10__default.join(repoRoot, "packages", "database", "package.json"),
12311
- path10__default.join(repoRoot, "package.json")
12585
+ path11__default.join(repoRoot, "packages", "database", "package.json"),
12586
+ path11__default.join(repoRoot, "package.json")
12312
12587
  ];
12313
12588
  for (const pkgPath of candidates) {
12314
12589
  if (!existsSync(pkgPath)) continue;
@@ -12346,7 +12621,7 @@ var setupRolesActor = fromPromise(
12346
12621
  label: "db roles setup",
12347
12622
  command: "pnpm",
12348
12623
  args: ["db:setup-roles"],
12349
- logFile: path10__default.join(tmpDir, "ci-db-roles-setup.log")
12624
+ logFile: path11__default.join(tmpDir, "ci-db-roles-setup.log")
12350
12625
  });
12351
12626
  const stdout = String(result.stdout ?? "");
12352
12627
  const appUrlMatch = stdout.match(/APP_DATABASE_URL=["']?([^"'\n]+)["']?/);
@@ -12459,14 +12734,14 @@ function getSchemaGitDiff(repoRoot) {
12459
12734
  }
12460
12735
  }
12461
12736
  function getIdempotentRoleNames2(repoRoot) {
12462
- const idempotentDir = path10__default.join(repoRoot, "supabase", "schemas", "idempotent");
12737
+ const idempotentDir = path11__default.join(repoRoot, "supabase", "schemas", "idempotent");
12463
12738
  const roles = [];
12464
12739
  try {
12465
12740
  const fs14 = __require("fs");
12466
12741
  if (!fs14.existsSync(idempotentDir)) return [];
12467
12742
  const files = fs14.readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
12468
12743
  for (const file of files) {
12469
- const content = fs14.readFileSync(path10__default.join(idempotentDir, file), "utf-8");
12744
+ const content = fs14.readFileSync(path11__default.join(idempotentDir, file), "utf-8");
12470
12745
  const roleMatches = content.matchAll(/CREATE\s+ROLE\s+(\w+)\s+WITH/gi);
12471
12746
  for (const match of roleMatches) {
12472
12747
  if (match[1]) roles.push(match[1].toLowerCase());
@@ -12563,7 +12838,7 @@ var syncSchemaActor = fromPromise(
12563
12838
  // Always verbose for full traceability
12564
12839
  ...skipCodegen ? ["--skip-codegen"] : []
12565
12840
  ];
12566
- 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`);
12567
12842
  await runLogged({
12568
12843
  cwd: repoRoot,
12569
12844
  env: baseEnv,
@@ -12703,7 +12978,7 @@ async function startSupabaseLocal(params) {
12703
12978
  label: "supabase start (local)",
12704
12979
  command: "supabase",
12705
12980
  args: ["start", "--exclude", exclude],
12706
- logFile: path10__default.join(params.tmpDir, "supabase-start-local.log")
12981
+ logFile: path11__default.join(params.tmpDir, "supabase-start-local.log")
12707
12982
  });
12708
12983
  }
12709
12984
  function getDefaultLocalSupabaseUrl(repoRoot) {
@@ -12731,7 +13006,7 @@ async function resolveLocalSupabaseEnv(params) {
12731
13006
  label: "supabase status (json)",
12732
13007
  command: "supabase",
12733
13008
  args: ["status", "--output", "json"],
12734
- logFile: path10__default.join(params.tmpDir, `supabase-status-${i + 1}.log`)
13009
+ logFile: path11__default.join(params.tmpDir, `supabase-status-${i + 1}.log`)
12735
13010
  });
12736
13011
  const parsed = JSON.parse(String(res.stdout ?? "{}"));
12737
13012
  const out = z.object({
@@ -12851,7 +13126,7 @@ async function findFilesRecursive(params) {
12851
13126
  continue;
12852
13127
  }
12853
13128
  for (const e of entries) {
12854
- const p = path10__default.join(dir, e.name);
13129
+ const p = path11__default.join(dir, e.name);
12855
13130
  if (e.isDirectory()) stack.push(p);
12856
13131
  else if (e.isFile() && params.suffixes.some((s) => p.endsWith(s))) out.push(p);
12857
13132
  }
@@ -12865,7 +13140,7 @@ async function queryScalar(params) {
12865
13140
  label: `psql scalar (${params.logName})`,
12866
13141
  command: "psql",
12867
13142
  args: [params.databaseUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", params.sql],
12868
- logFile: path10__default.join(params.tmpDir, `psql-${params.logName}.log`)
13143
+ logFile: path11__default.join(params.tmpDir, `psql-${params.logName}.log`)
12869
13144
  });
12870
13145
  return String(res.stdout ?? "").trim();
12871
13146
  }
@@ -12993,8 +13268,8 @@ function isPlaywrightIgnored(filePath) {
12993
13268
  async function detectGeneratedE2eCapabilities(params) {
12994
13269
  const caps = /* @__PURE__ */ new Set();
12995
13270
  const diagnostics = {};
12996
- const layer4Dir = path10__default.join(params.repoRoot, ".runa", "tests", "layer4");
12997
- 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");
12998
13273
  const hasLayer4Dir = await pathExists(layer4Dir);
12999
13274
  const hasTmpDir = await pathExists(tmpDir);
13000
13275
  if (!hasLayer4Dir && !hasTmpDir) {
@@ -13504,7 +13779,7 @@ init_esm_shims();
13504
13779
  // src/commands/ci/utils/test-parallel.ts
13505
13780
  init_esm_shims();
13506
13781
  async function readLayerResult(tmpDir, layer) {
13507
- const resultFile = path10__default.join(tmpDir, `vitest-layer${layer}-result.json`);
13782
+ const resultFile = path11__default.join(tmpDir, `vitest-layer${layer}-result.json`);
13508
13783
  try {
13509
13784
  const content = await readFile(resultFile, "utf-8");
13510
13785
  return JSON.parse(content);
@@ -13622,8 +13897,8 @@ async function waitUntilAllFinished(params) {
13622
13897
  async function runLayersInParallel(params) {
13623
13898
  const spawned = [];
13624
13899
  for (const layer of params.layers) {
13625
- const logFile = path10__default.join(params.tmpDir, `layer${layer}.log`);
13626
- 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`);
13627
13902
  const proc = runLogged({
13628
13903
  cwd: params.repoRoot,
13629
13904
  env: {
@@ -13666,7 +13941,7 @@ async function runLayersInParallel(params) {
13666
13941
  for (const p of spawned) {
13667
13942
  const codeRaw = p.exitCode ?? await p.procPromise;
13668
13943
  const code = Number.isNaN(codeRaw) ? 1 : codeRaw;
13669
- 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`);
13670
13945
  const wasKilled = killedLayerSet.has(p.layer);
13671
13946
  const actualResult = waitResult.successMap.get(p.layer) ?? {
13672
13947
  success: code === 0,
@@ -13681,9 +13956,9 @@ async function runLayersInParallel(params) {
13681
13956
  skippedReason: actualResult.skippedReason,
13682
13957
  killed: wasKilled,
13683
13958
  killedBy: wasKilled ? failFastSource : void 0,
13684
- logPath: path10__default.relative(params.repoRoot, p.logFile),
13685
- exitPath: path10__default.relative(params.repoRoot, p.exitFile),
13686
- 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),
13687
13962
  // Test count information
13688
13963
  totalTests: actualResult.totalTests,
13689
13964
  passedTests: actualResult.passedTests,
@@ -16979,13 +17254,20 @@ init_esm_shims();
16979
17254
  // src/commands/db/utils/db-target.ts
16980
17255
  init_esm_shims();
16981
17256
  init_env();
16982
- init_constants();
17257
+ init_local_supabase();
16983
17258
  function getLocalDatabaseUrl() {
16984
- const ports = detectSupabasePorts(process.cwd());
16985
- 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";
16986
17263
  }
16987
17264
  function isLocalDatabaseUrl(url) {
16988
- 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
+ }
16989
17271
  }
16990
17272
  function resolveDatabaseUrl(environment) {
16991
17273
  switch (environment) {
@@ -18286,6 +18568,60 @@ function handleHazards(hazards, input3) {
18286
18568
  );
18287
18569
  }
18288
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
+ }
18289
18625
  function executePgSchemaDiffPlan(dbUrl, schemasDir, includeSchemas, verbose, options) {
18290
18626
  const planArgs = [
18291
18627
  "plan",
@@ -18321,6 +18657,10 @@ function executePgSchemaDiffPlan(dbUrl, schemasDir, includeSchemas, verbose, opt
18321
18657
  logger4.error(`Exit code: ${planResult.status}`);
18322
18658
  logger4.error(`Signal: ${planResult.signal || "none"}`);
18323
18659
  logger4.error(`Stderr: ${planStderr || "(empty)"}`);
18660
+ const extDetection = detectMissingExtensionType(planStderr || planOutput);
18661
+ if (extDetection.detected) {
18662
+ logger4.error(formatExtensionErrorHint(extDetection));
18663
+ }
18324
18664
  throw new Error(
18325
18665
  `pg-schema-diff plan failed (exit ${planResult.status}): ${planStderr || "(no output)"}`
18326
18666
  );
@@ -18378,6 +18718,10 @@ async function executeApplyWithRetry(applyArgs, verbose, config) {
18378
18718
  }
18379
18719
  logger5.error("pg-schema-diff apply failed:");
18380
18720
  logger5.error(errorOutput);
18721
+ const extDetection = detectMissingExtensionType(errorOutput);
18722
+ if (extDetection.detected) {
18723
+ logger5.error(formatExtensionErrorHint(extDetection));
18724
+ }
18381
18725
  return {
18382
18726
  success: false,
18383
18727
  error: new Error(`pg-schema-diff apply failed: ${errorOutput}`),
@@ -19844,16 +20188,16 @@ var ERROR_MESSAGES2 = {
19844
20188
  SCHEMA_NOT_FOUND: "Schema file not found"
19845
20189
  };
19846
20190
  function containsPathTraversal2(inputPath) {
19847
- const normalized = path10__default.normalize(inputPath);
20191
+ const normalized = path11__default.normalize(inputPath);
19848
20192
  return normalized.includes("..") || inputPath.includes("\0");
19849
20193
  }
19850
20194
  function isPathWithinBase(filePath, baseDir) {
19851
20195
  try {
19852
- const resolvedFile = path10__default.resolve(filePath);
19853
- const resolvedBase = path10__default.resolve(baseDir);
19854
- const normalizedFile = path10__default.normalize(resolvedFile);
19855
- const normalizedBase = path10__default.normalize(resolvedBase);
19856
- 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);
19857
20201
  } catch {
19858
20202
  return false;
19859
20203
  }
@@ -19862,13 +20206,13 @@ function validateSchemaPath(dbPackagePath, projectRoot = process.cwd()) {
19862
20206
  if (containsPathTraversal2(dbPackagePath)) {
19863
20207
  throw new Error(ERROR_MESSAGES2.PATH_TRAVERSAL);
19864
20208
  }
19865
- const schemaEntry = path10__default.join(dbPackagePath, "src", "schema", "index.ts");
19866
- 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);
19867
20211
  let resolvedProjectRoot;
19868
20212
  try {
19869
20213
  resolvedProjectRoot = realpathSync(projectRoot);
19870
20214
  } catch {
19871
- resolvedProjectRoot = path10__default.resolve(projectRoot);
20215
+ resolvedProjectRoot = path11__default.resolve(projectRoot);
19872
20216
  }
19873
20217
  if (!isPathWithinBase(absoluteSchemaPath, resolvedProjectRoot)) {
19874
20218
  throw new Error(ERROR_MESSAGES2.PATH_TRAVERSAL);
@@ -20000,7 +20344,7 @@ function diffSchema(params) {
20000
20344
  };
20001
20345
  }
20002
20346
  function extractTablesFromIdempotentSql(idempotentDir, projectRoot = process.cwd()) {
20003
- const fullPath = path10__default.resolve(projectRoot, idempotentDir);
20347
+ const fullPath = path11__default.resolve(projectRoot, idempotentDir);
20004
20348
  if (!existsSync(fullPath)) {
20005
20349
  return [];
20006
20350
  }
@@ -20009,7 +20353,7 @@ function extractTablesFromIdempotentSql(idempotentDir, projectRoot = process.cwd
20009
20353
  try {
20010
20354
  const files = readdirSync(fullPath).filter((f) => f.endsWith(".sql"));
20011
20355
  for (const file of files) {
20012
- const filePath = path10__default.join(fullPath, file);
20356
+ const filePath = path11__default.join(fullPath, file);
20013
20357
  const content = readFileSync(filePath, "utf-8");
20014
20358
  const contentWithoutComments = content.replace(/--.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
20015
20359
  for (const match of contentWithoutComments.matchAll(createTablePattern)) {
@@ -20232,7 +20576,7 @@ async function validateGitHubOutputPath(filePath) {
20232
20576
  if (!filePath || filePath.trim().length === 0) {
20233
20577
  return { valid: false, resolvedPath: null, error: "Empty file path" };
20234
20578
  }
20235
- const normalizedPath = path10__default.normalize(filePath);
20579
+ const normalizedPath = path11__default.normalize(filePath);
20236
20580
  if (normalizedPath.includes("..")) {
20237
20581
  return {
20238
20582
  valid: false,
@@ -20240,7 +20584,7 @@ async function validateGitHubOutputPath(filePath) {
20240
20584
  error: "Path traversal detected (..) in file path"
20241
20585
  };
20242
20586
  }
20243
- const absolutePath = path10__default.resolve(normalizedPath);
20587
+ const absolutePath = path11__default.resolve(normalizedPath);
20244
20588
  for (const forbidden of FORBIDDEN_PATHS) {
20245
20589
  if (absolutePath.startsWith(forbidden) || absolutePath.includes(forbidden)) {
20246
20590
  return {
@@ -20719,7 +21063,7 @@ async function analyzeSchemaChanges() {
20719
21063
  try {
20720
21064
  const { getDatabasePackagePath: getDatabasePackagePath2 } = await Promise.resolve().then(() => (init_config_loader(), config_loader_exports));
20721
21065
  const dbPath = await getDatabasePackagePath2();
20722
- const schemaPath = path10__default.join(dbPath, "src/schema/");
21066
+ const schemaPath = path11__default.join(dbPath, "src/schema/");
20723
21067
  const { stdout } = await execa("git", ["diff", "--cached", "--", schemaPath]);
20724
21068
  const lines = stdout.split("\n");
20725
21069
  return parseDiffLines(lines);
@@ -20998,7 +21342,7 @@ function categorizeRisks(risks) {
20998
21342
  }
20999
21343
 
21000
21344
  // src/commands/db/utils/preflight-check.ts
21001
- init_constants();
21345
+ init_local_supabase();
21002
21346
  init_config_loader();
21003
21347
  function createInitialResult() {
21004
21348
  return {
@@ -21052,7 +21396,7 @@ function runDatabasePackageChecks(result, logger16, step) {
21052
21396
  logger16.error("Database package path is missing");
21053
21397
  return null;
21054
21398
  }
21055
- logger16.success(`Found database package: ${path10__default.basename(dbPackagePath)}`);
21399
+ logger16.success(`Found database package: ${path11__default.basename(dbPackagePath)}`);
21056
21400
  logger16.step("Checking schema files", step.next());
21057
21401
  const schemaCheck = checkSchemaFiles(dbPackagePath);
21058
21402
  if (!schemaCheck.exists) {
@@ -21176,9 +21520,9 @@ ${stderr}`.toLowerCase();
21176
21520
  }
21177
21521
  }
21178
21522
  async function testDatabaseConnection(projectRoot) {
21179
- const ports = detectSupabasePorts(projectRoot);
21180
- const dbPort = ports.db;
21181
- 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;
21182
21526
  let sql = null;
21183
21527
  try {
21184
21528
  sql = postgres(connectionUrl, {
@@ -21200,12 +21544,12 @@ async function testDatabaseConnection(projectRoot) {
21200
21544
  function checkDatabasePackage() {
21201
21545
  const cwd = process.cwd();
21202
21546
  const locations = [
21203
- path10__default.join(cwd, "packages", "database"),
21204
- path10__default.join(cwd, "packages", "db"),
21205
- 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")
21206
21550
  ];
21207
21551
  for (const location of locations) {
21208
- const configPath = path10__default.join(location, "drizzle.config.ts");
21552
+ const configPath = path11__default.join(location, "drizzle.config.ts");
21209
21553
  if (existsSync(configPath)) {
21210
21554
  return { exists: true, path: location };
21211
21555
  }
@@ -21250,7 +21594,7 @@ function countTsFilesRecursive(dir) {
21250
21594
  try {
21251
21595
  const entries = readdirSync(dir, { withFileTypes: true });
21252
21596
  for (const entry of entries) {
21253
- const fullPath = path10__default.join(dir, entry.name);
21597
+ const fullPath = path11__default.join(dir, entry.name);
21254
21598
  if (entry.isDirectory()) {
21255
21599
  count += countTsFilesRecursive(fullPath);
21256
21600
  } else if (entry.isFile() && entry.name.endsWith(".ts")) {
@@ -21262,7 +21606,7 @@ function countTsFilesRecursive(dir) {
21262
21606
  return count;
21263
21607
  }
21264
21608
  function checkSchemaFiles(dbPackagePath) {
21265
- const schemaDir = path10__default.join(dbPackagePath, "src", "schema");
21609
+ const schemaDir = path11__default.join(dbPackagePath, "src", "schema");
21266
21610
  if (!existsSync(schemaDir)) {
21267
21611
  return { exists: false, count: 0 };
21268
21612
  }
@@ -21299,9 +21643,9 @@ async function runOrphanCheck(env2, dbPackagePath, result, logger16, step) {
21299
21643
  logger16.step("Checking for orphaned database objects", step.next());
21300
21644
  try {
21301
21645
  const { expectedTables, expectedEnums } = await extractSchemaTablesAndEnums(dbPackagePath);
21302
- const databaseUrl = tryResolveDatabaseUrl("local") || "postgresql://postgres:postgres@localhost:54322/postgres";
21646
+ const databaseUrl = tryResolveDatabaseUrl("local") || buildLocalDatabaseUrl(process.cwd());
21303
21647
  const { dbTables, dbEnums } = await fetchDbTablesAndEnums(databaseUrl, {
21304
- schemaDir: path10__default.join(dbPackagePath, "src", "schema")
21648
+ schemaDir: path11__default.join(dbPackagePath, "src", "schema")
21305
21649
  });
21306
21650
  let excludeFromOrphanDetection = [];
21307
21651
  let idempotentSqlDir = "supabase/schemas/idempotent";
@@ -21339,61 +21683,43 @@ async function runOrphanCheck(env2, dbPackagePath, result, logger16, step) {
21339
21683
  logger16.warn(`Orphan check skipped: ${message}`);
21340
21684
  }
21341
21685
  }
21342
- function runExtensionConfigCheck(result, logger16, step) {
21686
+ function runExtensionConfigCheck(_result, logger16, step) {
21343
21687
  logger16.step("Checking PostgreSQL extension configuration", step.next());
21344
21688
  try {
21345
21689
  const extensionResult = checkExtensionConfig(process.cwd());
21346
- if (extensionResult.usedExtensions.length === 0) {
21347
- logger16.success("No extensions detected in SQL files");
21690
+ if (!extensionResult || typeof extensionResult !== "object") {
21691
+ logger16.warn("Extension config check returned invalid result");
21348
21692
  return;
21349
21693
  }
21350
- if (extensionResult.passed) {
21351
- logger16.success(
21352
- `All ${extensionResult.usedExtensions.length} extension(s) are enabled in config.toml`
21353
- );
21694
+ const usedExtensions = extensionResult.usedExtensions ?? [];
21695
+ if (usedExtensions.length === 0) {
21696
+ logger16.success("No extensions detected in SQL files");
21354
21697
  return;
21355
21698
  }
21356
- if (extensionResult.supabaseManagedExtensions.length > 0) {
21357
- logger16.info(
21358
- `Supabase-managed: ${extensionResult.supabaseManagedExtensions.join(", ")} (auto-enabled)`
21359
- );
21699
+ const sqlManaged = extensionResult.sqlManagedExtensions ?? [];
21700
+ const supabaseManaged = extensionResult.supabaseManagedExtensions ?? [];
21701
+ const parts = [];
21702
+ if (sqlManaged.length > 0) {
21703
+ parts.push(`${sqlManaged.length} SQL-managed`);
21360
21704
  }
21361
- if (extensionResult.missingExtensions.length > 0) {
21362
- for (const warning of extensionResult.warnings) {
21363
- recordWarning(result, warning);
21364
- }
21365
- logger16.warn(
21366
- `Missing ${extensionResult.missingExtensions.length} extension(s) in config.toml:`
21367
- );
21368
- for (const ext of extensionResult.missingExtensions) {
21369
- const sqlFile = extensionResult.sqlFilePaths.get(ext);
21370
- logger16.info(` \u2022 ${ext}${sqlFile ? ` (used in ${path10__default.basename(sqlFile)})` : ""}`);
21371
- }
21372
- logger16.info("");
21373
- logger16.info(" To fix, add to supabase/config.toml:");
21374
- logger16.info(" [db.extensions]");
21375
- for (const ext of extensionResult.missingExtensions) {
21376
- logger16.info(` ${ext} = "enabled"`);
21377
- }
21378
- logger16.info("");
21379
- logger16.info(" Then restart Supabase: supabase stop && supabase start");
21380
- logger16.info("");
21705
+ if (supabaseManaged.length > 0) {
21706
+ parts.push(`${supabaseManaged.length} Supabase-managed`);
21381
21707
  }
21382
- if (extensionResult.notes.length > 0) {
21383
- for (const note of extensionResult.notes) {
21384
- logger16.info(` Note: ${note}`);
21385
- }
21386
- logger16.info("");
21708
+ const summary = parts.join(", ");
21709
+ logger16.success(`${usedExtensions.length} extension(s) found (${summary})`);
21710
+ const notes = extensionResult.notes ?? [];
21711
+ for (const note of notes) {
21712
+ logger16.info(` ${note}`);
21387
21713
  }
21388
21714
  } catch (error) {
21389
21715
  const message = error instanceof Error ? error.message : "Unknown error";
21390
- logger16.warn(`Extension config check skipped: ${message}`);
21716
+ logger16.warn(`Extension config check failed: ${message}`);
21391
21717
  }
21392
21718
  }
21393
21719
  async function runSqlSchemaRiskCheck(result, logger16, step) {
21394
21720
  logger16.step("Checking SQL schema for risky patterns", step.next());
21395
21721
  const cwd = process.cwd();
21396
- const sqlDir = path10__default.join(cwd, "supabase", "schemas", "declarative");
21722
+ const sqlDir = path11__default.join(cwd, "supabase", "schemas", "declarative");
21397
21723
  if (!existsSync(sqlDir)) {
21398
21724
  logger16.success("No SQL schema directory found (supabase/schemas/declarative/)");
21399
21725
  return;
@@ -21406,7 +21732,7 @@ async function runSqlSchemaRiskCheck(result, logger16, step) {
21406
21732
  }
21407
21733
  const allRisks = [];
21408
21734
  for (const sqlFile of sqlFiles) {
21409
- const filePath = path10__default.join(sqlDir, sqlFile);
21735
+ const filePath = path11__default.join(sqlDir, sqlFile);
21410
21736
  const risks = await detectSchemaRisks(filePath);
21411
21737
  for (const risk of risks) {
21412
21738
  allRisks.push({ ...risk, file: sqlFile });
@@ -23158,7 +23484,7 @@ async function checkPort(port) {
23158
23484
  };
23159
23485
  }
23160
23486
  function detectSupabasePortsFromConfig() {
23161
- const configPath = path10__default.join(process.cwd(), "supabase", "config.toml");
23487
+ const configPath = path11__default.join(process.cwd(), "supabase", "config.toml");
23162
23488
  const BASE_PORTS = { api: 54321, db: 54322, studio: 54323, inbucket: 54324 };
23163
23489
  if (!existsSync(configPath)) {
23164
23490
  return Object.values(BASE_PORTS);
@@ -23247,7 +23573,7 @@ var BASE_PORT = 54321;
23247
23573
  var PORTS_PER_SLOT = 10;
23248
23574
  var TOTAL_SLOTS = 100;
23249
23575
  function calculatePortOffset(projectPath) {
23250
- const normalizedPath = path10__default.resolve(projectPath);
23576
+ const normalizedPath = path11__default.resolve(projectPath);
23251
23577
  const hash = createHash("md5").update(normalizedPath).digest("hex");
23252
23578
  return parseInt(hash.slice(0, 8), 16) % TOTAL_SLOTS;
23253
23579
  }
@@ -23268,7 +23594,7 @@ function getSupabasePorts(projectPath) {
23268
23594
  }
23269
23595
  function updateSupabaseConfigPorts(projectPath) {
23270
23596
  const ports = getSupabasePorts(projectPath);
23271
- const configPath = path10__default.join(projectPath, "supabase", "config.toml");
23597
+ const configPath = path11__default.join(projectPath, "supabase", "config.toml");
23272
23598
  if (!existsSync(configPath)) {
23273
23599
  return { updated: false, ports, configPath };
23274
23600
  }
@@ -23303,7 +23629,7 @@ function getPortAllocationSummary(projectPath) {
23303
23629
  const ports = getSupabasePorts(projectPath);
23304
23630
  const offset = calculatePortOffset(projectPath);
23305
23631
  return [
23306
- `Port allocation for: ${path10__default.basename(projectPath)}`,
23632
+ `Port allocation for: ${path11__default.basename(projectPath)}`,
23307
23633
  ` Slot: ${offset} (hash-based)`,
23308
23634
  ` API: ${ports.api}`,
23309
23635
  ` DB: ${ports.db}`,
@@ -23337,7 +23663,7 @@ function parseSeedPaths(configPath) {
23337
23663
  }
23338
23664
  }
23339
23665
  async function applySeedFile(seedPath, dbUrl) {
23340
- const supabaseDir = path10__default.join(process.cwd(), "supabase");
23666
+ const supabaseDir = path11__default.join(process.cwd(), "supabase");
23341
23667
  const absolutePath = resolveSafePath(supabaseDir, seedPath);
23342
23668
  if (!existsSync(absolutePath)) {
23343
23669
  return;
@@ -23348,12 +23674,12 @@ async function applySeedFile(seedPath, dbUrl) {
23348
23674
  });
23349
23675
  }
23350
23676
  async function applySeeds2(configPath) {
23351
- const configFile = path10__default.join(process.cwd(), "supabase", "config.toml");
23677
+ const configFile = path11__default.join(process.cwd(), "supabase", "config.toml");
23352
23678
  const seedPaths = parseSeedPaths(configFile);
23353
23679
  if (seedPaths.length === 0) {
23354
23680
  return;
23355
23681
  }
23356
- const supabaseDir = path10__default.join(process.cwd(), "supabase");
23682
+ const supabaseDir = path11__default.join(process.cwd(), "supabase");
23357
23683
  const safePaths = filterSafePaths(seedPaths, supabaseDir);
23358
23684
  if (safePaths.length === 0) {
23359
23685
  return;
@@ -23771,7 +24097,7 @@ var validateCommand = new Command("validate").description("Validate schema files
23771
24097
  const logger16 = createCLILogger("db:validate");
23772
24098
  try {
23773
24099
  logger16.section("Schema Validation");
23774
- const schemasPath = path10__default.join(process.cwd(), "packages", "database", "src", "schema");
24100
+ const schemasPath = path11__default.join(process.cwd(), "packages", "database", "src", "schema");
23775
24101
  if (!existsSync(schemasPath)) {
23776
24102
  throw new CLIError("Schema directory not found", "SCHEMA_DIR_NOT_FOUND", [
23777
24103
  `Expected location: ${schemasPath}`,
@@ -23936,8 +24262,8 @@ var generateCommand = new Command("generate").description("Generate TypeScript t
23936
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) => {
23937
24263
  const logger16 = createCLILogger("db:schema:list");
23938
24264
  try {
23939
- const dbPackagePath = path10__default.join(process.cwd(), "packages", "database");
23940
- 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"))) {
23941
24267
  throw new CLIError("drizzle.config.ts not found", "CONFIG_NOT_FOUND", [
23942
24268
  `Expected location: ${dbPackagePath}/drizzle.config.ts`,
23943
24269
  "Ensure you are in the project root",
@@ -25176,7 +25502,7 @@ var testGenCommand = new Command("test:gen").description("Generate pgTAP behavio
25176
25502
  const databaseUrl = options.db || process.env.DATABASE_URL || getLocalDbUrl();
25177
25503
  const schemas = options.schemas ? options.schemas.split(",") : void 0;
25178
25504
  const dbPackage = databasePaths.package();
25179
- 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");
25180
25506
  const outputPath = options.output || defaultOutputPath;
25181
25507
  spinner.text = "Generating pgTAP behavior tests...";
25182
25508
  const result = await dbGeneratePgTapTests({
@@ -26188,108 +26514,8 @@ async function getVercelRootDirectory() {
26188
26514
  return info?.rootDirectory ?? null;
26189
26515
  }
26190
26516
 
26191
- // src/commands/env/constants/local-supabase.ts
26192
- init_esm_shims();
26193
- var DEFAULT_API_PORT = 54321;
26194
- var DEFAULT_DB_PORT = 54322;
26195
- function parsePortFromToml(content, section, key) {
26196
- const sectionRegex = new RegExp(`\\[${section}\\]([\\s\\S]*?)(?=\\n\\[|$)`, "g");
26197
- const sectionMatch = sectionRegex.exec(content);
26198
- if (!sectionMatch) return null;
26199
- const sectionContent = sectionMatch[1];
26200
- const keyRegex = new RegExp(`^\\s*${key}\\s*=\\s*(\\d+)`, "m");
26201
- const keyMatch = keyRegex.exec(sectionContent);
26202
- if (!keyMatch) return null;
26203
- const port = Number.parseInt(keyMatch[1], 10);
26204
- return Number.isFinite(port) && port > 0 && port < 65536 ? port : null;
26205
- }
26206
- function readPortsFromConfigToml(projectRoot) {
26207
- const configPath = path10__default.join(projectRoot, "supabase", "config.toml");
26208
- try {
26209
- const content = readFileSync(configPath, "utf-8");
26210
- const apiPort = parsePortFromToml(content, "api", "port");
26211
- const dbPort = parsePortFromToml(content, "db", "port");
26212
- if (apiPort !== null || dbPort !== null) {
26213
- return {
26214
- api: apiPort ?? DEFAULT_API_PORT,
26215
- db: dbPort ?? DEFAULT_DB_PORT
26216
- };
26217
- }
26218
- return null;
26219
- } catch {
26220
- return null;
26221
- }
26222
- }
26223
- function detectLocalSupabasePorts(projectRoot = process.cwd()) {
26224
- const configPorts = readPortsFromConfigToml(projectRoot);
26225
- if (configPorts) {
26226
- return configPorts;
26227
- }
26228
- return {
26229
- api: DEFAULT_API_PORT,
26230
- db: DEFAULT_DB_PORT
26231
- };
26232
- }
26233
- var LOCAL_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
26234
- var LOCAL_SUPABASE_SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU";
26235
- function buildLocalSupabaseUrl(projectRoot = process.cwd()) {
26236
- const ports = detectLocalSupabasePorts(projectRoot);
26237
- return `http://127.0.0.1:${ports.api}`;
26238
- }
26239
- function buildLocalDatabaseUrl(projectRoot = process.cwd()) {
26240
- const ports = detectLocalSupabasePorts(projectRoot);
26241
- return `postgresql://postgres:postgres@127.0.0.1:${ports.db}/postgres`;
26242
- }
26243
- function getLocalSupabaseEnvValues(projectRoot = process.cwd()) {
26244
- const supabaseUrl = buildLocalSupabaseUrl(projectRoot);
26245
- const databaseUrl = buildLocalDatabaseUrl(projectRoot);
26246
- return {
26247
- // Database URLs
26248
- DATABASE_URL: databaseUrl,
26249
- DATABASE_URL_ADMIN: databaseUrl,
26250
- DATABASE_URL_SERVICE: databaseUrl,
26251
- // Supabase URLs and keys
26252
- NEXT_PUBLIC_SUPABASE_URL: supabaseUrl,
26253
- NEXT_PUBLIC_SUPABASE_ANON_KEY: LOCAL_SUPABASE_ANON_KEY,
26254
- SUPABASE_SERVICE_ROLE_KEY: LOCAL_SUPABASE_SERVICE_ROLE_KEY
26255
- };
26256
- }
26257
- function getLocalValueDescriptions(projectRoot = process.cwd()) {
26258
- const ports = detectLocalSupabasePorts(projectRoot);
26259
- return {
26260
- DATABASE_URL: `localhost:${ports.db} (PostgreSQL)`,
26261
- DATABASE_URL_ADMIN: `localhost:${ports.db} (PostgreSQL)`,
26262
- DATABASE_URL_SERVICE: `localhost:${ports.db} (PostgreSQL)`,
26263
- NEXT_PUBLIC_SUPABASE_URL: `localhost:${ports.api} (Supabase API)`,
26264
- NEXT_PUBLIC_SUPABASE_ANON_KEY: "local anon key (supabase-demo)",
26265
- SUPABASE_SERVICE_ROLE_KEY: "local service key (supabase-demo)"
26266
- };
26267
- }
26268
- var LOCAL_SUPABASE_ENV_VALUES = getLocalSupabaseEnvValues();
26269
- getLocalValueDescriptions();
26270
- function validateLocalhostValues(envValues) {
26271
- const urlKeys = [
26272
- "DATABASE_URL",
26273
- "DATABASE_URL_ADMIN",
26274
- "DATABASE_URL_SERVICE",
26275
- "NEXT_PUBLIC_SUPABASE_URL"
26276
- ];
26277
- const invalidEntries = [];
26278
- for (const key of urlKeys) {
26279
- const value = envValues[key];
26280
- if (value && !value.includes("127.0.0.1") && !value.includes("localhost")) {
26281
- invalidEntries.push(key);
26282
- }
26283
- }
26284
- if (invalidEntries.length > 0) {
26285
- throw new Error(
26286
- `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.`
26287
- );
26288
- }
26289
- }
26290
- validateLocalhostValues(LOCAL_SUPABASE_ENV_VALUES);
26291
-
26292
26517
  // src/commands/env/commands/env-pull.ts
26518
+ init_local_supabase();
26293
26519
  var ERROR_MESSAGES3 = {
26294
26520
  INVALID_PATH: "Invalid working directory path",
26295
26521
  PATH_TRAVERSAL: "Working directory path validation failed",
@@ -26321,16 +26547,16 @@ function sanitizeErrorMessage(message) {
26321
26547
  return sanitized;
26322
26548
  }
26323
26549
  function containsPathTraversal3(inputPath) {
26324
- const normalized = path10__default.normalize(inputPath);
26550
+ const normalized = path11__default.normalize(inputPath);
26325
26551
  return normalized.includes("..") || inputPath.includes("\0");
26326
26552
  }
26327
26553
  function isPathWithinBase2(filePath, baseDir) {
26328
26554
  try {
26329
- const resolvedFile = path10__default.resolve(filePath);
26330
- const resolvedBase = path10__default.resolve(baseDir);
26331
- const normalizedFile = path10__default.normalize(resolvedFile);
26332
- const normalizedBase = path10__default.normalize(resolvedBase);
26333
- 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);
26334
26560
  } catch {
26335
26561
  return false;
26336
26562
  }
@@ -26339,12 +26565,12 @@ function validateCustomWorkingDir(cwdPath, projectRoot) {
26339
26565
  if (containsPathTraversal3(cwdPath)) {
26340
26566
  throw new CLIError(ERROR_MESSAGES3.PATH_TRAVERSAL, "ENV_PULL_PATH_TRAVERSAL");
26341
26567
  }
26342
- 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);
26343
26569
  let resolvedProjectRoot;
26344
26570
  try {
26345
26571
  resolvedProjectRoot = realpathSync(projectRoot);
26346
26572
  } catch {
26347
- resolvedProjectRoot = path10__default.resolve(projectRoot);
26573
+ resolvedProjectRoot = path11__default.resolve(projectRoot);
26348
26574
  }
26349
26575
  if (!isPathWithinBase2(absolutePath, resolvedProjectRoot)) {
26350
26576
  throw new CLIError(ERROR_MESSAGES3.PATH_TRAVERSAL, "ENV_PULL_PATH_TRAVERSAL");
@@ -26371,6 +26597,27 @@ function validateAppDirectory2(appName, projectRoot) {
26371
26597
  }
26372
26598
  return appDir;
26373
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
+ }
26374
26621
  var EnvPullOutputSchema = z.object({
26375
26622
  results: z.array(
26376
26623
  z.object({
@@ -26384,6 +26631,10 @@ var EnvPullOutputSchema = z.object({
26384
26631
  totalPulled: z.number(),
26385
26632
  totalFailed: z.number(),
26386
26633
  totalEncrypted: z.number().optional(),
26634
+ localBootstrap: z.object({
26635
+ status: z.enum(["ok", "partial", "missing"]),
26636
+ missing: z.array(z.string())
26637
+ }).optional(),
26387
26638
  /** Vercel Root Directory sync result */
26388
26639
  vercelSync: z.object({
26389
26640
  detected: z.boolean(),
@@ -26516,60 +26767,74 @@ function removePrivateKeysFromEnvFile(filePath) {
26516
26767
  writeFileSync(filePath, `${newContent}
26517
26768
  `, "utf-8");
26518
26769
  }
26519
- function replaceWithLocalValues(filePath, logger16, dryRun = false) {
26770
+ function replaceWithLocalValues(filePath, workDir, logger16, dryRun = false) {
26520
26771
  if (!existsSync(filePath)) {
26521
26772
  logger16.warn(" \u26A0\uFE0F .env.development not found (was pull successful?)");
26522
- return;
26773
+ return missingLocalBootstrapReport();
26523
26774
  }
26524
26775
  const content = readFileSync(filePath, "utf-8");
26525
26776
  if (!content.trim()) {
26526
26777
  logger16.warn(" \u26A0\uFE0F .env.development is empty (no env vars in Vercel?)");
26527
- return;
26778
+ return missingLocalBootstrapReport();
26528
26779
  }
26529
26780
  const parsed = parse(content);
26530
26781
  if (Object.keys(parsed).length === 0) {
26531
26782
  logger16.warn(" \u26A0\uFE0F No valid env vars found in .env.development (check syntax)");
26532
- return;
26783
+ return missingLocalBootstrapReport();
26533
26784
  }
26534
- const projectRoot = process.cwd();
26535
- const localEnvValues = getLocalSupabaseEnvValues(projectRoot);
26536
- const localDescriptions = getLocalValueDescriptions(projectRoot);
26785
+ const localEnvValues = getLocalSupabaseEnvValues(workDir);
26786
+ const localDescriptions = getLocalValueDescriptions(workDir);
26537
26787
  const replacementKeys = Object.keys(localEnvValues);
26538
26788
  const replacedKeys = [];
26789
+ const hasAnySupabaseKey = Object.keys(parsed).some((key) => key.includes("SUPABASE") || key.includes("DATABASE_URL")) || replacementKeys.some((key) => key in parsed);
26539
26790
  for (const key of replacementKeys) {
26540
- if (key in parsed && localEnvValues[key]) {
26791
+ if (key in parsed || hasAnySupabaseKey) {
26541
26792
  parsed[key] = localEnvValues[key];
26542
26793
  replacedKeys.push(key);
26543
26794
  }
26544
26795
  }
26545
26796
  if (replacedKeys.length === 0) {
26546
- const hasAnySupabaseKey = Object.keys(parsed).some(
26797
+ const hasAnySupabaseKey2 = Object.keys(parsed).some(
26547
26798
  (k) => k.includes("SUPABASE") || k.includes("DATABASE_URL")
26548
26799
  );
26549
- if (hasAnySupabaseKey) {
26800
+ if (hasAnySupabaseKey2) {
26550
26801
  logger16.warn(" \u26A0\uFE0F Found Supabase keys but none matched local replacement patterns");
26551
26802
  } else {
26552
26803
  logger16.info(" No Supabase variables found (may be expected for new projects)");
26553
26804
  }
26554
- 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
+ );
26555
26812
  }
26813
+ const ensureRequired = bootstrapStatus.status === "ok";
26556
26814
  const newContent = Object.entries(parsed).map(([key, value]) => `${key}=${formatEnvValue(value)}`).join("\n");
26557
26815
  if (dryRun) {
26558
- 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:`);
26559
26817
  for (const key of replacedKeys) {
26560
26818
  const description = localDescriptions[key] || "localhost";
26561
26819
  logger16.info(` ${key} \u2192 ${description}`);
26562
26820
  }
26821
+ logger16.info(
26822
+ ` ${ensureRequired ? "\u2705" : "\u26A0\uFE0F"} Local bootstrap keys ready: ${ensureRequired ? "yes" : "partial"}`
26823
+ );
26563
26824
  logger16.info(" (dry-run: no files modified)");
26564
- return;
26825
+ return bootstrapStatus;
26565
26826
  }
26566
26827
  writeFileSync(filePath, `${newContent}
26567
26828
  `, "utf-8");
26568
- logger16.success(` \u{1F3E0} Replaced ${replacedKeys.length} variables with localhost values:`);
26829
+ logger16.success(` \u{1F3E0} Replaced ${replacedKeys.length} variables with local values:`);
26569
26830
  for (const key of replacedKeys) {
26570
26831
  const description = localDescriptions[key] || "localhost";
26571
26832
  logger16.info(` ${key} \u2192 ${description}`);
26572
26833
  }
26834
+ logger16.info(
26835
+ ` ${ensureRequired ? "\u2705" : "\u26A0\uFE0F"} Local bootstrap keys ready: ${ensureRequired ? "yes" : "partial"}`
26836
+ );
26837
+ return bootstrapStatus;
26573
26838
  }
26574
26839
  async function encryptFile2(workDir, filePath, logger16) {
26575
26840
  if (!existsSync(filePath)) {
@@ -26801,13 +27066,20 @@ async function runEnvPullAction(options) {
26801
27066
  }
26802
27067
  logger16.info("");
26803
27068
  const results = await pullAllEnvironments(workDir, environments, auth, logger16);
26804
- if (!options.productionAll) {
27069
+ const shouldEvaluateLocalBootstrap = !options.productionAll && (!options.environment || options.environment === "development");
27070
+ let localBootstrap;
27071
+ if (shouldEvaluateLocalBootstrap) {
26805
27072
  const devResult = results.find((r) => r.environment === "development" && r.success);
26806
27073
  if (devResult) {
26807
27074
  logger16.info("");
26808
27075
  logger16.info("Applying local Supabase values to .env.development...");
26809
- 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)");
26810
27080
  }
27081
+ } else {
27082
+ localBootstrap = void 0;
26811
27083
  }
26812
27084
  if (options.encrypt && !options.check) {
26813
27085
  await encryptPulledFiles(workDir, results, logger16);
@@ -26828,6 +27100,7 @@ async function runEnvPullAction(options) {
26828
27100
  totalPulled,
26829
27101
  totalFailed,
26830
27102
  totalEncrypted: options.encrypt ? totalEncrypted : void 0,
27103
+ localBootstrap,
26831
27104
  vercelSync: vercelSyncResult
26832
27105
  });
26833
27106
  if (totalFailed > 0) {
@@ -28567,13 +28840,13 @@ z.object({
28567
28840
 
28568
28841
  // src/commands/hotfix/metadata.ts
28569
28842
  function getHotfixDir(targetDir) {
28570
- return path10__default.join(targetDir, ".runa", "hotfix");
28843
+ return path11__default.join(targetDir, ".runa", "hotfix");
28571
28844
  }
28572
28845
  function getCurrentFile(targetDir) {
28573
- return path10__default.join(getHotfixDir(targetDir), "current.json");
28846
+ return path11__default.join(getHotfixDir(targetDir), "current.json");
28574
28847
  }
28575
28848
  function getArchiveDir(targetDir) {
28576
- return path10__default.join(getHotfixDir(targetDir), "archive");
28849
+ return path11__default.join(getHotfixDir(targetDir), "archive");
28577
28850
  }
28578
28851
  async function ensureHotfixDir(targetDir) {
28579
28852
  await mkdir(getHotfixDir(targetDir), { recursive: true });
@@ -28583,7 +28856,7 @@ async function ensureArchiveDir(targetDir) {
28583
28856
  }
28584
28857
  async function getHotfixMetadata(input3 = {}) {
28585
28858
  const parsed = GetHotfixInputSchema.parse(input3);
28586
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
28859
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28587
28860
  const currentFile = getCurrentFile(targetDir);
28588
28861
  if (!existsSync(currentFile)) {
28589
28862
  return null;
@@ -28593,7 +28866,7 @@ async function getHotfixMetadata(input3 = {}) {
28593
28866
  }
28594
28867
  async function createHotfixMetadata(input3) {
28595
28868
  const parsed = CreateHotfixMetadataInputSchema.parse(input3);
28596
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
28869
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28597
28870
  await ensureHotfixDir(targetDir);
28598
28871
  const metadata = {
28599
28872
  branch: parsed.branch,
@@ -28610,7 +28883,7 @@ async function createHotfixMetadata(input3) {
28610
28883
  }
28611
28884
  async function updateHotfixStatus(input3) {
28612
28885
  const parsed = UpdateHotfixInputSchema.parse(input3);
28613
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
28886
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28614
28887
  const current = await getHotfixMetadata({ targetDir });
28615
28888
  if (!current) {
28616
28889
  throw createError("HOTFIX_NOT_FOUND");
@@ -28627,13 +28900,13 @@ async function updateHotfixStatus(input3) {
28627
28900
  return updated;
28628
28901
  }
28629
28902
  async function archiveHotfix(targetDir) {
28630
- const dir = targetDir ? path10__default.resolve(targetDir) : process.cwd();
28903
+ const dir = targetDir ? path11__default.resolve(targetDir) : process.cwd();
28631
28904
  const current = await getHotfixMetadata({ targetDir: dir });
28632
28905
  if (!current) {
28633
28906
  throw createError("HOTFIX_NOT_FOUND");
28634
28907
  }
28635
28908
  await ensureArchiveDir(dir);
28636
- const archiveFile = path10__default.join(
28909
+ const archiveFile = path11__default.join(
28637
28910
  getArchiveDir(dir),
28638
28911
  `${current.branch.replace(/\//g, "-")}-${Date.now()}.json`
28639
28912
  );
@@ -28649,7 +28922,7 @@ async function archiveHotfix(targetDir) {
28649
28922
  return archived;
28650
28923
  }
28651
28924
  async function cancelHotfix(targetDir) {
28652
- const dir = targetDir ? path10__default.resolve(targetDir) : process.cwd();
28925
+ const dir = targetDir ? path11__default.resolve(targetDir) : process.cwd();
28653
28926
  await updateHotfixStatus({
28654
28927
  status: "cancelled",
28655
28928
  completedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -28659,7 +28932,7 @@ async function cancelHotfix(targetDir) {
28659
28932
  }
28660
28933
  async function listArchivedHotfixes(input3 = {}) {
28661
28934
  const parsed = ListArchivedHotfixesInputSchema.parse(input3);
28662
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
28935
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28663
28936
  const archiveDir = getArchiveDir(targetDir);
28664
28937
  if (!existsSync(archiveDir)) {
28665
28938
  return { hotfixes: [] };
@@ -28668,7 +28941,7 @@ async function listArchivedHotfixes(input3 = {}) {
28668
28941
  const hotfixes = [];
28669
28942
  for (const file of files.filter((f) => f.endsWith(".json"))) {
28670
28943
  try {
28671
- const content = await readFile(path10__default.join(archiveDir, file), "utf-8");
28944
+ const content = await readFile(path11__default.join(archiveDir, file), "utf-8");
28672
28945
  hotfixes.push(HotfixMetadataSchema.parse(JSON.parse(content)));
28673
28946
  } catch {
28674
28947
  }
@@ -30168,13 +30441,13 @@ function validateVersion(version) {
30168
30441
  }
30169
30442
  }
30170
30443
  function getCacheBase() {
30171
- return path10__default.join(os.homedir(), ".cache", "runa", "templates");
30444
+ return path11__default.join(os.homedir(), ".cache", "runa", "templates");
30172
30445
  }
30173
30446
  function getCacheDir(version) {
30174
30447
  validateVersion(version);
30175
30448
  const cacheBase = getCacheBase();
30176
- const cacheDir = path10__default.join(cacheBase, version);
30177
- const resolvedCacheDir = path10__default.resolve(cacheDir);
30449
+ const cacheDir = path11__default.join(cacheBase, version);
30450
+ const resolvedCacheDir = path11__default.resolve(cacheDir);
30178
30451
  if (!isPathContained(cacheBase, resolvedCacheDir)) {
30179
30452
  throw new CLIError(
30180
30453
  "Security: cache directory would escape allowed location.",
@@ -30186,7 +30459,7 @@ function getCacheDir(version) {
30186
30459
  }
30187
30460
  function isCached(version) {
30188
30461
  const cacheDir = getCacheDir(version);
30189
- const templatesDir = path10__default.join(cacheDir, "templates");
30462
+ const templatesDir = path11__default.join(cacheDir, "templates");
30190
30463
  return fs5__default.existsSync(templatesDir);
30191
30464
  }
30192
30465
  var scopedAuthToken = null;
@@ -30237,13 +30510,13 @@ async function createTempPackageJson(tempDir, version) {
30237
30510
  [TEMPLATES_PACKAGE_NAME]: version
30238
30511
  }
30239
30512
  };
30240
- 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));
30241
30514
  }
30242
30515
  async function createTempNpmrc(tempDir) {
30243
30516
  const npmrc = `@r06-dev:registry=${GITHUB_PACKAGES_REGISTRY}
30244
30517
  //npm.pkg.github.com/:_authToken=\${NODE_AUTH_TOKEN}
30245
30518
  `;
30246
- await writeFile(path10__default.join(tempDir, ".npmrc"), npmrc);
30519
+ await writeFile(path11__default.join(tempDir, ".npmrc"), npmrc);
30247
30520
  }
30248
30521
  async function installTemplates(tempDir, authToken, verbose) {
30249
30522
  try {
@@ -30301,10 +30574,10 @@ async function installTemplates(tempDir, authToken, verbose) {
30301
30574
  async function verifyNoSymlinks(dir, baseDir) {
30302
30575
  const entries = await readdir(dir, { withFileTypes: true });
30303
30576
  for (const entry of entries) {
30304
- const fullPath = path10__default.join(dir, entry.name);
30577
+ const fullPath = path11__default.join(dir, entry.name);
30305
30578
  const stats = await lstat(fullPath);
30306
30579
  if (stats.isSymbolicLink()) {
30307
- const relativePath = path10__default.relative(baseDir, fullPath);
30580
+ const relativePath = path11__default.relative(baseDir, fullPath);
30308
30581
  throw new CLIError(
30309
30582
  "Security: Symlink detected in template package.",
30310
30583
  "SYMLINK_ATTACK_DETECTED",
@@ -30322,7 +30595,7 @@ async function verifyNoSymlinks(dir, baseDir) {
30322
30595
  }
30323
30596
  }
30324
30597
  async function copyToCache(tempDir, cacheDir) {
30325
- 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");
30326
30599
  if (!fs5__default.existsSync(sourceTemplates)) {
30327
30600
  throw new CLIError("Templates directory not found in package.", "TEMPLATES_DIR_NOT_FOUND", [
30328
30601
  `Expected: ${sourceTemplates}`,
@@ -30332,7 +30605,7 @@ async function copyToCache(tempDir, cacheDir) {
30332
30605
  }
30333
30606
  await verifyNoSymlinks(sourceTemplates, sourceTemplates);
30334
30607
  await mkdir(cacheDir, { recursive: true });
30335
- const targetTemplates = path10__default.join(cacheDir, "templates");
30608
+ const targetTemplates = path11__default.join(cacheDir, "templates");
30336
30609
  await cp(sourceTemplates, targetTemplates, {
30337
30610
  recursive: true,
30338
30611
  dereference: false
@@ -30354,7 +30627,7 @@ async function fetchTemplates(options = {}) {
30354
30627
  };
30355
30628
  }
30356
30629
  const cacheDir = getCacheDir(version);
30357
- const templatesDir = path10__default.join(cacheDir, "templates");
30630
+ const templatesDir = path11__default.join(cacheDir, "templates");
30358
30631
  if (!fresh && isCached(version)) {
30359
30632
  if (verbose) {
30360
30633
  console.log(`Using cached templates v${version}: ${templatesDir}`);
@@ -30370,7 +30643,7 @@ async function fetchTemplates(options = {}) {
30370
30643
  if (fresh && fs5__default.existsSync(cacheDir)) {
30371
30644
  await rm(cacheDir, { recursive: true, force: true });
30372
30645
  }
30373
- const tempDir = path10__default.join(os.tmpdir(), `runa-templates-${Date.now()}`);
30646
+ const tempDir = path11__default.join(os.tmpdir(), `runa-templates-${Date.now()}`);
30374
30647
  await mkdir(tempDir, { recursive: true });
30375
30648
  try {
30376
30649
  if (verbose) {
@@ -30398,11 +30671,11 @@ async function fetchTemplates(options = {}) {
30398
30671
  }
30399
30672
  var MAX_WORKSPACE_TRAVERSAL_DEPTH = 10;
30400
30673
  function isLegitimateWorkspaceRoot(workspaceRoot) {
30401
- const pnpmWorkspaceFile = path10__default.join(workspaceRoot, "pnpm-workspace.yaml");
30674
+ const pnpmWorkspaceFile = path11__default.join(workspaceRoot, "pnpm-workspace.yaml");
30402
30675
  if (!fs5__default.existsSync(pnpmWorkspaceFile)) {
30403
30676
  return false;
30404
30677
  }
30405
- const rootPackageFile = path10__default.join(workspaceRoot, "package.json");
30678
+ const rootPackageFile = path11__default.join(workspaceRoot, "package.json");
30406
30679
  if (!fs5__default.existsSync(rootPackageFile)) {
30407
30680
  return false;
30408
30681
  }
@@ -30416,24 +30689,24 @@ function isLegitimateWorkspaceRoot(workspaceRoot) {
30416
30689
  }
30417
30690
  }
30418
30691
  function resolveWorkspaceTemplates() {
30419
- let current = path10__default.resolve(process.cwd());
30420
- const root = path10__default.parse(current).root;
30692
+ let current = path11__default.resolve(process.cwd());
30693
+ const root = path11__default.parse(current).root;
30421
30694
  let depth = 0;
30422
30695
  while (current !== root && depth < MAX_WORKSPACE_TRAVERSAL_DEPTH) {
30423
30696
  if (!isLegitimateWorkspaceRoot(current)) {
30424
- current = path10__default.dirname(current);
30697
+ current = path11__default.dirname(current);
30425
30698
  depth++;
30426
30699
  continue;
30427
30700
  }
30428
- const packagesTemplates = path10__default.join(current, "packages", "runa-templates", "templates");
30429
- const normalizedTemplatesPath = path10__default.resolve(packagesTemplates);
30430
- if (!normalizedTemplatesPath.startsWith(current + path10__default.sep)) {
30431
- 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);
30432
30705
  depth++;
30433
30706
  continue;
30434
30707
  }
30435
30708
  if (fs5__default.existsSync(normalizedTemplatesPath)) {
30436
- const markerFile = path10__default.join(current, "packages", "runa-templates", "package.json");
30709
+ const markerFile = path11__default.join(current, "packages", "runa-templates", "package.json");
30437
30710
  if (fs5__default.existsSync(markerFile)) {
30438
30711
  try {
30439
30712
  const pkg = JSON.parse(fs5__default.readFileSync(markerFile, "utf-8"));
@@ -30444,7 +30717,7 @@ function resolveWorkspaceTemplates() {
30444
30717
  }
30445
30718
  }
30446
30719
  }
30447
- current = path10__default.dirname(current);
30720
+ current = path11__default.dirname(current);
30448
30721
  depth++;
30449
30722
  }
30450
30723
  return void 0;
@@ -30453,9 +30726,9 @@ function resolveWorkspaceTemplates() {
30453
30726
  // src/commands/init.ts
30454
30727
  function checkZodVersion(_logger) {
30455
30728
  const zodPaths = [
30456
- path10__default.join(process.cwd(), "node_modules", "zod", "package.json"),
30729
+ path11__default.join(process.cwd(), "node_modules", "zod", "package.json"),
30457
30730
  // Check home directory node_modules (common source of conflicts)
30458
- path10__default.join(process.env.HOME ?? "", "node_modules", "zod", "package.json")
30731
+ path11__default.join(process.env.HOME ?? "", "node_modules", "zod", "package.json")
30459
30732
  ];
30460
30733
  for (const zodPath of zodPaths) {
30461
30734
  if (!fs5__default.existsSync(zodPath)) continue;
@@ -30469,7 +30742,7 @@ function checkZodVersion(_logger) {
30469
30742
  "ZOD_VERSION_INCOMPATIBLE",
30470
30743
  [
30471
30744
  "runa SDK requires zod v4.x, but found zod v3.x",
30472
- `Conflicting zod found at: ${path10__default.dirname(zodPath)}`,
30745
+ `Conflicting zod found at: ${path11__default.dirname(zodPath)}`,
30473
30746
  "",
30474
30747
  "Solutions:",
30475
30748
  "1. Run from a clean project directory without existing node_modules",
@@ -30721,7 +30994,7 @@ var initCommand = new Command("init").description("Initialize pj-repo with runa
30721
30994
  try {
30722
30995
  if (options.repairConfig) {
30723
30996
  logger16.section("Repairing runa.config.ts");
30724
- const projectName2 = path10__default.basename(process.cwd());
30997
+ const projectName2 = path11__default.basename(process.cwd());
30725
30998
  const repairResult = repairRunaConfig(process.cwd(), projectName2);
30726
30999
  if (repairResult.success) {
30727
31000
  logger16.success("\u2705 Config file repaired successfully");
@@ -30772,7 +31045,7 @@ var initCommand = new Command("init").description("Initialize pj-repo with runa
30772
31045
  existingConfig,
30773
31046
  force: options.force === true
30774
31047
  });
30775
- const projectName = path10__default.basename(process.cwd());
31048
+ const projectName = path11__default.basename(process.cwd());
30776
31049
  logger16.info(`Project: ${projectName}`);
30777
31050
  logger16.step("Applying templates (SDK)", 1);
30778
31051
  const result = await initProject({
@@ -30869,7 +31142,9 @@ var InjectTestAttrsInputSchema = z.object({
30869
31142
  /** Manifest output directory */
30870
31143
  manifestDir: z.string().default(".runa"),
30871
31144
  /** Resolve Zod schemas to JSON Schema (v7+) for API contracts */
30872
- 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)
30873
31148
  }).strict();
30874
31149
  var FileChangeSchema = z.object({
30875
31150
  filePath: z.string(),
@@ -30881,6 +31156,51 @@ var MachineWithoutE2EMetaSchema = z.object({
30881
31156
  id: z.string(),
30882
31157
  sourceFile: z.string()
30883
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();
30884
31204
  var InjectTestAttrsOutputSchema = z.object({
30885
31205
  totalFiles: z.number(),
30886
31206
  changedFiles: z.number(),
@@ -30892,17 +31212,98 @@ var InjectTestAttrsOutputSchema = z.object({
30892
31212
  /** Number of machines in manifest */
30893
31213
  manifestMachineCount: z.number().optional(),
30894
31214
  /** Machines without meta.e2e annotation (opt-in warning) */
30895
- 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()
30896
31220
  }).strict();
30897
31221
 
30898
31222
  // src/commands/inject-test-attrs/processor.ts
30899
31223
  init_esm_shims();
30900
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
+
30901
31302
  // src/commands/inject-test-attrs/formatter.ts
30902
31303
  init_esm_shims();
30903
31304
  async function formatFilesWithBiome(files, cwd) {
30904
31305
  if (files.length === 0) return;
30905
- const relativePaths = files.map((f) => path10.relative(cwd, f));
31306
+ const relativePaths = files.map((f) => path11.relative(cwd, f));
30906
31307
  try {
30907
31308
  await execa("pnpm", ["exec", "biome", "format", "--write", ...relativePaths], {
30908
31309
  cwd,
@@ -30994,7 +31395,8 @@ function emptyResult(filePath) {
30994
31395
  changed: false,
30995
31396
  actions: [],
30996
31397
  fields: [],
30997
- testIds: []
31398
+ testIds: [],
31399
+ resolutionDetails: []
30998
31400
  };
30999
31401
  }
31000
31402
  function ensureDirectoryExists(dirPath) {
@@ -31004,7 +31406,7 @@ function ensureDirectoryExists(dirPath) {
31004
31406
  }
31005
31407
  function getGeneratorVersion() {
31006
31408
  try {
31007
- const pkgPath = path10.resolve(__dirname$1, "../../../package.json");
31409
+ const pkgPath = path11.resolve(__dirname$1, "../../../package.json");
31008
31410
  if (fs5.existsSync(pkgPath)) {
31009
31411
  const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
31010
31412
  return pkg.version ?? "unknown";
@@ -31019,15 +31421,15 @@ function detectPlatform(repoRoot) {
31019
31421
  const nextConfigPatterns = ["next.config.ts", "next.config.js", "next.config.mjs"];
31020
31422
  for (const pattern of nextConfigPatterns) {
31021
31423
  const paths = [
31022
- path10.join(repoRoot, pattern),
31023
- path10.join(repoRoot, "apps", "web", pattern),
31024
- 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)
31025
31427
  ];
31026
31428
  if (paths.some((p) => fs5.existsSync(p))) {
31027
31429
  return "nextjs";
31028
31430
  }
31029
31431
  }
31030
- const appJsonPath = path10.join(repoRoot, "app.json");
31432
+ const appJsonPath = path11.join(repoRoot, "app.json");
31031
31433
  if (fs5.existsSync(appJsonPath)) {
31032
31434
  try {
31033
31435
  const appJson = JSON.parse(fs5.readFileSync(appJsonPath, "utf-8"));
@@ -31037,7 +31439,7 @@ function detectPlatform(repoRoot) {
31037
31439
  } catch {
31038
31440
  }
31039
31441
  }
31040
- if (fs5.existsSync(path10.join(repoRoot, "expo.json"))) {
31442
+ if (fs5.existsSync(path11.join(repoRoot, "expo.json"))) {
31041
31443
  return "expo";
31042
31444
  }
31043
31445
  const electronPatterns = [
@@ -31046,56 +31448,38 @@ function detectPlatform(repoRoot) {
31046
31448
  "electron.vite.config.ts",
31047
31449
  "electron.vite.config.js"
31048
31450
  ];
31049
- if (electronPatterns.some((p) => fs5.existsSync(path10.join(repoRoot, p)))) {
31451
+ if (electronPatterns.some((p) => fs5.existsSync(path11.join(repoRoot, p)))) {
31050
31452
  return "electron";
31051
31453
  }
31052
31454
  return "unknown";
31053
31455
  }
31054
- function findPossibleHonoDirs(repoRoot) {
31055
- const possibleDirs = [];
31056
- const appsDir = path10.join(repoRoot, "apps");
31057
- if (fs5.existsSync(appsDir)) {
31058
- try {
31059
- const apps = fs5.readdirSync(appsDir, { withFileTypes: true });
31060
- for (const app of apps) {
31061
- if (app.isDirectory()) {
31062
- const routesDir = path10.join(appsDir, app.name, "routes");
31063
- if (fs5.existsSync(routesDir)) {
31064
- const files = fs5.readdirSync(routesDir);
31065
- const hasRouteFiles = files.some(
31066
- (f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.endsWith(".spec.ts")
31067
- );
31068
- if (hasRouteFiles) {
31069
- possibleDirs.push(`apps/${app.name}/routes`);
31070
- }
31071
- }
31072
- }
31073
- }
31074
- } catch {
31075
- }
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;
31076
31464
  }
31077
- const packagesDir = path10.join(repoRoot, "packages");
31078
- if (fs5.existsSync(packagesDir)) {
31079
- try {
31080
- const packages = fs5.readdirSync(packagesDir, { withFileTypes: true });
31081
- for (const pkg of packages) {
31082
- if (pkg.isDirectory()) {
31083
- const routesDir = path10.join(packagesDir, pkg.name, "routes");
31084
- if (fs5.existsSync(routesDir)) {
31085
- const files = fs5.readdirSync(routesDir);
31086
- const hasRouteFiles = files.some(
31087
- (f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.endsWith(".spec.ts")
31088
- );
31089
- if (hasRouteFiles) {
31090
- possibleDirs.push(`packages/${pkg.name}/routes`);
31091
- }
31092
- }
31093
- }
31094
- }
31095
- } catch {
31096
- }
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 [];
31097
31476
  }
31098
- return possibleDirs;
31477
+ }
31478
+ function findPossibleHonoDirs(repoRoot) {
31479
+ return [
31480
+ ...collectRouteDirsInScope(repoRoot, "apps"),
31481
+ ...collectRouteDirsInScope(repoRoot, "packages")
31482
+ ];
31099
31483
  }
31100
31484
  function collectManifestWarnings(repoRoot, platform, apiContracts, machinesWithoutE2EMeta, totalMachines) {
31101
31485
  const warnings = [];
@@ -31146,15 +31530,18 @@ function printManifestWarnings(warnings, verbose) {
31146
31530
  for (const detail of warning.details) {
31147
31531
  console.log(detail);
31148
31532
  }
31149
- if (warning.details.length < warning._totalCount) {
31150
- console.log(` ... and more`);
31151
- }
31152
31533
  }
31153
31534
  if (warning.fix) {
31154
31535
  console.log(` \u2192 ${warning.fix}`);
31155
31536
  }
31156
31537
  }
31157
31538
  }
31539
+ function toDetectionWarnings(warnings) {
31540
+ return warnings.map((warning) => ({
31541
+ severity: warning.severity,
31542
+ message: warning.message
31543
+ }));
31544
+ }
31158
31545
  function normalizeToCanonicalId(id) {
31159
31546
  return id.replace(/-([a-z])/g, (_, c) => c.toUpperCase()).replace(/Machine$/i, "");
31160
31547
  }
@@ -31242,7 +31629,7 @@ async function analyzeHonoRoutes(repoRoot, verbose, resolveSchemas = false) {
31242
31629
  return { apiContracts: [], schemasResolved: false };
31243
31630
  }
31244
31631
  if (verbose) {
31245
- console.log(` Analyzing Hono routes in: ${path10.relative(repoRoot, routesPath)}`);
31632
+ console.log(` Analyzing Hono routes in: ${path11.relative(repoRoot, routesPath)}`);
31246
31633
  if (resolveSchemas) {
31247
31634
  console.log(" Schema resolution enabled (--resolve-schemas)");
31248
31635
  }
@@ -31288,7 +31675,7 @@ async function analyzeHonoRoutes(repoRoot, verbose, resolveSchemas = false) {
31288
31675
  return { apiContracts: [], schemasResolved: false };
31289
31676
  }
31290
31677
  }
31291
- async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSchemas = false) {
31678
+ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSchemas = false, diagnosticsInput) {
31292
31679
  const registry = getInjectionRegistry();
31293
31680
  const generatorVersion = getGeneratorVersion();
31294
31681
  const e2eManifest = buildManifest(registry, generatorVersion);
@@ -31302,18 +31689,18 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31302
31689
  }
31303
31690
  const definitionMap = buildDefinitionMap(machineDefinitions);
31304
31691
  const enhancedMachines = buildEnhancedMachines(e2eManifest, definitionMap, machineDefinitions);
31305
- const absoluteManifestDir = path10.isAbsolute(manifestDir) ? manifestDir : path10.join(repoRoot, manifestDir);
31692
+ const absoluteManifestDir = path11.isAbsolute(manifestDir) ? manifestDir : path11.join(repoRoot, manifestDir);
31306
31693
  if (!isPathContained(repoRoot, absoluteManifestDir)) {
31307
31694
  throw new Error(
31308
31695
  `Security error: Manifest directory '${manifestDir}' would escape the project root. The --manifest-dir must be a relative path within the project directory.`
31309
31696
  );
31310
31697
  }
31311
31698
  ensureDirectoryExists(absoluteManifestDir);
31312
- const generatedDir = path10.join(absoluteManifestDir, "generated");
31699
+ const generatedDir = path11.join(absoluteManifestDir, "generated");
31313
31700
  ensureDirectoryExists(generatedDir);
31314
- const manifestsDir = path10.join(absoluteManifestDir, "manifests");
31701
+ const manifestsDir = path11.join(absoluteManifestDir, "manifests");
31315
31702
  ensureDirectoryExists(manifestsDir);
31316
- const tsPath = path10.join(generatedDir, "selectors.ts");
31703
+ const tsPath = path11.join(generatedDir, "selectors.ts");
31317
31704
  await fs5.promises.writeFile(tsPath, generateSelectorTypeScript(e2eManifest), "utf-8");
31318
31705
  const unifiedRegistry = getUnifiedRegistry();
31319
31706
  const machineLinks = buildMachineLinks();
@@ -31328,6 +31715,29 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31328
31715
  const jstOffset = 9 * 60 * 60 * 1e3;
31329
31716
  const jst = new Date(now.getTime() + jstOffset);
31330
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
+ });
31331
31741
  const unifiedManifest = {
31332
31742
  version: manifestVersion,
31333
31743
  generatedAt: generatedAtJST,
@@ -31340,17 +31750,15 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31340
31750
  authBoundaries: unifiedRegistry.authBoundaries,
31341
31751
  machineDefinitions: unifiedRegistry.machineDefinitions,
31342
31752
  machineLinks,
31343
- apiContracts
31753
+ apiContracts,
31754
+ detectionDiagnostics
31344
31755
  };
31345
- const manifestPath = path10.join(manifestsDir, "manifest.json");
31756
+ const manifestPath = path11.join(manifestsDir, "manifest.json");
31346
31757
  await fs5.promises.writeFile(manifestPath, JSON.stringify(unifiedManifest, null, 2), "utf-8");
31347
- const machinesWithoutE2EMeta = machineDefinitions.filter(
31348
- (def) => !def.hasE2EMeta && typeof def.id === "string"
31349
- ).map((def) => ({ id: def.id, sourceFile: def.sourceFile }));
31350
31758
  if (verbose) {
31351
- console.log(`Generated selectors: ${path10.relative(repoRoot, tsPath)}`);
31759
+ console.log(`Generated selectors: ${path11.relative(repoRoot, tsPath)}`);
31352
31760
  console.log(
31353
- `Generated manifest: ${path10.relative(repoRoot, manifestPath)} (v${manifestVersion})`
31761
+ `Generated manifest: ${path11.relative(repoRoot, manifestPath)} (v${manifestVersion})`
31354
31762
  );
31355
31763
  console.log(` Platform: ${platform}`);
31356
31764
  console.log(` Machine definitions: ${machineDefinitions.length}`);
@@ -31364,19 +31772,15 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31364
31772
  ` API contracts: ${apiContracts.length}${schemasResolved ? " (with schemas)" : ""}`
31365
31773
  );
31366
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
+ );
31367
31778
  }
31368
- const warnings = collectManifestWarnings(
31369
- repoRoot,
31370
- platform,
31371
- apiContracts,
31372
- machinesWithoutE2EMeta,
31373
- machineDefinitions.length
31374
- );
31375
- printManifestWarnings(warnings, verbose);
31376
31779
  return {
31377
- manifestPath: path10.relative(repoRoot, tsPath),
31780
+ manifestPath: path11.relative(repoRoot, tsPath),
31378
31781
  machineCount: Object.keys(enhancedMachines).length,
31379
- machinesWithoutE2EMeta
31782
+ machinesWithoutE2EMeta,
31783
+ detectionDiagnostics
31380
31784
  };
31381
31785
  }
31382
31786
 
@@ -31408,7 +31812,7 @@ function registerExistingInjections(machineIds, attrs, sourceFile) {
31408
31812
  }
31409
31813
  async function preprocessFile(filePath, repoRoot, options) {
31410
31814
  let code = await fs5.promises.readFile(filePath, "utf-8");
31411
- const relativePath = path10.relative(repoRoot, filePath);
31815
+ const relativePath = path11.relative(repoRoot, filePath);
31412
31816
  collectRouteInfo(relativePath, code, options.verbose);
31413
31817
  const hasMarker = code.includes(CLI_INJECTION_MARKER);
31414
31818
  if (hasMarker && options.force) {
@@ -31439,14 +31843,15 @@ async function preprocessFile(filePath, repoRoot, options) {
31439
31843
  injectedCount: 0,
31440
31844
  machineIds,
31441
31845
  changed: false,
31442
- ...attrs
31846
+ ...attrs,
31847
+ resolutionDetails: []
31443
31848
  }
31444
31849
  };
31445
31850
  }
31446
31851
  return { code, hasMarker: false, skipped: false };
31447
31852
  }
31448
31853
  function transformAndRegister(filePath, code, repoRoot, options) {
31449
- const relativePath = path10.relative(repoRoot, filePath);
31854
+ const relativePath = path11.relative(repoRoot, filePath);
31450
31855
  const readAndParseFile = createReadAndParseFile(options.verbose);
31451
31856
  const resolveImportPath = createResolveImportPath();
31452
31857
  try {
@@ -31462,6 +31867,14 @@ function transformAndRegister(filePath, code, repoRoot, options) {
31462
31867
  const transformedCode = markerComment + result.code;
31463
31868
  const { actions, fields, testIds } = extractInjectedAttributes(transformedCode);
31464
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
+ }));
31465
31878
  registerExistingInjections(machineIds, { actions, fields, testIds }, relativePath);
31466
31879
  return {
31467
31880
  filePath,
@@ -31471,7 +31884,8 @@ function transformAndRegister(filePath, code, repoRoot, options) {
31471
31884
  transformedCode,
31472
31885
  actions,
31473
31886
  fields,
31474
- testIds
31887
+ testIds,
31888
+ resolutionDetails
31475
31889
  };
31476
31890
  } catch (error) {
31477
31891
  if (options.verbose) {
@@ -31492,7 +31906,7 @@ async function processFileForChildInjection(filePath, repoRoot, options) {
31492
31906
  if (prep.skipped && prep.skipResult) return prep.skipResult;
31493
31907
  const result = transformAndRegister(filePath, prep.code, repoRoot, options);
31494
31908
  if (options.verbose && result.changed && result.injectedCount > 0) {
31495
- const relativePath = path10.relative(repoRoot, filePath);
31909
+ const relativePath = path11.relative(repoRoot, filePath);
31496
31910
  console.log(
31497
31911
  ` [child] Injected ${result.injectedCount} attrs in ${relativePath} (actions: ${result.actions.join(", ")})`
31498
31912
  );
@@ -31512,7 +31926,7 @@ async function handleChangedFile(result, check, repoRoot, verbose, state2) {
31512
31926
  await fs5.promises.writeFile(result.filePath, result.transformedCode, "utf-8");
31513
31927
  state2.filesToFormat.push(result.filePath);
31514
31928
  if (verbose) {
31515
- const relativePath = path10.relative(repoRoot, result.filePath);
31929
+ const relativePath = path11.relative(repoRoot, result.filePath);
31516
31930
  console.log(` Injected ${result.injectedCount} attrs in ${relativePath}`);
31517
31931
  }
31518
31932
  }
@@ -31523,6 +31937,60 @@ async function formatChangedFiles(filesToFormat, repoRoot, verbose) {
31523
31937
  }
31524
31938
  await formatFilesWithBiome(filesToFormat, repoRoot);
31525
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
+ }
31526
31994
  function mightContainMachineDefinition(code) {
31527
31995
  return code.includes("createMachine");
31528
31996
  }
@@ -31546,13 +32014,34 @@ async function categorizeFiles(files) {
31546
32014
  return { withMachineDefinitions, withMachineHooks, withJsxOnly };
31547
32015
  }
31548
32016
  async function processFiles(options) {
31549
- 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;
31550
32028
  clearInjectionRegistry();
31551
32029
  clearUnifiedRegistry();
31552
32030
  const files = await discoverFiles(repoRoot, include, exclude);
31553
32031
  if (verbose) console.log(`Found ${files.length} files to process`);
31554
- const state2 = { changes: [], filesToFormat: [], totalInjections: 0 };
32032
+ const state2 = {
32033
+ changes: [],
32034
+ filesToFormat: [],
32035
+ totalInjections: 0,
32036
+ resolutionDetails: []
32037
+ };
31555
32038
  const { withMachineDefinitions, withMachineHooks, withJsxOnly } = await categorizeFiles(files);
32039
+ const scanSummary = createScanSummary({
32040
+ files,
32041
+ withMachineDefinitions,
32042
+ withMachineHooks,
32043
+ withJsxOnly
32044
+ });
31556
32045
  if (verbose) {
31557
32046
  console.log(` Files with machine definitions: ${withMachineDefinitions.length}`);
31558
32047
  console.log(` Files with machine hooks: ${withMachineHooks.length}`);
@@ -31562,46 +32051,50 @@ async function processFiles(options) {
31562
32051
  for (const filePath of withMachineDefinitions) {
31563
32052
  try {
31564
32053
  const code = await fs5.promises.readFile(filePath, "utf-8");
31565
- const relativePath = path10.relative(repoRoot, filePath);
32054
+ const relativePath = path11.relative(repoRoot, filePath);
31566
32055
  collectRouteInfo(relativePath, code, verbose);
31567
32056
  } catch {
31568
32057
  }
31569
32058
  }
31570
32059
  for (const filePath of withMachineHooks) {
31571
32060
  const result = await processFile(filePath, repoRoot, processOpts);
32061
+ state2.resolutionDetails.push(...result.resolutionDetails);
31572
32062
  await handleChangedFile(result, check, repoRoot, verbose, state2);
31573
32063
  }
31574
32064
  for (const filePath of withJsxOnly) {
31575
32065
  const result = await processFileForChildInjection(filePath, repoRoot, processOpts);
32066
+ state2.resolutionDetails.push(...result.resolutionDetails);
31576
32067
  await handleChangedFile(result, check, repoRoot, verbose, state2);
31577
32068
  }
31578
32069
  if (!check) {
31579
32070
  await formatChangedFiles(state2.filesToFormat, repoRoot, verbose);
31580
32071
  }
31581
32072
  postProcessRegistries();
31582
- let manifestPath;
31583
- let manifestMachineCount;
31584
- let machinesWithoutE2EMeta;
31585
- if (manifest && !check) {
31586
- const manifestResult = await generateManifestFiles(
31587
- manifestDir,
31588
- repoRoot,
31589
- verbose,
31590
- resolveSchemas ?? false
31591
- );
31592
- manifestPath = manifestResult.manifestPath;
31593
- manifestMachineCount = manifestResult.machineCount;
31594
- machinesWithoutE2EMeta = manifestResult.machinesWithoutE2EMeta;
31595
- }
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;
31596
32087
  return {
31597
32088
  totalFiles: files.length,
31598
32089
  changedFiles: state2.changes.length,
31599
32090
  totalInjections: state2.totalInjections,
31600
32091
  changes: state2.changes,
31601
- exitCode: check && state2.changes.length > 0 ? 1 : 0,
31602
- manifestPath,
31603
- manifestMachineCount,
31604
- machinesWithoutE2EMeta
32092
+ exitCode,
32093
+ manifestPath: manifestArtifacts.manifestPath,
32094
+ manifestMachineCount: manifestArtifacts.manifestMachineCount,
32095
+ machinesWithoutE2EMeta: manifestArtifacts.machinesWithoutE2EMeta,
32096
+ detectionDiagnostics: manifestArtifacts.detectionDiagnostics,
32097
+ strictDetect: manifestArtifacts.strictDetectStatus
31605
32098
  };
31606
32099
  }
31607
32100
 
@@ -31661,6 +32154,35 @@ function logMachinesWithoutE2EMeta(result, logger16) {
31661
32154
  logger16.info(" }");
31662
32155
  logger16.info(" See: .claude/rules/xstate-design.md#meta.e2e");
31663
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
+ }
31664
32186
  async function injectTestAttrsAction(rawOptions, command) {
31665
32187
  const logger16 = createCLILogger("manifest");
31666
32188
  const parseResult = InjectTestAttrsInputSchema.safeParse(rawOptions);
@@ -31671,6 +32193,20 @@ async function injectTestAttrsAction(rawOptions, command) {
31671
32193
  ]);
31672
32194
  }
31673
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
+ }
31674
32210
  const repoRoot = findProjectRoot$1() ?? process.cwd();
31675
32211
  if (!options.check) {
31676
32212
  logger16.section("Generating manifest (manifest.json)");
@@ -31689,6 +32225,8 @@ async function injectTestAttrsAction(rawOptions, command) {
31689
32225
  logResultSummary(result, options, logger16);
31690
32226
  logManifestInfo(result, logger16);
31691
32227
  logMachinesWithoutE2EMeta(result, logger16);
32228
+ logDetectionDiagnostics(result, logger16);
32229
+ logStrictDetect(result, logger16);
31692
32230
  emitJsonSuccess(command, InjectTestAttrsOutputSchema, result);
31693
32231
  if (result.exitCode !== 0) {
31694
32232
  process.exit(result.exitCode);
@@ -31708,7 +32246,7 @@ var injectTestAttrsCommand = new Command("inject-test-attrs").description("Injec
31708
32246
  "**/*.test.*",
31709
32247
  "**/*.spec.*",
31710
32248
  "**/*.stories.*"
31711
- ]).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) => {
31712
32250
  await injectTestAttrsAction(rawOptions, injectTestAttrsCommand);
31713
32251
  });
31714
32252
 
@@ -31772,7 +32310,7 @@ var manifestCommand = new Command("manifest").description("Generate E2E manifest
31772
32310
  "**/*.test.*",
31773
32311
  "**/*.spec.*",
31774
32312
  "**/*.stories.*"
31775
- ]).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) => {
31776
32314
  await injectTestAttrsAction(options, manifestCommand);
31777
32315
  });
31778
32316
 
@@ -31831,7 +32369,7 @@ function assertNodeAuthToken(options) {
31831
32369
  }
31832
32370
  }
31833
32371
  function getPackageVersion(packagePath) {
31834
- const packageJsonPath = path10__default.join(packagePath, "package.json");
32372
+ const packageJsonPath = path11__default.join(packagePath, "package.json");
31835
32373
  if (!existsSync(packageJsonPath)) {
31836
32374
  throw new CLIError(`package.json not found at ${packagePath}`, "PACKAGE_NOT_FOUND");
31837
32375
  }
@@ -31850,7 +32388,7 @@ function resolveWorkspaceDependencies(workspaceRoot, packages, logger16) {
31850
32388
  const sdkPackage = packages.find((p) => p.name === "SDK");
31851
32389
  const xstatePluginPackage = packages.find((p) => p.name === "xstate-test-plugin");
31852
32390
  if (!sdkPackage) return;
31853
- const cliPackagePath = path10__default.join(workspaceRoot, "packages", "cli", "package.json");
32391
+ const cliPackagePath = path11__default.join(workspaceRoot, "packages", "cli", "package.json");
31854
32392
  if (!existsSync(cliPackagePath)) return;
31855
32393
  let content = readFileSync(cliPackagePath, "utf-8");
31856
32394
  let updated = false;
@@ -31879,7 +32417,7 @@ function resolveWorkspaceDependencies(workspaceRoot, packages, logger16) {
31879
32417
  }
31880
32418
  }
31881
32419
  function restoreWorkspaceDependencies(workspaceRoot) {
31882
- const cliPackagePath = path10__default.join(workspaceRoot, "packages", "cli", "package.json");
32420
+ const cliPackagePath = path11__default.join(workspaceRoot, "packages", "cli", "package.json");
31883
32421
  if (!existsSync(cliPackagePath)) return;
31884
32422
  let content = readFileSync(cliPackagePath, "utf-8");
31885
32423
  content = content.replace(/"@runa-ai\/runa": "\^[\d.]+"/, '"@runa-ai/runa": "workspace:*"');
@@ -31991,7 +32529,7 @@ function collectPackageInfo(workspaceRoot, logger16, stepNum) {
31991
32529
  logger16.step("Collecting package info", stepNum);
31992
32530
  const packages = [];
31993
32531
  for (const pkgConfig of PUBLISHABLE_PACKAGES) {
31994
- const pkgPath = path10__default.join(workspaceRoot, "packages", pkgConfig.dir);
32532
+ const pkgPath = path11__default.join(workspaceRoot, "packages", pkgConfig.dir);
31995
32533
  const version = getPackageVersion(pkgPath);
31996
32534
  const exists = checkVersionExists(pkgConfig.publishName, version);
31997
32535
  packages.push({
@@ -33380,8 +33918,8 @@ var compareActor = fromPromise(async ({ input: input3 }) => {
33380
33918
  const result = compareBothFiles(
33381
33919
  runaRelPath,
33382
33920
  templateRelPath,
33383
- path10.join(repoRoot, runaRelPath),
33384
- path10.join(templateDir, templateRelPath),
33921
+ path11.join(repoRoot, runaRelPath),
33922
+ path11.join(templateDir, templateRelPath),
33385
33923
  runaFile.category,
33386
33924
  options.diff ?? false
33387
33925
  );
@@ -33832,7 +34370,7 @@ var discoverActor = fromPromise(async ({ input: input3 }) => {
33832
34370
  const runaPattern = rule.runa;
33833
34371
  const runaFiles = await globFiles(repoRoot, runaPattern);
33834
34372
  for (const file of runaFiles) {
33835
- const relativePath = path10.relative(repoRoot, file.absolutePath);
34373
+ const relativePath = path11.relative(repoRoot, file.absolutePath);
33836
34374
  const key = generateComparisonKey(relativePath, false);
33837
34375
  inventory.runaFiles.set(relativePath, {
33838
34376
  ...file,
@@ -33846,7 +34384,7 @@ var discoverActor = fromPromise(async ({ input: input3 }) => {
33846
34384
  const templatePattern = rule.template;
33847
34385
  const templateFiles = await globFiles(templateDir, templatePattern);
33848
34386
  for (const file of templateFiles) {
33849
- const relativePath = path10.relative(templateDir, file.absolutePath);
34387
+ const relativePath = path11.relative(templateDir, file.absolutePath);
33850
34388
  const key = generateComparisonKey(relativePath, true);
33851
34389
  inventory.templateFiles.set(relativePath, {
33852
34390
  ...file,
@@ -33895,7 +34433,7 @@ async function matchDoubleWildcard(ctx, entries) {
33895
34433
  await walkAndMatch({ ...ctx, partIndex: ctx.partIndex + 1 });
33896
34434
  for (const entry of entries) {
33897
34435
  if (entry.isDirectory()) {
33898
- const subDir = path10.join(ctx.currentDir, entry.name);
34436
+ const subDir = path11.join(ctx.currentDir, entry.name);
33899
34437
  await walkAndMatch({ ...ctx, currentDir: subDir });
33900
34438
  }
33901
34439
  }
@@ -33904,7 +34442,7 @@ async function matchSingleWildcard(ctx, entries, pattern, isLastPart) {
33904
34442
  const regex = patternToRegex(pattern);
33905
34443
  for (const entry of entries) {
33906
34444
  if (regex.test(entry.name)) {
33907
- const entryPath = path10.join(ctx.currentDir, entry.name);
34445
+ const entryPath = path11.join(ctx.currentDir, entry.name);
33908
34446
  await processEntry(ctx, entryPath, entry.isFile(), entry.isDirectory(), isLastPart);
33909
34447
  }
33910
34448
  }
@@ -33914,14 +34452,14 @@ async function matchBraceExpansion(ctx, entries, pattern, isLastPart) {
33914
34452
  for (const option of options) {
33915
34453
  for (const entry of entries) {
33916
34454
  if (entry.name === option) {
33917
- const entryPath = path10.join(ctx.currentDir, entry.name);
34455
+ const entryPath = path11.join(ctx.currentDir, entry.name);
33918
34456
  await processEntry(ctx, entryPath, entry.isFile(), entry.isDirectory(), isLastPart);
33919
34457
  }
33920
34458
  }
33921
34459
  }
33922
34460
  }
33923
34461
  async function matchLiteral(ctx, pattern, isLastPart) {
33924
- const entryPath = path10.join(ctx.currentDir, pattern);
34462
+ const entryPath = path11.join(ctx.currentDir, pattern);
33925
34463
  if (!fs5.existsSync(entryPath)) return;
33926
34464
  const stats = fs5.statSync(entryPath);
33927
34465
  await processEntry(ctx, entryPath, stats.isFile(), stats.isDirectory(), isLastPart);
@@ -34446,15 +34984,15 @@ function printActionsNeeded(logger16, actions) {
34446
34984
  );
34447
34985
  }
34448
34986
  function findRepoRoot3(startDir) {
34449
- const { existsSync: existsSync51, readFileSync: readFileSync29 } = __require("fs");
34987
+ const { existsSync: existsSync52, readFileSync: readFileSync29 } = __require("fs");
34450
34988
  const { join: join23, dirname: dirname5 } = __require("path");
34451
34989
  let current = startDir;
34452
34990
  while (current !== dirname5(current)) {
34453
- if (existsSync51(join23(current, "turbo.json"))) {
34991
+ if (existsSync52(join23(current, "turbo.json"))) {
34454
34992
  return current;
34455
34993
  }
34456
34994
  const pkgPath = join23(current, "package.json");
34457
- if (existsSync51(pkgPath)) {
34995
+ if (existsSync52(pkgPath)) {
34458
34996
  try {
34459
34997
  const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
34460
34998
  if (pkg.workspaces) {
@@ -34522,10 +35060,10 @@ function generateReportOutput(output3, isJsonMode) {
34522
35060
  };
34523
35061
  }
34524
35062
  function validateRunaRepo(repoRoot) {
34525
- const { existsSync: existsSync51 } = __require("fs");
35063
+ const { existsSync: existsSync52 } = __require("fs");
34526
35064
  const { join: join23 } = __require("path");
34527
35065
  const templateDir = join23(repoRoot, "packages/runa-templates/templates");
34528
- if (!existsSync51(templateDir)) {
35066
+ if (!existsSync52(templateDir)) {
34529
35067
  throw new CLIError("template-check is a runa-repo only command", "NOT_RUNA_REPO", [
34530
35068
  "This command compares runa-repo with pj-repo templates",
34531
35069
  "It should only be run in the runa repository",
@@ -34627,11 +35165,29 @@ init_esm_shims();
34627
35165
 
34628
35166
  // src/commands/test/commands/test.ts
34629
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
+ }
34630
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(
34631
35180
  "--report-json <path>",
34632
35181
  "Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
34633
- ).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) => {
34634
35189
  try {
35190
+ const effectiveRequireManifest = resolveEffectiveRequireManifest(options);
34635
35191
  const output3 = await runTest({
34636
35192
  layer: options.layer !== void 0 ? Number.parseInt(options.layer, 10) : void 0,
34637
35193
  from: options.from !== void 0 ? Number.parseInt(options.from, 10) : void 0,
@@ -34646,7 +35202,8 @@ var testCommand = new Command("test").description("Run tests (compat). Prefer: t
34646
35202
  baseUrl: options.baseUrl,
34647
35203
  changed: options.changed,
34648
35204
  base: options.base,
34649
- skipMissing: options.skipMissing
35205
+ skipMissing: options.skipMissing,
35206
+ requireManifest: effectiveRequireManifest
34650
35207
  });
34651
35208
  emitJsonSuccess(testCommand, TestRunOutputSchema, output3);
34652
35209
  } catch (error) {
@@ -34744,11 +35301,29 @@ var testApiCommand = new Command("test:api").description("Run Layer 3: API tests
34744
35301
 
34745
35302
  // src/commands/test/commands/test-e2e.ts
34746
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
+ }
34747
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(
34748
35322
  "--report-json <path>",
34749
35323
  "Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
34750
35324
  ).option("--verbose", "Verbose output (full error details, environment info)").action(async (options) => {
34751
35325
  try {
35326
+ const effectiveRequireManifest = resolveEffectiveRequireManifest2(options);
34752
35327
  const output3 = await runTestIntegration({
34753
35328
  ci: options.ci ?? false,
34754
35329
  record: options.record,
@@ -34758,6 +35333,7 @@ var testE2ECommand = new Command("test:e2e").description("Run Layer 4: E2E tests
34758
35333
  advanced: options.advanced,
34759
35334
  auto: options.auto,
34760
35335
  baseUrl: options.baseUrl,
35336
+ requireManifest: effectiveRequireManifest,
34761
35337
  invokedAs: "runa test:e2e"
34762
35338
  });
34763
35339
  emitJsonSuccess(testE2ECommand, TestIntegrationOutputSchema, output3);
@@ -34778,8 +35354,15 @@ var testE2ECommand = new Command("test:e2e").description("Run Layer 4: E2E tests
34778
35354
  );
34779
35355
  }
34780
35356
  });
34781
- 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) => {
34782
35364
  try {
35365
+ const effectiveRequireManifest = resolveEffectiveRequireManifest2(options);
34783
35366
  const output3 = await runTestIntegration({
34784
35367
  ci: options.ci ?? false,
34785
35368
  record: options.record,
@@ -34789,6 +35372,7 @@ var testBrowserCommand = new Command("test:browser").description("Run Layer 4: B
34789
35372
  advanced: options.advanced,
34790
35373
  auto: options.auto,
34791
35374
  baseUrl: options.baseUrl,
35375
+ requireManifest: effectiveRequireManifest,
34792
35376
  invokedAs: "runa test:browser"
34793
35377
  });
34794
35378
  emitJsonSuccess(testBrowserCommand, TestIntegrationOutputSchema, output3);
@@ -34861,11 +35445,29 @@ var testLintCommand = new Command("test:lint").description("Run Layer 0: Lint (t
34861
35445
 
34862
35446
  // src/commands/test/commands/test-integration.ts
34863
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
+ }
34864
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(
34865
35466
  "--report-json <path>",
34866
35467
  "Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
34867
35468
  ).option("--verbose", "Verbose output (full error details, environment info)").action(async (options) => {
34868
35469
  try {
35470
+ const effectiveRequireManifest = resolveEffectiveRequireManifest3(options);
34869
35471
  const output3 = await runTestIntegration({
34870
35472
  ci: options.ci ?? false,
34871
35473
  record: options.record,
@@ -34875,6 +35477,7 @@ var testIntegrationCommand = new Command("test:integration").description("Run La
34875
35477
  advanced: options.advanced,
34876
35478
  auto: options.auto,
34877
35479
  baseUrl: options.baseUrl,
35480
+ requireManifest: effectiveRequireManifest,
34878
35481
  invokedAs: "runa test:integration"
34879
35482
  });
34880
35483
  emitJsonSuccess(testIntegrationCommand, TestIntegrationOutputSchema, output3);
@@ -34920,7 +35523,7 @@ function injectTestAttrsIfLayer4(layer, options) {
34920
35523
  "Run `runa inject-test-attrs` manually to see detailed errors",
34921
35524
  "Ensure XState machines exist in your project",
34922
35525
  "Check that machines have valid meta.e2e definitions",
34923
- "Or remove --require-manifest flag to continue with fallback behavior"
35526
+ "Or pass --allow-manifest-fallback to continue with fallback behavior"
34924
35527
  ],
34925
35528
  error instanceof Error ? error : void 0
34926
35529
  );
@@ -34930,10 +35533,17 @@ function injectTestAttrsIfLayer4(layer, options) {
34930
35533
  }
34931
35534
  }
34932
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
+ }
34933
35542
  async function runSingleLayer(params) {
35543
+ const effectiveRequireManifest = resolveEffectiveRequireManifest4(params.layer, params.options);
34934
35544
  injectTestAttrsIfLayer4(params.layer, {
34935
35545
  verbose: params.options.verbose,
34936
- requireManifest: params.options.requireManifest
35546
+ requireManifest: effectiveRequireManifest
34937
35547
  });
34938
35548
  try {
34939
35549
  const output3 = await runTest({
@@ -34950,7 +35560,7 @@ async function runSingleLayer(params) {
34950
35560
  reviewSnapshots: params.options.reviewSnapshots,
34951
35561
  forceRegenerate: params.options.force,
34952
35562
  skipGeneration: params.options.skipGeneration,
34953
- requireManifest: params.options.requireManifest,
35563
+ requireManifest: effectiveRequireManifest,
34954
35564
  invokedAs: `runa test:layer${params.layer}`
34955
35565
  });
34956
35566
  emitJsonSuccess(params.cmd, TestRunOutputSchema, output3);
@@ -34984,6 +35594,13 @@ function validateGenerationFlags(layer, opts) {
34984
35594
  ["Use --auto (implementation-driven) OR --generate/--advanced (XState-driven)"]
34985
35595
  );
34986
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
+ }
34987
35604
  }
34988
35605
  function validateSnapshotFlags(opts) {
34989
35606
  if (opts.reviewSnapshots && opts.ci) {
@@ -35022,6 +35639,9 @@ function createLayerCommand(layer) {
35022
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(
35023
35640
  "--require-manifest",
35024
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)"
35025
35645
  );
35026
35646
  }
35027
35647
  return cmd;
@@ -36870,8 +37490,8 @@ var logger13 = createCLILogger("watch");
36870
37490
  function addFallbackSchemaPatterns(patterns) {
36871
37491
  const detected = detectDatabasePackage(process.cwd());
36872
37492
  if (detected) {
36873
- patterns.push(path10__default.join(detected, "src/schema/**/*.ts"));
36874
- 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"));
36875
37495
  return;
36876
37496
  }
36877
37497
  for (const candidate of DATABASE_PACKAGE_CANDIDATES) {
@@ -36885,8 +37505,8 @@ async function buildSchemaPatterns() {
36885
37505
  const patterns = ["supabase/schemas/**/*.sql"];
36886
37506
  try {
36887
37507
  const dbPackagePath = await getDatabasePackagePath();
36888
- patterns.push(path10__default.join(dbPackagePath, "src/schema/**/*.ts"));
36889
- 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"));
36890
37510
  } catch {
36891
37511
  addFallbackSchemaPatterns(patterns);
36892
37512
  }