@runa-ai/runa-cli 0.5.51 → 0.5.53

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 (47) hide show
  1. package/dist/commands/build/machine.d.ts.map +1 -1
  2. package/dist/commands/ci/machine/commands/ci-local.d.ts.map +1 -1
  3. package/dist/commands/ci/machine/commands/ci-pr.d.ts.map +1 -1
  4. package/dist/commands/ci/machine/commands/runtime-env.d.ts +8 -0
  5. package/dist/commands/ci/machine/commands/runtime-env.d.ts.map +1 -0
  6. package/dist/commands/ci/machine/contract.d.ts +1 -0
  7. package/dist/commands/ci/machine/contract.d.ts.map +1 -1
  8. package/dist/commands/ci/machine/helpers.d.ts +13 -0
  9. package/dist/commands/ci/machine/helpers.d.ts.map +1 -1
  10. package/dist/commands/ci/machine/machine.d.ts +1 -0
  11. package/dist/commands/ci/machine/machine.d.ts.map +1 -1
  12. package/dist/commands/db/apply/helpers/pg-schema-diff-helpers.d.ts +14 -0
  13. package/dist/commands/db/apply/helpers/pg-schema-diff-helpers.d.ts.map +1 -1
  14. package/dist/commands/db/apply/helpers/retry-logic.d.ts.map +1 -1
  15. package/dist/commands/db/constants.d.ts +3 -3
  16. package/dist/commands/db/constants.d.ts.map +1 -1
  17. package/dist/commands/db/utils/db-target.d.ts.map +1 -1
  18. package/dist/commands/db/utils/preflight-check.d.ts.map +1 -1
  19. package/dist/commands/db/utils/schema-detector.d.ts.map +1 -1
  20. package/dist/commands/db/utils/sql-table-extractor.d.ts.map +1 -1
  21. package/dist/commands/env/commands/env-pull.d.ts.map +1 -1
  22. package/dist/commands/env/constants/local-supabase.d.ts +30 -62
  23. package/dist/commands/env/constants/local-supabase.d.ts.map +1 -1
  24. package/dist/commands/inject-test-attrs/action.d.ts.map +1 -1
  25. package/dist/commands/inject-test-attrs/commands/inject-test-attrs.d.ts.map +1 -1
  26. package/dist/commands/inject-test-attrs/contract.d.ts +118 -0
  27. package/dist/commands/inject-test-attrs/contract.d.ts.map +1 -1
  28. package/dist/commands/inject-test-attrs/detection-diagnostics.d.ts +67 -0
  29. package/dist/commands/inject-test-attrs/detection-diagnostics.d.ts.map +1 -0
  30. package/dist/commands/inject-test-attrs/manifest-generator.d.ts +7 -1
  31. package/dist/commands/inject-test-attrs/manifest-generator.d.ts.map +1 -1
  32. package/dist/commands/inject-test-attrs/processor-utils.d.ts.map +1 -1
  33. package/dist/commands/inject-test-attrs/processor.d.ts.map +1 -1
  34. package/dist/commands/inject-test-attrs/types.d.ts +57 -0
  35. package/dist/commands/inject-test-attrs/types.d.ts.map +1 -1
  36. package/dist/commands/manifest/index.d.ts.map +1 -1
  37. package/dist/commands/test/commands/test-e2e.d.ts.map +1 -1
  38. package/dist/commands/test/commands/test-integration.d.ts.map +1 -1
  39. package/dist/commands/test/commands/test-layer.d.ts.map +1 -1
  40. package/dist/commands/test/commands/test.d.ts.map +1 -1
  41. package/dist/index.js +1718 -725
  42. package/dist/internal/machines/index.d.ts +1 -0
  43. package/dist/internal/machines/index.d.ts.map +1 -1
  44. package/dist/internal/machines/snapshot-helpers.d.ts +30 -0
  45. package/dist/internal/machines/snapshot-helpers.d.ts.map +1 -0
  46. package/dist/validators/risk-detector.d.ts.map +1 -1
  47. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module';
3
- import * as path10 from 'path';
4
- import path10__default, { join, dirname, resolve, relative, basename, sep, isAbsolute, normalize } from 'path';
3
+ import * as path11 from 'path';
4
+ import path11__default, { join, dirname, resolve, relative, basename, sep, isAbsolute, normalize } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
- import { execSync, spawnSync, execFileSync, exec, spawn } from 'child_process';
7
6
  import * as fs5 from 'fs';
8
7
  import fs5__default, { existsSync, readFileSync, readdirSync, mkdtempSync, writeFileSync, mkdirSync, copyFileSync, createWriteStream, statSync, rmSync, realpathSync, renameSync, promises, lstatSync, accessSync, constants, chmodSync, unlinkSync } from 'fs';
8
+ import { execSync, spawnSync, execFileSync, exec, spawn } from 'child_process';
9
9
  import { createCLILogger, cacheClear, CacheClearOutputSchema, CLIError, cachePrune, CachePruneOutputSchema, cacheStats, CacheStatsOutputSchema, cacheList, CacheListOutputSchema, cacheInvalidate, CacheInvalidateOutputSchema, syncFromProduction, dbGenerateDiagram, DbDiagramGenerateOutputSchema, createDbSnapshot, syncDatabase, emitDbPushFailureCapsule, emitDbAnnotations, writeDbPushStepSummary, exportDbReportJson, DbSyncOutputSchema, databasePaths, detectRequiredServices, formatDetectionResults, dbStart, DbLifecycleStartOutputSchema, dbStop, DbLifecycleStopOutputSchema, dbReset, DbLifecycleResetOutputSchema, dbValidateSchemas, DbSchemaValidateOutputSchema, DbSchemaRisksOutputSchema, dbDetectSchemaRisks, dbApplySchemas, DbSchemaApplyOutputSchema, dbGenerateTypes, DbSchemaGenerateOutputSchema, extractSchemaFilter, dbSeedInit, DbSeedInitOutputSchema, dbSeedValidate, DbSeedValidateOutputSchema, dbSeedGenerate, DbSeedGenerateOutputSchema, dbVerifySeeds, DbSeedVerifyOutputSchema, DbSnapshotCreateOutputSchema, restoreDbSnapshot, DbSnapshotRestoreOutputSchema, listDbSnapshots, DbSnapshotListOutputSchema, dbGeneratePgTapTests, DbTestGenOutputSchema, dbUpdateGoldenRecord, DbTestUpdateGoldenOutputSchema, repairRunaConfig, detectExistingInitConfig, initProject, validateInitResult, linkCliGlobally, LinkCliOutputSchema, unlinkCliGlobally, UnlinkCliOutputSchema, checkRepoStatus, CheckRepoStatusOutputSchema, enableTelemetry, disableTelemetry, getTelemetryStatus, uploadTelemetry, TelemetryUploadOutputSchema, runTest, TestRunOutputSchema, runTestService, TestServiceOutputSchema, runTestIntegration, TestIntegrationOutputSchema, runTestStatic, TestStaticOutputSchema, generateOwaspTop10Tests, TestOwaspGenerateOutputSchema, updateGoldenRecord, generateE2ETests, generateSecurityTests, generateUnitTests, generateApiTests, generateComponentTests, generateE2EScaffold, validateConfig, ValidateConfigOutputSchema, deploySchemaToProduction, WorkflowNotifyOutputSchema, devopsSync, workflowSync, validateInfrastructure, emitWorkflowValidateFailureCapsule, emitWorkflowAnnotations, writeWorkflowValidateStepSummary, exportWorkflowReportJson, WorkflowValidateInfrastructureOutputSchema, createSuccessEnvelopeSchema, CLI_CONTRACT_VERSION, runChecks, RunCheckOutputSchema, formatDuration as formatDuration$1, GITHUB_API, loadRunaConfig, getClassificationForProfile, loadRunaConfigOrThrow, recordSchemaAudit, RecordSchemaAuditOutputSchema, createBackup, CreateBackupOutputSchema, listBackups, ListBackupsOutputSchema, getBackupMetadata, restoreBackup, RestoreBackupOutputSchema, deleteBackup, DeleteBackupOutputSchema, detectSchemaNames, SUPABASE_SYSTEM_SCHEMAS, dbSeedApply, writeDbSeedStepSummary, DbSeedApplyOutputSchema, emitDbSeedFailureCapsule, syncEnvironment, EnvSyncOutputSchema, detectDatabasePackage, findProjectRoot as findProjectRoot$1, TelemetryEnableOutputSchema, TelemetryDisableOutputSchema, TelemetryStatusOutputSchema, workflowNotify, DevOpsSyncOutputSchema, WorkflowSyncOutputSchema, formatCLIError, getStatusIcon as getStatusIcon$1, findWorkspaceRoot as findWorkspaceRoot$1, checkExtensionConfig, UpgradeTransaction, readRunaVersion, syncTemplates, SyncOutputSchema, DATABASE_PACKAGE_CANDIDATES, ErrorEnvelopeSchema, preCheckSync, findConflictFiles, TestUnitGenOutputSchema, TestE2EGenerateOutputSchema, TestSecurityGenOutputSchema, TestApiGenOutputSchema, TestComponentGenOutputSchema } from '@runa-ai/runa';
10
10
  import { z } from 'zod';
11
11
  import fs9, { mkdir, writeFile, appendFile, readFile, rm, stat, realpath, cp, readdir, lstat } from 'fs/promises';
@@ -33,7 +33,7 @@ import { createJiti } from 'jiti';
33
33
  import ora from 'ora';
34
34
  import { stdout, stdin } from 'process';
35
35
  import * as readline from 'readline/promises';
36
- import { clearInjectionRegistry, clearUnifiedRegistry, postProcessRegistries, isPageFile, collectPageInfo, isLayoutFile, collectLayoutInfo, isApiRouteFile, collectApiRouteInfo, isMiddlewareFile, collectAuthBoundaries, hasMachineDefinition, collectMachineDefinition, getInjectionRegistry, buildManifest, getAllMachineDefinitions, generateSelectorTypeScript, getUnifiedRegistry, buildMachineLinks, createReadAndParseFile, createResolveImportPath, transformSync, registerInjection } from '@runa-ai/runa-xstate-test-plugin/standalone';
36
+ import { clearInjectionRegistry, clearUnifiedRegistry, postProcessRegistries, isPageFile, collectPageInfo, isLayoutFile, collectLayoutInfo, isApiRouteFile, collectApiRouteInfo, isMiddlewareFile, collectAuthBoundaries, hasMachineDefinition, collectMachineDefinition, createReadAndParseFile, createResolveImportPath, transformSync, getInjectionRegistry, buildManifest, getAllMachineDefinitions, generateSelectorTypeScript, getUnifiedRegistry, buildMachineLinks, registerInjection } from '@runa-ai/runa-xstate-test-plugin/standalone';
37
37
  import { listSessions, formatDuration as formatDuration$2, cleanupStaleSessions, removeSession, isSessionCheckDisabled, getCurrentSessionId, checkActiveSessions, createSession, addActivity, checkConflicts, formatConflictDetails } from '@runa-ai/runa/session';
38
38
  import { render, Box, Text } from 'ink';
39
39
  import Spinner from 'ink-spinner';
@@ -73,10 +73,230 @@ var getFilename, getDirname, __dirname$1;
73
73
  var init_esm_shims = __esm({
74
74
  "../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/esm_shims.js"() {
75
75
  getFilename = () => fileURLToPath(import.meta.url);
76
- getDirname = () => path10__default.dirname(getFilename());
76
+ getDirname = () => path11__default.dirname(getFilename());
77
77
  __dirname$1 = /* @__PURE__ */ getDirname();
78
78
  }
79
79
  });
80
+ function isValidPort(value) {
81
+ if (typeof value !== "number") {
82
+ return false;
83
+ }
84
+ return Number.isInteger(value) && value > 0 && value < 65536;
85
+ }
86
+ function asPort(value, fallback) {
87
+ const parsed = typeof value === "number" ? value : typeof value === "string" ? Number.parseInt(value, 10) : NaN;
88
+ return isValidPort(parsed) ? parsed : fallback;
89
+ }
90
+ function asHost(value) {
91
+ if (!value) return null;
92
+ const trimmed = value.trim();
93
+ return trimmed.length > 0 ? trimmed : null;
94
+ }
95
+ function getStatusValue(status, keys) {
96
+ for (const key of keys) {
97
+ const value = status[key];
98
+ if (typeof value === "string" && value.trim()) {
99
+ return value.trim();
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+ function extractHost(rawUrl) {
105
+ if (!rawUrl) return null;
106
+ try {
107
+ return new URL(rawUrl).hostname;
108
+ } catch {
109
+ return null;
110
+ }
111
+ }
112
+ function extractPort(rawUrl) {
113
+ if (!rawUrl) return null;
114
+ try {
115
+ const port = new URL(rawUrl).port;
116
+ if (!port) return null;
117
+ const parsed = Number.parseInt(port, 10);
118
+ return isValidPort(parsed) ? parsed : null;
119
+ } catch {
120
+ const match = rawUrl.match(/:(\d+)\//);
121
+ if (!match) return null;
122
+ const parsed = Number.parseInt(match[1], 10);
123
+ return isValidPort(parsed) ? parsed : null;
124
+ }
125
+ }
126
+ function parseTomlPort(content, section, key) {
127
+ const sectionRegex = new RegExp(`\\[${section}\\]([\\s\\S]*?)(?=\\n\\[|$)`, "m");
128
+ const sectionMatch = sectionRegex.exec(content);
129
+ if (!sectionMatch) return null;
130
+ const sectionContent = sectionMatch[1];
131
+ const keyRegex = new RegExp(`^\\s*${key}\\s*=\\s*(\\d+)`, "m");
132
+ const keyMatch = keyRegex.exec(sectionContent);
133
+ if (!keyMatch) return null;
134
+ const parsed = Number.parseInt(keyMatch[1], 10);
135
+ return isValidPort(parsed) ? parsed : null;
136
+ }
137
+ function parseTomlPorts(configRoot) {
138
+ const configPath = path11__default.join(configRoot, "supabase", "config.toml");
139
+ if (!existsSync(configPath)) return null;
140
+ try {
141
+ const content = readFileSync(configPath, "utf-8");
142
+ return {
143
+ api: parseTomlPort(content, "api", "port"),
144
+ db: parseTomlPort(content, "db", "port")
145
+ };
146
+ } catch {
147
+ return null;
148
+ }
149
+ }
150
+ function detectStatus(projectRoot) {
151
+ try {
152
+ const result = spawnSync("supabase", ["status", "--output", "json"], {
153
+ cwd: projectRoot,
154
+ encoding: "utf-8",
155
+ stdio: ["pipe", "pipe", "pipe"],
156
+ timeout: 5e3
157
+ });
158
+ if (result.status !== 0 || !result.stdout) return null;
159
+ const jsonMatch = result.stdout.match(/\{[\s\S]*\}/);
160
+ if (!jsonMatch) return null;
161
+ return JSON.parse(jsonMatch[0]);
162
+ } catch {
163
+ return null;
164
+ }
165
+ }
166
+ function resolveSupabaseRoot(projectRoot) {
167
+ const start = path11__default.resolve(projectRoot);
168
+ let current = start;
169
+ while (true) {
170
+ if (existsSync(path11__default.join(current, "supabase", "config.toml"))) {
171
+ return current;
172
+ }
173
+ const parent = path11__default.dirname(current);
174
+ if (parent === current) {
175
+ return start;
176
+ }
177
+ current = parent;
178
+ }
179
+ }
180
+ function isAllowedLocalhostHost(host) {
181
+ return host === "127.0.0.1" || host === "localhost" || host === "host.docker.internal";
182
+ }
183
+ function readSupabaseOverrides() {
184
+ return {
185
+ host: asHost(process.env.LOCAL_SUPABASE_HOST),
186
+ api: asPort(process.env.LOCAL_SUPABASE_API_PORT, DEFAULT_API_PORT),
187
+ db: asPort(process.env.LOCAL_SUPABASE_DB_PORT, DEFAULT_DB_PORT),
188
+ studio: asPort(process.env.LOCAL_SUPABASE_STUDIO_PORT, DEFAULT_STUDIO_PORT)
189
+ };
190
+ }
191
+ function detectLocalSupabasePorts(projectRoot = process.cwd()) {
192
+ const resolvedRoot = resolveSupabaseRoot(projectRoot);
193
+ const overrides = readSupabaseOverrides();
194
+ const status = detectStatus(resolvedRoot);
195
+ const tomlPorts = parseTomlPorts(resolvedRoot);
196
+ const statusApiUrl = status ? getStatusValue(status, ["API_URL", "API URL", "api_url"]) : null;
197
+ const statusDbUrl = status ? getStatusValue(status, ["DB_URL", "DB URL", "db_url"]) : null;
198
+ const statusStudioUrl = status ? getStatusValue(status, ["STUDIO_URL", "Studio URL", "studio_url"]) : null;
199
+ const detectedHost = asHost(
200
+ overrides.host ?? extractHost(statusApiUrl) ?? extractHost(statusDbUrl) ?? extractHost(statusStudioUrl)
201
+ );
202
+ const detectedApiPort = asPort(
203
+ overrides.api !== DEFAULT_API_PORT ? overrides.api : void 0,
204
+ extractPort(statusApiUrl) ?? tomlPorts?.api ?? DEFAULT_API_PORT
205
+ );
206
+ const detectedDbPort = asPort(
207
+ overrides.db !== DEFAULT_DB_PORT ? overrides.db : void 0,
208
+ extractPort(statusDbUrl) ?? tomlPorts?.db ?? DEFAULT_DB_PORT
209
+ );
210
+ const detectedStudioPort = asPort(
211
+ overrides.studio !== DEFAULT_STUDIO_PORT ? overrides.studio : void 0,
212
+ extractPort(statusStudioUrl) ?? detectedApiPort + 2
213
+ );
214
+ return {
215
+ host: detectedHost ?? DEFAULT_HOST,
216
+ api: detectedApiPort,
217
+ db: detectedDbPort,
218
+ studio: detectedStudioPort
219
+ };
220
+ }
221
+ function buildLocalSupabaseUrl(projectRoot = process.cwd()) {
222
+ const config = detectLocalSupabasePorts(projectRoot);
223
+ return `http://${config.host}:${config.api}`;
224
+ }
225
+ function buildLocalDatabaseUrl(projectRoot = process.cwd()) {
226
+ const config = detectLocalSupabasePorts(projectRoot);
227
+ return `postgresql://postgres:postgres@${config.host}:${config.db}/postgres`;
228
+ }
229
+ function getLocalSupabaseEnvValues(projectRoot = process.cwd()) {
230
+ const config = detectLocalSupabasePorts(projectRoot);
231
+ const supabaseUrl = buildLocalSupabaseUrl(projectRoot);
232
+ const databaseUrl = buildLocalDatabaseUrl(projectRoot);
233
+ return {
234
+ LOCAL_SUPABASE_HOST: config.host,
235
+ LOCAL_SUPABASE_API_PORT: String(config.api),
236
+ LOCAL_SUPABASE_DB_PORT: String(config.db),
237
+ DATABASE_URL: databaseUrl,
238
+ DATABASE_URL_ADMIN: databaseUrl,
239
+ DATABASE_URL_SERVICE: databaseUrl,
240
+ NEXT_PUBLIC_SUPABASE_URL: supabaseUrl,
241
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: LOCAL_SUPABASE_ANON_KEY,
242
+ SUPABASE_SERVICE_ROLE_KEY: LOCAL_SUPABASE_SERVICE_ROLE_KEY
243
+ };
244
+ }
245
+ function getLocalValueDescriptions(projectRoot = process.cwd()) {
246
+ const config = detectLocalSupabasePorts(projectRoot);
247
+ return {
248
+ LOCAL_SUPABASE_HOST: `supabase local host ${config.host}`,
249
+ LOCAL_SUPABASE_API_PORT: `supabase local api port ${config.api}`,
250
+ LOCAL_SUPABASE_DB_PORT: `supabase local db port ${config.db}`,
251
+ DATABASE_URL: `supabase local DB ${config.host}:${config.db}`,
252
+ DATABASE_URL_ADMIN: `supabase local DB ${config.host}:${config.db}`,
253
+ DATABASE_URL_SERVICE: `supabase local DB ${config.host}:${config.db}`,
254
+ NEXT_PUBLIC_SUPABASE_URL: `supabase local API ${config.host}:${config.api}`,
255
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: "local anon key (supabase-demo)",
256
+ SUPABASE_SERVICE_ROLE_KEY: "local service key (supabase-demo)"
257
+ };
258
+ }
259
+ function validateLocalhostValues(envValues) {
260
+ const urlKeys = [
261
+ "DATABASE_URL",
262
+ "DATABASE_URL_ADMIN",
263
+ "DATABASE_URL_SERVICE",
264
+ "NEXT_PUBLIC_SUPABASE_URL"
265
+ ];
266
+ const invalidEntries = [];
267
+ for (const key of urlKeys) {
268
+ const value = envValues[key];
269
+ if (!value) continue;
270
+ try {
271
+ const hostname = new URL(value).hostname;
272
+ if (!isAllowedLocalhostHost(hostname)) {
273
+ invalidEntries.push(key);
274
+ }
275
+ } catch {
276
+ invalidEntries.push(key);
277
+ }
278
+ }
279
+ if (invalidEntries.length > 0) {
280
+ throw new Error(
281
+ `Local Supabase replacement aborted: not a local endpoint. The following keys are not local: ${invalidEntries.join(", ")}`
282
+ );
283
+ }
284
+ }
285
+ var DEFAULT_HOST, DEFAULT_API_PORT, DEFAULT_DB_PORT, DEFAULT_STUDIO_PORT, LOCAL_SUPABASE_ANON_KEY, LOCAL_SUPABASE_SERVICE_ROLE_KEY, LOCAL_SUPABASE_ENV_VALUES;
286
+ var init_local_supabase = __esm({
287
+ "src/commands/env/constants/local-supabase.ts"() {
288
+ init_esm_shims();
289
+ DEFAULT_HOST = "127.0.0.1";
290
+ DEFAULT_API_PORT = 54321;
291
+ DEFAULT_DB_PORT = 54322;
292
+ DEFAULT_STUDIO_PORT = 54323;
293
+ LOCAL_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
294
+ LOCAL_SUPABASE_SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU";
295
+ LOCAL_SUPABASE_ENV_VALUES = getLocalSupabaseEnvValues();
296
+ getLocalValueDescriptions();
297
+ validateLocalhostValues(LOCAL_SUPABASE_ENV_VALUES);
298
+ }
299
+ });
80
300
 
81
301
  // src/commands/db/constants.ts
82
302
  var constants_exports = {};
@@ -113,7 +333,7 @@ function detectSupabasePorts(projectRoot) {
113
333
  const apiUrl = status.API_URL || status["API URL"] || status.api_url;
114
334
  const dbUrl = status.DB_URL || status["DB URL"] || status.db_url;
115
335
  const studioUrl = status.STUDIO_URL || status["Studio URL"] || status.studio_url;
116
- const extractPort = (url) => {
336
+ const extractPort2 = (url) => {
117
337
  try {
118
338
  const parsed = new URL(url);
119
339
  return parsed.port ? Number.parseInt(parsed.port, 10) : null;
@@ -122,28 +342,38 @@ function detectSupabasePorts(projectRoot) {
122
342
  return match ? Number.parseInt(match[1], 10) : null;
123
343
  }
124
344
  };
125
- const apiPort = apiUrl ? extractPort(apiUrl) : null;
126
- const dbPort = dbUrl ? extractPort(dbUrl) : null;
127
- const studioPort = studioUrl ? extractPort(studioUrl) : null;
345
+ const apiPort = apiUrl ? extractPort2(apiUrl) : null;
346
+ const dbPort = dbUrl ? extractPort2(dbUrl) : null;
347
+ const studioPort = studioUrl ? extractPort2(studioUrl) : null;
128
348
  if (!apiPort || !dbPort) {
129
349
  throw new Error(
130
350
  "Could not detect Supabase ports from status output.\n\nTry restarting Supabase: supabase stop && supabase start"
131
351
  );
132
352
  }
133
- return { api: apiPort, db: dbPort, studio: studioPort ?? apiPort + 2 };
353
+ return {
354
+ api: apiPort,
355
+ db: dbPort,
356
+ studio: studioPort ?? apiPort + 2
357
+ };
134
358
  }
135
359
  function getSupabaseAccessPoints(projectRoot) {
136
- const ports = detectSupabasePorts(projectRoot);
360
+ const ports = detectLocalSupabasePorts(projectRoot);
361
+ const buildSupabaseUrl = (port) => {
362
+ const url = new URL(buildLocalSupabaseUrl(projectRoot));
363
+ url.port = String(port);
364
+ return url.toString().replace(/\/$/, "");
365
+ };
137
366
  return {
138
- studio: `http://127.0.0.1:${ports.studio}`,
139
- api: `http://127.0.0.1:${ports.api}`,
140
- db: `postgresql://postgres:postgres@127.0.0.1:${ports.db}/postgres`
367
+ studio: buildSupabaseUrl(ports.studio),
368
+ api: buildLocalSupabaseUrl(projectRoot),
369
+ db: buildLocalDatabaseUrl(projectRoot)
141
370
  };
142
371
  }
143
372
  var DATABASE_DEFAULTS, SEED_DEFAULTS, SCRIPT_LOCATIONS, ERROR_MESSAGES;
144
373
  var init_constants = __esm({
145
374
  "src/commands/db/constants.ts"() {
146
375
  init_esm_shims();
376
+ init_local_supabase();
147
377
  DATABASE_DEFAULTS = {
148
378
  // Supabase Local defaults (for development)
149
379
  // Note: PORT is detected from running Supabase instance
@@ -152,7 +382,9 @@ var init_constants = __esm({
152
382
  // This is a documented public value, not a secret.
153
383
  // Production uses environment variables via .env.production.
154
384
  SUPABASE_LOCAL: {
155
- HOST: "127.0.0.1",
385
+ get HOST() {
386
+ return detectLocalSupabasePorts().host;
387
+ },
156
388
  get PORT() {
157
389
  return detectSupabasePorts().db;
158
390
  },
@@ -186,15 +418,15 @@ var init_constants = __esm({
186
418
  if (databaseUrl) {
187
419
  try {
188
420
  const url2 = new URL(databaseUrl);
189
- const isLocalhost = url2.hostname === "127.0.0.1" || url2.hostname === "localhost";
421
+ const isLocalhost = url2.hostname === "127.0.0.1" || url2.hostname === "localhost" || url2.hostname === "host.docker.internal";
190
422
  if (isLocalhost) {
191
423
  return databaseUrl;
192
424
  }
193
425
  } catch {
194
426
  }
195
427
  }
196
- const host = process.env.LOCAL_DB_HOST || process.env.DB_HOST || this.SUPABASE_LOCAL.HOST;
197
- const port = process.env.LOCAL_DB_PORT || process.env.DB_PORT || String(this.SUPABASE_LOCAL.PORT);
428
+ const host = process.env.LOCAL_DB_HOST || process.env.DB_HOST || process.env.LOCAL_SUPABASE_HOST || this.SUPABASE_LOCAL.HOST;
429
+ const port = process.env.LOCAL_DB_PORT || process.env.DB_PORT || process.env.LOCAL_SUPABASE_DB_PORT || String(this.SUPABASE_LOCAL.PORT);
198
430
  const user = process.env.LOCAL_DB_USER || process.env.DB_USER || this.SUPABASE_LOCAL.USER;
199
431
  const password = process.env.LOCAL_DB_PASSWORD || process.env.DB_PASSWORD || this.SUPABASE_LOCAL.PASSWORD;
200
432
  const database = process.env.LOCAL_DB_NAME || process.env.DB_NAME || this.SUPABASE_LOCAL.DATABASE;
@@ -748,11 +980,11 @@ function validateRunaConfig(config) {
748
980
  };
749
981
  }
750
982
  function hasValidDatabaseIndicators(dir) {
751
- const hasPrimaryIndicator = existsSync(path10__default.join(dir, "drizzle.config.ts")) || existsSync(path10__default.join(dir, "supabase", "schemas")) || existsSync(path10__default.join(dir, "src", "schema")) || existsSync(path10__default.join(dir, "scripts", "db-sync.ts"));
983
+ const hasPrimaryIndicator = existsSync(path11__default.join(dir, "drizzle.config.ts")) || existsSync(path11__default.join(dir, "supabase", "schemas")) || existsSync(path11__default.join(dir, "src", "schema")) || existsSync(path11__default.join(dir, "scripts", "db-sync.ts"));
752
984
  if (hasPrimaryIndicator) {
753
985
  return true;
754
986
  }
755
- const pkgJsonPath = path10__default.join(dir, "package.json");
987
+ const pkgJsonPath = path11__default.join(dir, "package.json");
756
988
  if (existsSync(pkgJsonPath)) {
757
989
  try {
758
990
  const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
@@ -768,15 +1000,15 @@ function hasValidDatabaseIndicators(dir) {
768
1000
  function tryResolveFromConfig(cwd) {
769
1001
  try {
770
1002
  const loaded = loadRunaConfigOrThrow(cwd);
771
- const configDir = path10__default.dirname(loaded.configPath);
1003
+ const configDir = path11__default.dirname(loaded.configPath);
772
1004
  const config = loaded.config;
773
1005
  if (config.project.monorepo === false && hasValidDatabaseIndicators(configDir)) {
774
1006
  return configDir;
775
1007
  }
776
1008
  const dbConfig = getDatabaseConfig(config);
777
1009
  const schemaPath = dbConfig.schemaPath;
778
- const dbPath = schemaPath.includes("/src/") ? schemaPath.split("/src/")[0] : schemaPath.startsWith("src/") ? "." : path10__default.dirname(schemaPath);
779
- const fullPath = dbPath === "." ? configDir : path10__default.join(configDir, dbPath);
1010
+ const dbPath = schemaPath.includes("/src/") ? schemaPath.split("/src/")[0] : schemaPath.startsWith("src/") ? "." : path11__default.dirname(schemaPath);
1011
+ const fullPath = dbPath === "." ? configDir : path11__default.join(configDir, dbPath);
780
1012
  return existsSync(fullPath) ? fullPath : null;
781
1013
  } catch {
782
1014
  return null;
@@ -789,9 +1021,9 @@ async function getDatabasePackagePath(cwd = process.cwd()) {
789
1021
  if (dbPackage) return dbPackage;
790
1022
  const baseDir = findWorkspaceRoot(cwd) || cwd;
791
1023
  const conventionalPaths = [
792
- path10__default.join(baseDir, "packages", "database"),
793
- path10__default.join(baseDir, "packages", "db"),
794
- path10__default.join(baseDir, "db"),
1024
+ path11__default.join(baseDir, "packages", "database"),
1025
+ path11__default.join(baseDir, "packages", "db"),
1026
+ path11__default.join(baseDir, "db"),
795
1027
  baseDir
796
1028
  ];
797
1029
  for (const candidate of conventionalPaths) {
@@ -822,14 +1054,14 @@ Solutions:
822
1054
  async function getSDKScriptsPath(cwd = process.cwd()) {
823
1055
  const sdkPackage = findPackage("sdk", cwd);
824
1056
  if (sdkPackage) {
825
- const scriptsPath = path10__default.join(sdkPackage, "scripts");
1057
+ const scriptsPath = path11__default.join(sdkPackage, "scripts");
826
1058
  if (existsSync(scriptsPath)) {
827
1059
  return scriptsPath;
828
1060
  }
829
1061
  }
830
1062
  const workspaceRoot = findWorkspaceRoot(cwd);
831
1063
  const baseDir = workspaceRoot || cwd;
832
- const installedPath = path10__default.join(baseDir, "node_modules", "@runa-ai", "runa", "scripts");
1064
+ const installedPath = path11__default.join(baseDir, "node_modules", "@runa-ai", "runa", "scripts");
833
1065
  if (existsSync(installedPath)) {
834
1066
  return installedPath;
835
1067
  }
@@ -840,14 +1072,14 @@ async function getSDKScriptsPath(cwd = process.cwd()) {
840
1072
  async function getSDKTemplatesPath(cwd = process.cwd()) {
841
1073
  const sdkPackage = findPackage("sdk", cwd);
842
1074
  if (sdkPackage) {
843
- const templatesPath = path10__default.join(sdkPackage, "templates");
1075
+ const templatesPath = path11__default.join(sdkPackage, "templates");
844
1076
  if (existsSync(templatesPath)) {
845
1077
  return templatesPath;
846
1078
  }
847
1079
  }
848
1080
  const workspaceRoot = findWorkspaceRoot(cwd);
849
1081
  const baseDir = workspaceRoot || cwd;
850
- const installedPath = path10__default.join(baseDir, "node_modules", "@runa-ai", "runa", "templates");
1082
+ const installedPath = path11__default.join(baseDir, "node_modules", "@runa-ai", "runa", "templates");
851
1083
  if (existsSync(installedPath)) {
852
1084
  return installedPath;
853
1085
  }
@@ -929,7 +1161,7 @@ var CLI_VERSION, HAS_ADMIN_COMMAND;
929
1161
  var init_version = __esm({
930
1162
  "src/version.ts"() {
931
1163
  init_esm_shims();
932
- CLI_VERSION = "0.5.51";
1164
+ CLI_VERSION = "0.5.53";
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) {
@@ -5119,6 +5351,87 @@ var BuildOutputSchema = z.object({
5119
5351
  // src/commands/build/machine.ts
5120
5352
  init_esm_shims();
5121
5353
 
5354
+ // src/internal/machines/index.ts
5355
+ init_esm_shims();
5356
+
5357
+ // src/internal/machines/machine-runner.ts
5358
+ init_esm_shims();
5359
+ function getOutputOrThrow(snapshot2) {
5360
+ const s = snapshot2;
5361
+ if (s.output === void 0) {
5362
+ throw new CLIError("Machine completed without output", "MACHINE_NO_OUTPUT", [
5363
+ "Ensure the machine defines an `output:` function."
5364
+ ]);
5365
+ }
5366
+ return s.output;
5367
+ }
5368
+ async function runMachine(params) {
5369
+ const timeoutMs = params.timeoutMs ?? 10 * 60 * 1e3;
5370
+ return new Promise((resolve12, reject) => {
5371
+ const actor = createActor(params.machine, { input: params.input });
5372
+ const timer = setTimeout(() => {
5373
+ try {
5374
+ actor.stop?.();
5375
+ } catch {
5376
+ }
5377
+ reject(
5378
+ new CLIError("Machine execution timed out", "MACHINE_TIMEOUT", [
5379
+ `Timeout: ${timeoutMs}ms`,
5380
+ "Consider increasing timeoutMs for long-running operations."
5381
+ ])
5382
+ );
5383
+ }, timeoutMs);
5384
+ const sub = actor.subscribe((snapshot2) => {
5385
+ try {
5386
+ params.onSnapshot?.(snapshot2);
5387
+ const stateName = params.helpers.getStateName(snapshot2);
5388
+ params.onTransition?.(stateName);
5389
+ if (params.helpers.isComplete(snapshot2)) {
5390
+ clearTimeout(timer);
5391
+ sub.unsubscribe();
5392
+ const out = getOutputOrThrow(snapshot2);
5393
+ resolve12(out);
5394
+ }
5395
+ } catch (err) {
5396
+ clearTimeout(timer);
5397
+ sub.unsubscribe();
5398
+ reject(err);
5399
+ }
5400
+ });
5401
+ try {
5402
+ actor.start();
5403
+ actor.send({ type: "START" });
5404
+ } catch (err) {
5405
+ clearTimeout(timer);
5406
+ sub.unsubscribe();
5407
+ reject(err);
5408
+ }
5409
+ });
5410
+ }
5411
+
5412
+ // src/internal/machines/snapshot-helpers.ts
5413
+ init_esm_shims();
5414
+ function getSnapshotStateName(snapshot2) {
5415
+ if (typeof snapshot2.value === "string") {
5416
+ return snapshot2.value;
5417
+ }
5418
+ if (!snapshot2.value || typeof snapshot2.value !== "object") {
5419
+ return "unknown";
5420
+ }
5421
+ const entries = Object.entries(snapshot2.value);
5422
+ if (entries.length === 0) {
5423
+ return "unknown";
5424
+ }
5425
+ const [parent, child] = entries[0];
5426
+ if (typeof child === "string") {
5427
+ return `${parent}.${child}`;
5428
+ }
5429
+ return parent;
5430
+ }
5431
+ function isSnapshotComplete(snapshot2) {
5432
+ return snapshot2.status === "done";
5433
+ }
5434
+
5122
5435
  // src/commands/build/actors/index.ts
5123
5436
  init_esm_shims();
5124
5437
 
@@ -5329,7 +5642,7 @@ function pipeToSharedLog(params) {
5329
5642
  }
5330
5643
  async function ensureRunaTmpDir(cwd) {
5331
5644
  const root = cwd ?? process.cwd();
5332
- const dir = path10__default.join(root, ".runa", "tmp");
5645
+ const dir = path11__default.join(root, ".runa", "tmp");
5333
5646
  await mkdir(dir, { recursive: true });
5334
5647
  return dir;
5335
5648
  }
@@ -5354,7 +5667,7 @@ var buildActor = fromPromise(
5354
5667
  const { repoRoot, tmpDir, hasTurbo, e2e, env: env2 = process.env } = input3;
5355
5668
  const startTime = Date.now();
5356
5669
  try {
5357
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
5670
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
5358
5671
  await mkdir(fullTmpDir, { recursive: true });
5359
5672
  const buildEnv = { ...env2 };
5360
5673
  if (e2e) {
@@ -5363,7 +5676,7 @@ var buildActor = fromPromise(
5363
5676
  buildEnv.TURBO_FORCE = "true";
5364
5677
  console.log(" E2E mode enabled: NEXT_PUBLIC_E2E_TEST=true, TURBO_FORCE=true");
5365
5678
  }
5366
- const hasApps = existsSync(path10__default.join(repoRoot, "apps"));
5679
+ const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
5367
5680
  let args;
5368
5681
  if (hasTurbo) {
5369
5682
  args = hasApps ? ["turbo", "run", "build", "--filter=./apps/*", "--filter=./packages/*"] : ["turbo", "run", "build"];
@@ -5376,7 +5689,7 @@ var buildActor = fromPromise(
5376
5689
  label: "build",
5377
5690
  command: "pnpm",
5378
5691
  args,
5379
- logFile: path10__default.join(fullTmpDir, "build.log")
5692
+ logFile: path11__default.join(fullTmpDir, "build.log")
5380
5693
  });
5381
5694
  return {
5382
5695
  passed: true,
@@ -5615,7 +5928,7 @@ function deleteIfExists(fullPath, displayPath, verbose) {
5615
5928
  function deleteRootDirectories(repoRoot, dirs, verbose) {
5616
5929
  const deleted = [];
5617
5930
  for (const dir of dirs) {
5618
- const fullPath = path10__default.join(repoRoot, dir);
5931
+ const fullPath = path11__default.join(repoRoot, dir);
5619
5932
  if (deleteIfExists(fullPath, dir, verbose)) {
5620
5933
  deleted.push(dir);
5621
5934
  }
@@ -5626,13 +5939,13 @@ function cleanMonorepoPackages(repoRoot, dirs, verbose) {
5626
5939
  const deleted = [];
5627
5940
  const subdirs = ["apps", "packages"];
5628
5941
  for (const subdir of subdirs) {
5629
- const subdirPath = path10__default.join(repoRoot, subdir);
5942
+ const subdirPath = path11__default.join(repoRoot, subdir);
5630
5943
  if (!existsSync(subdirPath)) continue;
5631
5944
  const entries = __require("fs").readdirSync(subdirPath, { withFileTypes: true });
5632
5945
  for (const entry of entries) {
5633
5946
  if (!entry.isDirectory()) continue;
5634
5947
  for (const dir of dirs) {
5635
- const targetPath = path10__default.join(subdirPath, entry.name, dir);
5948
+ const targetPath = path11__default.join(subdirPath, entry.name, dir);
5636
5949
  const displayPath = `${subdir}/${entry.name}/${dir}`;
5637
5950
  if (deleteIfExists(targetPath, displayPath, verbose)) {
5638
5951
  deleted.push(displayPath);
@@ -5651,7 +5964,7 @@ var cleanActor = fromPromise(
5651
5964
  async ({ input: input3 }) => {
5652
5965
  const { repoRoot, tmpDir, verbose = false } = input3;
5653
5966
  try {
5654
- await mkdir(path10__default.join(repoRoot, tmpDir), { recursive: true });
5967
+ await mkdir(path11__default.join(repoRoot, tmpDir), { recursive: true });
5655
5968
  if (verbose) {
5656
5969
  console.log("Cleaning build caches...");
5657
5970
  }
@@ -5673,7 +5986,7 @@ var freshActor = fromPromise(
5673
5986
  async ({ input: input3 }) => {
5674
5987
  const { repoRoot, tmpDir, verbose = false } = input3;
5675
5988
  try {
5676
- await mkdir(path10__default.join(repoRoot, tmpDir), { recursive: true });
5989
+ await mkdir(path11__default.join(repoRoot, tmpDir), { recursive: true });
5677
5990
  if (verbose) {
5678
5991
  console.log("Fresh install: cleaning all caches and node_modules...");
5679
5992
  }
@@ -5745,7 +6058,7 @@ var dbSyncActor = fromPromise(
5745
6058
  const { repoRoot, tmpDir, env: env2 = process.env } = input3;
5746
6059
  const startTime = Date.now();
5747
6060
  try {
5748
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
6061
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
5749
6062
  await mkdir(fullTmpDir, { recursive: true });
5750
6063
  await runLogged({
5751
6064
  cwd: repoRoot,
@@ -5753,7 +6066,7 @@ var dbSyncActor = fromPromise(
5753
6066
  label: "db-sync",
5754
6067
  command: "pnpm",
5755
6068
  args: ["exec", "runa", "db", "sync", "--auto-approve"],
5756
- logFile: path10__default.join(fullTmpDir, "db-sync.log")
6069
+ logFile: path11__default.join(fullTmpDir, "db-sync.log")
5757
6070
  });
5758
6071
  return {
5759
6072
  passed: true,
@@ -5789,7 +6102,7 @@ var manifestActor = fromPromise(
5789
6102
  const { repoRoot, tmpDir, env: env2 = process.env } = input3;
5790
6103
  const startTime = Date.now();
5791
6104
  try {
5792
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
6105
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
5793
6106
  await mkdir(fullTmpDir, { recursive: true });
5794
6107
  await runLogged({
5795
6108
  cwd: repoRoot,
@@ -5797,7 +6110,7 @@ var manifestActor = fromPromise(
5797
6110
  label: "manifest",
5798
6111
  command: "pnpm",
5799
6112
  args: ["exec", "runa", "manifest"],
5800
- logFile: path10__default.join(fullTmpDir, "manifest.log")
6113
+ logFile: path11__default.join(fullTmpDir, "manifest.log")
5801
6114
  });
5802
6115
  return {
5803
6116
  passed: true,
@@ -6061,7 +6374,7 @@ function buildOutput(typeCheckPassed, lintPassed, typeCheckDurationMs, lintDurat
6061
6374
  var staticChecksActor = fromPromise(
6062
6375
  async ({ input: input3 }) => {
6063
6376
  const { repoRoot, tmpDir, hasTurbo, env: env2 = process.env, skipTypes, skipLint } = input3;
6064
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
6377
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
6065
6378
  await mkdir(fullTmpDir, { recursive: true });
6066
6379
  const startTime = Date.now();
6067
6380
  const checksToRun = [];
@@ -6075,7 +6388,7 @@ var staticChecksActor = fromPromise(
6075
6388
  label: "type-check",
6076
6389
  command: cmd.command,
6077
6390
  args: cmd.args,
6078
- logFile: path10__default.join(fullTmpDir, "type-check.log")
6391
+ logFile: path11__default.join(fullTmpDir, "type-check.log")
6079
6392
  })
6080
6393
  );
6081
6394
  checkOrder.push("type-check");
@@ -6089,7 +6402,7 @@ var staticChecksActor = fromPromise(
6089
6402
  label: "lint",
6090
6403
  command: cmd.command,
6091
6404
  args: cmd.args,
6092
- logFile: path10__default.join(fullTmpDir, "lint.log")
6405
+ logFile: path11__default.join(fullTmpDir, "lint.log")
6093
6406
  })
6094
6407
  );
6095
6408
  checkOrder.push("lint");
@@ -6133,14 +6446,14 @@ var validateActor = fromPromise(
6133
6446
  let manifestsExist = true;
6134
6447
  const buildOutputPaths = [
6135
6448
  // Single app
6136
- path10__default.join(repoRoot, ".next"),
6137
- path10__default.join(repoRoot, "dist"),
6449
+ path11__default.join(repoRoot, ".next"),
6450
+ path11__default.join(repoRoot, "dist"),
6138
6451
  // Monorepo apps
6139
- path10__default.join(repoRoot, "apps", "web", ".next"),
6140
- path10__default.join(repoRoot, "apps", "dashboard", ".next"),
6452
+ path11__default.join(repoRoot, "apps", "web", ".next"),
6453
+ path11__default.join(repoRoot, "apps", "dashboard", ".next"),
6141
6454
  // Packages
6142
- path10__default.join(repoRoot, "packages", "cli", "dist"),
6143
- path10__default.join(repoRoot, "packages", "sdk", "dist")
6455
+ path11__default.join(repoRoot, "packages", "cli", "dist"),
6456
+ path11__default.join(repoRoot, "packages", "sdk", "dist")
6144
6457
  ];
6145
6458
  for (const outputPath of buildOutputPaths) {
6146
6459
  if (existsSync(outputPath)) {
@@ -6154,7 +6467,7 @@ var validateActor = fromPromise(
6154
6467
  );
6155
6468
  }
6156
6469
  if (!skipManifest) {
6157
- const manifestPath = path10__default.join(repoRoot, ".runa", "manifests", "manifest.json");
6470
+ const manifestPath = path11__default.join(repoRoot, ".runa", "manifests", "manifest.json");
6158
6471
  if (!existsSync(manifestPath)) {
6159
6472
  manifestsExist = false;
6160
6473
  warnings.push("No manifest.json found. E2E test generation may be affected.");
@@ -6213,35 +6526,35 @@ function isE2EMode({ context }) {
6213
6526
  return context.input.e2e;
6214
6527
  }
6215
6528
  function detectDatabase(repoRoot) {
6216
- const configPath = path10__default.join(repoRoot, "runa.config.ts");
6529
+ const configPath = path11__default.join(repoRoot, "runa.config.ts");
6217
6530
  if (!existsSync(configPath)) {
6218
- const jsConfigPath = path10__default.join(repoRoot, "runa.config.js");
6531
+ const jsConfigPath = path11__default.join(repoRoot, "runa.config.js");
6219
6532
  if (!existsSync(jsConfigPath)) {
6220
6533
  return false;
6221
6534
  }
6222
6535
  }
6223
- const supabaseDir = path10__default.join(repoRoot, "supabase");
6536
+ const supabaseDir = path11__default.join(repoRoot, "supabase");
6224
6537
  if (existsSync(supabaseDir)) {
6225
6538
  return true;
6226
6539
  }
6227
- const databasePkg = path10__default.join(repoRoot, "packages", "database");
6540
+ const databasePkg = path11__default.join(repoRoot, "packages", "database");
6228
6541
  if (existsSync(databasePkg)) {
6229
6542
  return true;
6230
6543
  }
6231
6544
  return false;
6232
6545
  }
6233
6546
  function detectManifestTask(repoRoot) {
6234
- const runaConfigPath = path10__default.join(repoRoot, "runa.config.ts");
6547
+ const runaConfigPath = path11__default.join(repoRoot, "runa.config.ts");
6235
6548
  if (existsSync(runaConfigPath)) {
6236
6549
  return true;
6237
6550
  }
6238
- const rootPkgPath = path10__default.join(repoRoot, "package.json");
6551
+ const rootPkgPath = path11__default.join(repoRoot, "package.json");
6239
6552
  if (hasXStateDependency(rootPkgPath)) {
6240
6553
  return true;
6241
6554
  }
6242
6555
  const appDirs = ["apps/web", "apps/app", "apps/dashboard", "app"];
6243
6556
  for (const appDir of appDirs) {
6244
- const appPkgPath = path10__default.join(repoRoot, appDir, "package.json");
6557
+ const appPkgPath = path11__default.join(repoRoot, appDir, "package.json");
6245
6558
  if (hasXStateDependency(appPkgPath)) {
6246
6559
  return true;
6247
6560
  }
@@ -6268,7 +6581,7 @@ function hasXStateDependency(pkgPath) {
6268
6581
  }
6269
6582
  }
6270
6583
  function detectTurbo(repoRoot) {
6271
- const turboJsonPath = path10__default.join(repoRoot, "turbo.json");
6584
+ const turboJsonPath = path11__default.join(repoRoot, "turbo.json");
6272
6585
  return existsSync(turboJsonPath);
6273
6586
  }
6274
6587
  var guards = {
@@ -7118,20 +7431,10 @@ var buildMachine = setup({
7118
7431
  output: ({ context }) => createOutput(context)
7119
7432
  });
7120
7433
  function getStateName(snapshot2) {
7121
- if (typeof snapshot2.value === "string") {
7122
- return snapshot2.value;
7123
- }
7124
- const topLevel = Object.keys(snapshot2.value)[0];
7125
- if (topLevel && typeof snapshot2.value === "object") {
7126
- const nested = snapshot2.value[topLevel];
7127
- if (nested && typeof nested === "string") {
7128
- return `${topLevel}.${nested}`;
7129
- }
7130
- }
7131
- return topLevel ?? "unknown";
7434
+ return getSnapshotStateName(snapshot2);
7132
7435
  }
7133
7436
  function isComplete(snapshot2) {
7134
- return snapshot2.status === "done";
7437
+ return isSnapshotComplete(snapshot2);
7135
7438
  }
7136
7439
 
7137
7440
  // src/commands/build/commands/build.ts
@@ -7276,15 +7579,15 @@ function printSummary(logger16, output3) {
7276
7579
  }
7277
7580
  }
7278
7581
  function findRepoRoot(startDir) {
7279
- const { existsSync: existsSync51, readFileSync: readFileSync29 } = __require("fs");
7582
+ const { existsSync: existsSync52, readFileSync: readFileSync29 } = __require("fs");
7280
7583
  const { join: join23, dirname: dirname5 } = __require("path");
7281
7584
  let current = startDir;
7282
7585
  while (current !== dirname5(current)) {
7283
- if (existsSync51(join23(current, "turbo.json"))) {
7586
+ if (existsSync52(join23(current, "turbo.json"))) {
7284
7587
  return current;
7285
7588
  }
7286
7589
  const pkgPath = join23(current, "package.json");
7287
- if (existsSync51(pkgPath)) {
7590
+ if (existsSync52(pkgPath)) {
7288
7591
  try {
7289
7592
  const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
7290
7593
  if (pkg.workspaces) {
@@ -7527,42 +7830,42 @@ function resolvePolicy(_config, _repoKind) {
7527
7830
  };
7528
7831
  }
7529
7832
  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"));
7833
+ const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
7834
+ const hasPackages = existsSync(path11__default.join(repoRoot, "packages"));
7835
+ const hasTurbo = existsSync(path11__default.join(repoRoot, "turbo.json"));
7533
7836
  if (hasApps || hasPackages || hasTurbo) {
7534
7837
  return "monorepo";
7535
7838
  }
7536
- const hasSrc = existsSync(path10__default.join(repoRoot, "src"));
7537
- const hasApp = existsSync(path10__default.join(repoRoot, "app"));
7839
+ const hasSrc = existsSync(path11__default.join(repoRoot, "src"));
7840
+ const hasApp = existsSync(path11__default.join(repoRoot, "app"));
7538
7841
  if (hasSrc || hasApp) {
7539
7842
  return "pj-repo";
7540
7843
  }
7541
7844
  return "unknown";
7542
7845
  }
7543
7846
  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"))) {
7847
+ 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
7848
  return true;
7546
7849
  }
7547
- if (existsSync(path10__default.join(dir, "vite.config.js")) || existsSync(path10__default.join(dir, "vite.config.ts"))) {
7850
+ if (existsSync(path11__default.join(dir, "vite.config.js")) || existsSync(path11__default.join(dir, "vite.config.ts"))) {
7548
7851
  return true;
7549
7852
  }
7550
- if (existsSync(path10__default.join(dir, "remix.config.js"))) {
7853
+ if (existsSync(path11__default.join(dir, "remix.config.js"))) {
7551
7854
  return true;
7552
7855
  }
7553
- if (existsSync(path10__default.join(dir, "astro.config.mjs")) || existsSync(path10__default.join(dir, "astro.config.ts"))) {
7856
+ if (existsSync(path11__default.join(dir, "astro.config.mjs")) || existsSync(path11__default.join(dir, "astro.config.ts"))) {
7554
7857
  return true;
7555
7858
  }
7556
- if (existsSync(path10__default.join(dir, "nuxt.config.js")) || existsSync(path10__default.join(dir, "nuxt.config.ts"))) {
7859
+ if (existsSync(path11__default.join(dir, "nuxt.config.js")) || existsSync(path11__default.join(dir, "nuxt.config.ts"))) {
7557
7860
  return true;
7558
7861
  }
7559
- if (existsSync(path10__default.join(dir, "svelte.config.js"))) {
7862
+ if (existsSync(path11__default.join(dir, "svelte.config.js"))) {
7560
7863
  return true;
7561
7864
  }
7562
7865
  return false;
7563
7866
  }
7564
7867
  function hasPackageJson(dir) {
7565
- return existsSync(path10__default.join(dir, "package.json"));
7868
+ return existsSync(path11__default.join(dir, "package.json"));
7566
7869
  }
7567
7870
  var PORT_PATTERNS = [
7568
7871
  /-p\s*([0-9]+)/i,
@@ -7582,7 +7885,7 @@ function extractPortFromScript(script) {
7582
7885
  return null;
7583
7886
  }
7584
7887
  function readPortFromScripts(appDir) {
7585
- const pkgPath = path10__default.join(appDir, "package.json");
7888
+ const pkgPath = path11__default.join(appDir, "package.json");
7586
7889
  if (!existsSync(pkgPath)) return 3e3;
7587
7890
  try {
7588
7891
  const { readFileSync: readFileSync29 } = __require("fs");
@@ -7601,30 +7904,30 @@ function readPortFromScripts(appDir) {
7601
7904
  return 3e3;
7602
7905
  }
7603
7906
  function findWebAppUnderApps(repoRoot) {
7604
- const appsDir = path10__default.join(repoRoot, "apps");
7907
+ const appsDir = path11__default.join(repoRoot, "apps");
7605
7908
  if (!existsSync(appsDir)) return null;
7606
7909
  try {
7607
7910
  const { readdirSync: readdirSync12 } = __require("fs");
7608
7911
  const entries = readdirSync12(appsDir, { withFileTypes: true });
7609
7912
  const priority = ["web", "dashboard", "app", "frontend", "client"];
7610
7913
  for (const name of priority) {
7611
- const candidate = path10__default.join(appsDir, name);
7914
+ const candidate = path11__default.join(appsDir, name);
7612
7915
  if (hasKnownFrameworkConfig(candidate)) return candidate;
7613
7916
  }
7614
7917
  for (const entry of entries) {
7615
7918
  if (!entry.isDirectory()) continue;
7616
7919
  if (priority.includes(entry.name)) continue;
7617
- const candidate = path10__default.join(appsDir, entry.name);
7920
+ const candidate = path11__default.join(appsDir, entry.name);
7618
7921
  if (hasKnownFrameworkConfig(candidate)) return candidate;
7619
7922
  }
7620
7923
  for (const name of priority) {
7621
- const candidate = path10__default.join(appsDir, name);
7924
+ const candidate = path11__default.join(appsDir, name);
7622
7925
  if (hasPackageJson(candidate)) return candidate;
7623
7926
  }
7624
7927
  for (const entry of entries) {
7625
7928
  if (!entry.isDirectory()) continue;
7626
7929
  if (priority.includes(entry.name)) continue;
7627
- const candidate = path10__default.join(appsDir, entry.name);
7930
+ const candidate = path11__default.join(appsDir, entry.name);
7628
7931
  if (hasPackageJson(candidate)) return candidate;
7629
7932
  }
7630
7933
  } catch {
@@ -7633,7 +7936,7 @@ function findWebAppUnderApps(repoRoot) {
7633
7936
  }
7634
7937
  function detectApp(repoRoot, configOverride) {
7635
7938
  if (configOverride?.directory && configOverride.directory !== ".") {
7636
- const configuredDir = path10__default.join(repoRoot, configOverride.directory);
7939
+ const configuredDir = path11__default.join(repoRoot, configOverride.directory);
7637
7940
  if (existsSync(configuredDir) && hasPackageJson(configuredDir)) {
7638
7941
  return {
7639
7942
  appDir: configuredDir,
@@ -7768,7 +8071,7 @@ function pipeChildOutputToLog(params) {
7768
8071
  return { cleanup };
7769
8072
  }
7770
8073
  async function writeEnvLocal(params) {
7771
- const filePath = path10__default.join(params.appDir, ".env.local");
8074
+ const filePath = path11__default.join(params.appDir, ".env.local");
7772
8075
  const content = `${Object.entries(params.values).map(([k, v]) => `${k}=${v}`).join("\n")}
7773
8076
  `;
7774
8077
  await writeFile(filePath, content, "utf-8");
@@ -7858,10 +8161,10 @@ function determineAppCommand(mode, isMonorepo2, rootScripts, appScripts, repoRoo
7858
8161
  }
7859
8162
  if (appHasCiScript || appHasDefaultScript) {
7860
8163
  const scriptName = appHasCiScript ? ciScriptName : "start";
7861
- const dirArgs2 = isMonorepo2 ? ["-C", path10__default.relative(repoRoot, appDir)] : [];
8164
+ const dirArgs2 = isMonorepo2 ? ["-C", path11__default.relative(repoRoot, appDir)] : [];
7862
8165
  return { command: ["pnpm", ...dirArgs2, scriptName], useRootScript: false };
7863
8166
  }
7864
- const dirArgs = isMonorepo2 ? ["-C", path10__default.relative(repoRoot, appDir)] : [];
8167
+ const dirArgs = isMonorepo2 ? ["-C", path11__default.relative(repoRoot, appDir)] : [];
7865
8168
  return {
7866
8169
  command: ["pnpm", ...dirArgs, "exec", "next", nextCommand, "-p", String(port)],
7867
8170
  useRootScript: false
@@ -7869,17 +8172,17 @@ function determineAppCommand(mode, isMonorepo2, rootScripts, appScripts, repoRoo
7869
8172
  }
7870
8173
  var NEXT_CRITICAL_FILES = ["routes-manifest.json", "build-manifest.json"];
7871
8174
  function cleanStaleNextDevState(appDir) {
7872
- const nextDir = path10__default.join(appDir, ".next");
8175
+ const nextDir = path11__default.join(appDir, ".next");
7873
8176
  if (!existsSync(nextDir)) {
7874
8177
  return { cleaned: false };
7875
8178
  }
7876
8179
  for (const file of NEXT_CRITICAL_FILES) {
7877
- if (!existsSync(path10__default.join(nextDir, file))) {
8180
+ if (!existsSync(path11__default.join(nextDir, file))) {
7878
8181
  cleanNextDir(nextDir, `Missing ${file}`);
7879
8182
  return { cleaned: true, reason: `Missing ${file}` };
7880
8183
  }
7881
8184
  }
7882
- const serverDir = path10__default.join(nextDir, "server");
8185
+ const serverDir = path11__default.join(nextDir, "server");
7883
8186
  if (!existsSync(serverDir)) {
7884
8187
  try {
7885
8188
  const nextStat = statSync(nextDir);
@@ -7901,7 +8204,7 @@ function cleanNextDir(nextDir, reason) {
7901
8204
  console.log("[runa] Cleanup complete");
7902
8205
  } catch {
7903
8206
  const staleDir = `${nextDir}-stale-${Date.now()}`;
7904
- console.log(`[runa] Could not remove .next, quarantining to ${path10__default.basename(staleDir)}`);
8207
+ console.log(`[runa] Could not remove .next, quarantining to ${path11__default.basename(staleDir)}`);
7905
8208
  try {
7906
8209
  renameSync(nextDir, staleDir);
7907
8210
  } catch {
@@ -7912,8 +8215,8 @@ function cleanNextDir(nextDir, reason) {
7912
8215
  async function startAppBackground(params) {
7913
8216
  const mode = params.mode ?? "start";
7914
8217
  const isMonorepo2 = params.appDir !== params.repoRoot;
7915
- const rootPkgPath = path10__default.join(params.repoRoot, "package.json");
7916
- const appPkgPath = path10__default.join(params.appDir, "package.json");
8218
+ const rootPkgPath = path11__default.join(params.repoRoot, "package.json");
8219
+ const appPkgPath = path11__default.join(params.appDir, "package.json");
7917
8220
  const rootScripts = await readPackageScripts(rootPkgPath);
7918
8221
  const appScripts = isMonorepo2 ? await readPackageScripts(appPkgPath) : rootScripts;
7919
8222
  const { command, useRootScript } = determineAppCommand(
@@ -7925,7 +8228,7 @@ async function startAppBackground(params) {
7925
8228
  params.appDir,
7926
8229
  params.port
7927
8230
  );
7928
- const appLog = path10__default.join(params.tmpDir, "app.log");
8231
+ const appLog = path11__default.join(params.tmpDir, "app.log");
7929
8232
  const out = createWriteStream(appLog, { flags: "a" });
7930
8233
  const commandStr = command.join(" ");
7931
8234
  const modeLabel = mode === "dev" ? "development (hot reload)" : "production";
@@ -7934,7 +8237,7 @@ async function startAppBackground(params) {
7934
8237
  `[runa] Mode: ${modeLabel}`,
7935
8238
  `[runa] Command: ${commandStr}`,
7936
8239
  `[runa] Working directory: ${params.repoRoot}`,
7937
- `[runa] App directory: ${path10__default.relative(params.repoRoot, params.appDir) || "."}`,
8240
+ `[runa] App directory: ${path11__default.relative(params.repoRoot, params.appDir) || "."}`,
7938
8241
  useRootScript ? "[runa] Using root package.json script" : "[runa] Using app package.json script",
7939
8242
  "---",
7940
8243
  ""
@@ -7955,12 +8258,12 @@ async function startAppBackground(params) {
7955
8258
  streamToTerminal: params.stream
7956
8259
  });
7957
8260
  const pid = child.pid ?? -1;
7958
- await writeFile(path10__default.join(params.tmpDir, "app.pid"), `${pid}
8261
+ await writeFile(path11__default.join(params.tmpDir, "app.pid"), `${pid}
7959
8262
  `, "utf-8");
7960
8263
  return { pid, cleanupStreams };
7961
8264
  }
7962
8265
  async function waitForAppReady(params) {
7963
- const logFilePath = params.tmpDir ? path10__default.join(params.tmpDir, "app.log") : void 0;
8266
+ const logFilePath = params.tmpDir ? path11__default.join(params.tmpDir, "app.log") : void 0;
7964
8267
  await waitHttpOk({
7965
8268
  url: `http://127.0.0.1:${params.port}/`,
7966
8269
  timeoutSeconds: params.timeoutSeconds,
@@ -8100,7 +8403,7 @@ var e2eMeta2 = {
8100
8403
  var appStartActor = fromPromise(
8101
8404
  async ({ input: input3 }) => {
8102
8405
  const { repoRoot, appDir, port, tmpDir, stream } = input3;
8103
- const fullTmpDir = path10__default.join(repoRoot, tmpDir);
8406
+ const fullTmpDir = path11__default.join(repoRoot, tmpDir);
8104
8407
  await mkdir(fullTmpDir, { recursive: true });
8105
8408
  cleanStaleNextDevState(appDir);
8106
8409
  const result = await startAppBackground({
@@ -8368,11 +8671,11 @@ function printSummary2(logger16, output3) {
8368
8671
  }
8369
8672
  function findRepoRoot2(startDir) {
8370
8673
  let current = startDir;
8371
- while (current !== path10__default.dirname(current)) {
8372
- if (existsSync(path10__default.join(current, "turbo.json"))) {
8674
+ while (current !== path11__default.dirname(current)) {
8675
+ if (existsSync(path11__default.join(current, "turbo.json"))) {
8373
8676
  return current;
8374
8677
  }
8375
- const pkgPath = path10__default.join(current, "package.json");
8678
+ const pkgPath = path11__default.join(current, "package.json");
8376
8679
  if (existsSync(pkgPath)) {
8377
8680
  try {
8378
8681
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
@@ -8382,7 +8685,7 @@ function findRepoRoot2(startDir) {
8382
8685
  } catch {
8383
8686
  }
8384
8687
  }
8385
- current = path10__default.dirname(current);
8688
+ current = path11__default.dirname(current);
8386
8689
  }
8387
8690
  return startDir;
8388
8691
  }
@@ -8569,19 +8872,19 @@ function isSupportedNodeEnv(value) {
8569
8872
  function findProjectRoot(from) {
8570
8873
  const workspaceRoot = findWorkspaceRoot(from);
8571
8874
  if (workspaceRoot) return workspaceRoot;
8572
- let current = path10__default.resolve(from);
8573
- const root = path10__default.parse(current).root;
8875
+ let current = path11__default.resolve(from);
8876
+ const root = path11__default.parse(current).root;
8574
8877
  let depth = 0;
8575
8878
  while (current !== root && depth < MAX_DIRECTORY_TRAVERSAL_DEPTH) {
8576
- const hasGit = existsSync(path10__default.join(current, ".git"));
8577
- const hasPackageJson2 = existsSync(path10__default.join(current, "package.json"));
8879
+ const hasGit = existsSync(path11__default.join(current, ".git"));
8880
+ const hasPackageJson2 = existsSync(path11__default.join(current, "package.json"));
8578
8881
  if (hasGit || hasPackageJson2) return current;
8579
- const parent = path10__default.dirname(current);
8882
+ const parent = path11__default.dirname(current);
8580
8883
  if (parent === current) break;
8581
8884
  current = parent;
8582
8885
  depth++;
8583
8886
  }
8584
- return path10__default.resolve(from);
8887
+ return path11__default.resolve(from);
8585
8888
  }
8586
8889
  function mapRunaEnvToVercelEnv(runaEnv) {
8587
8890
  if (runaEnv === "preview") return "preview";
@@ -8622,7 +8925,7 @@ function loadEnvFiles(options = {}) {
8622
8925
  const nodeEnv = resolveNodeEnv(options.nodeEnv);
8623
8926
  const projectRoot = findProjectRoot(cwd);
8624
8927
  const vercelEnv = options.vercelEnv ?? inferVercelEnv({ nodeEnv, runaEnv: options.runaEnv });
8625
- const keysFile = path10__default.join(projectRoot, ".env.keys");
8928
+ const keysFile = path11__default.join(projectRoot, ".env.keys");
8626
8929
  const baseFilePaths = buildBaseEnvFilePaths({ nodeEnv, vercelEnv });
8627
8930
  const runaFilePaths = options.runaEnv ? buildRunaEnvFilePaths(options.runaEnv) : [];
8628
8931
  const allRelPaths = [...baseFilePaths, ...runaFilePaths];
@@ -8632,7 +8935,7 @@ function loadEnvFiles(options = {}) {
8632
8935
  const filePaths = [
8633
8936
  keysFile,
8634
8937
  // Load keys first
8635
- ...allRelPaths.map((rel) => path10__default.join(projectRoot, rel)).filter(existsSync)
8938
+ ...allRelPaths.map((rel) => path11__default.join(projectRoot, rel)).filter(existsSync)
8636
8939
  ];
8637
8940
  config({
8638
8941
  path: filePaths,
@@ -8641,7 +8944,7 @@ function loadEnvFiles(options = {}) {
8641
8944
  quiet: true
8642
8945
  // Suppress dotenvx verbose output
8643
8946
  });
8644
- loadedFiles = allRelPaths.filter((rel) => existsSync(path10__default.join(projectRoot, rel)));
8947
+ loadedFiles = allRelPaths.filter((rel) => existsSync(path11__default.join(projectRoot, rel)));
8645
8948
  } else {
8646
8949
  const targetEnv = { ...process.env };
8647
8950
  loadedFiles = [
@@ -8716,8 +9019,8 @@ function buildRunaEnvFilePaths(runaEnv) {
8716
9019
  function loadEnvFilesIntoTarget(params) {
8717
9020
  const loadedFiles = [];
8718
9021
  for (const relPath of params.relPaths) {
8719
- const fullPath = path10__default.join(params.projectRoot, relPath);
8720
- const resolvedPath = path10__default.resolve(fullPath);
9022
+ const fullPath = path11__default.join(params.projectRoot, relPath);
9023
+ const resolvedPath = path11__default.resolve(fullPath);
8721
9024
  if (!isPathContained(params.projectRoot, resolvedPath)) {
8722
9025
  continue;
8723
9026
  }
@@ -8985,7 +9288,7 @@ async function runTool(params) {
8985
9288
  exitCode,
8986
9289
  issueCount,
8987
9290
  durationMs,
8988
- outputPath: path10__default.relative(process.cwd(), params.outputPath)
9291
+ outputPath: path11__default.relative(process.cwd(), params.outputPath)
8989
9292
  });
8990
9293
  });
8991
9294
  proc.on("error", async () => {
@@ -9004,7 +9307,7 @@ async function runTool(params) {
9004
9307
  exitCode: -1,
9005
9308
  issueCount: 0,
9006
9309
  durationMs,
9007
- outputPath: path10__default.relative(process.cwd(), params.outputPath)
9310
+ outputPath: path11__default.relative(process.cwd(), params.outputPath)
9008
9311
  });
9009
9312
  });
9010
9313
  });
@@ -9036,7 +9339,7 @@ async function executeWorkflowCheck(params) {
9036
9339
  label: params.label,
9037
9340
  command: params.command,
9038
9341
  args: params.args,
9039
- outputPath: path10__default.join(params.logDir, `${params.name}-output.txt`),
9342
+ outputPath: path11__default.join(params.logDir, `${params.name}-output.txt`),
9040
9343
  parseIssueCount: params.parseIssueCount
9041
9344
  });
9042
9345
  logCheckResult(result, params.isWarningOnly ?? false);
@@ -9108,7 +9411,7 @@ async function runCiChecks(options) {
9108
9411
  const mode = options.mode === "github-actions" ? "github-actions" : "local";
9109
9412
  const isCI3 = mode === "github-actions";
9110
9413
  const workflowsChanged = options.workflowsChanged;
9111
- const logDir = path10__default.join(process.cwd(), ".runa", "tmp", "workflow");
9414
+ const logDir = path11__default.join(process.cwd(), ".runa", "tmp", "workflow");
9112
9415
  await mkdir(logDir, { recursive: true });
9113
9416
  console.log("");
9114
9417
  console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
@@ -9117,7 +9420,7 @@ async function runCiChecks(options) {
9117
9420
  console.log("");
9118
9421
  const results = await executeChecks(workflowsChanged, logDir);
9119
9422
  const summary = buildChecksSummary(startedAt, workflowsChanged, results);
9120
- const summaryPath = path10__default.join(logDir, "checks-summary.json");
9423
+ const summaryPath = path11__default.join(logDir, "checks-summary.json");
9121
9424
  await writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
9122
9425
  if (isCI3) {
9123
9426
  await appendGithubStepSummary(buildStepSummaryMarkdown(summary));
@@ -9184,7 +9487,7 @@ function printFinalOutput(summary, summaryPath) {
9184
9487
  console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
9185
9488
  console.log(`${summary.status === "failure" ? "\u274C" : "\u2705"} Workflow Checks: ${summary.status}`);
9186
9489
  console.log(` Duration: ${formatDuration$1(summary.durationMs)}`);
9187
- console.log(` Summary: ${path10__default.relative(process.cwd(), summaryPath)}`);
9490
+ console.log(` Summary: ${path11__default.relative(process.cwd(), summaryPath)}`);
9188
9491
  console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
9189
9492
  }
9190
9493
  var ciChecksCommand = new Command("checks").description("Run workflow checks (actionlint, zizmor)").option("--mode <mode>", "Execution mode (github-actions | local)", "local").option("--workflows-changed", "Indicate workflows have changed", false).action(runCiChecks);
@@ -9197,10 +9500,10 @@ init_esm_shims();
9197
9500
  var CiConfigSchema = z.record(z.string(), z.unknown());
9198
9501
  async function loadCiConfig(params) {
9199
9502
  const override = typeof params.overridePath === "string" && params.overridePath.trim().length > 0 ? params.overridePath.trim() : null;
9200
- const defaultPath = path10__default.join(params.repoRoot, ".runa", "ci.config.json");
9503
+ const defaultPath = path11__default.join(params.repoRoot, ".runa", "ci.config.json");
9201
9504
  const resolvedPath = override ?? (existsSync(defaultPath) ? defaultPath : null);
9202
9505
  if (!resolvedPath) return { configPath: null, config: null };
9203
- const abs = path10__default.isAbsolute(resolvedPath) ? resolvedPath : path10__default.join(params.repoRoot, resolvedPath);
9506
+ const abs = path11__default.isAbsolute(resolvedPath) ? resolvedPath : path11__default.join(params.repoRoot, resolvedPath);
9204
9507
  if (!existsSync(abs)) return { configPath: abs, config: null };
9205
9508
  const raw = await readFile(abs, "utf-8");
9206
9509
  const parsed = JSON.parse(raw);
@@ -9302,9 +9605,9 @@ var CiSummarySchema = z.object({
9302
9605
  async function writeCiSummary(params) {
9303
9606
  const cwd = params.cwd ?? process.cwd();
9304
9607
  const parsed = CiSummarySchema.parse(params.summary);
9305
- const dir = path10__default.join(cwd, ".runa", "tmp");
9608
+ const dir = path11__default.join(cwd, ".runa", "tmp");
9306
9609
  await mkdir(dir, { recursive: true });
9307
- const filePath = path10__default.join(dir, "ci-summary.json");
9610
+ const filePath = path11__default.join(dir, "ci-summary.json");
9308
9611
  await writeFile(filePath, `${JSON.stringify(parsed, null, 2)}
9309
9612
  `, "utf-8");
9310
9613
  return filePath;
@@ -9509,6 +9812,89 @@ var EXCLUDED_SCHEMAS = /* @__PURE__ */ new Set([
9509
9812
  "pgbouncer",
9510
9813
  "cron"
9511
9814
  ]);
9815
+ function stripSqlCommentsPreserveStrings(content) {
9816
+ let result = "";
9817
+ let i = 0;
9818
+ let inSingleQuote = false;
9819
+ let inDoubleQuote = false;
9820
+ let inDollarQuote = false;
9821
+ let dollarTag = "";
9822
+ while (i < content.length) {
9823
+ const char = content[i] ?? "";
9824
+ const next = content[i + 1] ?? "";
9825
+ if (!inSingleQuote && !inDoubleQuote && !inDollarQuote && char === "-" && next === "-") {
9826
+ while (i < content.length && content[i] !== "\n") {
9827
+ result += " ";
9828
+ i++;
9829
+ }
9830
+ continue;
9831
+ }
9832
+ if (!inSingleQuote && !inDoubleQuote && !inDollarQuote && char === "/" && next === "*") {
9833
+ result += " ";
9834
+ result += " ";
9835
+ i += 2;
9836
+ while (i < content.length) {
9837
+ const blockChar = content[i] ?? "";
9838
+ const blockNext = content[i + 1] ?? "";
9839
+ if (blockChar === "*" && blockNext === "/") {
9840
+ result += " ";
9841
+ result += " ";
9842
+ i += 2;
9843
+ break;
9844
+ }
9845
+ result += blockChar === "\n" ? "\n" : " ";
9846
+ i++;
9847
+ }
9848
+ continue;
9849
+ }
9850
+ if (!inSingleQuote && !inDoubleQuote && char === "$") {
9851
+ if (inDollarQuote) {
9852
+ const closeTag = `$${dollarTag}$`;
9853
+ if (content.slice(i).startsWith(closeTag)) {
9854
+ result += closeTag;
9855
+ i += closeTag.length;
9856
+ inDollarQuote = false;
9857
+ dollarTag = "";
9858
+ continue;
9859
+ }
9860
+ } else {
9861
+ const tagMatch = content.slice(i).match(/^\$([a-zA-Z_][a-zA-Z0-9_]*)?\$/);
9862
+ if (tagMatch) {
9863
+ inDollarQuote = true;
9864
+ dollarTag = tagMatch[1] ?? "";
9865
+ result += tagMatch[0];
9866
+ i += tagMatch[0].length;
9867
+ continue;
9868
+ }
9869
+ }
9870
+ }
9871
+ if (!inDoubleQuote && !inDollarQuote && char === "'") {
9872
+ if (inSingleQuote && next === "'") {
9873
+ result += "''";
9874
+ i += 2;
9875
+ continue;
9876
+ }
9877
+ inSingleQuote = !inSingleQuote;
9878
+ result += char;
9879
+ i++;
9880
+ continue;
9881
+ }
9882
+ if (!inSingleQuote && !inDollarQuote && char === '"') {
9883
+ if (inDoubleQuote && next === '"') {
9884
+ result += '""';
9885
+ i += 2;
9886
+ continue;
9887
+ }
9888
+ inDoubleQuote = !inDoubleQuote;
9889
+ result += char;
9890
+ i++;
9891
+ continue;
9892
+ }
9893
+ result += char;
9894
+ i++;
9895
+ }
9896
+ return result;
9897
+ }
9512
9898
  function detectAppSchemas(schemasDir, verbose) {
9513
9899
  const schemas = /* @__PURE__ */ new Set(["public"]);
9514
9900
  if (!existsSync(schemasDir)) {
@@ -9517,12 +9903,13 @@ function detectAppSchemas(schemasDir, verbose) {
9517
9903
  const files = readdirSync(schemasDir).filter((f) => f.endsWith(".sql"));
9518
9904
  for (const file of files) {
9519
9905
  const content = readFileSync(join(schemasDir, file), "utf-8");
9520
- const contentWithoutComments = content.replace(/--[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
9906
+ const contentWithoutComments = stripSqlCommentsPreserveStrings(content);
9521
9907
  const matches = contentWithoutComments.matchAll(
9522
- /^\s*CREATE\s+SCHEMA\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)/gim
9908
+ /^\s*CREATE\s+SCHEMA\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:"((?:[^"]|"")*)"|([a-zA-Z_][a-zA-Z0-9_]*))/gim
9523
9909
  );
9524
9910
  for (const match of Array.from(matches)) {
9525
- const schemaName = match[1].toLowerCase();
9911
+ const schemaNameRaw = (match[1] ?? match[2] ?? "").replace(/""/g, '"');
9912
+ const schemaName = schemaNameRaw.toLowerCase();
9526
9913
  if (!EXCLUDED_SCHEMAS.has(schemaName)) {
9527
9914
  schemas.add(schemaName);
9528
9915
  }
@@ -9553,12 +9940,12 @@ async function detectStack(repoRoot, tmpDir, productionDbUrlAdmin) {
9553
9940
  label: "detect-stack",
9554
9941
  command: "pnpm",
9555
9942
  args: ["exec", "runa", "db", "detect-stack", "--quiet"],
9556
- logFile: path10__default.join(tmpDir, "detect-stack.log")
9943
+ logFile: path11__default.join(tmpDir, "detect-stack.log")
9557
9944
  });
9558
9945
  return String(res.stdout ?? "").trim();
9559
9946
  }
9560
9947
  function checkIfInitialDeployment(repoRoot, productionDbUrl) {
9561
- const schemasDir = path10__default.join(repoRoot, "supabase", "schemas", "declarative");
9948
+ const schemasDir = path11__default.join(repoRoot, "supabase", "schemas", "declarative");
9562
9949
  let schemas;
9563
9950
  try {
9564
9951
  schemas = detectAppSchemas(schemasDir, false);
@@ -9624,9 +10011,9 @@ function checkIfInitialDeployment(repoRoot, productionDbUrl) {
9624
10011
  }
9625
10012
  }
9626
10013
  async function showSchemaDiff(repoRoot, tmpDir) {
9627
- const diffLog = path10__default.join(tmpDir, "schema-diff.log");
10014
+ const diffLog = path11__default.join(tmpDir, "schema-diff.log");
9628
10015
  const safeEnv = getSafeEnv();
9629
- const declarativeSqlPath = path10__default.join(repoRoot, "supabase/schemas/declarative");
10016
+ const declarativeSqlPath = path11__default.join(repoRoot, "supabase/schemas/declarative");
9630
10017
  if (existsSync(declarativeSqlPath)) {
9631
10018
  await runLogged({
9632
10019
  cwd: repoRoot,
@@ -9640,8 +10027,8 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9640
10027
  }
9641
10028
  const detected = detectDatabasePackage(repoRoot);
9642
10029
  if (detected) {
9643
- const schemaPath = path10__default.join(detected, "src", "schema");
9644
- if (existsSync(path10__default.join(repoRoot, schemaPath))) {
10030
+ const schemaPath = path11__default.join(detected, "src", "schema");
10031
+ if (existsSync(path11__default.join(repoRoot, schemaPath))) {
9645
10032
  await runLogged({
9646
10033
  cwd: repoRoot,
9647
10034
  env: safeEnv,
@@ -9654,8 +10041,8 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9654
10041
  }
9655
10042
  }
9656
10043
  for (const candidate of DATABASE_PACKAGE_CANDIDATES) {
9657
- const candidatePath = path10__default.join("packages", candidate, "src", "schema");
9658
- if (existsSync(path10__default.join(repoRoot, candidatePath))) {
10044
+ const candidatePath = path11__default.join("packages", candidate, "src", "schema");
10045
+ if (existsSync(path11__default.join(repoRoot, candidatePath))) {
9659
10046
  await runLogged({
9660
10047
  cwd: repoRoot,
9661
10048
  env: safeEnv,
@@ -9667,7 +10054,7 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9667
10054
  return;
9668
10055
  }
9669
10056
  }
9670
- if (existsSync(path10__default.join(repoRoot, "src", "schema"))) {
10057
+ if (existsSync(path11__default.join(repoRoot, "src", "schema"))) {
9671
10058
  await runLogged({
9672
10059
  cwd: repoRoot,
9673
10060
  env: safeEnv,
@@ -9679,7 +10066,7 @@ async function showSchemaDiff(repoRoot, tmpDir) {
9679
10066
  }
9680
10067
  }
9681
10068
  async function detectRisks(repoRoot, tmpDir) {
9682
- const logFile = path10__default.join(tmpDir, "db-risks.log");
10069
+ const logFile = path11__default.join(tmpDir, "db-risks.log");
9683
10070
  try {
9684
10071
  const env2 = getFilteredEnv();
9685
10072
  await runLogged({
@@ -9725,7 +10112,7 @@ async function snapshotCreate(repoRoot, tmpDir, productionDbUrlAdmin, commit) {
9725
10112
  label: "snapshot create production",
9726
10113
  command: "pnpm",
9727
10114
  args: ["exec", "runa", "db", "snapshot", "create", "production", "--commit", commit],
9728
- logFile: path10__default.join(tmpDir, "snapshot-create.log")
10115
+ logFile: path11__default.join(tmpDir, "snapshot-create.log")
9729
10116
  });
9730
10117
  }
9731
10118
  async function snapshotRestoreLatest(repoRoot, tmpDir, productionDbUrlAdmin) {
@@ -9738,7 +10125,7 @@ async function snapshotRestoreLatest(repoRoot, tmpDir, productionDbUrlAdmin) {
9738
10125
  label: "snapshot restore production (latest)",
9739
10126
  command: "pnpm",
9740
10127
  args: ["exec", "runa", "db", "snapshot", "restore", "production", "--latest", "--auto-approve"],
9741
- logFile: path10__default.join(tmpDir, "snapshot-restore.log")
10128
+ logFile: path11__default.join(tmpDir, "snapshot-restore.log")
9742
10129
  });
9743
10130
  }
9744
10131
  function parseApplyLog(logContent) {
@@ -9802,7 +10189,7 @@ async function applyProductionSchema(repoRoot, tmpDir, productionDbUrlAdmin, pro
9802
10189
  if (options?.maxLockWaitMs !== void 0) {
9803
10190
  args.push("--max-lock-wait-ms", String(options.maxLockWaitMs));
9804
10191
  }
9805
- const logPath = path10__default.join(tmpDir, "db-apply-production.log");
10192
+ const logPath = path11__default.join(tmpDir, "db-apply-production.log");
9806
10193
  const startTime = Date.now();
9807
10194
  await runLogged({
9808
10195
  cwd: repoRoot,
@@ -9847,11 +10234,11 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
9847
10234
  label: "git log (commit message)",
9848
10235
  command: "git",
9849
10236
  args: ["log", "-1", "--pretty=format:%s"],
9850
- logFile: path10__default.join(tmpDir, "git-commit-message.log")
10237
+ logFile: path11__default.join(tmpDir, "git-commit-message.log")
9851
10238
  });
9852
10239
  const commitMsg = String(msg.stdout ?? "").trim();
9853
10240
  const schemaPaths = [];
9854
- const declarativeSqlPath = path10__default.join(repoRoot, "supabase/schemas/declarative");
10241
+ const declarativeSqlPath = path11__default.join(repoRoot, "supabase/schemas/declarative");
9855
10242
  if (existsSync(declarativeSqlPath)) {
9856
10243
  schemaPaths.push("supabase/schemas/declarative/");
9857
10244
  } else {
@@ -9871,7 +10258,7 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
9871
10258
  label: "git diff (schema)",
9872
10259
  command: "git",
9873
10260
  args: ["diff", "origin/main", "HEAD", "--", ...schemaPaths],
9874
- logFile: path10__default.join(tmpDir, "git-schema-diff.log")
10261
+ logFile: path11__default.join(tmpDir, "git-schema-diff.log")
9875
10262
  });
9876
10263
  const diffRaw = String(diff.stdout ?? "");
9877
10264
  const diffLimited = diffRaw.length > 1e4 ? diffRaw.slice(0, 1e4) : diffRaw;
@@ -9900,7 +10287,7 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
9900
10287
  "--environment",
9901
10288
  "production"
9902
10289
  ],
9903
- logFile: path10__default.join(tmpDir, "db-audit-record.log")
10290
+ logFile: path11__default.join(tmpDir, "db-audit-record.log")
9904
10291
  });
9905
10292
  }
9906
10293
  async function notifyDeployment(repoRoot, tmpDir, params) {
@@ -9928,7 +10315,7 @@ async function notifyDeployment(repoRoot, tmpDir, params) {
9928
10315
  "--type",
9929
10316
  "production-schema"
9930
10317
  ],
9931
- logFile: path10__default.join(tmpDir, "notify-deployment.log")
10318
+ logFile: path11__default.join(tmpDir, "notify-deployment.log")
9932
10319
  });
9933
10320
  }
9934
10321
 
@@ -10290,7 +10677,7 @@ $$;
10290
10677
  label: `repair timestamps (${params.labelPrefix})`,
10291
10678
  command: "psql",
10292
10679
  args: [...psql.args, "-v", "ON_ERROR_STOP=1", "-c", sql],
10293
- logFile: path10__default.join(params.tmpDir, `timestamp-repair-${params.labelPrefix}.log`)
10680
+ logFile: path11__default.join(params.tmpDir, `timestamp-repair-${params.labelPrefix}.log`)
10294
10681
  });
10295
10682
  }
10296
10683
 
@@ -10722,7 +11109,7 @@ async function runCiProdApply(params) {
10722
11109
  overridePath: params.options.config
10723
11110
  });
10724
11111
  if (cfg.configPath)
10725
- params.summary.detected.configPath = path10__default.relative(params.repoRoot, cfg.configPath);
11112
+ params.summary.detected.configPath = path11__default.relative(params.repoRoot, cfg.configPath);
10726
11113
  if (cfg.config) params.summary.detected.config = cfg.config;
10727
11114
  requireCiAutoApprove({ mode: params.summary.mode, autoApprove: params.options.autoApprove });
10728
11115
  const inputs = resolveProdApplyInputs();
@@ -10815,7 +11202,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
10815
11202
  await appendGithubStepSummary(
10816
11203
  buildCiProdApplyStepSummaryMarkdown({
10817
11204
  summary,
10818
- summaryPath: path10__default.relative(repoRoot, summaryPath)
11205
+ summaryPath: path11__default.relative(repoRoot, summaryPath)
10819
11206
  })
10820
11207
  );
10821
11208
  if (summary.mode === "github-actions") {
@@ -10831,7 +11218,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
10831
11218
  const summaryPath = await writeCiSummary({ summary });
10832
11219
  logSection("Result");
10833
11220
  console.log(`status: ${summary.status}`);
10834
- console.log(`summary: ${path10__default.relative(repoRoot, summaryPath)}`);
11221
+ console.log(`summary: ${path11__default.relative(repoRoot, summaryPath)}`);
10835
11222
  logNextActions([
10836
11223
  "Inspect .runa/tmp logs (db-apply-production.log, snapshot-*.log)",
10837
11224
  "If rollback succeeded, database should be restored to pre-deploy snapshot"
@@ -10839,7 +11226,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
10839
11226
  await appendGithubStepSummary(
10840
11227
  buildCiProdApplyStepSummaryMarkdown({
10841
11228
  summary,
10842
- summaryPath: path10__default.relative(repoRoot, summaryPath)
11229
+ summaryPath: path11__default.relative(repoRoot, summaryPath)
10843
11230
  })
10844
11231
  );
10845
11232
  await maybePostFailureComment({
@@ -10910,7 +11297,7 @@ function getChecks() {
10910
11297
  }
10911
11298
  async function runCheck(check, logDir) {
10912
11299
  const startTime = Date.now();
10913
- const logPath = path10__default.join(logDir, `${check.name}.log`);
11300
+ const logPath = path11__default.join(logDir, `${check.name}.log`);
10914
11301
  return new Promise((resolve12) => {
10915
11302
  const proc = spawn(check.command, check.args, {
10916
11303
  cwd: process.cwd(),
@@ -10940,7 +11327,7 @@ async function runCheck(check, logDir) {
10940
11327
  status: exitCode === 0 ? "passed" : "failed",
10941
11328
  exitCode,
10942
11329
  durationMs,
10943
- logPath: path10__default.relative(process.cwd(), logPath)
11330
+ logPath: path11__default.relative(process.cwd(), logPath)
10944
11331
  });
10945
11332
  });
10946
11333
  proc.on("error", async () => {
@@ -10955,7 +11342,7 @@ async function runCheck(check, logDir) {
10955
11342
  status: "failed",
10956
11343
  exitCode: 1,
10957
11344
  durationMs,
10958
- logPath: path10__default.relative(process.cwd(), logPath)
11345
+ logPath: path11__default.relative(process.cwd(), logPath)
10959
11346
  });
10960
11347
  });
10961
11348
  });
@@ -11083,19 +11470,19 @@ function printFinalStaticOutput(summary, summaryPath) {
11083
11470
  console.log(`${summary.status === "success" ? "\u2705" : "\u274C"} Static Analysis: ${summary.status}`);
11084
11471
  console.log(` Duration: ${formatDuration$1(summary.durationMs)}`);
11085
11472
  console.log(` Passed: ${summary.passedCount}/${summary.checks.length}`);
11086
- console.log(` Summary: ${path10__default.relative(process.cwd(), summaryPath)}`);
11473
+ console.log(` Summary: ${path11__default.relative(process.cwd(), summaryPath)}`);
11087
11474
  console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
11088
11475
  }
11089
11476
  async function runCiStatic(options) {
11090
11477
  const startedAt = /* @__PURE__ */ new Date();
11091
11478
  const isCI3 = options.mode === "github-actions";
11092
- const logDir = path10__default.join(process.cwd(), ".runa", "tmp", "workflow");
11479
+ const logDir = path11__default.join(process.cwd(), ".runa", "tmp", "workflow");
11093
11480
  await mkdir(logDir, { recursive: true });
11094
11481
  const checksToRun = getChecksToRun(options);
11095
11482
  printStaticHeader(options);
11096
11483
  const results = options.parallel ? await runChecksParallel(checksToRun, logDir) : await runChecksSequential(checksToRun, logDir);
11097
11484
  const summary = buildStaticSummary(startedAt, results);
11098
- const summaryPath = path10__default.join(logDir, "static-summary.json");
11485
+ const summaryPath = path11__default.join(logDir, "static-summary.json");
11099
11486
  await writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
11100
11487
  if (isCI3) {
11101
11488
  await appendGithubStepSummary(buildStepSummaryMarkdown2(summary));
@@ -11125,9 +11512,9 @@ var appBuildActor = fromPromise(
11125
11512
  async ({ input: input3 }) => {
11126
11513
  const { repoRoot, tmpDir, env: env2 = process.env } = input3;
11127
11514
  try {
11128
- const hasTurbo = existsSync(path10__default.join(repoRoot, "turbo.json"));
11129
- const hasApps = existsSync(path10__default.join(repoRoot, "apps"));
11130
- const hasAppsWeb = existsSync(path10__default.join(repoRoot, "apps", "web"));
11515
+ const hasTurbo = existsSync(path11__default.join(repoRoot, "turbo.json"));
11516
+ const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
11517
+ const hasAppsWeb = existsSync(path11__default.join(repoRoot, "apps", "web"));
11131
11518
  const args = hasTurbo ? hasApps && !hasAppsWeb ? ["turbo", "run", "build", "--filter=./apps/*"] : ["turbo", "run", "build"] : ["build"];
11132
11519
  await runLogged({
11133
11520
  cwd: repoRoot,
@@ -11135,7 +11522,7 @@ var appBuildActor = fromPromise(
11135
11522
  label: "build",
11136
11523
  command: "pnpm",
11137
11524
  args,
11138
- logFile: path10__default.join(tmpDir, "build.log")
11525
+ logFile: path11__default.join(tmpDir, "build.log")
11139
11526
  });
11140
11527
  return { passed: true };
11141
11528
  } catch (error) {
@@ -11151,14 +11538,14 @@ var appBuildActor = fromPromise(
11151
11538
  init_esm_shims();
11152
11539
  var APP_CANDIDATES = ["web", "dashboard", "app", "frontend", "client"];
11153
11540
  function findExistingAppDirs(repoRoot) {
11154
- const appsDir = path10__default.join(repoRoot, "apps");
11541
+ const appsDir = path11__default.join(repoRoot, "apps");
11155
11542
  if (!existsSync(appsDir)) return [];
11156
11543
  try {
11157
11544
  const entries = readdirSync(appsDir, { withFileTypes: true });
11158
11545
  const found = [];
11159
11546
  for (const entry of entries) {
11160
11547
  if (!entry.isDirectory()) continue;
11161
- const pkgJson = path10__default.join(appsDir, entry.name, "package.json");
11548
+ const pkgJson = path11__default.join(appsDir, entry.name, "package.json");
11162
11549
  if (existsSync(pkgJson)) {
11163
11550
  found.push(`apps/${entry.name}`);
11164
11551
  }
@@ -11178,9 +11565,9 @@ function findExistingAppDirs(repoRoot) {
11178
11565
  }
11179
11566
  }
11180
11567
  function validateAppDir(repoRoot, appDir) {
11181
- const pkgJsonPath = path10__default.join(appDir, "package.json");
11568
+ const pkgJsonPath = path11__default.join(appDir, "package.json");
11182
11569
  if (!existsSync(appDir)) {
11183
- const relPath = path10__default.relative(repoRoot, appDir) || ".";
11570
+ const relPath = path11__default.relative(repoRoot, appDir) || ".";
11184
11571
  const suggestions = findExistingAppDirs(repoRoot);
11185
11572
  const errorParts = [`App directory not found: ${relPath}`];
11186
11573
  if (suggestions.length > 0) {
@@ -11202,7 +11589,7 @@ function validateAppDir(repoRoot, appDir) {
11202
11589
  return errorParts.join("\n");
11203
11590
  }
11204
11591
  if (!existsSync(pkgJsonPath)) {
11205
- const relPath = path10__default.relative(repoRoot, appDir) || ".";
11592
+ const relPath = path11__default.relative(repoRoot, appDir) || ".";
11206
11593
  return `No package.json found in app directory: ${relPath}`;
11207
11594
  }
11208
11595
  return null;
@@ -11259,9 +11646,9 @@ init_esm_shims();
11259
11646
  async function runAppBuild(params) {
11260
11647
  const { repoRoot, tmpDir, env: env2 } = params;
11261
11648
  try {
11262
- const hasTurbo = existsSync(path10__default.join(repoRoot, "turbo.json"));
11263
- const hasApps = existsSync(path10__default.join(repoRoot, "apps"));
11264
- const hasAppsWeb = existsSync(path10__default.join(repoRoot, "apps", "web"));
11649
+ const hasTurbo = existsSync(path11__default.join(repoRoot, "turbo.json"));
11650
+ const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
11651
+ const hasAppsWeb = existsSync(path11__default.join(repoRoot, "apps", "web"));
11265
11652
  const args = hasTurbo ? hasApps && !hasAppsWeb ? ["turbo", "run", "build", "--filter=./apps/*"] : ["turbo", "run", "build"] : ["build"];
11266
11653
  await runLogged({
11267
11654
  cwd: repoRoot,
@@ -11269,7 +11656,7 @@ async function runAppBuild(params) {
11269
11656
  label: "build",
11270
11657
  command: "pnpm",
11271
11658
  args,
11272
- logFile: path10__default.join(tmpDir, "build.log")
11659
+ logFile: path11__default.join(tmpDir, "build.log")
11273
11660
  });
11274
11661
  return { passed: true };
11275
11662
  } catch (error) {
@@ -11288,7 +11675,7 @@ async function runManifestGenerate(params) {
11288
11675
  label: "manifest:generate",
11289
11676
  command: "pnpm",
11290
11677
  args: ["manifest:generate"],
11291
- logFile: path10__default.join(tmpDir, "manifest-generate.log")
11678
+ logFile: path11__default.join(tmpDir, "manifest-generate.log")
11292
11679
  });
11293
11680
  return { generated: true };
11294
11681
  } catch (error) {
@@ -11308,7 +11695,7 @@ async function runPlaywrightInstall(params) {
11308
11695
  label: "playwright install",
11309
11696
  command: "pnpm",
11310
11697
  args,
11311
- logFile: path10__default.join(tmpDir, "playwright-install.log")
11698
+ logFile: path11__default.join(tmpDir, "playwright-install.log")
11312
11699
  });
11313
11700
  return { installed: true };
11314
11701
  } catch (error) {
@@ -11381,7 +11768,7 @@ var playwrightInstallActor = fromPromise(
11381
11768
  label: "playwright install",
11382
11769
  command: "pnpm",
11383
11770
  args,
11384
- logFile: path10__default.join(tmpDir, "playwright-install.log")
11771
+ logFile: path11__default.join(tmpDir, "playwright-install.log")
11385
11772
  });
11386
11773
  return { installed: true };
11387
11774
  } catch (error) {
@@ -11405,7 +11792,7 @@ var staticChecksActor2 = fromPromise(
11405
11792
  label: "type-check",
11406
11793
  command: "pnpm",
11407
11794
  args: ["type-check"],
11408
- logFile: path10__default.join(tmpDir, "type-check.log")
11795
+ logFile: path11__default.join(tmpDir, "type-check.log")
11409
11796
  }),
11410
11797
  runLogged({
11411
11798
  cwd: repoRoot,
@@ -11413,7 +11800,7 @@ var staticChecksActor2 = fromPromise(
11413
11800
  label: "lint",
11414
11801
  command: "pnpm",
11415
11802
  args: ["lint"],
11416
- logFile: path10__default.join(tmpDir, "lint.log")
11803
+ logFile: path11__default.join(tmpDir, "lint.log")
11417
11804
  })
11418
11805
  ]);
11419
11806
  const typeCheckPassed = typeCheckResult.status === "fulfilled";
@@ -11564,7 +11951,7 @@ var applySeedsActor = fromPromise(
11564
11951
  label: `db seed (${envArg})`,
11565
11952
  command: "pnpm",
11566
11953
  args: ["exec", "runa", "db", "seed", envArg, "--auto-approve"],
11567
- logFile: path10__default.join(tmpDir, `ci-db-seed-${envArg}.log`)
11954
+ logFile: path11__default.join(tmpDir, `ci-db-seed-${envArg}.log`)
11568
11955
  });
11569
11956
  return { applied: true };
11570
11957
  } catch (error) {
@@ -11942,7 +12329,7 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
11942
12329
  label: `probe pgtap (best-effort, ${params.label})`,
11943
12330
  command: "psql",
11944
12331
  args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", probeSql],
11945
- logFile: path10__default.join(params.tmpDir, `pgtap-probe-${params.label}.log`)
12332
+ logFile: path11__default.join(params.tmpDir, `pgtap-probe-${params.label}.log`)
11946
12333
  }).catch(() => null);
11947
12334
  const raw = String(probe?.stdout ?? "").trim();
11948
12335
  const [availableRaw, installedRaw] = raw.split(",");
@@ -11957,11 +12344,11 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
11957
12344
  label: `ensure pgtap (best-effort, ${params.label})`,
11958
12345
  command: "psql",
11959
12346
  args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-c", installSql],
11960
- logFile: path10__default.join(params.tmpDir, `pgtap-ensure-${params.label}.log`)
12347
+ logFile: path11__default.join(params.tmpDir, `pgtap-ensure-${params.label}.log`)
11961
12348
  }).catch(async (error) => {
11962
12349
  try {
11963
12350
  await writeFile(
11964
- path10__default.join(params.tmpDir, `pgtap-ensure-${params.label}.failed`),
12351
+ path11__default.join(params.tmpDir, `pgtap-ensure-${params.label}.failed`),
11965
12352
  `${error instanceof Error ? error.message : String(error)}
11966
12353
  `,
11967
12354
  "utf-8"
@@ -11975,7 +12362,7 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
11975
12362
  label: `probe pgtap (best-effort, ${params.label}, after)`,
11976
12363
  command: "psql",
11977
12364
  args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", probeSql],
11978
- logFile: path10__default.join(params.tmpDir, `pgtap-probe-${params.label}-after.log`)
12365
+ logFile: path11__default.join(params.tmpDir, `pgtap-probe-${params.label}-after.log`)
11979
12366
  }).catch(() => null);
11980
12367
  const afterRaw = String(probeAfter?.stdout ?? "").trim();
11981
12368
  const [availableAfterRaw, installedAfterRaw] = afterRaw.split(",");
@@ -12096,14 +12483,14 @@ function extractSqlFromSchemaChanges(fullOutput) {
12096
12483
  return null;
12097
12484
  }
12098
12485
  function getIdempotentRoleNames(repoRoot) {
12099
- const idempotentDir = path10__default.join(repoRoot, "supabase", "schemas", "idempotent");
12486
+ const idempotentDir = path11__default.join(repoRoot, "supabase", "schemas", "idempotent");
12100
12487
  const roles = [];
12101
12488
  try {
12102
12489
  const fs14 = __require("fs");
12103
12490
  if (!fs14.existsSync(idempotentDir)) return [];
12104
12491
  const files = fs14.readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
12105
12492
  for (const file of files) {
12106
- const content = fs14.readFileSync(path10__default.join(idempotentDir, file), "utf-8");
12493
+ const content = fs14.readFileSync(path11__default.join(idempotentDir, file), "utf-8");
12107
12494
  const roleMatches = content.matchAll(/CREATE\s+ROLE\s+(\w+)\s+WITH/gi);
12108
12495
  for (const match of roleMatches) {
12109
12496
  if (match[1]) roles.push(match[1].toLowerCase());
@@ -12244,7 +12631,7 @@ var productionPreviewActor = fromPromise(
12244
12631
  );
12245
12632
  return buildSkipResult(!!productionUrl);
12246
12633
  }
12247
- const logFile = path10__default.join(tmpDir, "ci-production-preview.log");
12634
+ const logFile = path11__default.join(tmpDir, "ci-production-preview.log");
12248
12635
  console.log("\u25B6 production preview (dry-run): runa db apply production --check");
12249
12636
  try {
12250
12637
  const result = await execa(
@@ -12334,7 +12721,7 @@ var resetDbActor = fromPromise(
12334
12721
  label: "db reset (local)",
12335
12722
  command: "npx",
12336
12723
  args: ["supabase", "db", "reset", "--local"],
12337
- logFile: path10__default.join(tmpDir, "ci-db-reset.log")
12724
+ logFile: path11__default.join(tmpDir, "ci-db-reset.log")
12338
12725
  });
12339
12726
  return { reset: true };
12340
12727
  } catch (error) {
@@ -12350,8 +12737,8 @@ var resetDbActor = fromPromise(
12350
12737
  init_esm_shims();
12351
12738
  async function hasSetupRolesScript(repoRoot) {
12352
12739
  const candidates = [
12353
- path10__default.join(repoRoot, "packages", "database", "package.json"),
12354
- path10__default.join(repoRoot, "package.json")
12740
+ path11__default.join(repoRoot, "packages", "database", "package.json"),
12741
+ path11__default.join(repoRoot, "package.json")
12355
12742
  ];
12356
12743
  for (const pkgPath of candidates) {
12357
12744
  if (!existsSync(pkgPath)) continue;
@@ -12389,7 +12776,7 @@ var setupRolesActor = fromPromise(
12389
12776
  label: "db roles setup",
12390
12777
  command: "pnpm",
12391
12778
  args: ["db:setup-roles"],
12392
- logFile: path10__default.join(tmpDir, "ci-db-roles-setup.log")
12779
+ logFile: path11__default.join(tmpDir, "ci-db-roles-setup.log")
12393
12780
  });
12394
12781
  const stdout = String(result.stdout ?? "");
12395
12782
  const appUrlMatch = stdout.match(/APP_DATABASE_URL=["']?([^"'\n]+)["']?/);
@@ -12502,14 +12889,14 @@ function getSchemaGitDiff(repoRoot) {
12502
12889
  }
12503
12890
  }
12504
12891
  function getIdempotentRoleNames2(repoRoot) {
12505
- const idempotentDir = path10__default.join(repoRoot, "supabase", "schemas", "idempotent");
12892
+ const idempotentDir = path11__default.join(repoRoot, "supabase", "schemas", "idempotent");
12506
12893
  const roles = [];
12507
12894
  try {
12508
12895
  const fs14 = __require("fs");
12509
12896
  if (!fs14.existsSync(idempotentDir)) return [];
12510
12897
  const files = fs14.readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
12511
12898
  for (const file of files) {
12512
- const content = fs14.readFileSync(path10__default.join(idempotentDir, file), "utf-8");
12899
+ const content = fs14.readFileSync(path11__default.join(idempotentDir, file), "utf-8");
12513
12900
  const roleMatches = content.matchAll(/CREATE\s+ROLE\s+(\w+)\s+WITH/gi);
12514
12901
  for (const match of roleMatches) {
12515
12902
  if (match[1]) roles.push(match[1].toLowerCase());
@@ -12606,7 +12993,7 @@ var syncSchemaActor = fromPromise(
12606
12993
  // Always verbose for full traceability
12607
12994
  ...skipCodegen ? ["--skip-codegen"] : []
12608
12995
  ];
12609
- const logFile = path10__default.join(tmpDir, `ci-db-${useDbApply ? "apply" : "sync"}-${envArg}.log`);
12996
+ const logFile = path11__default.join(tmpDir, `ci-db-${useDbApply ? "apply" : "sync"}-${envArg}.log`);
12610
12997
  await runLogged({
12611
12998
  cwd: repoRoot,
12612
12999
  env: baseEnv,
@@ -12746,7 +13133,7 @@ async function startSupabaseLocal(params) {
12746
13133
  label: "supabase start (local)",
12747
13134
  command: "supabase",
12748
13135
  args: ["start", "--exclude", exclude],
12749
- logFile: path10__default.join(params.tmpDir, "supabase-start-local.log")
13136
+ logFile: path11__default.join(params.tmpDir, "supabase-start-local.log")
12750
13137
  });
12751
13138
  }
12752
13139
  function getDefaultLocalSupabaseUrl(repoRoot) {
@@ -12774,7 +13161,7 @@ async function resolveLocalSupabaseEnv(params) {
12774
13161
  label: "supabase status (json)",
12775
13162
  command: "supabase",
12776
13163
  args: ["status", "--output", "json"],
12777
- logFile: path10__default.join(params.tmpDir, `supabase-status-${i + 1}.log`)
13164
+ logFile: path11__default.join(params.tmpDir, `supabase-status-${i + 1}.log`)
12778
13165
  });
12779
13166
  const parsed = JSON.parse(String(res.stdout ?? "{}"));
12780
13167
  const out = z.object({
@@ -12894,7 +13281,7 @@ async function findFilesRecursive(params) {
12894
13281
  continue;
12895
13282
  }
12896
13283
  for (const e of entries) {
12897
- const p = path10__default.join(dir, e.name);
13284
+ const p = path11__default.join(dir, e.name);
12898
13285
  if (e.isDirectory()) stack.push(p);
12899
13286
  else if (e.isFile() && params.suffixes.some((s) => p.endsWith(s))) out.push(p);
12900
13287
  }
@@ -12908,7 +13295,7 @@ async function queryScalar(params) {
12908
13295
  label: `psql scalar (${params.logName})`,
12909
13296
  command: "psql",
12910
13297
  args: [params.databaseUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", params.sql],
12911
- logFile: path10__default.join(params.tmpDir, `psql-${params.logName}.log`)
13298
+ logFile: path11__default.join(params.tmpDir, `psql-${params.logName}.log`)
12912
13299
  });
12913
13300
  return String(res.stdout ?? "").trim();
12914
13301
  }
@@ -13036,8 +13423,8 @@ function isPlaywrightIgnored(filePath) {
13036
13423
  async function detectGeneratedE2eCapabilities(params) {
13037
13424
  const caps = /* @__PURE__ */ new Set();
13038
13425
  const diagnostics = {};
13039
- const layer4Dir = path10__default.join(params.repoRoot, ".runa", "tests", "layer4");
13040
- const tmpDir = path10__default.join(params.repoRoot, ".runa", "tmp");
13426
+ const layer4Dir = path11__default.join(params.repoRoot, ".runa", "tests", "layer4");
13427
+ const tmpDir = path11__default.join(params.repoRoot, ".runa", "tmp");
13041
13428
  const hasLayer4Dir = await pathExists(layer4Dir);
13042
13429
  const hasTmpDir = await pathExists(tmpDir);
13043
13430
  if (!hasLayer4Dir && !hasTmpDir) {
@@ -13547,7 +13934,7 @@ init_esm_shims();
13547
13934
  // src/commands/ci/utils/test-parallel.ts
13548
13935
  init_esm_shims();
13549
13936
  async function readLayerResult(tmpDir, layer) {
13550
- const resultFile = path10__default.join(tmpDir, `vitest-layer${layer}-result.json`);
13937
+ const resultFile = path11__default.join(tmpDir, `vitest-layer${layer}-result.json`);
13551
13938
  try {
13552
13939
  const content = await readFile(resultFile, "utf-8");
13553
13940
  return JSON.parse(content);
@@ -13665,8 +14052,8 @@ async function waitUntilAllFinished(params) {
13665
14052
  async function runLayersInParallel(params) {
13666
14053
  const spawned = [];
13667
14054
  for (const layer of params.layers) {
13668
- const logFile = path10__default.join(params.tmpDir, `layer${layer}.log`);
13669
- const exitFile = path10__default.join(params.tmpDir, `layer${layer}.exit`);
14055
+ const logFile = path11__default.join(params.tmpDir, `layer${layer}.log`);
14056
+ const exitFile = path11__default.join(params.tmpDir, `layer${layer}.exit`);
13670
14057
  const proc = runLogged({
13671
14058
  cwd: params.repoRoot,
13672
14059
  env: {
@@ -13709,7 +14096,7 @@ async function runLayersInParallel(params) {
13709
14096
  for (const p of spawned) {
13710
14097
  const codeRaw = p.exitCode ?? await p.procPromise;
13711
14098
  const code = Number.isNaN(codeRaw) ? 1 : codeRaw;
13712
- const resultFile = path10__default.join(params.tmpDir, `vitest-layer${p.layer}-result.json`);
14099
+ const resultFile = path11__default.join(params.tmpDir, `vitest-layer${p.layer}-result.json`);
13713
14100
  const wasKilled = killedLayerSet.has(p.layer);
13714
14101
  const actualResult = waitResult.successMap.get(p.layer) ?? {
13715
14102
  success: code === 0,
@@ -13724,9 +14111,9 @@ async function runLayersInParallel(params) {
13724
14111
  skippedReason: actualResult.skippedReason,
13725
14112
  killed: wasKilled,
13726
14113
  killedBy: wasKilled ? failFastSource : void 0,
13727
- logPath: path10__default.relative(params.repoRoot, p.logFile),
13728
- exitPath: path10__default.relative(params.repoRoot, p.exitFile),
13729
- resultPath: path10__default.relative(params.repoRoot, resultFile),
14114
+ logPath: path11__default.relative(params.repoRoot, p.logFile),
14115
+ exitPath: path11__default.relative(params.repoRoot, p.exitFile),
14116
+ resultPath: path11__default.relative(params.repoRoot, resultFile),
13730
14117
  // Test count information
13731
14118
  totalTests: actualResult.totalTests,
13732
14119
  passedTests: actualResult.passedTests,
@@ -14835,6 +15222,24 @@ function getSupabaseUrlWithFallback(context) {
14835
15222
  function getSupabaseAnonKeyWithFallback(context) {
14836
15223
  return context.supabase?.anonKey || DEFAULT_LOCAL_ANON_KEY;
14837
15224
  }
15225
+ function buildRuntimeEnv(context, options = {}) {
15226
+ const env2 = {
15227
+ ...context.input.runtimeEnv ?? {},
15228
+ DATABASE_URL: getDatabaseUrlForRuntime(context),
15229
+ NEXT_PUBLIC_SUPABASE_URL: getSupabaseUrlWithFallback(context),
15230
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: getSupabaseAnonKeyWithFallback(context)
15231
+ };
15232
+ if (options.enablePublicE2EFlag) {
15233
+ env2.NEXT_PUBLIC_E2E_TEST = "true";
15234
+ }
15235
+ if (options.enableServerE2EFlag) {
15236
+ env2.E2E_TEST = "true";
15237
+ }
15238
+ if (options.baseUrl) {
15239
+ env2.BASE_URL = options.baseUrl;
15240
+ }
15241
+ return env2;
15242
+ }
14838
15243
  function computeExitCodeFromLayerResults(layerResults) {
14839
15244
  const classification = getClassificationForProfile("runa-strict");
14840
15245
  const classificationMap = new Map(classification.map((c) => [c.layer, c.level]));
@@ -15323,7 +15728,7 @@ ${generateProgressCommentBody(progressInput)}`;
15323
15728
  tmpDir: assertTmpDir(context),
15324
15729
  // Execute if GH_DATABASE_URL_ADMIN is set (dry-run will determine if changes exist)
15325
15730
  // PRD: GH_DATABASE_URL_ADMIN = postgres role (DDL capable)
15326
- shouldExecute: !!(process.env.GH_DATABASE_URL_ADMIN || process.env.GH_DATABASE_URL)
15731
+ shouldExecute: Boolean(context.input.productionDatabaseUrl?.trim())
15327
15732
  }),
15328
15733
  onDone: {
15329
15734
  target: "collectSchemaStats",
@@ -15515,14 +15920,10 @@ ${generateProgressCommentBody(progressInput)}`;
15515
15920
  input: ({ context }) => ({
15516
15921
  repoRoot: assertRepoRoot(context),
15517
15922
  tmpDir: assertTmpDir(context),
15518
- env: {
15519
- ...process.env,
15520
- DATABASE_URL: getDatabaseUrlForRuntime(context),
15521
- NEXT_PUBLIC_SUPABASE_URL: getSupabaseUrlWithFallback(context),
15522
- NEXT_PUBLIC_SUPABASE_ANON_KEY: getSupabaseAnonKeyWithFallback(context),
15523
- // CRITICAL: Required for XState Test Plugin to inject data-state attributes
15524
- NEXT_PUBLIC_E2E_TEST: "true"
15525
- },
15923
+ env: buildRuntimeEnv(context, {
15924
+ // Required for XState Test Plugin to inject data-state attributes.
15925
+ enablePublicE2EFlag: true
15926
+ }),
15526
15927
  isCI: context.input.isCI ?? false,
15527
15928
  skipPlaywright: shouldSkipPlaywrightInstall(context)
15528
15929
  }),
@@ -15573,16 +15974,11 @@ ${generateProgressCommentBody(progressInput)}`;
15573
15974
  tmpDir: assertTmpDir(context),
15574
15975
  appDir: context.app?.appDir ?? assertRepoRoot(context),
15575
15976
  port: context.app?.port ?? 3e3,
15576
- env: {
15577
- ...process.env,
15578
- DATABASE_URL: getDatabaseUrlForRuntime(context),
15579
- NEXT_PUBLIC_SUPABASE_URL: getSupabaseUrlWithFallback(context),
15580
- NEXT_PUBLIC_SUPABASE_ANON_KEY: getSupabaseAnonKeyWithFallback(context),
15581
- // CRITICAL: Required for middleware to bypass auth in E2E tests
15582
- // E2E_TEST is server-only (proxy.ts), NEXT_PUBLIC_E2E_TEST is for build-time (xstate-test-plugin)
15583
- E2E_TEST: "true",
15584
- NEXT_PUBLIC_E2E_TEST: "true"
15585
- }
15977
+ env: buildRuntimeEnv(context, {
15978
+ // E2E_TEST is server-only (proxy.ts), NEXT_PUBLIC_E2E_TEST is for build-time.
15979
+ enableServerE2EFlag: true,
15980
+ enablePublicE2EFlag: true
15981
+ })
15586
15982
  }),
15587
15983
  onDone: [
15588
15984
  {
@@ -15687,12 +16083,7 @@ ${generateProgressCommentBody(progressInput)}`;
15687
16083
  // ci-local: all selected layers, ci-pr: only core layers (1,2,3)
15688
16084
  layers: getLayersForCorePhase(context.selectedLayers, context.mode),
15689
16085
  baseUrl: context.baseUrl ?? `http://localhost:${context.app?.port ?? 3e3}`,
15690
- env: {
15691
- ...process.env,
15692
- DATABASE_URL: getDatabaseUrlForRuntime(context),
15693
- NEXT_PUBLIC_SUPABASE_URL: getSupabaseUrlWithFallback(context),
15694
- NEXT_PUBLIC_SUPABASE_ANON_KEY: getSupabaseAnonKeyWithFallback(context)
15695
- },
16086
+ env: buildRuntimeEnv(context),
15696
16087
  failFast: true
15697
16088
  }),
15698
16089
  onDone: [
@@ -15846,15 +16237,10 @@ ${generateCommentBody(commentInput)}`;
15846
16237
  tmpDir: assertTmpDir(context),
15847
16238
  layers: [E2E_LAYER],
15848
16239
  baseUrl: e2eBaseUrl,
15849
- env: {
15850
- ...process.env,
15851
- DATABASE_URL: getDatabaseUrlForRuntime(context),
15852
- NEXT_PUBLIC_SUPABASE_URL: getSupabaseUrlWithFallback(context),
15853
- NEXT_PUBLIC_SUPABASE_ANON_KEY: getSupabaseAnonKeyWithFallback(context),
15854
- // CRITICAL: Set BASE_URL for Playwright config and test fixtures
15855
- // This ensures cookies are set on the same domain Playwright uses
15856
- BASE_URL: e2eBaseUrl
15857
- },
16240
+ env: buildRuntimeEnv(context, {
16241
+ // Ensures cookies are set on the same domain Playwright uses.
16242
+ baseUrl: e2eBaseUrl
16243
+ }),
15858
16244
  failFast: false
15859
16245
  // Don't fail-fast for E2E (warning-only)
15860
16246
  };
@@ -16048,19 +16434,10 @@ ${generateCommentBody(commentInput)}`;
16048
16434
  output: ({ context }) => createOutput3(context)
16049
16435
  });
16050
16436
  function getStateName3(snapshot2) {
16051
- const value = snapshot2.value;
16052
- if (typeof value === "string") return value;
16053
- const keys = Object.keys(value);
16054
- if (keys.length > 0) {
16055
- const parent = keys[0];
16056
- const child = value[parent];
16057
- if (typeof child === "string") return `${parent}.${child}`;
16058
- return parent;
16059
- }
16060
- return "unknown";
16437
+ return getSnapshotStateName(snapshot2);
16061
16438
  }
16062
16439
  function isComplete3(snapshot2) {
16063
- return snapshot2.status === "done";
16440
+ return isSnapshotComplete(snapshot2);
16064
16441
  }
16065
16442
 
16066
16443
  // src/commands/ci/machine/commands/machine-runner.ts
@@ -16309,6 +16686,18 @@ async function flushAndExit(exitCode) {
16309
16686
  process.exit(exitCode);
16310
16687
  }
16311
16688
 
16689
+ // src/commands/ci/machine/commands/runtime-env.ts
16690
+ init_esm_shims();
16691
+ function captureRuntimeEnv(source = process.env) {
16692
+ const captured = {};
16693
+ for (const [key, value] of Object.entries(source)) {
16694
+ if (value !== void 0) {
16695
+ captured[key] = value;
16696
+ }
16697
+ }
16698
+ return captured;
16699
+ }
16700
+
16312
16701
  // src/commands/ci/machine/commands/ci-local.ts
16313
16702
  var isGitHubActionsMode = false;
16314
16703
  var currentGroup = null;
@@ -16430,7 +16819,8 @@ function buildMachineInput(options) {
16430
16819
  dbMode: void 0,
16431
16820
  // PRD: GH_DATABASE_URL_ADMIN = postgres role (DDL capable, for pg_dump)
16432
16821
  productionDatabaseUrl: process.env.GH_DATABASE_URL_ADMIN || process.env.GH_DATABASE_URL,
16433
- databaseUrl: process.env.DATABASE_URL
16822
+ databaseUrl: process.env.DATABASE_URL,
16823
+ runtimeEnv: captureRuntimeEnv()
16434
16824
  };
16435
16825
  }
16436
16826
  function handleCiError(error, logger16) {
@@ -16496,6 +16886,8 @@ z.object({
16496
16886
  productionDatabaseUrl: z.string().optional(),
16497
16887
  /** Local database URL */
16498
16888
  databaseUrl: z.string().optional(),
16889
+ /** Sanitized process.env captured at entry point */
16890
+ runtimeEnv: z.record(z.string(), z.string()).optional(),
16499
16891
  // === GitHub Actions Environment ===
16500
16892
  /** GitHub ref (e.g., refs/pull/123/merge) */
16501
16893
  githubRef: z.string().optional(),
@@ -16947,6 +17339,7 @@ function optionsToMachineInput(options) {
16947
17339
  databaseUrl: process.env.DATABASE_URL,
16948
17340
  // PRD: GH_DATABASE_URL_ADMIN = postgres role (DDL capable, for pg-schema-diff dry-run)
16949
17341
  productionDatabaseUrl: process.env.GH_DATABASE_URL_ADMIN || process.env.GH_DATABASE_URL,
17342
+ runtimeEnv: captureRuntimeEnv(),
16950
17343
  githubRef: process.env.GITHUB_REF,
16951
17344
  // FIX: Read action from GITHUB_EVENT_PATH JSON, not non-existent GITHUB_EVENT_ACTION env var
16952
17345
  githubEventAction: getGitHubEventAction(),
@@ -17022,13 +17415,20 @@ init_esm_shims();
17022
17415
  // src/commands/db/utils/db-target.ts
17023
17416
  init_esm_shims();
17024
17417
  init_env();
17025
- init_constants();
17418
+ init_local_supabase();
17026
17419
  function getLocalDatabaseUrl() {
17027
- const ports = detectSupabasePorts(process.cwd());
17028
- return `postgresql://postgres:postgres@localhost:${ports.db}/postgres`;
17420
+ return buildLocalDatabaseUrl(process.cwd());
17421
+ }
17422
+ function isLocalHostname(hostname) {
17423
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "host.docker.internal";
17029
17424
  }
17030
17425
  function isLocalDatabaseUrl(url) {
17031
- return url.includes("localhost") || url.includes("127.0.0.1") || url.includes("host.docker.internal");
17426
+ try {
17427
+ const parsed = new URL(url);
17428
+ return isLocalHostname(parsed.hostname);
17429
+ } catch {
17430
+ return false;
17431
+ }
17032
17432
  }
17033
17433
  function resolveDatabaseUrl(environment) {
17034
17434
  switch (environment) {
@@ -17186,21 +17586,35 @@ async function getSqlParserUtils() {
17186
17586
  await isAstParserAvailable();
17187
17587
  return sqlParserUtils;
17188
17588
  }
17589
+ var SQL_IDENTIFIER = String.raw`(?:"(?:[^"]|"")*"|[a-zA-Z_][a-zA-Z0-9_]*)`;
17189
17590
  var SQL_PATTERNS = {
17190
17591
  // CREATE TABLE [IF NOT EXISTS] schema.table_name (
17191
- createTable: /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)\.(\w+)\s*\(/gi,
17592
+ createTable: new RegExp(
17593
+ `CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${SQL_IDENTIFIER})\\.(${SQL_IDENTIFIER})\\s*\\(`,
17594
+ "gi"
17595
+ ),
17192
17596
  // PRIMARY KEY (columns)
17193
17597
  primaryKey: /PRIMARY\s+KEY\s*\(([^)]+)\)/gi,
17194
17598
  // FOREIGN KEY (column) REFERENCES schema.table(column) [ON DELETE|UPDATE ...]
17195
- foreignKey: /FOREIGN\s+KEY\s*\((\w+)\)\s*REFERENCES\s+(\w+)\.(\w+)\s*\((\w+)\)(?:\s+ON\s+DELETE\s+(\w+(?:\s+\w+)?))?(?:\s+ON\s+UPDATE\s+(\w+(?:\s+\w+)?))?/gi,
17599
+ foreignKey: new RegExp(
17600
+ `FOREIGN\\s+KEY\\s*\\((${SQL_IDENTIFIER})\\)\\s*REFERENCES\\s+(${SQL_IDENTIFIER})\\.(${SQL_IDENTIFIER})\\s*\\((${SQL_IDENTIFIER})\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?(?:\\s+ON\\s+UPDATE\\s+(\\w+(?:\\s+\\w+)?))?`,
17601
+ "gi"
17602
+ ),
17196
17603
  // REFERENCES schema.table(column) - inline column constraint
17197
- inlineReference: /(\w+)\s+\w+[^,]*REFERENCES\s+(\w+)\.(\w+)\s*\((\w+)\)/gi,
17604
+ inlineReference: new RegExp(
17605
+ `(${SQL_IDENTIFIER})\\s+\\w+[\\w\\s()]*REFERENCES\\s+(${SQL_IDENTIFIER})\\.(${SQL_IDENTIFIER})\\s*\\((${SQL_IDENTIFIER})\\)`,
17606
+ "gi"
17607
+ ),
17198
17608
  // CREATE [UNIQUE] INDEX name ON schema.table (columns)
17199
- createIndex: /CREATE\s+(UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)\s+ON\s+(\w+)\.(\w+)\s*\(([^)]+)\)/gi,
17609
+ createIndex: new RegExp(
17610
+ `CREATE\\s+(UNIQUE\\s+)?INDEX\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${SQL_IDENTIFIER})\\s+ON\\s+(${SQL_IDENTIFIER})\\.(${SQL_IDENTIFIER})\\s*\\(([^)]+)\\)`,
17611
+ "gi"
17612
+ ),
17200
17613
  // ALTER TABLE ... ENABLE ROW LEVEL SECURITY
17201
- enableRls: /ALTER\s+TABLE\s+(\w+)\.(\w+)\s+ENABLE\s+ROW\s+LEVEL\s+SECURITY/gi,
17202
- // CREATE POLICY name ON schema.table FOR command USING (...) [WITH CHECK (...)]
17203
- createPolicy: /CREATE\s+POLICY\s+"?(\w+)"?\s+ON\s+(\w+)\.(\w+)\s+(?:AS\s+\w+\s+)?FOR\s+(\w+)\s+(?:TO\s+\w+\s+)?(?:USING\s*\(([^)]+)\))?(?:\s+WITH\s+CHECK\s*\(([^)]+)\))?/gi
17614
+ enableRls: new RegExp(
17615
+ `ALTER\\s+TABLE\\s+(${SQL_IDENTIFIER})\\.(${SQL_IDENTIFIER})\\s+ENABLE\\s+ROW\\s+LEVEL\\s+SECURITY`,
17616
+ "gi"
17617
+ )
17204
17618
  };
17205
17619
  function snakeToCamel2(str) {
17206
17620
  return str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
@@ -17235,6 +17649,96 @@ function extractTableBody(content, startPos) {
17235
17649
  function normalizeType(type) {
17236
17650
  return type.trim().replace(/\s+/g, " ").toLowerCase().replace("character varying", "varchar").replace("timestamp with time zone", "timestamptz").replace("timestamp without time zone", "timestamp");
17237
17651
  }
17652
+ function unquoteIdentifier(identifier) {
17653
+ const trimmed = identifier.trim();
17654
+ if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
17655
+ return trimmed.slice(1, -1).replace(/""/g, '"');
17656
+ }
17657
+ return trimmed;
17658
+ }
17659
+ function stripSqlCommentsPreserveStrings2(content) {
17660
+ let result = "";
17661
+ let i = 0;
17662
+ let inSingleQuote = false;
17663
+ let inDoubleQuote = false;
17664
+ let inDollarQuote = false;
17665
+ let dollarTag = "";
17666
+ while (i < content.length) {
17667
+ const char = content[i] ?? "";
17668
+ const next = content[i + 1] ?? "";
17669
+ if (!inSingleQuote && !inDoubleQuote && !inDollarQuote && char === "-" && next === "-") {
17670
+ while (i < content.length && content[i] !== "\n") {
17671
+ result += " ";
17672
+ i++;
17673
+ }
17674
+ continue;
17675
+ }
17676
+ if (!inSingleQuote && !inDoubleQuote && !inDollarQuote && char === "/" && next === "*") {
17677
+ result += " ";
17678
+ result += " ";
17679
+ i += 2;
17680
+ while (i < content.length) {
17681
+ const blockChar = content[i] ?? "";
17682
+ const blockNext = content[i + 1] ?? "";
17683
+ if (blockChar === "*" && blockNext === "/") {
17684
+ result += " ";
17685
+ result += " ";
17686
+ i += 2;
17687
+ break;
17688
+ }
17689
+ result += blockChar === "\n" ? "\n" : " ";
17690
+ i++;
17691
+ }
17692
+ continue;
17693
+ }
17694
+ if (!inSingleQuote && !inDoubleQuote && char === "$") {
17695
+ if (inDollarQuote) {
17696
+ const closeTag = `$${dollarTag}$`;
17697
+ if (content.slice(i).startsWith(closeTag)) {
17698
+ result += closeTag;
17699
+ i += closeTag.length;
17700
+ inDollarQuote = false;
17701
+ dollarTag = "";
17702
+ continue;
17703
+ }
17704
+ } else {
17705
+ const tagMatch = content.slice(i).match(/^\$([a-zA-Z_][a-zA-Z0-9_]*)?\$/);
17706
+ if (tagMatch) {
17707
+ inDollarQuote = true;
17708
+ dollarTag = tagMatch[1] ?? "";
17709
+ result += tagMatch[0];
17710
+ i += tagMatch[0].length;
17711
+ continue;
17712
+ }
17713
+ }
17714
+ }
17715
+ if (!inDoubleQuote && !inDollarQuote && char === "'") {
17716
+ if (inSingleQuote && next === "'") {
17717
+ result += "''";
17718
+ i += 2;
17719
+ continue;
17720
+ }
17721
+ inSingleQuote = !inSingleQuote;
17722
+ result += char;
17723
+ i++;
17724
+ continue;
17725
+ }
17726
+ if (!inSingleQuote && !inDollarQuote && char === '"') {
17727
+ if (inDoubleQuote && next === '"') {
17728
+ result += '""';
17729
+ i += 2;
17730
+ continue;
17731
+ }
17732
+ inDoubleQuote = !inDoubleQuote;
17733
+ result += char;
17734
+ i++;
17735
+ continue;
17736
+ }
17737
+ result += char;
17738
+ i++;
17739
+ }
17740
+ return result;
17741
+ }
17238
17742
  function parseIndexColumns(rawColumns) {
17239
17743
  return rawColumns.split(",").map((col) => {
17240
17744
  const trimmed = col.trim();
@@ -17271,8 +17775,8 @@ function findTablesRegex(ctx) {
17271
17775
  const tables = [];
17272
17776
  const regex = new RegExp(SQL_PATTERNS.createTable.source, "gi");
17273
17777
  for (const match of ctx.content.matchAll(regex)) {
17274
- const schema = match[1] ?? "";
17275
- const name = match[2] ?? "";
17778
+ const schema = unquoteIdentifier(match[1] ?? "");
17779
+ const name = unquoteIdentifier(match[2] ?? "");
17276
17780
  if (!schema || !name) continue;
17277
17781
  const lineNumber = getLineNumber(ctx.content, match.index ?? 0);
17278
17782
  const tableBody = extractTableBody(ctx.content, match.index ?? 0);
@@ -17294,10 +17798,10 @@ function parseColumnsRegex(tableBody) {
17294
17798
  const trimmed = line.trim();
17295
17799
  if (shouldSkipColumnLine(trimmed)) continue;
17296
17800
  const columnMatch = trimmed.match(
17297
- /^(\w+)\s+([\w\s()]+?)(?:\s+(NOT\s+NULL|NULL))?(?:\s+DEFAULT\s+[^,]+)?(?:\s+REFERENCES)?(?:,|$)/i
17801
+ /^((?:"(?:[^"]|"")*"|[a-zA-Z_][a-zA-Z0-9_]*))\s+([\w\s()]+?)(?:\s+(NOT\s+NULL|NULL))?(?:\s+DEFAULT\s+[^,]+)?(?:\s+REFERENCES)?(?:,|$)/i
17298
17802
  );
17299
17803
  if (columnMatch) {
17300
- const name = columnMatch[1] ?? "";
17804
+ const name = unquoteIdentifier(columnMatch[1] ?? "");
17301
17805
  if (!name || seen.has(name) || isReservedKeyword(name)) continue;
17302
17806
  seen.add(name);
17303
17807
  const rawType = columnMatch[2] ?? "";
@@ -17319,7 +17823,7 @@ function parsePrimaryKeyRegex(tableBody) {
17319
17823
  const regex = new RegExp(SQL_PATTERNS.primaryKey.source, "gi");
17320
17824
  const match = regex.exec(tableBody);
17321
17825
  if (match) {
17322
- return match[1]?.split(",").map((col) => col.trim());
17826
+ return match[1]?.split(",").map((col) => unquoteIdentifier(col.trim())).filter(Boolean) ?? [];
17323
17827
  }
17324
17828
  return [];
17325
17829
  }
@@ -17327,12 +17831,12 @@ function parseExplicitForeignKeys(tableBody) {
17327
17831
  const fks = [];
17328
17832
  const fkRegex = new RegExp(SQL_PATTERNS.foreignKey.source, "gi");
17329
17833
  for (const match of tableBody.matchAll(fkRegex)) {
17330
- const column = match[1] ?? "";
17331
- const refTable = match[4] ?? "";
17834
+ const column = unquoteIdentifier(match[1] ?? "");
17835
+ const refTable = unquoteIdentifier(match[4] ?? "");
17332
17836
  if (!column || !refTable) continue;
17333
17837
  fks.push({
17334
17838
  column,
17335
- referencesTable: `${match[2] ?? ""}.${match[3] ?? ""}`,
17839
+ referencesTable: `${unquoteIdentifier(match[2] ?? "")}.${unquoteIdentifier(match[3] ?? "")}`,
17336
17840
  referencesColumn: refTable,
17337
17841
  onDelete: normalizeOnAction(match[5]),
17338
17842
  onUpdate: normalizeOnAction(match[6])
@@ -17344,13 +17848,13 @@ function parseInlineForeignKeys(tableBody, existingColumns) {
17344
17848
  const fks = [];
17345
17849
  const inlineRegex = new RegExp(SQL_PATTERNS.inlineReference.source, "gi");
17346
17850
  for (const match of tableBody.matchAll(inlineRegex)) {
17347
- const inlineCol = match[1] ?? "";
17851
+ const inlineCol = unquoteIdentifier(match[1] ?? "");
17348
17852
  if (existingColumns.has(inlineCol)) continue;
17349
- const inlineRefCol = match[4] ?? "";
17853
+ const inlineRefCol = unquoteIdentifier(match[4] ?? "");
17350
17854
  if (!inlineCol || !inlineRefCol) continue;
17351
17855
  fks.push({
17352
17856
  column: inlineCol,
17353
- referencesTable: `${match[2] ?? ""}.${match[3] ?? ""}`,
17857
+ referencesTable: `${unquoteIdentifier(match[2] ?? "")}.${unquoteIdentifier(match[3] ?? "")}`,
17354
17858
  referencesColumn: inlineRefCol
17355
17859
  });
17356
17860
  }
@@ -17366,8 +17870,10 @@ function parseIndexesRegex(content, schema, tableName) {
17366
17870
  const indexes = [];
17367
17871
  const regex = new RegExp(SQL_PATTERNS.createIndex.source, "gi");
17368
17872
  for (const match of content.matchAll(regex)) {
17369
- if (match[3] === schema && match[4] === tableName) {
17370
- const indexName = match[2] ?? "";
17873
+ const indexSchema = unquoteIdentifier(match[3] ?? "");
17874
+ const indexTable = unquoteIdentifier(match[4] ?? "");
17875
+ if (indexSchema === schema && indexTable === tableName) {
17876
+ const indexName = unquoteIdentifier(match[2] ?? "");
17371
17877
  if (!indexName) continue;
17372
17878
  const rawColumns = match[5] ?? "";
17373
17879
  indexes.push({
@@ -17382,26 +17888,200 @@ function parseIndexesRegex(content, schema, tableName) {
17382
17888
  function hasRlsEnabledRegex(content, schema, tableName) {
17383
17889
  const regex = new RegExp(SQL_PATTERNS.enableRls.source, "gi");
17384
17890
  for (const match of content.matchAll(regex)) {
17385
- if (match[1] === schema && match[2] === tableName) {
17891
+ const matchSchema = unquoteIdentifier(match[1] ?? "");
17892
+ const matchTable = unquoteIdentifier(match[2] ?? "");
17893
+ if (matchSchema === schema && matchTable === tableName) {
17386
17894
  return true;
17387
17895
  }
17388
17896
  }
17389
17897
  return false;
17390
17898
  }
17899
+ function extractCreatePolicyStatements(content) {
17900
+ const statements = [];
17901
+ const startRegex = /\bCREATE\s+POLICY\b/gi;
17902
+ let match;
17903
+ while ((match = startRegex.exec(content)) !== null) {
17904
+ const startIndex = match.index ?? 0;
17905
+ const endIndex = findSqlStatementEndForPolicy(content, startIndex);
17906
+ statements.push(content.slice(startIndex, endIndex).trim());
17907
+ }
17908
+ return statements;
17909
+ }
17910
+ function findSqlStatementEndForPolicy(content, startIndex) {
17911
+ let inSingleQuote = false;
17912
+ let inDoubleQuote = false;
17913
+ let inDollarQuote = false;
17914
+ let dollarTag = "";
17915
+ for (let i = startIndex; i < content.length; i++) {
17916
+ const char = content[i] ?? "";
17917
+ const next = content[i + 1] ?? "";
17918
+ if (!inSingleQuote && !inDoubleQuote && !inDollarQuote) {
17919
+ if (char === "-" && next === "-") {
17920
+ const newlineIndex = content.indexOf("\n", i);
17921
+ if (newlineIndex === -1) return content.length;
17922
+ i = newlineIndex;
17923
+ continue;
17924
+ }
17925
+ if (char === "/" && next === "*") {
17926
+ const closeIndex = content.indexOf("*/", i + 2);
17927
+ if (closeIndex === -1) return content.length;
17928
+ i = closeIndex + 1;
17929
+ continue;
17930
+ }
17931
+ }
17932
+ if (!inSingleQuote && !inDoubleQuote && char === "$") {
17933
+ if (inDollarQuote) {
17934
+ const closeTag = `$${dollarTag}$`;
17935
+ if (content.slice(i).startsWith(closeTag)) {
17936
+ i += closeTag.length - 1;
17937
+ inDollarQuote = false;
17938
+ dollarTag = "";
17939
+ continue;
17940
+ }
17941
+ } else {
17942
+ const tagMatch = content.slice(i).match(/^\$([a-zA-Z_][a-zA-Z0-9_]*)?\$/);
17943
+ if (tagMatch) {
17944
+ inDollarQuote = true;
17945
+ dollarTag = tagMatch[1] ?? "";
17946
+ i += tagMatch[0].length - 1;
17947
+ continue;
17948
+ }
17949
+ }
17950
+ }
17951
+ if (!inDoubleQuote && !inDollarQuote && char === "'") {
17952
+ if (inSingleQuote) {
17953
+ if (next === "'") {
17954
+ i++;
17955
+ continue;
17956
+ }
17957
+ inSingleQuote = false;
17958
+ } else {
17959
+ inSingleQuote = true;
17960
+ }
17961
+ continue;
17962
+ }
17963
+ if (!inSingleQuote && !inDollarQuote && char === '"') {
17964
+ if (inDoubleQuote) {
17965
+ if (next === '"') {
17966
+ i++;
17967
+ continue;
17968
+ }
17969
+ inDoubleQuote = false;
17970
+ } else {
17971
+ inDoubleQuote = true;
17972
+ }
17973
+ continue;
17974
+ }
17975
+ if (!inSingleQuote && !inDoubleQuote && !inDollarQuote && char === ";") {
17976
+ return i + 1;
17977
+ }
17978
+ }
17979
+ return content.length;
17980
+ }
17981
+ function extractBalancedClause(statement, startIndex) {
17982
+ const openParenIndex = statement.indexOf("(", startIndex);
17983
+ if (openParenIndex === -1) return void 0;
17984
+ let depth = 0;
17985
+ let clauseStart = -1;
17986
+ let inSingleQuote = false;
17987
+ let inDoubleQuote = false;
17988
+ let inDollarQuote = false;
17989
+ let dollarTag = "";
17990
+ for (let i = openParenIndex; i < statement.length; i++) {
17991
+ const char = statement[i] ?? "";
17992
+ const next = statement[i + 1] ?? "";
17993
+ if (!inSingleQuote && !inDoubleQuote && !inDollarQuote) {
17994
+ if (char === "-" && next === "-") {
17995
+ const newlineIndex = statement.indexOf("\n", i);
17996
+ if (newlineIndex === -1) break;
17997
+ i = newlineIndex;
17998
+ continue;
17999
+ }
18000
+ if (char === "/" && next === "*") {
18001
+ const closeIndex = statement.indexOf("*/", i + 2);
18002
+ if (closeIndex === -1) break;
18003
+ i = closeIndex + 1;
18004
+ continue;
18005
+ }
18006
+ }
18007
+ if (!inSingleQuote && !inDoubleQuote && char === "$") {
18008
+ if (inDollarQuote) {
18009
+ const closeTag = `$${dollarTag}$`;
18010
+ if (statement.slice(i).startsWith(closeTag)) {
18011
+ i += closeTag.length - 1;
18012
+ inDollarQuote = false;
18013
+ dollarTag = "";
18014
+ continue;
18015
+ }
18016
+ } else {
18017
+ const tagMatch = statement.slice(i).match(/^\$([a-zA-Z_][a-zA-Z0-9_]*)?\$/);
18018
+ if (tagMatch) {
18019
+ inDollarQuote = true;
18020
+ dollarTag = tagMatch[1] ?? "";
18021
+ i += tagMatch[0].length - 1;
18022
+ continue;
18023
+ }
18024
+ }
18025
+ }
18026
+ if (!inDoubleQuote && !inDollarQuote && char === "'") {
18027
+ if (inSingleQuote) {
18028
+ if (next === "'") {
18029
+ i++;
18030
+ continue;
18031
+ }
18032
+ inSingleQuote = false;
18033
+ } else {
18034
+ inSingleQuote = true;
18035
+ }
18036
+ continue;
18037
+ }
18038
+ if (!inSingleQuote && !inDollarQuote && char === '"') {
18039
+ if (inDoubleQuote) {
18040
+ if (next === '"') {
18041
+ i++;
18042
+ continue;
18043
+ }
18044
+ inDoubleQuote = false;
18045
+ } else {
18046
+ inDoubleQuote = true;
18047
+ }
18048
+ continue;
18049
+ }
18050
+ if (inSingleQuote || inDoubleQuote || inDollarQuote) continue;
18051
+ if (char === "(") {
18052
+ if (depth === 0) clauseStart = i + 1;
18053
+ depth++;
18054
+ } else if (char === ")") {
18055
+ depth--;
18056
+ if (depth === 0 && clauseStart !== -1) {
18057
+ return statement.slice(clauseStart, i).trim();
18058
+ }
18059
+ }
18060
+ }
18061
+ return void 0;
18062
+ }
17391
18063
  function parsePoliciesRegex(content, schema, tableName) {
17392
18064
  const policies = [];
17393
- const regex = new RegExp(SQL_PATTERNS.createPolicy.source, "gi");
17394
- for (const match of content.matchAll(regex)) {
17395
- const policyName = match[1] ?? "";
17396
- if (!policyName) continue;
17397
- if (match[2] === schema && match[3] === tableName) {
17398
- policies.push({
17399
- name: policyName,
17400
- command: match[4]?.toUpperCase(),
17401
- using: match[5] || void 0,
17402
- withCheck: match[6] || void 0
17403
- });
17404
- }
18065
+ const statements = extractCreatePolicyStatements(content);
18066
+ const headerRegex = new RegExp(
18067
+ `^\\s*CREATE\\s+POLICY\\s+(?:"((?:[^"]|"")*)"|([a-zA-Z_][a-zA-Z0-9_]*))\\s+ON\\s+(${SQL_IDENTIFIER})\\.(${SQL_IDENTIFIER})(?:\\s+AS\\s+\\w+)?(?:\\s+FOR\\s+(\\w+))?`,
18068
+ "i"
18069
+ );
18070
+ for (const statement of statements) {
18071
+ const match = statement.match(headerRegex);
18072
+ if (!match) continue;
18073
+ const policyName = unquoteIdentifier(match[1] ?? match[2] ?? "");
18074
+ const policySchema = unquoteIdentifier(match[3] ?? "");
18075
+ const policyTable = unquoteIdentifier(match[4] ?? "");
18076
+ if (!policyName || policySchema !== schema || policyTable !== tableName) continue;
18077
+ const usingIndex = statement.search(/\bUSING\s*\(/i);
18078
+ const withCheckIndex = statement.search(/\bWITH\s+CHECK\s*\(/i);
18079
+ policies.push({
18080
+ name: policyName,
18081
+ command: (match[5] || "ALL").toUpperCase(),
18082
+ using: usingIndex !== -1 ? extractBalancedClause(statement, usingIndex) : void 0,
18083
+ withCheck: withCheckIndex !== -1 ? extractBalancedClause(statement, withCheckIndex) : void 0
18084
+ });
17405
18085
  }
17406
18086
  return policies;
17407
18087
  }
@@ -17502,7 +18182,8 @@ function buildTableEntryRegex(table, content, filePath, opts) {
17502
18182
  };
17503
18183
  }
17504
18184
  function processTablesFromFileRegex(filePath, opts, seen) {
17505
- const content = readFileSync(filePath, "utf-8");
18185
+ const rawContent = readFileSync(filePath, "utf-8");
18186
+ const content = stripSqlCommentsPreserveStrings2(rawContent);
17506
18187
  const ctx = { content, lines: content.split("\n") };
17507
18188
  const tables = findTablesRegex(ctx);
17508
18189
  const entries = [];
@@ -18329,6 +19010,60 @@ function handleHazards(hazards, input3) {
18329
19010
  );
18330
19011
  }
18331
19012
  }
19013
+ var TYPE_TO_EXTENSION = {
19014
+ geometry: "postgis",
19015
+ geography: "postgis",
19016
+ box2d: "postgis",
19017
+ box3d: "postgis",
19018
+ raster: "postgis_raster",
19019
+ vector: "vector",
19020
+ halfvec: "vector",
19021
+ sparsevec: "vector",
19022
+ cube: "cube",
19023
+ hstore: "hstore",
19024
+ ltree: "ltree",
19025
+ citext: "citext"
19026
+ };
19027
+ function detectMissingExtensionType(errorOutput) {
19028
+ const typePattern = /type ["']?(\w+)["']? does not exist/gi;
19029
+ const matches = [...errorOutput.matchAll(typePattern)];
19030
+ const missingTypes = [...new Set(matches.map((m) => m[1].toLowerCase()))];
19031
+ if (missingTypes.length === 0) {
19032
+ return { detected: false, missingTypes: [], suggestedExtensions: [] };
19033
+ }
19034
+ const extensions = /* @__PURE__ */ new Set();
19035
+ for (const type of missingTypes) {
19036
+ const ext = TYPE_TO_EXTENSION[type];
19037
+ if (ext) extensions.add(ext);
19038
+ }
19039
+ return {
19040
+ detected: true,
19041
+ missingTypes,
19042
+ suggestedExtensions: [...extensions]
19043
+ };
19044
+ }
19045
+ function formatExtensionErrorHint(detection) {
19046
+ if (!detection.detected) return "";
19047
+ const lines = [];
19048
+ lines.push("");
19049
+ lines.push("Missing extension type(s) detected:");
19050
+ for (const type of detection.missingTypes) {
19051
+ const ext = TYPE_TO_EXTENSION[type];
19052
+ lines.push(` type "${type}" \u2192 extension: ${ext ?? "unknown"}`);
19053
+ }
19054
+ if (detection.suggestedExtensions.length > 0) {
19055
+ lines.push("");
19056
+ lines.push("Fix 1: Add to supabase/schemas/idempotent/00_extensions.sql:");
19057
+ for (const ext of detection.suggestedExtensions) {
19058
+ lines.push(` CREATE EXTENSION IF NOT EXISTS ${ext};`);
19059
+ }
19060
+ const extList = detection.suggestedExtensions.map((e) => `'${e}'`).join(", ");
19061
+ lines.push("");
19062
+ lines.push("Fix 2: Configure shadow DB in runa.config.ts:");
19063
+ lines.push(` database: { pgSchemaDiff: { shadowDbExtensions: [${extList}] } }`);
19064
+ }
19065
+ return lines.join("\n");
19066
+ }
18332
19067
  function executePgSchemaDiffPlan(dbUrl, schemasDir, includeSchemas, verbose, options) {
18333
19068
  const planArgs = [
18334
19069
  "plan",
@@ -18364,6 +19099,10 @@ function executePgSchemaDiffPlan(dbUrl, schemasDir, includeSchemas, verbose, opt
18364
19099
  logger4.error(`Exit code: ${planResult.status}`);
18365
19100
  logger4.error(`Signal: ${planResult.signal || "none"}`);
18366
19101
  logger4.error(`Stderr: ${planStderr || "(empty)"}`);
19102
+ const extDetection = detectMissingExtensionType(planStderr || planOutput);
19103
+ if (extDetection.detected) {
19104
+ logger4.error(formatExtensionErrorHint(extDetection));
19105
+ }
18367
19106
  throw new Error(
18368
19107
  `pg-schema-diff plan failed (exit ${planResult.status}): ${planStderr || "(no output)"}`
18369
19108
  );
@@ -18421,6 +19160,10 @@ async function executeApplyWithRetry(applyArgs, verbose, config) {
18421
19160
  }
18422
19161
  logger5.error("pg-schema-diff apply failed:");
18423
19162
  logger5.error(errorOutput);
19163
+ const extDetection = detectMissingExtensionType(errorOutput);
19164
+ if (extDetection.detected) {
19165
+ logger5.error(formatExtensionErrorHint(extDetection));
19166
+ }
18424
19167
  return {
18425
19168
  success: false,
18426
19169
  error: new Error(`pg-schema-diff apply failed: ${errorOutput}`),
@@ -19887,16 +20630,16 @@ var ERROR_MESSAGES2 = {
19887
20630
  SCHEMA_NOT_FOUND: "Schema file not found"
19888
20631
  };
19889
20632
  function containsPathTraversal2(inputPath) {
19890
- const normalized = path10__default.normalize(inputPath);
20633
+ const normalized = path11__default.normalize(inputPath);
19891
20634
  return normalized.includes("..") || inputPath.includes("\0");
19892
20635
  }
19893
20636
  function isPathWithinBase(filePath, baseDir) {
19894
20637
  try {
19895
- const resolvedFile = path10__default.resolve(filePath);
19896
- const resolvedBase = path10__default.resolve(baseDir);
19897
- const normalizedFile = path10__default.normalize(resolvedFile);
19898
- const normalizedBase = path10__default.normalize(resolvedBase);
19899
- return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase + path10__default.sep);
20638
+ const resolvedFile = path11__default.resolve(filePath);
20639
+ const resolvedBase = path11__default.resolve(baseDir);
20640
+ const normalizedFile = path11__default.normalize(resolvedFile);
20641
+ const normalizedBase = path11__default.normalize(resolvedBase);
20642
+ return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase + path11__default.sep);
19900
20643
  } catch {
19901
20644
  return false;
19902
20645
  }
@@ -19905,13 +20648,13 @@ function validateSchemaPath(dbPackagePath, projectRoot = process.cwd()) {
19905
20648
  if (containsPathTraversal2(dbPackagePath)) {
19906
20649
  throw new Error(ERROR_MESSAGES2.PATH_TRAVERSAL);
19907
20650
  }
19908
- const schemaEntry = path10__default.join(dbPackagePath, "src", "schema", "index.ts");
19909
- const absoluteSchemaPath = path10__default.resolve(projectRoot, schemaEntry);
20651
+ const schemaEntry = path11__default.join(dbPackagePath, "src", "schema", "index.ts");
20652
+ const absoluteSchemaPath = path11__default.resolve(projectRoot, schemaEntry);
19910
20653
  let resolvedProjectRoot;
19911
20654
  try {
19912
20655
  resolvedProjectRoot = realpathSync(projectRoot);
19913
20656
  } catch {
19914
- resolvedProjectRoot = path10__default.resolve(projectRoot);
20657
+ resolvedProjectRoot = path11__default.resolve(projectRoot);
19915
20658
  }
19916
20659
  if (!isPathWithinBase(absoluteSchemaPath, resolvedProjectRoot)) {
19917
20660
  throw new Error(ERROR_MESSAGES2.PATH_TRAVERSAL);
@@ -20043,7 +20786,7 @@ function diffSchema(params) {
20043
20786
  };
20044
20787
  }
20045
20788
  function extractTablesFromIdempotentSql(idempotentDir, projectRoot = process.cwd()) {
20046
- const fullPath = path10__default.resolve(projectRoot, idempotentDir);
20789
+ const fullPath = path11__default.resolve(projectRoot, idempotentDir);
20047
20790
  if (!existsSync(fullPath)) {
20048
20791
  return [];
20049
20792
  }
@@ -20052,7 +20795,7 @@ function extractTablesFromIdempotentSql(idempotentDir, projectRoot = process.cwd
20052
20795
  try {
20053
20796
  const files = readdirSync(fullPath).filter((f) => f.endsWith(".sql"));
20054
20797
  for (const file of files) {
20055
- const filePath = path10__default.join(fullPath, file);
20798
+ const filePath = path11__default.join(fullPath, file);
20056
20799
  const content = readFileSync(filePath, "utf-8");
20057
20800
  const contentWithoutComments = content.replace(/--.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
20058
20801
  for (const match of contentWithoutComments.matchAll(createTablePattern)) {
@@ -20275,7 +21018,7 @@ async function validateGitHubOutputPath(filePath) {
20275
21018
  if (!filePath || filePath.trim().length === 0) {
20276
21019
  return { valid: false, resolvedPath: null, error: "Empty file path" };
20277
21020
  }
20278
- const normalizedPath = path10__default.normalize(filePath);
21021
+ const normalizedPath = path11__default.normalize(filePath);
20279
21022
  if (normalizedPath.includes("..")) {
20280
21023
  return {
20281
21024
  valid: false,
@@ -20283,7 +21026,7 @@ async function validateGitHubOutputPath(filePath) {
20283
21026
  error: "Path traversal detected (..) in file path"
20284
21027
  };
20285
21028
  }
20286
- const absolutePath = path10__default.resolve(normalizedPath);
21029
+ const absolutePath = path11__default.resolve(normalizedPath);
20287
21030
  for (const forbidden of FORBIDDEN_PATHS) {
20288
21031
  if (absolutePath.startsWith(forbidden) || absolutePath.includes(forbidden)) {
20289
21032
  return {
@@ -20637,64 +21380,6 @@ var diffVisualCommand = new Command("diff-visual").description("Visualize schema
20637
21380
  // src/commands/db/commands/db-drizzle.ts
20638
21381
  init_esm_shims();
20639
21382
 
20640
- // src/internal/machines/index.ts
20641
- init_esm_shims();
20642
-
20643
- // src/internal/machines/machine-runner.ts
20644
- init_esm_shims();
20645
- function getOutputOrThrow(snapshot2) {
20646
- const s = snapshot2;
20647
- if (s.output === void 0) {
20648
- throw new CLIError("Machine completed without output", "MACHINE_NO_OUTPUT", [
20649
- "Ensure the machine defines an `output:` function."
20650
- ]);
20651
- }
20652
- return s.output;
20653
- }
20654
- async function runMachine(params) {
20655
- const timeoutMs = params.timeoutMs ?? 10 * 60 * 1e3;
20656
- return new Promise((resolve12, reject) => {
20657
- const actor = createActor(params.machine, { input: params.input });
20658
- const timer = setTimeout(() => {
20659
- try {
20660
- actor.stop?.();
20661
- } catch {
20662
- }
20663
- reject(
20664
- new CLIError("Machine execution timed out", "MACHINE_TIMEOUT", [
20665
- `Timeout: ${timeoutMs}ms`,
20666
- "Consider increasing timeoutMs for long-running operations."
20667
- ])
20668
- );
20669
- }, timeoutMs);
20670
- const sub = actor.subscribe((snapshot2) => {
20671
- try {
20672
- params.onSnapshot?.(snapshot2);
20673
- const stateName = params.helpers.getStateName(snapshot2);
20674
- params.onTransition?.(stateName);
20675
- if (params.helpers.isComplete(snapshot2)) {
20676
- clearTimeout(timer);
20677
- sub.unsubscribe();
20678
- const out = getOutputOrThrow(snapshot2);
20679
- resolve12(out);
20680
- }
20681
- } catch (err) {
20682
- clearTimeout(timer);
20683
- sub.unsubscribe();
20684
- reject(err);
20685
- }
20686
- });
20687
- try {
20688
- actor.start();
20689
- actor.send({ type: "START" });
20690
- } catch (err) {
20691
- clearTimeout(timer);
20692
- sub.unsubscribe();
20693
- reject(err);
20694
- }
20695
- });
20696
- }
20697
-
20698
21383
  // src/utils/execution-plan.ts
20699
21384
  init_esm_shims();
20700
21385
  function getChangeIcon(type) {
@@ -20762,7 +21447,7 @@ async function analyzeSchemaChanges() {
20762
21447
  try {
20763
21448
  const { getDatabasePackagePath: getDatabasePackagePath2 } = await Promise.resolve().then(() => (init_config_loader(), config_loader_exports));
20764
21449
  const dbPath = await getDatabasePackagePath2();
20765
- const schemaPath = path10__default.join(dbPath, "src/schema/");
21450
+ const schemaPath = path11__default.join(dbPath, "src/schema/");
20766
21451
  const { stdout } = await execa("git", ["diff", "--cached", "--", schemaPath]);
20767
21452
  const lines = stdout.split("\n");
20768
21453
  return parseDiffLines(lines);
@@ -20965,6 +21650,10 @@ var RISK_PATTERNS = [
20965
21650
  function normalizeContent(content) {
20966
21651
  return content.replace(/--[^\n]*/g, " ").replace(/\/\*[\s\S]*?\*\//g, " ").replace(/\s+/g, " ").trim();
20967
21652
  }
21653
+ function stripSqlCommentsPreserveLines(content) {
21654
+ const lineMasked = content.replace(/--[^\n]*/g, (match) => " ".repeat(match.length));
21655
+ return lineMasked.replace(/\/\*[\s\S]*?\*\//g, (match) => match.replace(/[^\n]/g, " "));
21656
+ }
20968
21657
  function maskWrapperFunctions(content) {
20969
21658
  const wrapperPattern = /CREATE\s+(?:OR\s+REPLACE\s+)?FUNCTION\s+(?:public\.)?runa_auth_\w+\s*\([^)]*\)[^$]*(\$[a-zA-Z_]*\$)[\s\S]*?\1;?/gi;
20970
21659
  return content.replace(wrapperPattern, "/* WRAPPER_FUNCTION_MASKED */");
@@ -20979,6 +21668,9 @@ function findLineNumber(originalContent, matchText) {
20979
21668
  const beforeMatch = originalContent.substring(0, match.index);
20980
21669
  return beforeMatch.split("\n").length;
20981
21670
  }
21671
+ function lineNumberFromIndex(content, index) {
21672
+ return content.substring(0, Math.max(0, index)).split("\n").length;
21673
+ }
20982
21674
  function detectRisksFromContent(normalizedContent, originalContent) {
20983
21675
  const risks = [];
20984
21676
  const seenDescriptions = /* @__PURE__ */ new Set();
@@ -21001,18 +21693,18 @@ function detectRisksFromContent(normalizedContent, originalContent) {
21001
21693
  }
21002
21694
  return risks;
21003
21695
  }
21004
- function detectForeignKeyRisks(lines) {
21696
+ function detectForeignKeyRisks(originalContent) {
21005
21697
  const risks = [];
21006
- const fkPattern = /REFERENCES\s+[\w."]+\s*\(/i;
21007
- for (let i = 0; i < lines.length; i++) {
21008
- if (fkPattern.test(lines[i])) {
21009
- risks.push({
21010
- level: "low",
21011
- description: "Foreign key columns should have indexes",
21012
- mitigation: "Add index on foreign key column for better performance",
21013
- line: i + 1
21014
- });
21015
- }
21698
+ const fkPattern = /REFERENCES\s+[\w."]+\s*\(/gi;
21699
+ const contentWithoutComments = stripSqlCommentsPreserveLines(originalContent);
21700
+ let match;
21701
+ while ((match = fkPattern.exec(contentWithoutComments)) !== null) {
21702
+ risks.push({
21703
+ level: "low",
21704
+ description: "Foreign key columns should have indexes",
21705
+ mitigation: "Add index on foreign key column for better performance",
21706
+ line: lineNumberFromIndex(originalContent, match.index ?? 0)
21707
+ });
21016
21708
  }
21017
21709
  return risks;
21018
21710
  }
@@ -21024,9 +21716,8 @@ async function detectSchemaRisks(filePath) {
21024
21716
  const content = await readFile(filePath, "utf-8");
21025
21717
  const maskedContent = maskWrapperFunctions(content);
21026
21718
  const normalizedContent = normalizeContent(maskedContent);
21027
- const lines = content.split("\n");
21028
21719
  const contentRisks = detectRisksFromContent(normalizedContent, content);
21029
- const fkRisks = detectForeignKeyRisks(lines);
21720
+ const fkRisks = detectForeignKeyRisks(content);
21030
21721
  return [...contentRisks, ...fkRisks];
21031
21722
  } catch (_error) {
21032
21723
  return [];
@@ -21041,7 +21732,7 @@ function categorizeRisks(risks) {
21041
21732
  }
21042
21733
 
21043
21734
  // src/commands/db/utils/preflight-check.ts
21044
- init_constants();
21735
+ init_local_supabase();
21045
21736
  init_config_loader();
21046
21737
  function createInitialResult() {
21047
21738
  return {
@@ -21095,7 +21786,7 @@ function runDatabasePackageChecks(result, logger16, step) {
21095
21786
  logger16.error("Database package path is missing");
21096
21787
  return null;
21097
21788
  }
21098
- logger16.success(`Found database package: ${path10__default.basename(dbPackagePath)}`);
21789
+ logger16.success(`Found database package: ${path11__default.basename(dbPackagePath)}`);
21099
21790
  logger16.step("Checking schema files", step.next());
21100
21791
  const schemaCheck = checkSchemaFiles(dbPackagePath);
21101
21792
  if (!schemaCheck.exists) {
@@ -21219,9 +21910,9 @@ ${stderr}`.toLowerCase();
21219
21910
  }
21220
21911
  }
21221
21912
  async function testDatabaseConnection(projectRoot) {
21222
- const ports = detectSupabasePorts(projectRoot);
21223
- const dbPort = ports.db;
21224
- const connectionUrl = `postgresql://postgres:postgres@127.0.0.1:${dbPort}/postgres`;
21913
+ const resolvedRoot = process.cwd();
21914
+ const connectionUrl = buildLocalDatabaseUrl(resolvedRoot);
21915
+ const dbPort = detectLocalSupabasePorts(resolvedRoot).db;
21225
21916
  let sql = null;
21226
21917
  try {
21227
21918
  sql = postgres(connectionUrl, {
@@ -21243,12 +21934,12 @@ async function testDatabaseConnection(projectRoot) {
21243
21934
  function checkDatabasePackage() {
21244
21935
  const cwd = process.cwd();
21245
21936
  const locations = [
21246
- path10__default.join(cwd, "packages", "database"),
21247
- path10__default.join(cwd, "packages", "db"),
21248
- path10__default.join(cwd, "db")
21937
+ path11__default.join(cwd, "packages", "database"),
21938
+ path11__default.join(cwd, "packages", "db"),
21939
+ path11__default.join(cwd, "db")
21249
21940
  ];
21250
21941
  for (const location of locations) {
21251
- const configPath = path10__default.join(location, "drizzle.config.ts");
21942
+ const configPath = path11__default.join(location, "drizzle.config.ts");
21252
21943
  if (existsSync(configPath)) {
21253
21944
  return { exists: true, path: location };
21254
21945
  }
@@ -21293,7 +21984,7 @@ function countTsFilesRecursive(dir) {
21293
21984
  try {
21294
21985
  const entries = readdirSync(dir, { withFileTypes: true });
21295
21986
  for (const entry of entries) {
21296
- const fullPath = path10__default.join(dir, entry.name);
21987
+ const fullPath = path11__default.join(dir, entry.name);
21297
21988
  if (entry.isDirectory()) {
21298
21989
  count += countTsFilesRecursive(fullPath);
21299
21990
  } else if (entry.isFile() && entry.name.endsWith(".ts")) {
@@ -21305,7 +21996,7 @@ function countTsFilesRecursive(dir) {
21305
21996
  return count;
21306
21997
  }
21307
21998
  function checkSchemaFiles(dbPackagePath) {
21308
- const schemaDir = path10__default.join(dbPackagePath, "src", "schema");
21999
+ const schemaDir = path11__default.join(dbPackagePath, "src", "schema");
21309
22000
  if (!existsSync(schemaDir)) {
21310
22001
  return { exists: false, count: 0 };
21311
22002
  }
@@ -21342,9 +22033,9 @@ async function runOrphanCheck(env2, dbPackagePath, result, logger16, step) {
21342
22033
  logger16.step("Checking for orphaned database objects", step.next());
21343
22034
  try {
21344
22035
  const { expectedTables, expectedEnums } = await extractSchemaTablesAndEnums(dbPackagePath);
21345
- const databaseUrl = tryResolveDatabaseUrl("local") || "postgresql://postgres:postgres@localhost:54322/postgres";
22036
+ const databaseUrl = tryResolveDatabaseUrl("local") || buildLocalDatabaseUrl(process.cwd());
21346
22037
  const { dbTables, dbEnums } = await fetchDbTablesAndEnums(databaseUrl, {
21347
- schemaDir: path10__default.join(dbPackagePath, "src", "schema")
22038
+ schemaDir: path11__default.join(dbPackagePath, "src", "schema")
21348
22039
  });
21349
22040
  let excludeFromOrphanDetection = [];
21350
22041
  let idempotentSqlDir = "supabase/schemas/idempotent";
@@ -21386,31 +22077,39 @@ function runExtensionConfigCheck(_result, logger16, step) {
21386
22077
  logger16.step("Checking PostgreSQL extension configuration", step.next());
21387
22078
  try {
21388
22079
  const extensionResult = checkExtensionConfig(process.cwd());
21389
- if (extensionResult.usedExtensions.length === 0) {
22080
+ if (!extensionResult || typeof extensionResult !== "object") {
22081
+ logger16.warn("Extension config check returned invalid result");
22082
+ return;
22083
+ }
22084
+ const usedExtensions = extensionResult.usedExtensions ?? [];
22085
+ if (usedExtensions.length === 0) {
21390
22086
  logger16.success("No extensions detected in SQL files");
21391
22087
  return;
21392
22088
  }
22089
+ const sqlManaged = extensionResult.sqlManagedExtensions ?? [];
22090
+ const supabaseManaged = extensionResult.supabaseManagedExtensions ?? [];
21393
22091
  const parts = [];
21394
- if (extensionResult.sqlManagedExtensions.length > 0) {
21395
- parts.push(`${extensionResult.sqlManagedExtensions.length} SQL-managed`);
22092
+ if (sqlManaged.length > 0) {
22093
+ parts.push(`${sqlManaged.length} SQL-managed`);
21396
22094
  }
21397
- if (extensionResult.supabaseManagedExtensions.length > 0) {
21398
- parts.push(`${extensionResult.supabaseManagedExtensions.length} Supabase-managed`);
22095
+ if (supabaseManaged.length > 0) {
22096
+ parts.push(`${supabaseManaged.length} Supabase-managed`);
21399
22097
  }
21400
22098
  const summary = parts.join(", ");
21401
- logger16.success(`${extensionResult.usedExtensions.length} extension(s) found (${summary})`);
21402
- for (const note of extensionResult.notes) {
22099
+ logger16.success(`${usedExtensions.length} extension(s) found (${summary})`);
22100
+ const notes = extensionResult.notes ?? [];
22101
+ for (const note of notes) {
21403
22102
  logger16.info(` ${note}`);
21404
22103
  }
21405
22104
  } catch (error) {
21406
22105
  const message = error instanceof Error ? error.message : "Unknown error";
21407
- logger16.warn(`Extension config check skipped: ${message}`);
22106
+ logger16.warn(`Extension config check failed: ${message}`);
21408
22107
  }
21409
22108
  }
21410
22109
  async function runSqlSchemaRiskCheck(result, logger16, step) {
21411
22110
  logger16.step("Checking SQL schema for risky patterns", step.next());
21412
22111
  const cwd = process.cwd();
21413
- const sqlDir = path10__default.join(cwd, "supabase", "schemas", "declarative");
22112
+ const sqlDir = path11__default.join(cwd, "supabase", "schemas", "declarative");
21414
22113
  if (!existsSync(sqlDir)) {
21415
22114
  logger16.success("No SQL schema directory found (supabase/schemas/declarative/)");
21416
22115
  return;
@@ -21423,7 +22122,7 @@ async function runSqlSchemaRiskCheck(result, logger16, step) {
21423
22122
  }
21424
22123
  const allRisks = [];
21425
22124
  for (const sqlFile of sqlFiles) {
21426
- const filePath = path10__default.join(sqlDir, sqlFile);
22125
+ const filePath = path11__default.join(sqlDir, sqlFile);
21427
22126
  const risks = await detectSchemaRisks(filePath);
21428
22127
  for (const risk of risks) {
21429
22128
  allRisks.push({ ...risk, file: sqlFile });
@@ -23175,7 +23874,7 @@ async function checkPort(port) {
23175
23874
  };
23176
23875
  }
23177
23876
  function detectSupabasePortsFromConfig() {
23178
- const configPath = path10__default.join(process.cwd(), "supabase", "config.toml");
23877
+ const configPath = path11__default.join(process.cwd(), "supabase", "config.toml");
23179
23878
  const BASE_PORTS = { api: 54321, db: 54322, studio: 54323, inbucket: 54324 };
23180
23879
  if (!existsSync(configPath)) {
23181
23880
  return Object.values(BASE_PORTS);
@@ -23264,7 +23963,7 @@ var BASE_PORT = 54321;
23264
23963
  var PORTS_PER_SLOT = 10;
23265
23964
  var TOTAL_SLOTS = 100;
23266
23965
  function calculatePortOffset(projectPath) {
23267
- const normalizedPath = path10__default.resolve(projectPath);
23966
+ const normalizedPath = path11__default.resolve(projectPath);
23268
23967
  const hash = createHash("md5").update(normalizedPath).digest("hex");
23269
23968
  return parseInt(hash.slice(0, 8), 16) % TOTAL_SLOTS;
23270
23969
  }
@@ -23285,7 +23984,7 @@ function getSupabasePorts(projectPath) {
23285
23984
  }
23286
23985
  function updateSupabaseConfigPorts(projectPath) {
23287
23986
  const ports = getSupabasePorts(projectPath);
23288
- const configPath = path10__default.join(projectPath, "supabase", "config.toml");
23987
+ const configPath = path11__default.join(projectPath, "supabase", "config.toml");
23289
23988
  if (!existsSync(configPath)) {
23290
23989
  return { updated: false, ports, configPath };
23291
23990
  }
@@ -23320,7 +24019,7 @@ function getPortAllocationSummary(projectPath) {
23320
24019
  const ports = getSupabasePorts(projectPath);
23321
24020
  const offset = calculatePortOffset(projectPath);
23322
24021
  return [
23323
- `Port allocation for: ${path10__default.basename(projectPath)}`,
24022
+ `Port allocation for: ${path11__default.basename(projectPath)}`,
23324
24023
  ` Slot: ${offset} (hash-based)`,
23325
24024
  ` API: ${ports.api}`,
23326
24025
  ` DB: ${ports.db}`,
@@ -23354,7 +24053,7 @@ function parseSeedPaths(configPath) {
23354
24053
  }
23355
24054
  }
23356
24055
  async function applySeedFile(seedPath, dbUrl) {
23357
- const supabaseDir = path10__default.join(process.cwd(), "supabase");
24056
+ const supabaseDir = path11__default.join(process.cwd(), "supabase");
23358
24057
  const absolutePath = resolveSafePath(supabaseDir, seedPath);
23359
24058
  if (!existsSync(absolutePath)) {
23360
24059
  return;
@@ -23365,12 +24064,12 @@ async function applySeedFile(seedPath, dbUrl) {
23365
24064
  });
23366
24065
  }
23367
24066
  async function applySeeds2(configPath) {
23368
- const configFile = path10__default.join(process.cwd(), "supabase", "config.toml");
24067
+ const configFile = path11__default.join(process.cwd(), "supabase", "config.toml");
23369
24068
  const seedPaths = parseSeedPaths(configFile);
23370
24069
  if (seedPaths.length === 0) {
23371
24070
  return;
23372
24071
  }
23373
- const supabaseDir = path10__default.join(process.cwd(), "supabase");
24072
+ const supabaseDir = path11__default.join(process.cwd(), "supabase");
23374
24073
  const safePaths = filterSafePaths(seedPaths, supabaseDir);
23375
24074
  if (safePaths.length === 0) {
23376
24075
  return;
@@ -23788,7 +24487,7 @@ var validateCommand = new Command("validate").description("Validate schema files
23788
24487
  const logger16 = createCLILogger("db:validate");
23789
24488
  try {
23790
24489
  logger16.section("Schema Validation");
23791
- const schemasPath = path10__default.join(process.cwd(), "packages", "database", "src", "schema");
24490
+ const schemasPath = path11__default.join(process.cwd(), "packages", "database", "src", "schema");
23792
24491
  if (!existsSync(schemasPath)) {
23793
24492
  throw new CLIError("Schema directory not found", "SCHEMA_DIR_NOT_FOUND", [
23794
24493
  `Expected location: ${schemasPath}`,
@@ -23953,8 +24652,8 @@ var generateCommand = new Command("generate").description("Generate TypeScript t
23953
24652
  var listCommand = new Command("list").description("List managed schemas from drizzle.config.ts").option("--sql", "Output as SQL-compatible string for IN clauses").option("--json", "Output as JSON array").action(async (options) => {
23954
24653
  const logger16 = createCLILogger("db:schema:list");
23955
24654
  try {
23956
- const dbPackagePath = path10__default.join(process.cwd(), "packages", "database");
23957
- if (!existsSync(path10__default.join(dbPackagePath, "drizzle.config.ts"))) {
24655
+ const dbPackagePath = path11__default.join(process.cwd(), "packages", "database");
24656
+ if (!existsSync(path11__default.join(dbPackagePath, "drizzle.config.ts"))) {
23958
24657
  throw new CLIError("drizzle.config.ts not found", "CONFIG_NOT_FOUND", [
23959
24658
  `Expected location: ${dbPackagePath}/drizzle.config.ts`,
23960
24659
  "Ensure you are in the project root",
@@ -25193,7 +25892,7 @@ var testGenCommand = new Command("test:gen").description("Generate pgTAP behavio
25193
25892
  const databaseUrl = options.db || process.env.DATABASE_URL || getLocalDbUrl();
25194
25893
  const schemas = options.schemas ? options.schemas.split(",") : void 0;
25195
25894
  const dbPackage = databasePaths.package();
25196
- const defaultOutputPath = path10__default.join(dbPackage, "tests/00_behavior.generated.test.sql");
25895
+ const defaultOutputPath = path11__default.join(dbPackage, "tests/00_behavior.generated.test.sql");
25197
25896
  const outputPath = options.output || defaultOutputPath;
25198
25897
  spinner.text = "Generating pgTAP behavior tests...";
25199
25898
  const result = await dbGeneratePgTapTests({
@@ -26205,108 +26904,8 @@ async function getVercelRootDirectory() {
26205
26904
  return info?.rootDirectory ?? null;
26206
26905
  }
26207
26906
 
26208
- // src/commands/env/constants/local-supabase.ts
26209
- init_esm_shims();
26210
- var DEFAULT_API_PORT = 54321;
26211
- var DEFAULT_DB_PORT = 54322;
26212
- function parsePortFromToml(content, section, key) {
26213
- const sectionRegex = new RegExp(`\\[${section}\\]([\\s\\S]*?)(?=\\n\\[|$)`, "g");
26214
- const sectionMatch = sectionRegex.exec(content);
26215
- if (!sectionMatch) return null;
26216
- const sectionContent = sectionMatch[1];
26217
- const keyRegex = new RegExp(`^\\s*${key}\\s*=\\s*(\\d+)`, "m");
26218
- const keyMatch = keyRegex.exec(sectionContent);
26219
- if (!keyMatch) return null;
26220
- const port = Number.parseInt(keyMatch[1], 10);
26221
- return Number.isFinite(port) && port > 0 && port < 65536 ? port : null;
26222
- }
26223
- function readPortsFromConfigToml(projectRoot) {
26224
- const configPath = path10__default.join(projectRoot, "supabase", "config.toml");
26225
- try {
26226
- const content = readFileSync(configPath, "utf-8");
26227
- const apiPort = parsePortFromToml(content, "api", "port");
26228
- const dbPort = parsePortFromToml(content, "db", "port");
26229
- if (apiPort !== null || dbPort !== null) {
26230
- return {
26231
- api: apiPort ?? DEFAULT_API_PORT,
26232
- db: dbPort ?? DEFAULT_DB_PORT
26233
- };
26234
- }
26235
- return null;
26236
- } catch {
26237
- return null;
26238
- }
26239
- }
26240
- function detectLocalSupabasePorts(projectRoot = process.cwd()) {
26241
- const configPorts = readPortsFromConfigToml(projectRoot);
26242
- if (configPorts) {
26243
- return configPorts;
26244
- }
26245
- return {
26246
- api: DEFAULT_API_PORT,
26247
- db: DEFAULT_DB_PORT
26248
- };
26249
- }
26250
- var LOCAL_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
26251
- var LOCAL_SUPABASE_SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU";
26252
- function buildLocalSupabaseUrl(projectRoot = process.cwd()) {
26253
- const ports = detectLocalSupabasePorts(projectRoot);
26254
- return `http://127.0.0.1:${ports.api}`;
26255
- }
26256
- function buildLocalDatabaseUrl(projectRoot = process.cwd()) {
26257
- const ports = detectLocalSupabasePorts(projectRoot);
26258
- return `postgresql://postgres:postgres@127.0.0.1:${ports.db}/postgres`;
26259
- }
26260
- function getLocalSupabaseEnvValues(projectRoot = process.cwd()) {
26261
- const supabaseUrl = buildLocalSupabaseUrl(projectRoot);
26262
- const databaseUrl = buildLocalDatabaseUrl(projectRoot);
26263
- return {
26264
- // Database URLs
26265
- DATABASE_URL: databaseUrl,
26266
- DATABASE_URL_ADMIN: databaseUrl,
26267
- DATABASE_URL_SERVICE: databaseUrl,
26268
- // Supabase URLs and keys
26269
- NEXT_PUBLIC_SUPABASE_URL: supabaseUrl,
26270
- NEXT_PUBLIC_SUPABASE_ANON_KEY: LOCAL_SUPABASE_ANON_KEY,
26271
- SUPABASE_SERVICE_ROLE_KEY: LOCAL_SUPABASE_SERVICE_ROLE_KEY
26272
- };
26273
- }
26274
- function getLocalValueDescriptions(projectRoot = process.cwd()) {
26275
- const ports = detectLocalSupabasePorts(projectRoot);
26276
- return {
26277
- DATABASE_URL: `localhost:${ports.db} (PostgreSQL)`,
26278
- DATABASE_URL_ADMIN: `localhost:${ports.db} (PostgreSQL)`,
26279
- DATABASE_URL_SERVICE: `localhost:${ports.db} (PostgreSQL)`,
26280
- NEXT_PUBLIC_SUPABASE_URL: `localhost:${ports.api} (Supabase API)`,
26281
- NEXT_PUBLIC_SUPABASE_ANON_KEY: "local anon key (supabase-demo)",
26282
- SUPABASE_SERVICE_ROLE_KEY: "local service key (supabase-demo)"
26283
- };
26284
- }
26285
- var LOCAL_SUPABASE_ENV_VALUES = getLocalSupabaseEnvValues();
26286
- getLocalValueDescriptions();
26287
- function validateLocalhostValues(envValues) {
26288
- const urlKeys = [
26289
- "DATABASE_URL",
26290
- "DATABASE_URL_ADMIN",
26291
- "DATABASE_URL_SERVICE",
26292
- "NEXT_PUBLIC_SUPABASE_URL"
26293
- ];
26294
- const invalidEntries = [];
26295
- for (const key of urlKeys) {
26296
- const value = envValues[key];
26297
- if (value && !value.includes("127.0.0.1") && !value.includes("localhost")) {
26298
- invalidEntries.push(key);
26299
- }
26300
- }
26301
- if (invalidEntries.length > 0) {
26302
- throw new Error(
26303
- `LOCAL_SUPABASE_ENV_VALUES safety check failed: The following keys do not point to localhost: ${invalidEntries.join(", ")}. This is a safety feature to prevent accidental production database connections during local development.`
26304
- );
26305
- }
26306
- }
26307
- validateLocalhostValues(LOCAL_SUPABASE_ENV_VALUES);
26308
-
26309
26907
  // src/commands/env/commands/env-pull.ts
26908
+ init_local_supabase();
26310
26909
  var ERROR_MESSAGES3 = {
26311
26910
  INVALID_PATH: "Invalid working directory path",
26312
26911
  PATH_TRAVERSAL: "Working directory path validation failed",
@@ -26338,16 +26937,16 @@ function sanitizeErrorMessage(message) {
26338
26937
  return sanitized;
26339
26938
  }
26340
26939
  function containsPathTraversal3(inputPath) {
26341
- const normalized = path10__default.normalize(inputPath);
26940
+ const normalized = path11__default.normalize(inputPath);
26342
26941
  return normalized.includes("..") || inputPath.includes("\0");
26343
26942
  }
26344
26943
  function isPathWithinBase2(filePath, baseDir) {
26345
26944
  try {
26346
- const resolvedFile = path10__default.resolve(filePath);
26347
- const resolvedBase = path10__default.resolve(baseDir);
26348
- const normalizedFile = path10__default.normalize(resolvedFile);
26349
- const normalizedBase = path10__default.normalize(resolvedBase);
26350
- return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase + path10__default.sep);
26945
+ const resolvedFile = path11__default.resolve(filePath);
26946
+ const resolvedBase = path11__default.resolve(baseDir);
26947
+ const normalizedFile = path11__default.normalize(resolvedFile);
26948
+ const normalizedBase = path11__default.normalize(resolvedBase);
26949
+ return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase + path11__default.sep);
26351
26950
  } catch {
26352
26951
  return false;
26353
26952
  }
@@ -26356,12 +26955,12 @@ function validateCustomWorkingDir(cwdPath, projectRoot) {
26356
26955
  if (containsPathTraversal3(cwdPath)) {
26357
26956
  throw new CLIError(ERROR_MESSAGES3.PATH_TRAVERSAL, "ENV_PULL_PATH_TRAVERSAL");
26358
26957
  }
26359
- const absolutePath = path10__default.isAbsolute(cwdPath) ? cwdPath : path10__default.resolve(projectRoot, cwdPath);
26958
+ const absolutePath = path11__default.isAbsolute(cwdPath) ? cwdPath : path11__default.resolve(projectRoot, cwdPath);
26360
26959
  let resolvedProjectRoot;
26361
26960
  try {
26362
26961
  resolvedProjectRoot = realpathSync(projectRoot);
26363
26962
  } catch {
26364
- resolvedProjectRoot = path10__default.resolve(projectRoot);
26963
+ resolvedProjectRoot = path11__default.resolve(projectRoot);
26365
26964
  }
26366
26965
  if (!isPathWithinBase2(absolutePath, resolvedProjectRoot)) {
26367
26966
  throw new CLIError(ERROR_MESSAGES3.PATH_TRAVERSAL, "ENV_PULL_PATH_TRAVERSAL");
@@ -26388,6 +26987,27 @@ function validateAppDirectory2(appName, projectRoot) {
26388
26987
  }
26389
26988
  return appDir;
26390
26989
  }
26990
+ var LOCAL_BOOTSTRAP_REQUIRED_KEYS = [
26991
+ "LOCAL_SUPABASE_HOST",
26992
+ "LOCAL_SUPABASE_API_PORT",
26993
+ "LOCAL_SUPABASE_DB_PORT"
26994
+ ];
26995
+ function getMissingLocalBootstrapKeys(parsed) {
26996
+ return LOCAL_BOOTSTRAP_REQUIRED_KEYS.filter((key) => !(key in parsed));
26997
+ }
26998
+ function getLocalBootstrapStatusFromParsed(parsed) {
26999
+ const missing = getMissingLocalBootstrapKeys(parsed);
27000
+ return {
27001
+ status: missing.length === 0 ? "ok" : "partial",
27002
+ missing
27003
+ };
27004
+ }
27005
+ function missingLocalBootstrapReport() {
27006
+ return {
27007
+ status: "missing",
27008
+ missing: [...LOCAL_BOOTSTRAP_REQUIRED_KEYS]
27009
+ };
27010
+ }
26391
27011
  var EnvPullOutputSchema = z.object({
26392
27012
  results: z.array(
26393
27013
  z.object({
@@ -26401,6 +27021,10 @@ var EnvPullOutputSchema = z.object({
26401
27021
  totalPulled: z.number(),
26402
27022
  totalFailed: z.number(),
26403
27023
  totalEncrypted: z.number().optional(),
27024
+ localBootstrap: z.object({
27025
+ status: z.enum(["ok", "partial", "missing"]),
27026
+ missing: z.array(z.string())
27027
+ }).optional(),
26404
27028
  /** Vercel Root Directory sync result */
26405
27029
  vercelSync: z.object({
26406
27030
  detected: z.boolean(),
@@ -26533,60 +27157,74 @@ function removePrivateKeysFromEnvFile(filePath) {
26533
27157
  writeFileSync(filePath, `${newContent}
26534
27158
  `, "utf-8");
26535
27159
  }
26536
- function replaceWithLocalValues(filePath, logger16, dryRun = false) {
27160
+ function replaceWithLocalValues(filePath, workDir, logger16, dryRun = false) {
26537
27161
  if (!existsSync(filePath)) {
26538
27162
  logger16.warn(" \u26A0\uFE0F .env.development not found (was pull successful?)");
26539
- return;
27163
+ return missingLocalBootstrapReport();
26540
27164
  }
26541
27165
  const content = readFileSync(filePath, "utf-8");
26542
27166
  if (!content.trim()) {
26543
27167
  logger16.warn(" \u26A0\uFE0F .env.development is empty (no env vars in Vercel?)");
26544
- return;
27168
+ return missingLocalBootstrapReport();
26545
27169
  }
26546
27170
  const parsed = parse(content);
26547
27171
  if (Object.keys(parsed).length === 0) {
26548
27172
  logger16.warn(" \u26A0\uFE0F No valid env vars found in .env.development (check syntax)");
26549
- return;
27173
+ return missingLocalBootstrapReport();
26550
27174
  }
26551
- const projectRoot = process.cwd();
26552
- const localEnvValues = getLocalSupabaseEnvValues(projectRoot);
26553
- const localDescriptions = getLocalValueDescriptions(projectRoot);
27175
+ const localEnvValues = getLocalSupabaseEnvValues(workDir);
27176
+ const localDescriptions = getLocalValueDescriptions(workDir);
26554
27177
  const replacementKeys = Object.keys(localEnvValues);
26555
27178
  const replacedKeys = [];
27179
+ const hasAnySupabaseKey = Object.keys(parsed).some((key) => key.includes("SUPABASE") || key.includes("DATABASE_URL")) || replacementKeys.some((key) => key in parsed);
26556
27180
  for (const key of replacementKeys) {
26557
- if (key in parsed && localEnvValues[key]) {
27181
+ if (key in parsed || hasAnySupabaseKey) {
26558
27182
  parsed[key] = localEnvValues[key];
26559
27183
  replacedKeys.push(key);
26560
27184
  }
26561
27185
  }
26562
27186
  if (replacedKeys.length === 0) {
26563
- const hasAnySupabaseKey = Object.keys(parsed).some(
27187
+ const hasAnySupabaseKey2 = Object.keys(parsed).some(
26564
27188
  (k) => k.includes("SUPABASE") || k.includes("DATABASE_URL")
26565
27189
  );
26566
- if (hasAnySupabaseKey) {
27190
+ if (hasAnySupabaseKey2) {
26567
27191
  logger16.warn(" \u26A0\uFE0F Found Supabase keys but none matched local replacement patterns");
26568
27192
  } else {
26569
27193
  logger16.info(" No Supabase variables found (may be expected for new projects)");
26570
27194
  }
26571
- return;
27195
+ return getLocalBootstrapStatusFromParsed(parsed);
26572
27196
  }
27197
+ const bootstrapStatus = getLocalBootstrapStatusFromParsed(parsed);
27198
+ if (bootstrapStatus.missing.length > 0) {
27199
+ logger16.warn(
27200
+ ` \u26A0\uFE0F Some local bootstrap keys were not updated: ${bootstrapStatus.missing.join(", ")}`
27201
+ );
27202
+ }
27203
+ const ensureRequired = bootstrapStatus.status === "ok";
26573
27204
  const newContent = Object.entries(parsed).map(([key, value]) => `${key}=${formatEnvValue(value)}`).join("\n");
26574
27205
  if (dryRun) {
26575
- logger16.info(` \u{1F3E0} Would replace ${replacedKeys.length} variables with localhost values:`);
27206
+ logger16.info(` \u{1F3E0} Would replace ${replacedKeys.length} variables with local values:`);
26576
27207
  for (const key of replacedKeys) {
26577
27208
  const description = localDescriptions[key] || "localhost";
26578
27209
  logger16.info(` ${key} \u2192 ${description}`);
26579
27210
  }
27211
+ logger16.info(
27212
+ ` ${ensureRequired ? "\u2705" : "\u26A0\uFE0F"} Local bootstrap keys ready: ${ensureRequired ? "yes" : "partial"}`
27213
+ );
26580
27214
  logger16.info(" (dry-run: no files modified)");
26581
- return;
27215
+ return bootstrapStatus;
26582
27216
  }
26583
27217
  writeFileSync(filePath, `${newContent}
26584
27218
  `, "utf-8");
26585
- logger16.success(` \u{1F3E0} Replaced ${replacedKeys.length} variables with localhost values:`);
27219
+ logger16.success(` \u{1F3E0} Replaced ${replacedKeys.length} variables with local values:`);
26586
27220
  for (const key of replacedKeys) {
26587
27221
  const description = localDescriptions[key] || "localhost";
26588
27222
  logger16.info(` ${key} \u2192 ${description}`);
26589
27223
  }
27224
+ logger16.info(
27225
+ ` ${ensureRequired ? "\u2705" : "\u26A0\uFE0F"} Local bootstrap keys ready: ${ensureRequired ? "yes" : "partial"}`
27226
+ );
27227
+ return bootstrapStatus;
26590
27228
  }
26591
27229
  async function encryptFile2(workDir, filePath, logger16) {
26592
27230
  if (!existsSync(filePath)) {
@@ -26818,13 +27456,20 @@ async function runEnvPullAction(options) {
26818
27456
  }
26819
27457
  logger16.info("");
26820
27458
  const results = await pullAllEnvironments(workDir, environments, auth, logger16);
26821
- if (!options.productionAll) {
27459
+ const shouldEvaluateLocalBootstrap = !options.productionAll && (!options.environment || options.environment === "development");
27460
+ let localBootstrap;
27461
+ if (shouldEvaluateLocalBootstrap) {
26822
27462
  const devResult = results.find((r) => r.environment === "development" && r.success);
26823
27463
  if (devResult) {
26824
27464
  logger16.info("");
26825
27465
  logger16.info("Applying local Supabase values to .env.development...");
26826
- replaceWithLocalValues(devResult.outputPath, logger16, options.check);
27466
+ localBootstrap = replaceWithLocalValues(devResult.outputPath, workDir, logger16, options.check);
27467
+ } else {
27468
+ localBootstrap = missingLocalBootstrapReport();
27469
+ logger16.warn(" LOCAL_BOOTSTRAP: skipped (development env pull failed or missing)");
26827
27470
  }
27471
+ } else {
27472
+ localBootstrap = void 0;
26828
27473
  }
26829
27474
  if (options.encrypt && !options.check) {
26830
27475
  await encryptPulledFiles(workDir, results, logger16);
@@ -26845,6 +27490,7 @@ async function runEnvPullAction(options) {
26845
27490
  totalPulled,
26846
27491
  totalFailed,
26847
27492
  totalEncrypted: options.encrypt ? totalEncrypted : void 0,
27493
+ localBootstrap,
26848
27494
  vercelSync: vercelSyncResult
26849
27495
  });
26850
27496
  if (totalFailed > 0) {
@@ -28584,13 +29230,13 @@ z.object({
28584
29230
 
28585
29231
  // src/commands/hotfix/metadata.ts
28586
29232
  function getHotfixDir(targetDir) {
28587
- return path10__default.join(targetDir, ".runa", "hotfix");
29233
+ return path11__default.join(targetDir, ".runa", "hotfix");
28588
29234
  }
28589
29235
  function getCurrentFile(targetDir) {
28590
- return path10__default.join(getHotfixDir(targetDir), "current.json");
29236
+ return path11__default.join(getHotfixDir(targetDir), "current.json");
28591
29237
  }
28592
29238
  function getArchiveDir(targetDir) {
28593
- return path10__default.join(getHotfixDir(targetDir), "archive");
29239
+ return path11__default.join(getHotfixDir(targetDir), "archive");
28594
29240
  }
28595
29241
  async function ensureHotfixDir(targetDir) {
28596
29242
  await mkdir(getHotfixDir(targetDir), { recursive: true });
@@ -28600,7 +29246,7 @@ async function ensureArchiveDir(targetDir) {
28600
29246
  }
28601
29247
  async function getHotfixMetadata(input3 = {}) {
28602
29248
  const parsed = GetHotfixInputSchema.parse(input3);
28603
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
29249
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28604
29250
  const currentFile = getCurrentFile(targetDir);
28605
29251
  if (!existsSync(currentFile)) {
28606
29252
  return null;
@@ -28610,7 +29256,7 @@ async function getHotfixMetadata(input3 = {}) {
28610
29256
  }
28611
29257
  async function createHotfixMetadata(input3) {
28612
29258
  const parsed = CreateHotfixMetadataInputSchema.parse(input3);
28613
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
29259
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28614
29260
  await ensureHotfixDir(targetDir);
28615
29261
  const metadata = {
28616
29262
  branch: parsed.branch,
@@ -28627,7 +29273,7 @@ async function createHotfixMetadata(input3) {
28627
29273
  }
28628
29274
  async function updateHotfixStatus(input3) {
28629
29275
  const parsed = UpdateHotfixInputSchema.parse(input3);
28630
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
29276
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28631
29277
  const current = await getHotfixMetadata({ targetDir });
28632
29278
  if (!current) {
28633
29279
  throw createError("HOTFIX_NOT_FOUND");
@@ -28644,13 +29290,13 @@ async function updateHotfixStatus(input3) {
28644
29290
  return updated;
28645
29291
  }
28646
29292
  async function archiveHotfix(targetDir) {
28647
- const dir = targetDir ? path10__default.resolve(targetDir) : process.cwd();
29293
+ const dir = targetDir ? path11__default.resolve(targetDir) : process.cwd();
28648
29294
  const current = await getHotfixMetadata({ targetDir: dir });
28649
29295
  if (!current) {
28650
29296
  throw createError("HOTFIX_NOT_FOUND");
28651
29297
  }
28652
29298
  await ensureArchiveDir(dir);
28653
- const archiveFile = path10__default.join(
29299
+ const archiveFile = path11__default.join(
28654
29300
  getArchiveDir(dir),
28655
29301
  `${current.branch.replace(/\//g, "-")}-${Date.now()}.json`
28656
29302
  );
@@ -28666,7 +29312,7 @@ async function archiveHotfix(targetDir) {
28666
29312
  return archived;
28667
29313
  }
28668
29314
  async function cancelHotfix(targetDir) {
28669
- const dir = targetDir ? path10__default.resolve(targetDir) : process.cwd();
29315
+ const dir = targetDir ? path11__default.resolve(targetDir) : process.cwd();
28670
29316
  await updateHotfixStatus({
28671
29317
  status: "cancelled",
28672
29318
  completedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -28676,7 +29322,7 @@ async function cancelHotfix(targetDir) {
28676
29322
  }
28677
29323
  async function listArchivedHotfixes(input3 = {}) {
28678
29324
  const parsed = ListArchivedHotfixesInputSchema.parse(input3);
28679
- const targetDir = parsed.targetDir ? path10__default.resolve(parsed.targetDir) : process.cwd();
29325
+ const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
28680
29326
  const archiveDir = getArchiveDir(targetDir);
28681
29327
  if (!existsSync(archiveDir)) {
28682
29328
  return { hotfixes: [] };
@@ -28685,7 +29331,7 @@ async function listArchivedHotfixes(input3 = {}) {
28685
29331
  const hotfixes = [];
28686
29332
  for (const file of files.filter((f) => f.endsWith(".json"))) {
28687
29333
  try {
28688
- const content = await readFile(path10__default.join(archiveDir, file), "utf-8");
29334
+ const content = await readFile(path11__default.join(archiveDir, file), "utf-8");
28689
29335
  hotfixes.push(HotfixMetadataSchema.parse(JSON.parse(content)));
28690
29336
  } catch {
28691
29337
  }
@@ -30185,13 +30831,13 @@ function validateVersion(version) {
30185
30831
  }
30186
30832
  }
30187
30833
  function getCacheBase() {
30188
- return path10__default.join(os.homedir(), ".cache", "runa", "templates");
30834
+ return path11__default.join(os.homedir(), ".cache", "runa", "templates");
30189
30835
  }
30190
30836
  function getCacheDir(version) {
30191
30837
  validateVersion(version);
30192
30838
  const cacheBase = getCacheBase();
30193
- const cacheDir = path10__default.join(cacheBase, version);
30194
- const resolvedCacheDir = path10__default.resolve(cacheDir);
30839
+ const cacheDir = path11__default.join(cacheBase, version);
30840
+ const resolvedCacheDir = path11__default.resolve(cacheDir);
30195
30841
  if (!isPathContained(cacheBase, resolvedCacheDir)) {
30196
30842
  throw new CLIError(
30197
30843
  "Security: cache directory would escape allowed location.",
@@ -30203,7 +30849,7 @@ function getCacheDir(version) {
30203
30849
  }
30204
30850
  function isCached(version) {
30205
30851
  const cacheDir = getCacheDir(version);
30206
- const templatesDir = path10__default.join(cacheDir, "templates");
30852
+ const templatesDir = path11__default.join(cacheDir, "templates");
30207
30853
  return fs5__default.existsSync(templatesDir);
30208
30854
  }
30209
30855
  var scopedAuthToken = null;
@@ -30254,13 +30900,13 @@ async function createTempPackageJson(tempDir, version) {
30254
30900
  [TEMPLATES_PACKAGE_NAME]: version
30255
30901
  }
30256
30902
  };
30257
- await writeFile(path10__default.join(tempDir, "package.json"), JSON.stringify(packageJson, null, 2));
30903
+ await writeFile(path11__default.join(tempDir, "package.json"), JSON.stringify(packageJson, null, 2));
30258
30904
  }
30259
30905
  async function createTempNpmrc(tempDir) {
30260
30906
  const npmrc = `@r06-dev:registry=${GITHUB_PACKAGES_REGISTRY}
30261
30907
  //npm.pkg.github.com/:_authToken=\${NODE_AUTH_TOKEN}
30262
30908
  `;
30263
- await writeFile(path10__default.join(tempDir, ".npmrc"), npmrc);
30909
+ await writeFile(path11__default.join(tempDir, ".npmrc"), npmrc);
30264
30910
  }
30265
30911
  async function installTemplates(tempDir, authToken, verbose) {
30266
30912
  try {
@@ -30318,10 +30964,10 @@ async function installTemplates(tempDir, authToken, verbose) {
30318
30964
  async function verifyNoSymlinks(dir, baseDir) {
30319
30965
  const entries = await readdir(dir, { withFileTypes: true });
30320
30966
  for (const entry of entries) {
30321
- const fullPath = path10__default.join(dir, entry.name);
30967
+ const fullPath = path11__default.join(dir, entry.name);
30322
30968
  const stats = await lstat(fullPath);
30323
30969
  if (stats.isSymbolicLink()) {
30324
- const relativePath = path10__default.relative(baseDir, fullPath);
30970
+ const relativePath = path11__default.relative(baseDir, fullPath);
30325
30971
  throw new CLIError(
30326
30972
  "Security: Symlink detected in template package.",
30327
30973
  "SYMLINK_ATTACK_DETECTED",
@@ -30339,7 +30985,7 @@ async function verifyNoSymlinks(dir, baseDir) {
30339
30985
  }
30340
30986
  }
30341
30987
  async function copyToCache(tempDir, cacheDir) {
30342
- const sourceTemplates = path10__default.join(tempDir, "node_modules", TEMPLATES_PACKAGE_NAME, "templates");
30988
+ const sourceTemplates = path11__default.join(tempDir, "node_modules", TEMPLATES_PACKAGE_NAME, "templates");
30343
30989
  if (!fs5__default.existsSync(sourceTemplates)) {
30344
30990
  throw new CLIError("Templates directory not found in package.", "TEMPLATES_DIR_NOT_FOUND", [
30345
30991
  `Expected: ${sourceTemplates}`,
@@ -30349,7 +30995,7 @@ async function copyToCache(tempDir, cacheDir) {
30349
30995
  }
30350
30996
  await verifyNoSymlinks(sourceTemplates, sourceTemplates);
30351
30997
  await mkdir(cacheDir, { recursive: true });
30352
- const targetTemplates = path10__default.join(cacheDir, "templates");
30998
+ const targetTemplates = path11__default.join(cacheDir, "templates");
30353
30999
  await cp(sourceTemplates, targetTemplates, {
30354
31000
  recursive: true,
30355
31001
  dereference: false
@@ -30371,7 +31017,7 @@ async function fetchTemplates(options = {}) {
30371
31017
  };
30372
31018
  }
30373
31019
  const cacheDir = getCacheDir(version);
30374
- const templatesDir = path10__default.join(cacheDir, "templates");
31020
+ const templatesDir = path11__default.join(cacheDir, "templates");
30375
31021
  if (!fresh && isCached(version)) {
30376
31022
  if (verbose) {
30377
31023
  console.log(`Using cached templates v${version}: ${templatesDir}`);
@@ -30387,7 +31033,7 @@ async function fetchTemplates(options = {}) {
30387
31033
  if (fresh && fs5__default.existsSync(cacheDir)) {
30388
31034
  await rm(cacheDir, { recursive: true, force: true });
30389
31035
  }
30390
- const tempDir = path10__default.join(os.tmpdir(), `runa-templates-${Date.now()}`);
31036
+ const tempDir = path11__default.join(os.tmpdir(), `runa-templates-${Date.now()}`);
30391
31037
  await mkdir(tempDir, { recursive: true });
30392
31038
  try {
30393
31039
  if (verbose) {
@@ -30415,11 +31061,11 @@ async function fetchTemplates(options = {}) {
30415
31061
  }
30416
31062
  var MAX_WORKSPACE_TRAVERSAL_DEPTH = 10;
30417
31063
  function isLegitimateWorkspaceRoot(workspaceRoot) {
30418
- const pnpmWorkspaceFile = path10__default.join(workspaceRoot, "pnpm-workspace.yaml");
31064
+ const pnpmWorkspaceFile = path11__default.join(workspaceRoot, "pnpm-workspace.yaml");
30419
31065
  if (!fs5__default.existsSync(pnpmWorkspaceFile)) {
30420
31066
  return false;
30421
31067
  }
30422
- const rootPackageFile = path10__default.join(workspaceRoot, "package.json");
31068
+ const rootPackageFile = path11__default.join(workspaceRoot, "package.json");
30423
31069
  if (!fs5__default.existsSync(rootPackageFile)) {
30424
31070
  return false;
30425
31071
  }
@@ -30433,24 +31079,24 @@ function isLegitimateWorkspaceRoot(workspaceRoot) {
30433
31079
  }
30434
31080
  }
30435
31081
  function resolveWorkspaceTemplates() {
30436
- let current = path10__default.resolve(process.cwd());
30437
- const root = path10__default.parse(current).root;
31082
+ let current = path11__default.resolve(process.cwd());
31083
+ const root = path11__default.parse(current).root;
30438
31084
  let depth = 0;
30439
31085
  while (current !== root && depth < MAX_WORKSPACE_TRAVERSAL_DEPTH) {
30440
31086
  if (!isLegitimateWorkspaceRoot(current)) {
30441
- current = path10__default.dirname(current);
31087
+ current = path11__default.dirname(current);
30442
31088
  depth++;
30443
31089
  continue;
30444
31090
  }
30445
- const packagesTemplates = path10__default.join(current, "packages", "runa-templates", "templates");
30446
- const normalizedTemplatesPath = path10__default.resolve(packagesTemplates);
30447
- if (!normalizedTemplatesPath.startsWith(current + path10__default.sep)) {
30448
- current = path10__default.dirname(current);
31091
+ const packagesTemplates = path11__default.join(current, "packages", "runa-templates", "templates");
31092
+ const normalizedTemplatesPath = path11__default.resolve(packagesTemplates);
31093
+ if (!normalizedTemplatesPath.startsWith(current + path11__default.sep)) {
31094
+ current = path11__default.dirname(current);
30449
31095
  depth++;
30450
31096
  continue;
30451
31097
  }
30452
31098
  if (fs5__default.existsSync(normalizedTemplatesPath)) {
30453
- const markerFile = path10__default.join(current, "packages", "runa-templates", "package.json");
31099
+ const markerFile = path11__default.join(current, "packages", "runa-templates", "package.json");
30454
31100
  if (fs5__default.existsSync(markerFile)) {
30455
31101
  try {
30456
31102
  const pkg = JSON.parse(fs5__default.readFileSync(markerFile, "utf-8"));
@@ -30461,7 +31107,7 @@ function resolveWorkspaceTemplates() {
30461
31107
  }
30462
31108
  }
30463
31109
  }
30464
- current = path10__default.dirname(current);
31110
+ current = path11__default.dirname(current);
30465
31111
  depth++;
30466
31112
  }
30467
31113
  return void 0;
@@ -30470,9 +31116,9 @@ function resolveWorkspaceTemplates() {
30470
31116
  // src/commands/init.ts
30471
31117
  function checkZodVersion(_logger) {
30472
31118
  const zodPaths = [
30473
- path10__default.join(process.cwd(), "node_modules", "zod", "package.json"),
31119
+ path11__default.join(process.cwd(), "node_modules", "zod", "package.json"),
30474
31120
  // Check home directory node_modules (common source of conflicts)
30475
- path10__default.join(process.env.HOME ?? "", "node_modules", "zod", "package.json")
31121
+ path11__default.join(process.env.HOME ?? "", "node_modules", "zod", "package.json")
30476
31122
  ];
30477
31123
  for (const zodPath of zodPaths) {
30478
31124
  if (!fs5__default.existsSync(zodPath)) continue;
@@ -30486,7 +31132,7 @@ function checkZodVersion(_logger) {
30486
31132
  "ZOD_VERSION_INCOMPATIBLE",
30487
31133
  [
30488
31134
  "runa SDK requires zod v4.x, but found zod v3.x",
30489
- `Conflicting zod found at: ${path10__default.dirname(zodPath)}`,
31135
+ `Conflicting zod found at: ${path11__default.dirname(zodPath)}`,
30490
31136
  "",
30491
31137
  "Solutions:",
30492
31138
  "1. Run from a clean project directory without existing node_modules",
@@ -30738,7 +31384,7 @@ var initCommand = new Command("init").description("Initialize pj-repo with runa
30738
31384
  try {
30739
31385
  if (options.repairConfig) {
30740
31386
  logger16.section("Repairing runa.config.ts");
30741
- const projectName2 = path10__default.basename(process.cwd());
31387
+ const projectName2 = path11__default.basename(process.cwd());
30742
31388
  const repairResult = repairRunaConfig(process.cwd(), projectName2);
30743
31389
  if (repairResult.success) {
30744
31390
  logger16.success("\u2705 Config file repaired successfully");
@@ -30789,7 +31435,7 @@ var initCommand = new Command("init").description("Initialize pj-repo with runa
30789
31435
  existingConfig,
30790
31436
  force: options.force === true
30791
31437
  });
30792
- const projectName = path10__default.basename(process.cwd());
31438
+ const projectName = path11__default.basename(process.cwd());
30793
31439
  logger16.info(`Project: ${projectName}`);
30794
31440
  logger16.step("Applying templates (SDK)", 1);
30795
31441
  const result = await initProject({
@@ -30886,7 +31532,9 @@ var InjectTestAttrsInputSchema = z.object({
30886
31532
  /** Manifest output directory */
30887
31533
  manifestDir: z.string().default(".runa"),
30888
31534
  /** Resolve Zod schemas to JSON Schema (v7+) for API contracts */
30889
- resolveSchemas: z.boolean().default(false)
31535
+ resolveSchemas: z.boolean().default(false),
31536
+ /** Fail when heuristic fallback detection is used */
31537
+ strictDetect: z.boolean().default(false)
30890
31538
  }).strict();
30891
31539
  var FileChangeSchema = z.object({
30892
31540
  filePath: z.string(),
@@ -30898,6 +31546,51 @@ var MachineWithoutE2EMetaSchema = z.object({
30898
31546
  id: z.string(),
30899
31547
  sourceFile: z.string()
30900
31548
  });
31549
+ var DetectionScanSummarySchema = z.object({
31550
+ totalFiles: z.number().int().nonnegative(),
31551
+ filesWithMachineDefinitions: z.number().int().nonnegative(),
31552
+ filesWithMachineHooks: z.number().int().nonnegative(),
31553
+ filesWithJsxOnly: z.number().int().nonnegative()
31554
+ }).strict();
31555
+ var MachineResolutionDetailSchema = z.object({
31556
+ filePath: z.string(),
31557
+ machineRef: z.string(),
31558
+ resolvedId: z.string(),
31559
+ source: z.enum(["explicit", "import", "inline", "fallback"])
31560
+ }).strict();
31561
+ var DetectionDiagnosticsSchema = z.object({
31562
+ schemaVersion: z.literal(1),
31563
+ scan: DetectionScanSummarySchema,
31564
+ resolution: z.object({
31565
+ totalMachineUsages: z.number().int().nonnegative(),
31566
+ bySource: z.object({
31567
+ explicit: z.number().int().nonnegative(),
31568
+ import: z.number().int().nonnegative(),
31569
+ inline: z.number().int().nonnegative(),
31570
+ fallback: z.number().int().nonnegative()
31571
+ }).strict(),
31572
+ fallbackRate: z.number().min(0).max(1),
31573
+ fallbackExamples: z.array(MachineResolutionDetailSchema)
31574
+ }).strict(),
31575
+ coverage: z.object({
31576
+ totalManifestMachines: z.number().int().nonnegative(),
31577
+ linkedManifestMachines: z.number().int().nonnegative(),
31578
+ unlinkedManifestMachines: z.number().int().nonnegative(),
31579
+ machineLinkCoverage: z.number().min(0).max(1),
31580
+ unlinkedManifestMachineIds: z.array(z.string())
31581
+ }).strict(),
31582
+ warnings: z.array(
31583
+ z.object({
31584
+ severity: z.enum(["warning", "info", "hint"]),
31585
+ message: z.string()
31586
+ }).strict()
31587
+ )
31588
+ }).strict();
31589
+ var StrictDetectStatusSchema = z.object({
31590
+ enabled: z.literal(true),
31591
+ passed: z.boolean(),
31592
+ reasons: z.array(z.string())
31593
+ }).strict();
30901
31594
  var InjectTestAttrsOutputSchema = z.object({
30902
31595
  totalFiles: z.number(),
30903
31596
  changedFiles: z.number(),
@@ -30909,17 +31602,98 @@ var InjectTestAttrsOutputSchema = z.object({
30909
31602
  /** Number of machines in manifest */
30910
31603
  manifestMachineCount: z.number().optional(),
30911
31604
  /** Machines without meta.e2e annotation (opt-in warning) */
30912
- machinesWithoutE2EMeta: z.array(MachineWithoutE2EMetaSchema).optional()
31605
+ machinesWithoutE2EMeta: z.array(MachineWithoutE2EMetaSchema).optional(),
31606
+ /** Structured diagnostics for detection quality */
31607
+ detectionDiagnostics: DetectionDiagnosticsSchema.optional(),
31608
+ /** Strict detection mode result */
31609
+ strictDetect: StrictDetectStatusSchema.optional()
30913
31610
  }).strict();
30914
31611
 
30915
31612
  // src/commands/inject-test-attrs/processor.ts
30916
31613
  init_esm_shims();
30917
31614
 
31615
+ // src/commands/inject-test-attrs/detection-diagnostics.ts
31616
+ init_esm_shims();
31617
+ var MAX_EXAMPLES = 20;
31618
+ function normalizeMachineId(id) {
31619
+ return id.replace(/-([a-z])/g, (_, char) => char.toUpperCase()).replace(/Machine$/i, "").toLowerCase();
31620
+ }
31621
+ function buildDetectionDiagnostics(params) {
31622
+ const bySource = {
31623
+ explicit: 0,
31624
+ import: 0,
31625
+ inline: 0,
31626
+ fallback: 0
31627
+ };
31628
+ const fallbackExamples = [];
31629
+ for (const detail of params.resolutionDetails) {
31630
+ bySource[detail.source] += 1;
31631
+ if (detail.source === "fallback" && fallbackExamples.length < MAX_EXAMPLES) {
31632
+ fallbackExamples.push(detail);
31633
+ }
31634
+ }
31635
+ const linkedMachineIds = new Set(
31636
+ params.machineLinks.filter((link) => link.usedIn.length > 0).map((link) => normalizeMachineId(link.machineName))
31637
+ );
31638
+ const linkedManifestMachineIds = [];
31639
+ const unlinkedManifestMachineIds = [];
31640
+ for (const machineId of params.manifestMachineIds) {
31641
+ if (linkedMachineIds.has(normalizeMachineId(machineId))) {
31642
+ linkedManifestMachineIds.push(machineId);
31643
+ continue;
31644
+ }
31645
+ unlinkedManifestMachineIds.push(machineId);
31646
+ }
31647
+ const totalMachineUsages = params.resolutionDetails.length;
31648
+ const fallbackRate = totalMachineUsages > 0 ? bySource.fallback / totalMachineUsages : 0;
31649
+ const totalManifestMachines = params.manifestMachineIds.length;
31650
+ const linkedManifestMachines = linkedManifestMachineIds.length;
31651
+ const machineLinkCoverage = totalManifestMachines > 0 ? linkedManifestMachines / totalManifestMachines : 1;
31652
+ return {
31653
+ schemaVersion: 1,
31654
+ scan: params.scanSummary,
31655
+ resolution: {
31656
+ totalMachineUsages,
31657
+ bySource,
31658
+ fallbackRate,
31659
+ fallbackExamples
31660
+ },
31661
+ coverage: {
31662
+ totalManifestMachines,
31663
+ linkedManifestMachines,
31664
+ unlinkedManifestMachines: totalManifestMachines - linkedManifestMachines,
31665
+ machineLinkCoverage,
31666
+ unlinkedManifestMachineIds: unlinkedManifestMachineIds.slice(0, MAX_EXAMPLES)
31667
+ },
31668
+ warnings: params.warnings
31669
+ };
31670
+ }
31671
+ function evaluateStrictDetect(diagnostics) {
31672
+ const reasons = [];
31673
+ const fallbackCount = diagnostics.resolution.bySource.fallback;
31674
+ if (fallbackCount > 0) {
31675
+ reasons.push(`fallback machine resolution detected (${fallbackCount})`);
31676
+ }
31677
+ if (diagnostics.scan.filesWithMachineHooks > 0 && diagnostics.resolution.totalMachineUsages === 0) {
31678
+ reasons.push(
31679
+ `machine hooks were detected in ${diagnostics.scan.filesWithMachineHooks} files, but no machine usages were resolved`
31680
+ );
31681
+ }
31682
+ if (diagnostics.resolution.totalMachineUsages > 0 && diagnostics.coverage.totalManifestMachines > 0 && diagnostics.coverage.linkedManifestMachines === 0) {
31683
+ reasons.push("machine usages were detected, but no machines were linked to routes/pages");
31684
+ }
31685
+ return {
31686
+ enabled: true,
31687
+ passed: reasons.length === 0,
31688
+ reasons
31689
+ };
31690
+ }
31691
+
30918
31692
  // src/commands/inject-test-attrs/formatter.ts
30919
31693
  init_esm_shims();
30920
31694
  async function formatFilesWithBiome(files, cwd) {
30921
31695
  if (files.length === 0) return;
30922
- const relativePaths = files.map((f) => path10.relative(cwd, f));
31696
+ const relativePaths = files.map((f) => path11.relative(cwd, f));
30923
31697
  try {
30924
31698
  await execa("pnpm", ["exec", "biome", "format", "--write", ...relativePaths], {
30925
31699
  cwd,
@@ -31011,7 +31785,8 @@ function emptyResult(filePath) {
31011
31785
  changed: false,
31012
31786
  actions: [],
31013
31787
  fields: [],
31014
- testIds: []
31788
+ testIds: [],
31789
+ resolutionDetails: []
31015
31790
  };
31016
31791
  }
31017
31792
  function ensureDirectoryExists(dirPath) {
@@ -31021,7 +31796,7 @@ function ensureDirectoryExists(dirPath) {
31021
31796
  }
31022
31797
  function getGeneratorVersion() {
31023
31798
  try {
31024
- const pkgPath = path10.resolve(__dirname$1, "../../../package.json");
31799
+ const pkgPath = path11.resolve(__dirname$1, "../../../package.json");
31025
31800
  if (fs5.existsSync(pkgPath)) {
31026
31801
  const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
31027
31802
  return pkg.version ?? "unknown";
@@ -31036,15 +31811,15 @@ function detectPlatform(repoRoot) {
31036
31811
  const nextConfigPatterns = ["next.config.ts", "next.config.js", "next.config.mjs"];
31037
31812
  for (const pattern of nextConfigPatterns) {
31038
31813
  const paths = [
31039
- path10.join(repoRoot, pattern),
31040
- path10.join(repoRoot, "apps", "web", pattern),
31041
- path10.join(repoRoot, "apps", "dashboard", pattern)
31814
+ path11.join(repoRoot, pattern),
31815
+ path11.join(repoRoot, "apps", "web", pattern),
31816
+ path11.join(repoRoot, "apps", "dashboard", pattern)
31042
31817
  ];
31043
31818
  if (paths.some((p) => fs5.existsSync(p))) {
31044
31819
  return "nextjs";
31045
31820
  }
31046
31821
  }
31047
- const appJsonPath = path10.join(repoRoot, "app.json");
31822
+ const appJsonPath = path11.join(repoRoot, "app.json");
31048
31823
  if (fs5.existsSync(appJsonPath)) {
31049
31824
  try {
31050
31825
  const appJson = JSON.parse(fs5.readFileSync(appJsonPath, "utf-8"));
@@ -31054,7 +31829,7 @@ function detectPlatform(repoRoot) {
31054
31829
  } catch {
31055
31830
  }
31056
31831
  }
31057
- if (fs5.existsSync(path10.join(repoRoot, "expo.json"))) {
31832
+ if (fs5.existsSync(path11.join(repoRoot, "expo.json"))) {
31058
31833
  return "expo";
31059
31834
  }
31060
31835
  const electronPatterns = [
@@ -31063,56 +31838,38 @@ function detectPlatform(repoRoot) {
31063
31838
  "electron.vite.config.ts",
31064
31839
  "electron.vite.config.js"
31065
31840
  ];
31066
- if (electronPatterns.some((p) => fs5.existsSync(path10.join(repoRoot, p)))) {
31841
+ if (electronPatterns.some((p) => fs5.existsSync(path11.join(repoRoot, p)))) {
31067
31842
  return "electron";
31068
31843
  }
31069
31844
  return "unknown";
31070
31845
  }
31071
- function findPossibleHonoDirs(repoRoot) {
31072
- const possibleDirs = [];
31073
- const appsDir = path10.join(repoRoot, "apps");
31074
- if (fs5.existsSync(appsDir)) {
31075
- try {
31076
- const apps = fs5.readdirSync(appsDir, { withFileTypes: true });
31077
- for (const app of apps) {
31078
- if (app.isDirectory()) {
31079
- const routesDir = path10.join(appsDir, app.name, "routes");
31080
- if (fs5.existsSync(routesDir)) {
31081
- const files = fs5.readdirSync(routesDir);
31082
- const hasRouteFiles = files.some(
31083
- (f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.endsWith(".spec.ts")
31084
- );
31085
- if (hasRouteFiles) {
31086
- possibleDirs.push(`apps/${app.name}/routes`);
31087
- }
31088
- }
31089
- }
31090
- }
31091
- } catch {
31092
- }
31846
+ function hasHonoRouteFiles(dir) {
31847
+ try {
31848
+ const files = fs5.readdirSync(dir);
31849
+ return files.some(
31850
+ (file) => file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".spec.ts")
31851
+ );
31852
+ } catch {
31853
+ return false;
31093
31854
  }
31094
- const packagesDir = path10.join(repoRoot, "packages");
31095
- if (fs5.existsSync(packagesDir)) {
31096
- try {
31097
- const packages = fs5.readdirSync(packagesDir, { withFileTypes: true });
31098
- for (const pkg of packages) {
31099
- if (pkg.isDirectory()) {
31100
- const routesDir = path10.join(packagesDir, pkg.name, "routes");
31101
- if (fs5.existsSync(routesDir)) {
31102
- const files = fs5.readdirSync(routesDir);
31103
- const hasRouteFiles = files.some(
31104
- (f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.endsWith(".spec.ts")
31105
- );
31106
- if (hasRouteFiles) {
31107
- possibleDirs.push(`packages/${pkg.name}/routes`);
31108
- }
31109
- }
31110
- }
31111
- }
31112
- } catch {
31113
- }
31855
+ }
31856
+ function collectRouteDirsInScope(repoRoot, scope) {
31857
+ const scopeDir = path11.join(repoRoot, scope);
31858
+ if (!fs5.existsSync(scopeDir)) {
31859
+ return [];
31114
31860
  }
31115
- return possibleDirs;
31861
+ try {
31862
+ const entries = fs5.readdirSync(scopeDir, { withFileTypes: true });
31863
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((entryName) => hasHonoRouteFiles(path11.join(scopeDir, entryName, "routes"))).map((entryName) => `${scope}/${entryName}/routes`);
31864
+ } catch {
31865
+ return [];
31866
+ }
31867
+ }
31868
+ function findPossibleHonoDirs(repoRoot) {
31869
+ return [
31870
+ ...collectRouteDirsInScope(repoRoot, "apps"),
31871
+ ...collectRouteDirsInScope(repoRoot, "packages")
31872
+ ];
31116
31873
  }
31117
31874
  function collectManifestWarnings(repoRoot, platform, apiContracts, machinesWithoutE2EMeta, totalMachines) {
31118
31875
  const warnings = [];
@@ -31163,15 +31920,18 @@ function printManifestWarnings(warnings, verbose) {
31163
31920
  for (const detail of warning.details) {
31164
31921
  console.log(detail);
31165
31922
  }
31166
- if (warning.details.length < warning._totalCount) {
31167
- console.log(` ... and more`);
31168
- }
31169
31923
  }
31170
31924
  if (warning.fix) {
31171
31925
  console.log(` \u2192 ${warning.fix}`);
31172
31926
  }
31173
31927
  }
31174
31928
  }
31929
+ function toDetectionWarnings(warnings) {
31930
+ return warnings.map((warning) => ({
31931
+ severity: warning.severity,
31932
+ message: warning.message
31933
+ }));
31934
+ }
31175
31935
  function normalizeToCanonicalId(id) {
31176
31936
  return id.replace(/-([a-z])/g, (_, c) => c.toUpperCase()).replace(/Machine$/i, "");
31177
31937
  }
@@ -31259,7 +32019,7 @@ async function analyzeHonoRoutes(repoRoot, verbose, resolveSchemas = false) {
31259
32019
  return { apiContracts: [], schemasResolved: false };
31260
32020
  }
31261
32021
  if (verbose) {
31262
- console.log(` Analyzing Hono routes in: ${path10.relative(repoRoot, routesPath)}`);
32022
+ console.log(` Analyzing Hono routes in: ${path11.relative(repoRoot, routesPath)}`);
31263
32023
  if (resolveSchemas) {
31264
32024
  console.log(" Schema resolution enabled (--resolve-schemas)");
31265
32025
  }
@@ -31305,7 +32065,7 @@ async function analyzeHonoRoutes(repoRoot, verbose, resolveSchemas = false) {
31305
32065
  return { apiContracts: [], schemasResolved: false };
31306
32066
  }
31307
32067
  }
31308
- async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSchemas = false) {
32068
+ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSchemas = false, diagnosticsInput) {
31309
32069
  const registry = getInjectionRegistry();
31310
32070
  const generatorVersion = getGeneratorVersion();
31311
32071
  const e2eManifest = buildManifest(registry, generatorVersion);
@@ -31319,18 +32079,18 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31319
32079
  }
31320
32080
  const definitionMap = buildDefinitionMap(machineDefinitions);
31321
32081
  const enhancedMachines = buildEnhancedMachines(e2eManifest, definitionMap, machineDefinitions);
31322
- const absoluteManifestDir = path10.isAbsolute(manifestDir) ? manifestDir : path10.join(repoRoot, manifestDir);
32082
+ const absoluteManifestDir = path11.isAbsolute(manifestDir) ? manifestDir : path11.join(repoRoot, manifestDir);
31323
32083
  if (!isPathContained(repoRoot, absoluteManifestDir)) {
31324
32084
  throw new Error(
31325
32085
  `Security error: Manifest directory '${manifestDir}' would escape the project root. The --manifest-dir must be a relative path within the project directory.`
31326
32086
  );
31327
32087
  }
31328
32088
  ensureDirectoryExists(absoluteManifestDir);
31329
- const generatedDir = path10.join(absoluteManifestDir, "generated");
32089
+ const generatedDir = path11.join(absoluteManifestDir, "generated");
31330
32090
  ensureDirectoryExists(generatedDir);
31331
- const manifestsDir = path10.join(absoluteManifestDir, "manifests");
32091
+ const manifestsDir = path11.join(absoluteManifestDir, "manifests");
31332
32092
  ensureDirectoryExists(manifestsDir);
31333
- const tsPath = path10.join(generatedDir, "selectors.ts");
32093
+ const tsPath = path11.join(generatedDir, "selectors.ts");
31334
32094
  await fs5.promises.writeFile(tsPath, generateSelectorTypeScript(e2eManifest), "utf-8");
31335
32095
  const unifiedRegistry = getUnifiedRegistry();
31336
32096
  const machineLinks = buildMachineLinks();
@@ -31345,6 +32105,29 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31345
32105
  const jstOffset = 9 * 60 * 60 * 1e3;
31346
32106
  const jst = new Date(now.getTime() + jstOffset);
31347
32107
  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`;
32108
+ const machinesWithoutE2EMeta = machineDefinitions.filter(
32109
+ (def) => !def.hasE2EMeta && typeof def.id === "string"
32110
+ ).map((def) => ({ id: def.id, sourceFile: def.sourceFile }));
32111
+ const warnings = collectManifestWarnings(
32112
+ repoRoot,
32113
+ platform,
32114
+ apiContracts,
32115
+ machinesWithoutE2EMeta,
32116
+ machineDefinitions.length
32117
+ );
32118
+ printManifestWarnings(warnings, verbose);
32119
+ const detectionDiagnostics = buildDetectionDiagnostics({
32120
+ scanSummary: diagnosticsInput?.scanSummary ?? {
32121
+ totalFiles: 0,
32122
+ filesWithMachineDefinitions: 0,
32123
+ filesWithMachineHooks: 0,
32124
+ filesWithJsxOnly: 0
32125
+ },
32126
+ resolutionDetails: diagnosticsInput?.resolutionDetails ?? [],
32127
+ manifestMachineIds: Object.keys(enhancedMachines),
32128
+ machineLinks,
32129
+ warnings: toDetectionWarnings(warnings)
32130
+ });
31348
32131
  const unifiedManifest = {
31349
32132
  version: manifestVersion,
31350
32133
  generatedAt: generatedAtJST,
@@ -31357,17 +32140,15 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31357
32140
  authBoundaries: unifiedRegistry.authBoundaries,
31358
32141
  machineDefinitions: unifiedRegistry.machineDefinitions,
31359
32142
  machineLinks,
31360
- apiContracts
32143
+ apiContracts,
32144
+ detectionDiagnostics
31361
32145
  };
31362
- const manifestPath = path10.join(manifestsDir, "manifest.json");
32146
+ const manifestPath = path11.join(manifestsDir, "manifest.json");
31363
32147
  await fs5.promises.writeFile(manifestPath, JSON.stringify(unifiedManifest, null, 2), "utf-8");
31364
- const machinesWithoutE2EMeta = machineDefinitions.filter(
31365
- (def) => !def.hasE2EMeta && typeof def.id === "string"
31366
- ).map((def) => ({ id: def.id, sourceFile: def.sourceFile }));
31367
32148
  if (verbose) {
31368
- console.log(`Generated selectors: ${path10.relative(repoRoot, tsPath)}`);
32149
+ console.log(`Generated selectors: ${path11.relative(repoRoot, tsPath)}`);
31369
32150
  console.log(
31370
- `Generated manifest: ${path10.relative(repoRoot, manifestPath)} (v${manifestVersion})`
32151
+ `Generated manifest: ${path11.relative(repoRoot, manifestPath)} (v${manifestVersion})`
31371
32152
  );
31372
32153
  console.log(` Platform: ${platform}`);
31373
32154
  console.log(` Machine definitions: ${machineDefinitions.length}`);
@@ -31381,19 +32162,15 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
31381
32162
  ` API contracts: ${apiContracts.length}${schemasResolved ? " (with schemas)" : ""}`
31382
32163
  );
31383
32164
  console.log(` Machine links: ${machineLinks.length}`);
32165
+ console.log(
32166
+ ` Detection: fallback=${detectionDiagnostics.resolution.bySource.fallback}, linkCoverage=${(detectionDiagnostics.coverage.machineLinkCoverage * 100).toFixed(1)}%`
32167
+ );
31384
32168
  }
31385
- const warnings = collectManifestWarnings(
31386
- repoRoot,
31387
- platform,
31388
- apiContracts,
31389
- machinesWithoutE2EMeta,
31390
- machineDefinitions.length
31391
- );
31392
- printManifestWarnings(warnings, verbose);
31393
32169
  return {
31394
- manifestPath: path10.relative(repoRoot, tsPath),
32170
+ manifestPath: path11.relative(repoRoot, tsPath),
31395
32171
  machineCount: Object.keys(enhancedMachines).length,
31396
- machinesWithoutE2EMeta
32172
+ machinesWithoutE2EMeta,
32173
+ detectionDiagnostics
31397
32174
  };
31398
32175
  }
31399
32176
 
@@ -31425,7 +32202,7 @@ function registerExistingInjections(machineIds, attrs, sourceFile) {
31425
32202
  }
31426
32203
  async function preprocessFile(filePath, repoRoot, options) {
31427
32204
  let code = await fs5.promises.readFile(filePath, "utf-8");
31428
- const relativePath = path10.relative(repoRoot, filePath);
32205
+ const relativePath = path11.relative(repoRoot, filePath);
31429
32206
  collectRouteInfo(relativePath, code, options.verbose);
31430
32207
  const hasMarker = code.includes(CLI_INJECTION_MARKER);
31431
32208
  if (hasMarker && options.force) {
@@ -31456,14 +32233,15 @@ async function preprocessFile(filePath, repoRoot, options) {
31456
32233
  injectedCount: 0,
31457
32234
  machineIds,
31458
32235
  changed: false,
31459
- ...attrs
32236
+ ...attrs,
32237
+ resolutionDetails: []
31460
32238
  }
31461
32239
  };
31462
32240
  }
31463
32241
  return { code, hasMarker: false, skipped: false };
31464
32242
  }
31465
32243
  function transformAndRegister(filePath, code, repoRoot, options) {
31466
- const relativePath = path10.relative(repoRoot, filePath);
32244
+ const relativePath = path11.relative(repoRoot, filePath);
31467
32245
  const readAndParseFile = createReadAndParseFile(options.verbose);
31468
32246
  const resolveImportPath = createResolveImportPath();
31469
32247
  try {
@@ -31479,6 +32257,14 @@ function transformAndRegister(filePath, code, repoRoot, options) {
31479
32257
  const transformedCode = markerComment + result.code;
31480
32258
  const { actions, fields, testIds } = extractInjectedAttributes(transformedCode);
31481
32259
  const machineIds = [...result.resolvedIds.values()];
32260
+ const resultWithResolution = result;
32261
+ const rawResolutionDetails = Array.isArray(resultWithResolution.resolutionDetails) ? resultWithResolution.resolutionDetails : [];
32262
+ const resolutionDetails = rawResolutionDetails.map((detail) => ({
32263
+ filePath: relativePath,
32264
+ machineRef: detail.machineRef,
32265
+ resolvedId: detail.resolvedId,
32266
+ source: detail.source
32267
+ }));
31482
32268
  registerExistingInjections(machineIds, { actions, fields, testIds }, relativePath);
31483
32269
  return {
31484
32270
  filePath,
@@ -31488,7 +32274,8 @@ function transformAndRegister(filePath, code, repoRoot, options) {
31488
32274
  transformedCode,
31489
32275
  actions,
31490
32276
  fields,
31491
- testIds
32277
+ testIds,
32278
+ resolutionDetails
31492
32279
  };
31493
32280
  } catch (error) {
31494
32281
  if (options.verbose) {
@@ -31509,7 +32296,7 @@ async function processFileForChildInjection(filePath, repoRoot, options) {
31509
32296
  if (prep.skipped && prep.skipResult) return prep.skipResult;
31510
32297
  const result = transformAndRegister(filePath, prep.code, repoRoot, options);
31511
32298
  if (options.verbose && result.changed && result.injectedCount > 0) {
31512
- const relativePath = path10.relative(repoRoot, filePath);
32299
+ const relativePath = path11.relative(repoRoot, filePath);
31513
32300
  console.log(
31514
32301
  ` [child] Injected ${result.injectedCount} attrs in ${relativePath} (actions: ${result.actions.join(", ")})`
31515
32302
  );
@@ -31529,7 +32316,7 @@ async function handleChangedFile(result, check, repoRoot, verbose, state2) {
31529
32316
  await fs5.promises.writeFile(result.filePath, result.transformedCode, "utf-8");
31530
32317
  state2.filesToFormat.push(result.filePath);
31531
32318
  if (verbose) {
31532
- const relativePath = path10.relative(repoRoot, result.filePath);
32319
+ const relativePath = path11.relative(repoRoot, result.filePath);
31533
32320
  console.log(` Injected ${result.injectedCount} attrs in ${relativePath}`);
31534
32321
  }
31535
32322
  }
@@ -31540,6 +32327,60 @@ async function formatChangedFiles(filesToFormat, repoRoot, verbose) {
31540
32327
  }
31541
32328
  await formatFilesWithBiome(filesToFormat, repoRoot);
31542
32329
  }
32330
+ function createScanSummary(params) {
32331
+ return {
32332
+ totalFiles: params.files.length,
32333
+ filesWithMachineDefinitions: params.withMachineDefinitions.length,
32334
+ filesWithMachineHooks: params.withMachineHooks.length,
32335
+ filesWithJsxOnly: params.withJsxOnly.length
32336
+ };
32337
+ }
32338
+ async function resolveManifestArtifacts(params) {
32339
+ let manifestPath;
32340
+ let manifestMachineCount;
32341
+ let machinesWithoutE2EMeta;
32342
+ let detectionDiagnostics;
32343
+ if (params.manifest && !params.check) {
32344
+ const diagnosticsInput = {
32345
+ scanSummary: params.scanSummary,
32346
+ resolutionDetails: params.resolutionDetails
32347
+ };
32348
+ const manifestResult = await generateManifestFiles(
32349
+ params.manifestDir,
32350
+ params.repoRoot,
32351
+ params.verbose,
32352
+ params.resolveSchemas,
32353
+ diagnosticsInput
32354
+ );
32355
+ manifestPath = manifestResult.manifestPath;
32356
+ manifestMachineCount = manifestResult.machineCount;
32357
+ machinesWithoutE2EMeta = manifestResult.machinesWithoutE2EMeta;
32358
+ detectionDiagnostics = manifestResult.detectionDiagnostics;
32359
+ } else if (params.manifest && params.check) {
32360
+ const warnings = [];
32361
+ detectionDiagnostics = buildDetectionDiagnostics({
32362
+ scanSummary: params.scanSummary,
32363
+ resolutionDetails: params.resolutionDetails,
32364
+ manifestMachineIds: [],
32365
+ machineLinks: [],
32366
+ warnings
32367
+ });
32368
+ }
32369
+ const strictDetectStatus = params.strictDetect ? detectionDiagnostics ? evaluateStrictDetect(detectionDiagnostics) : {
32370
+ enabled: true,
32371
+ passed: false,
32372
+ reasons: [
32373
+ "strict detect requires manifest diagnostics, but diagnostics were unavailable"
32374
+ ]
32375
+ } : void 0;
32376
+ return {
32377
+ manifestPath,
32378
+ manifestMachineCount,
32379
+ machinesWithoutE2EMeta,
32380
+ detectionDiagnostics,
32381
+ strictDetectStatus
32382
+ };
32383
+ }
31543
32384
  function mightContainMachineDefinition(code) {
31544
32385
  return code.includes("createMachine");
31545
32386
  }
@@ -31563,13 +32404,34 @@ async function categorizeFiles(files) {
31563
32404
  return { withMachineDefinitions, withMachineHooks, withJsxOnly };
31564
32405
  }
31565
32406
  async function processFiles(options) {
31566
- const { repoRoot, check, verbose, include, exclude, manifest, manifestDir, resolveSchemas } = options;
32407
+ const {
32408
+ repoRoot,
32409
+ check,
32410
+ verbose,
32411
+ include,
32412
+ exclude,
32413
+ manifest,
32414
+ manifestDir,
32415
+ resolveSchemas,
32416
+ strictDetect
32417
+ } = options;
31567
32418
  clearInjectionRegistry();
31568
32419
  clearUnifiedRegistry();
31569
32420
  const files = await discoverFiles(repoRoot, include, exclude);
31570
32421
  if (verbose) console.log(`Found ${files.length} files to process`);
31571
- const state2 = { changes: [], filesToFormat: [], totalInjections: 0 };
32422
+ const state2 = {
32423
+ changes: [],
32424
+ filesToFormat: [],
32425
+ totalInjections: 0,
32426
+ resolutionDetails: []
32427
+ };
31572
32428
  const { withMachineDefinitions, withMachineHooks, withJsxOnly } = await categorizeFiles(files);
32429
+ const scanSummary = createScanSummary({
32430
+ files,
32431
+ withMachineDefinitions,
32432
+ withMachineHooks,
32433
+ withJsxOnly
32434
+ });
31573
32435
  if (verbose) {
31574
32436
  console.log(` Files with machine definitions: ${withMachineDefinitions.length}`);
31575
32437
  console.log(` Files with machine hooks: ${withMachineHooks.length}`);
@@ -31579,46 +32441,50 @@ async function processFiles(options) {
31579
32441
  for (const filePath of withMachineDefinitions) {
31580
32442
  try {
31581
32443
  const code = await fs5.promises.readFile(filePath, "utf-8");
31582
- const relativePath = path10.relative(repoRoot, filePath);
32444
+ const relativePath = path11.relative(repoRoot, filePath);
31583
32445
  collectRouteInfo(relativePath, code, verbose);
31584
32446
  } catch {
31585
32447
  }
31586
32448
  }
31587
32449
  for (const filePath of withMachineHooks) {
31588
32450
  const result = await processFile(filePath, repoRoot, processOpts);
32451
+ state2.resolutionDetails.push(...result.resolutionDetails);
31589
32452
  await handleChangedFile(result, check, repoRoot, verbose, state2);
31590
32453
  }
31591
32454
  for (const filePath of withJsxOnly) {
31592
32455
  const result = await processFileForChildInjection(filePath, repoRoot, processOpts);
32456
+ state2.resolutionDetails.push(...result.resolutionDetails);
31593
32457
  await handleChangedFile(result, check, repoRoot, verbose, state2);
31594
32458
  }
31595
32459
  if (!check) {
31596
32460
  await formatChangedFiles(state2.filesToFormat, repoRoot, verbose);
31597
32461
  }
31598
32462
  postProcessRegistries();
31599
- let manifestPath;
31600
- let manifestMachineCount;
31601
- let machinesWithoutE2EMeta;
31602
- if (manifest && !check) {
31603
- const manifestResult = await generateManifestFiles(
31604
- manifestDir,
31605
- repoRoot,
31606
- verbose,
31607
- resolveSchemas ?? false
31608
- );
31609
- manifestPath = manifestResult.manifestPath;
31610
- manifestMachineCount = manifestResult.machineCount;
31611
- machinesWithoutE2EMeta = manifestResult.machinesWithoutE2EMeta;
31612
- }
32463
+ const manifestArtifacts = await resolveManifestArtifacts({
32464
+ manifest,
32465
+ check,
32466
+ manifestDir,
32467
+ repoRoot,
32468
+ verbose,
32469
+ resolveSchemas: resolveSchemas ?? false,
32470
+ strictDetect: strictDetect ?? false,
32471
+ scanSummary,
32472
+ resolutionDetails: state2.resolutionDetails
32473
+ });
32474
+ const hasCheckFailure = check && state2.changes.length > 0;
32475
+ const hasStrictDetectFailure = manifestArtifacts.strictDetectStatus?.passed === false;
32476
+ const exitCode = hasCheckFailure || hasStrictDetectFailure ? 1 : 0;
31613
32477
  return {
31614
32478
  totalFiles: files.length,
31615
32479
  changedFiles: state2.changes.length,
31616
32480
  totalInjections: state2.totalInjections,
31617
32481
  changes: state2.changes,
31618
- exitCode: check && state2.changes.length > 0 ? 1 : 0,
31619
- manifestPath,
31620
- manifestMachineCount,
31621
- machinesWithoutE2EMeta
32482
+ exitCode,
32483
+ manifestPath: manifestArtifacts.manifestPath,
32484
+ manifestMachineCount: manifestArtifacts.manifestMachineCount,
32485
+ machinesWithoutE2EMeta: manifestArtifacts.machinesWithoutE2EMeta,
32486
+ detectionDiagnostics: manifestArtifacts.detectionDiagnostics,
32487
+ strictDetect: manifestArtifacts.strictDetectStatus
31622
32488
  };
31623
32489
  }
31624
32490
 
@@ -31678,6 +32544,35 @@ function logMachinesWithoutE2EMeta(result, logger16) {
31678
32544
  logger16.info(" }");
31679
32545
  logger16.info(" See: .claude/rules/xstate-design.md#meta.e2e");
31680
32546
  }
32547
+ function logDetectionDiagnostics(result, logger16) {
32548
+ if (!result.detectionDiagnostics) return;
32549
+ const diagnostics = result.detectionDiagnostics;
32550
+ const fallbackCount = diagnostics.resolution.bySource.fallback;
32551
+ const fallbackRate = (diagnostics.resolution.fallbackRate * 100).toFixed(1);
32552
+ const coverage = (diagnostics.coverage.machineLinkCoverage * 100).toFixed(1);
32553
+ logger16.info("");
32554
+ logger16.info(
32555
+ `Detection diagnostics: usages=${diagnostics.resolution.totalMachineUsages}, fallback=${fallbackCount} (${fallbackRate}%), linkCoverage=${coverage}%`
32556
+ );
32557
+ if (fallbackCount > 0) {
32558
+ for (const item of diagnostics.resolution.fallbackExamples.slice(0, 5)) {
32559
+ logger16.warn(
32560
+ ` fallback: ${item.filePath} :: ${item.machineRef} -> ${item.resolvedId} (${item.source})`
32561
+ );
32562
+ }
32563
+ }
32564
+ }
32565
+ function logStrictDetect(result, logger16) {
32566
+ if (!result.strictDetect) return;
32567
+ if (result.strictDetect.passed) {
32568
+ logger16.success("Strict detect passed (no fallback resolution)");
32569
+ return;
32570
+ }
32571
+ logger16.error("Strict detect failed");
32572
+ for (const reason of result.strictDetect.reasons) {
32573
+ logger16.error(` - ${reason}`);
32574
+ }
32575
+ }
31681
32576
  async function injectTestAttrsAction(rawOptions, command) {
31682
32577
  const logger16 = createCLILogger("manifest");
31683
32578
  const parseResult = InjectTestAttrsInputSchema.safeParse(rawOptions);
@@ -31688,6 +32583,20 @@ async function injectTestAttrsAction(rawOptions, command) {
31688
32583
  ]);
31689
32584
  }
31690
32585
  const options = parseResult.data;
32586
+ if (options.strictDetect && options.check) {
32587
+ throw new CLIError(
32588
+ "--strict-detect cannot be used with --check",
32589
+ "STRICT_DETECT_CHECK_UNSUPPORTED",
32590
+ ["Run without --check to evaluate strict detection against manifest diagnostics"]
32591
+ );
32592
+ }
32593
+ if (options.strictDetect && !options.manifest) {
32594
+ throw new CLIError(
32595
+ "--strict-detect requires manifest generation",
32596
+ "STRICT_DETECT_MANIFEST_REQUIRED",
32597
+ ["Remove --no-manifest, or disable --strict-detect"]
32598
+ );
32599
+ }
31691
32600
  const repoRoot = findProjectRoot$1() ?? process.cwd();
31692
32601
  if (!options.check) {
31693
32602
  logger16.section("Generating manifest (manifest.json)");
@@ -31706,6 +32615,8 @@ async function injectTestAttrsAction(rawOptions, command) {
31706
32615
  logResultSummary(result, options, logger16);
31707
32616
  logManifestInfo(result, logger16);
31708
32617
  logMachinesWithoutE2EMeta(result, logger16);
32618
+ logDetectionDiagnostics(result, logger16);
32619
+ logStrictDetect(result, logger16);
31709
32620
  emitJsonSuccess(command, InjectTestAttrsOutputSchema, result);
31710
32621
  if (result.exitCode !== 0) {
31711
32622
  process.exit(result.exitCode);
@@ -31725,7 +32636,7 @@ var injectTestAttrsCommand = new Command("inject-test-attrs").description("Injec
31725
32636
  "**/*.test.*",
31726
32637
  "**/*.spec.*",
31727
32638
  "**/*.stories.*"
31728
- ]).option("--no-manifest", "Skip E2E selector manifest generation").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").action(async (rawOptions) => {
32639
+ ]).option("--no-manifest", "Skip E2E selector manifest generation").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").option("--strict-detect", "Fail when fallback machine detection is used (for deterministic CI)").action(async (rawOptions) => {
31729
32640
  await injectTestAttrsAction(rawOptions, injectTestAttrsCommand);
31730
32641
  });
31731
32642
 
@@ -31789,7 +32700,7 @@ var manifestCommand = new Command("manifest").description("Generate E2E manifest
31789
32700
  "**/*.test.*",
31790
32701
  "**/*.spec.*",
31791
32702
  "**/*.stories.*"
31792
- ]).option("--no-manifest", "Skip manifest file generation (attributes only)").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").action(async (options) => {
32703
+ ]).option("--no-manifest", "Skip manifest file generation (attributes only)").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").option("--strict-detect", "Fail when fallback machine detection is used (for deterministic CI)").action(async (options) => {
31793
32704
  await injectTestAttrsAction(options, manifestCommand);
31794
32705
  });
31795
32706
 
@@ -31848,7 +32759,7 @@ function assertNodeAuthToken(options) {
31848
32759
  }
31849
32760
  }
31850
32761
  function getPackageVersion(packagePath) {
31851
- const packageJsonPath = path10__default.join(packagePath, "package.json");
32762
+ const packageJsonPath = path11__default.join(packagePath, "package.json");
31852
32763
  if (!existsSync(packageJsonPath)) {
31853
32764
  throw new CLIError(`package.json not found at ${packagePath}`, "PACKAGE_NOT_FOUND");
31854
32765
  }
@@ -31867,7 +32778,7 @@ function resolveWorkspaceDependencies(workspaceRoot, packages, logger16) {
31867
32778
  const sdkPackage = packages.find((p) => p.name === "SDK");
31868
32779
  const xstatePluginPackage = packages.find((p) => p.name === "xstate-test-plugin");
31869
32780
  if (!sdkPackage) return;
31870
- const cliPackagePath = path10__default.join(workspaceRoot, "packages", "cli", "package.json");
32781
+ const cliPackagePath = path11__default.join(workspaceRoot, "packages", "cli", "package.json");
31871
32782
  if (!existsSync(cliPackagePath)) return;
31872
32783
  let content = readFileSync(cliPackagePath, "utf-8");
31873
32784
  let updated = false;
@@ -31896,7 +32807,7 @@ function resolveWorkspaceDependencies(workspaceRoot, packages, logger16) {
31896
32807
  }
31897
32808
  }
31898
32809
  function restoreWorkspaceDependencies(workspaceRoot) {
31899
- const cliPackagePath = path10__default.join(workspaceRoot, "packages", "cli", "package.json");
32810
+ const cliPackagePath = path11__default.join(workspaceRoot, "packages", "cli", "package.json");
31900
32811
  if (!existsSync(cliPackagePath)) return;
31901
32812
  let content = readFileSync(cliPackagePath, "utf-8");
31902
32813
  content = content.replace(/"@runa-ai\/runa": "\^[\d.]+"/, '"@runa-ai/runa": "workspace:*"');
@@ -32008,7 +32919,7 @@ function collectPackageInfo(workspaceRoot, logger16, stepNum) {
32008
32919
  logger16.step("Collecting package info", stepNum);
32009
32920
  const packages = [];
32010
32921
  for (const pkgConfig of PUBLISHABLE_PACKAGES) {
32011
- const pkgPath = path10__default.join(workspaceRoot, "packages", pkgConfig.dir);
32922
+ const pkgPath = path11__default.join(workspaceRoot, "packages", pkgConfig.dir);
32012
32923
  const version = getPackageVersion(pkgPath);
32013
32924
  const exists = checkVersionExists(pkgConfig.publishName, version);
32014
32925
  packages.push({
@@ -33397,8 +34308,8 @@ var compareActor = fromPromise(async ({ input: input3 }) => {
33397
34308
  const result = compareBothFiles(
33398
34309
  runaRelPath,
33399
34310
  templateRelPath,
33400
- path10.join(repoRoot, runaRelPath),
33401
- path10.join(templateDir, templateRelPath),
34311
+ path11.join(repoRoot, runaRelPath),
34312
+ path11.join(templateDir, templateRelPath),
33402
34313
  runaFile.category,
33403
34314
  options.diff ?? false
33404
34315
  );
@@ -33849,7 +34760,7 @@ var discoverActor = fromPromise(async ({ input: input3 }) => {
33849
34760
  const runaPattern = rule.runa;
33850
34761
  const runaFiles = await globFiles(repoRoot, runaPattern);
33851
34762
  for (const file of runaFiles) {
33852
- const relativePath = path10.relative(repoRoot, file.absolutePath);
34763
+ const relativePath = path11.relative(repoRoot, file.absolutePath);
33853
34764
  const key = generateComparisonKey(relativePath, false);
33854
34765
  inventory.runaFiles.set(relativePath, {
33855
34766
  ...file,
@@ -33863,7 +34774,7 @@ var discoverActor = fromPromise(async ({ input: input3 }) => {
33863
34774
  const templatePattern = rule.template;
33864
34775
  const templateFiles = await globFiles(templateDir, templatePattern);
33865
34776
  for (const file of templateFiles) {
33866
- const relativePath = path10.relative(templateDir, file.absolutePath);
34777
+ const relativePath = path11.relative(templateDir, file.absolutePath);
33867
34778
  const key = generateComparisonKey(relativePath, true);
33868
34779
  inventory.templateFiles.set(relativePath, {
33869
34780
  ...file,
@@ -33912,7 +34823,7 @@ async function matchDoubleWildcard(ctx, entries) {
33912
34823
  await walkAndMatch({ ...ctx, partIndex: ctx.partIndex + 1 });
33913
34824
  for (const entry of entries) {
33914
34825
  if (entry.isDirectory()) {
33915
- const subDir = path10.join(ctx.currentDir, entry.name);
34826
+ const subDir = path11.join(ctx.currentDir, entry.name);
33916
34827
  await walkAndMatch({ ...ctx, currentDir: subDir });
33917
34828
  }
33918
34829
  }
@@ -33921,7 +34832,7 @@ async function matchSingleWildcard(ctx, entries, pattern, isLastPart) {
33921
34832
  const regex = patternToRegex(pattern);
33922
34833
  for (const entry of entries) {
33923
34834
  if (regex.test(entry.name)) {
33924
- const entryPath = path10.join(ctx.currentDir, entry.name);
34835
+ const entryPath = path11.join(ctx.currentDir, entry.name);
33925
34836
  await processEntry(ctx, entryPath, entry.isFile(), entry.isDirectory(), isLastPart);
33926
34837
  }
33927
34838
  }
@@ -33931,14 +34842,14 @@ async function matchBraceExpansion(ctx, entries, pattern, isLastPart) {
33931
34842
  for (const option of options) {
33932
34843
  for (const entry of entries) {
33933
34844
  if (entry.name === option) {
33934
- const entryPath = path10.join(ctx.currentDir, entry.name);
34845
+ const entryPath = path11.join(ctx.currentDir, entry.name);
33935
34846
  await processEntry(ctx, entryPath, entry.isFile(), entry.isDirectory(), isLastPart);
33936
34847
  }
33937
34848
  }
33938
34849
  }
33939
34850
  }
33940
34851
  async function matchLiteral(ctx, pattern, isLastPart) {
33941
- const entryPath = path10.join(ctx.currentDir, pattern);
34852
+ const entryPath = path11.join(ctx.currentDir, pattern);
33942
34853
  if (!fs5.existsSync(entryPath)) return;
33943
34854
  const stats = fs5.statSync(entryPath);
33944
34855
  await processEntry(ctx, entryPath, stats.isFile(), stats.isDirectory(), isLastPart);
@@ -34463,15 +35374,15 @@ function printActionsNeeded(logger16, actions) {
34463
35374
  );
34464
35375
  }
34465
35376
  function findRepoRoot3(startDir) {
34466
- const { existsSync: existsSync51, readFileSync: readFileSync29 } = __require("fs");
35377
+ const { existsSync: existsSync52, readFileSync: readFileSync29 } = __require("fs");
34467
35378
  const { join: join23, dirname: dirname5 } = __require("path");
34468
35379
  let current = startDir;
34469
35380
  while (current !== dirname5(current)) {
34470
- if (existsSync51(join23(current, "turbo.json"))) {
35381
+ if (existsSync52(join23(current, "turbo.json"))) {
34471
35382
  return current;
34472
35383
  }
34473
35384
  const pkgPath = join23(current, "package.json");
34474
- if (existsSync51(pkgPath)) {
35385
+ if (existsSync52(pkgPath)) {
34475
35386
  try {
34476
35387
  const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
34477
35388
  if (pkg.workspaces) {
@@ -34539,10 +35450,10 @@ function generateReportOutput(output3, isJsonMode) {
34539
35450
  };
34540
35451
  }
34541
35452
  function validateRunaRepo(repoRoot) {
34542
- const { existsSync: existsSync51 } = __require("fs");
35453
+ const { existsSync: existsSync52 } = __require("fs");
34543
35454
  const { join: join23 } = __require("path");
34544
35455
  const templateDir = join23(repoRoot, "packages/runa-templates/templates");
34545
- if (!existsSync51(templateDir)) {
35456
+ if (!existsSync52(templateDir)) {
34546
35457
  throw new CLIError("template-check is a runa-repo only command", "NOT_RUNA_REPO", [
34547
35458
  "This command compares runa-repo with pj-repo templates",
34548
35459
  "It should only be run in the runa repository",
@@ -34644,11 +35555,29 @@ init_esm_shims();
34644
35555
 
34645
35556
  // src/commands/test/commands/test.ts
34646
35557
  init_esm_shims();
35558
+ function resolveEffectiveRequireManifest(options) {
35559
+ if (options.requireManifest && options.allowManifestFallback) {
35560
+ throw new CLIError(
35561
+ "--require-manifest and --allow-manifest-fallback are mutually exclusive",
35562
+ "TEST_MANIFEST_FLAGS_EXCLUSIVE",
35563
+ ["Use strict mode (default) OR explicitly allow fallback, but not both"]
35564
+ );
35565
+ }
35566
+ if (options.allowManifestFallback) return false;
35567
+ return options.requireManifest;
35568
+ }
34647
35569
  var testCommand = new Command("test").description("Run tests (compat). Prefer: test:layer0..4 or test:static/service/integration.").option("--layer <number>", "Run specific layer (0-4)").option("--from <number>", "Run from layer N to 4").option("--to <number>", "Run from layer 0 to N").option("--ci", "CI mode (fail fast, no interactive)").option("--verbose", "Verbose output").option("--record", "Record test results to database", true).option(
34648
35570
  "--report-json <path>",
34649
35571
  "Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
34650
- ).option("--generate", "Generate tests from XState before running (integration)").option("--advanced", "Generate advanced tests (integration)").option("--auto", "Zero-config auto-generation (integration)").option("--base-url <url>", "Override base URL (integration)").option("--changed", "Run only impacted layers based on git diff (service)").option("--base <ref>", "Base ref for --changed (service)").option("--skip-missing", "Skip layers with missing dependencies instead of failing").action(async (options) => {
35572
+ ).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(
35573
+ "--require-manifest",
35574
+ "Require manifest to be present and valid for Layer 3/4 tests (strict behavior)"
35575
+ ).option(
35576
+ "--allow-manifest-fallback",
35577
+ "Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
35578
+ ).action(async (options) => {
34651
35579
  try {
35580
+ const effectiveRequireManifest = resolveEffectiveRequireManifest(options);
34652
35581
  const output3 = await runTest({
34653
35582
  layer: options.layer !== void 0 ? Number.parseInt(options.layer, 10) : void 0,
34654
35583
  from: options.from !== void 0 ? Number.parseInt(options.from, 10) : void 0,
@@ -34663,7 +35592,8 @@ var testCommand = new Command("test").description("Run tests (compat). Prefer: t
34663
35592
  baseUrl: options.baseUrl,
34664
35593
  changed: options.changed,
34665
35594
  base: options.base,
34666
- skipMissing: options.skipMissing
35595
+ skipMissing: options.skipMissing,
35596
+ requireManifest: effectiveRequireManifest
34667
35597
  });
34668
35598
  emitJsonSuccess(testCommand, TestRunOutputSchema, output3);
34669
35599
  } catch (error) {
@@ -34761,11 +35691,29 @@ var testApiCommand = new Command("test:api").description("Run Layer 3: API tests
34761
35691
 
34762
35692
  // src/commands/test/commands/test-e2e.ts
34763
35693
  init_esm_shims();
35694
+ function resolveEffectiveRequireManifest2(options) {
35695
+ if (options.requireManifest && options.allowManifestFallback) {
35696
+ throw new CLIError(
35697
+ "--require-manifest and --allow-manifest-fallback are mutually exclusive",
35698
+ "TEST_E2E_MANIFEST_FLAGS_EXCLUSIVE",
35699
+ ["Use strict mode (default) OR explicitly allow fallback, but not both"]
35700
+ );
35701
+ }
35702
+ if (options.allowManifestFallback) return false;
35703
+ return options.requireManifest;
35704
+ }
34764
35705
  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(
35706
+ "--require-manifest",
35707
+ "Require manifest to be present and valid (strict behavior; enabled by default for Layer 4)"
35708
+ ).option(
35709
+ "--allow-manifest-fallback",
35710
+ "Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
35711
+ ).option(
34765
35712
  "--report-json <path>",
34766
35713
  "Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
34767
35714
  ).option("--verbose", "Verbose output (full error details, environment info)").action(async (options) => {
34768
35715
  try {
35716
+ const effectiveRequireManifest = resolveEffectiveRequireManifest2(options);
34769
35717
  const output3 = await runTestIntegration({
34770
35718
  ci: options.ci ?? false,
34771
35719
  record: options.record,
@@ -34775,6 +35723,7 @@ var testE2ECommand = new Command("test:e2e").description("Run Layer 4: E2E tests
34775
35723
  advanced: options.advanced,
34776
35724
  auto: options.auto,
34777
35725
  baseUrl: options.baseUrl,
35726
+ requireManifest: effectiveRequireManifest,
34778
35727
  invokedAs: "runa test:e2e"
34779
35728
  });
34780
35729
  emitJsonSuccess(testE2ECommand, TestIntegrationOutputSchema, output3);
@@ -34795,8 +35744,15 @@ var testE2ECommand = new Command("test:e2e").description("Run Layer 4: E2E tests
34795
35744
  );
34796
35745
  }
34797
35746
  });
34798
- var testBrowserCommand = new Command("test:browser").description("Run Layer 4: Browser tests (Playwright E2E) - Alias for test:e2e").option("--generate", "Generate tests from XState before running").option("--advanced", "Generate advanced tests").option("--auto", "Zero-config auto-generation").option("--ci", "CI mode (fail fast, no interactive)").option("--record", "Record test results to database", true).option("--base-url <url>", "Explicit base URL for E2E").option("--report-json <path>", "Export test report as JSON").option("--verbose", "Verbose output").action(async (options) => {
35747
+ 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(
35748
+ "--require-manifest",
35749
+ "Require manifest to be present and valid (strict behavior; enabled by default for Layer 4)"
35750
+ ).option(
35751
+ "--allow-manifest-fallback",
35752
+ "Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
35753
+ ).option("--report-json <path>", "Export test report as JSON").option("--verbose", "Verbose output").action(async (options) => {
34799
35754
  try {
35755
+ const effectiveRequireManifest = resolveEffectiveRequireManifest2(options);
34800
35756
  const output3 = await runTestIntegration({
34801
35757
  ci: options.ci ?? false,
34802
35758
  record: options.record,
@@ -34806,6 +35762,7 @@ var testBrowserCommand = new Command("test:browser").description("Run Layer 4: B
34806
35762
  advanced: options.advanced,
34807
35763
  auto: options.auto,
34808
35764
  baseUrl: options.baseUrl,
35765
+ requireManifest: effectiveRequireManifest,
34809
35766
  invokedAs: "runa test:browser"
34810
35767
  });
34811
35768
  emitJsonSuccess(testBrowserCommand, TestIntegrationOutputSchema, output3);
@@ -34878,11 +35835,29 @@ var testLintCommand = new Command("test:lint").description("Run Layer 0: Lint (t
34878
35835
 
34879
35836
  // src/commands/test/commands/test-integration.ts
34880
35837
  init_esm_shims();
35838
+ function resolveEffectiveRequireManifest3(options) {
35839
+ if (options.requireManifest && options.allowManifestFallback) {
35840
+ throw new CLIError(
35841
+ "--require-manifest and --allow-manifest-fallback are mutually exclusive",
35842
+ "TEST_INTEGRATION_MANIFEST_FLAGS_EXCLUSIVE",
35843
+ ["Use strict mode (default) OR explicitly allow fallback, but not both"]
35844
+ );
35845
+ }
35846
+ if (options.allowManifestFallback) return false;
35847
+ return options.requireManifest;
35848
+ }
34881
35849
  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(
35850
+ "--require-manifest",
35851
+ "Require manifest to be present and valid (strict behavior; enabled by default for Layer 4)"
35852
+ ).option(
35853
+ "--allow-manifest-fallback",
35854
+ "Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
35855
+ ).option(
34882
35856
  "--report-json <path>",
34883
35857
  "Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
34884
35858
  ).option("--verbose", "Verbose output (full error details, environment info)").action(async (options) => {
34885
35859
  try {
35860
+ const effectiveRequireManifest = resolveEffectiveRequireManifest3(options);
34886
35861
  const output3 = await runTestIntegration({
34887
35862
  ci: options.ci ?? false,
34888
35863
  record: options.record,
@@ -34892,6 +35867,7 @@ var testIntegrationCommand = new Command("test:integration").description("Run La
34892
35867
  advanced: options.advanced,
34893
35868
  auto: options.auto,
34894
35869
  baseUrl: options.baseUrl,
35870
+ requireManifest: effectiveRequireManifest,
34895
35871
  invokedAs: "runa test:integration"
34896
35872
  });
34897
35873
  emitJsonSuccess(testIntegrationCommand, TestIntegrationOutputSchema, output3);
@@ -34937,7 +35913,7 @@ function injectTestAttrsIfLayer4(layer, options) {
34937
35913
  "Run `runa inject-test-attrs` manually to see detailed errors",
34938
35914
  "Ensure XState machines exist in your project",
34939
35915
  "Check that machines have valid meta.e2e definitions",
34940
- "Or remove --require-manifest flag to continue with fallback behavior"
35916
+ "Or pass --allow-manifest-fallback to continue with fallback behavior"
34941
35917
  ],
34942
35918
  error instanceof Error ? error : void 0
34943
35919
  );
@@ -34947,10 +35923,17 @@ function injectTestAttrsIfLayer4(layer, options) {
34947
35923
  }
34948
35924
  }
34949
35925
  }
35926
+ function resolveEffectiveRequireManifest4(layer, options) {
35927
+ if (options.allowManifestFallback) return false;
35928
+ if (options.requireManifest !== void 0) return options.requireManifest;
35929
+ if (layer === 4 && process.env.RUNA_LAYER4_ALLOW_MANIFEST_FALLBACK !== "true") return true;
35930
+ return void 0;
35931
+ }
34950
35932
  async function runSingleLayer(params) {
35933
+ const effectiveRequireManifest = resolveEffectiveRequireManifest4(params.layer, params.options);
34951
35934
  injectTestAttrsIfLayer4(params.layer, {
34952
35935
  verbose: params.options.verbose,
34953
- requireManifest: params.options.requireManifest
35936
+ requireManifest: effectiveRequireManifest
34954
35937
  });
34955
35938
  try {
34956
35939
  const output3 = await runTest({
@@ -34967,7 +35950,7 @@ async function runSingleLayer(params) {
34967
35950
  reviewSnapshots: params.options.reviewSnapshots,
34968
35951
  forceRegenerate: params.options.force,
34969
35952
  skipGeneration: params.options.skipGeneration,
34970
- requireManifest: params.options.requireManifest,
35953
+ requireManifest: effectiveRequireManifest,
34971
35954
  invokedAs: `runa test:layer${params.layer}`
34972
35955
  });
34973
35956
  emitJsonSuccess(params.cmd, TestRunOutputSchema, output3);
@@ -35001,6 +35984,13 @@ function validateGenerationFlags(layer, opts) {
35001
35984
  ["Use --auto (implementation-driven) OR --generate/--advanced (XState-driven)"]
35002
35985
  );
35003
35986
  }
35987
+ if (layer === 4 && opts.requireManifest && opts.allowManifestFallback) {
35988
+ throw new CLIError(
35989
+ "--require-manifest and --allow-manifest-fallback are mutually exclusive",
35990
+ "TEST_LAYER_MANIFEST_FLAGS_EXCLUSIVE",
35991
+ ["Use strict mode (default) OR explicitly allow fallback, but not both"]
35992
+ );
35993
+ }
35004
35994
  }
35005
35995
  function validateSnapshotFlags(opts) {
35006
35996
  if (opts.reviewSnapshots && opts.ci) {
@@ -35039,6 +36029,9 @@ function createLayerCommand(layer) {
35039
36029
  cmd.option("--generate", "Generate tests from XState before running (Layer 4)").option("--advanced", "Generate advanced tests (requires --generate)").option("--auto", "Zero-config auto-generation (implementation-driven)").option("--update-snapshots", "Update visual baselines (Layer 4)").option("--filter <pattern>", 'Filter tests by pattern (e.g., "checkout-*")').option("--review-snapshots", "Interactive review of changed visual snapshots (Layer 4)").option("--force", "Force regenerate all tests, bypassing cache").option(
35040
36030
  "--require-manifest",
35041
36031
  "Require manifest to be present and valid (fail if missing or stale)"
36032
+ ).option(
36033
+ "--allow-manifest-fallback",
36034
+ "Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
35042
36035
  );
35043
36036
  }
35044
36037
  return cmd;
@@ -36887,8 +37880,8 @@ var logger13 = createCLILogger("watch");
36887
37880
  function addFallbackSchemaPatterns(patterns) {
36888
37881
  const detected = detectDatabasePackage(process.cwd());
36889
37882
  if (detected) {
36890
- patterns.push(path10__default.join(detected, "src/schema/**/*.ts"));
36891
- patterns.push(path10__default.join(detected, "sql/**/*.sql"));
37883
+ patterns.push(path11__default.join(detected, "src/schema/**/*.ts"));
37884
+ patterns.push(path11__default.join(detected, "sql/**/*.sql"));
36892
37885
  return;
36893
37886
  }
36894
37887
  for (const candidate of DATABASE_PACKAGE_CANDIDATES) {
@@ -36902,8 +37895,8 @@ async function buildSchemaPatterns() {
36902
37895
  const patterns = ["supabase/schemas/**/*.sql"];
36903
37896
  try {
36904
37897
  const dbPackagePath = await getDatabasePackagePath();
36905
- patterns.push(path10__default.join(dbPackagePath, "src/schema/**/*.ts"));
36906
- patterns.push(path10__default.join(dbPackagePath, "sql/**/*.sql"));
37898
+ patterns.push(path11__default.join(dbPackagePath, "src/schema/**/*.ts"));
37899
+ patterns.push(path11__default.join(dbPackagePath, "sql/**/*.sql"));
36907
37900
  } catch {
36908
37901
  addFallbackSchemaPatterns(patterns);
36909
37902
  }