@runa-ai/runa-cli 0.5.50 → 0.5.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/ci/utils/app-runtime.d.ts +16 -1
- package/dist/commands/ci/utils/app-runtime.d.ts.map +1 -1
- package/dist/commands/db/apply/helpers/pg-schema-diff-helpers.d.ts +14 -0
- package/dist/commands/db/apply/helpers/pg-schema-diff-helpers.d.ts.map +1 -1
- package/dist/commands/db/apply/helpers/retry-logic.d.ts.map +1 -1
- package/dist/commands/db/constants.d.ts +3 -3
- package/dist/commands/db/constants.d.ts.map +1 -1
- package/dist/commands/db/utils/db-target.d.ts.map +1 -1
- package/dist/commands/db/utils/preflight-check.d.ts.map +1 -1
- package/dist/commands/dev/machine.d.ts.map +1 -1
- package/dist/commands/env/commands/env-pull.d.ts.map +1 -1
- package/dist/commands/env/constants/local-supabase.d.ts +30 -62
- package/dist/commands/env/constants/local-supabase.d.ts.map +1 -1
- package/dist/commands/inject-test-attrs/action.d.ts.map +1 -1
- package/dist/commands/inject-test-attrs/commands/inject-test-attrs.d.ts.map +1 -1
- package/dist/commands/inject-test-attrs/contract.d.ts +118 -0
- package/dist/commands/inject-test-attrs/contract.d.ts.map +1 -1
- package/dist/commands/inject-test-attrs/detection-diagnostics.d.ts +67 -0
- package/dist/commands/inject-test-attrs/detection-diagnostics.d.ts.map +1 -0
- package/dist/commands/inject-test-attrs/manifest-generator.d.ts +7 -1
- package/dist/commands/inject-test-attrs/manifest-generator.d.ts.map +1 -1
- package/dist/commands/inject-test-attrs/processor-utils.d.ts.map +1 -1
- package/dist/commands/inject-test-attrs/processor.d.ts.map +1 -1
- package/dist/commands/inject-test-attrs/types.d.ts +57 -0
- package/dist/commands/inject-test-attrs/types.d.ts.map +1 -1
- package/dist/commands/manifest/index.d.ts.map +1 -1
- package/dist/commands/test/commands/test-e2e.d.ts.map +1 -1
- package/dist/commands/test/commands/test-integration.d.ts.map +1 -1
- package/dist/commands/test/commands/test-layer.d.ts.map +1 -1
- package/dist/commands/test/commands/test.d.ts.map +1 -1
- package/dist/index.js +1205 -585
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
|
-
import * as
|
|
4
|
-
import
|
|
3
|
+
import * as path11 from 'path';
|
|
4
|
+
import path11__default, { join, dirname, resolve, relative, basename, sep, isAbsolute, normalize } from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
-
import { execSync, spawnSync, execFileSync, exec, spawn } from 'child_process';
|
|
7
6
|
import * as fs5 from 'fs';
|
|
8
|
-
import fs5__default, { existsSync, readFileSync, readdirSync, mkdtempSync, writeFileSync, mkdirSync, copyFileSync, createWriteStream, statSync, rmSync, realpathSync, promises, lstatSync, accessSync, constants, chmodSync, unlinkSync } from 'fs';
|
|
7
|
+
import fs5__default, { existsSync, readFileSync, readdirSync, mkdtempSync, writeFileSync, mkdirSync, copyFileSync, createWriteStream, statSync, rmSync, realpathSync, renameSync, promises, lstatSync, accessSync, constants, chmodSync, unlinkSync } from 'fs';
|
|
8
|
+
import { execSync, spawnSync, execFileSync, exec, spawn } from 'child_process';
|
|
9
9
|
import { createCLILogger, cacheClear, CacheClearOutputSchema, CLIError, cachePrune, CachePruneOutputSchema, cacheStats, CacheStatsOutputSchema, cacheList, CacheListOutputSchema, cacheInvalidate, CacheInvalidateOutputSchema, syncFromProduction, dbGenerateDiagram, DbDiagramGenerateOutputSchema, createDbSnapshot, syncDatabase, emitDbPushFailureCapsule, emitDbAnnotations, writeDbPushStepSummary, exportDbReportJson, DbSyncOutputSchema, databasePaths, detectRequiredServices, formatDetectionResults, dbStart, DbLifecycleStartOutputSchema, dbStop, DbLifecycleStopOutputSchema, dbReset, DbLifecycleResetOutputSchema, dbValidateSchemas, DbSchemaValidateOutputSchema, DbSchemaRisksOutputSchema, dbDetectSchemaRisks, dbApplySchemas, DbSchemaApplyOutputSchema, dbGenerateTypes, DbSchemaGenerateOutputSchema, extractSchemaFilter, dbSeedInit, DbSeedInitOutputSchema, dbSeedValidate, DbSeedValidateOutputSchema, dbSeedGenerate, DbSeedGenerateOutputSchema, dbVerifySeeds, DbSeedVerifyOutputSchema, DbSnapshotCreateOutputSchema, restoreDbSnapshot, DbSnapshotRestoreOutputSchema, listDbSnapshots, DbSnapshotListOutputSchema, dbGeneratePgTapTests, DbTestGenOutputSchema, dbUpdateGoldenRecord, DbTestUpdateGoldenOutputSchema, repairRunaConfig, detectExistingInitConfig, initProject, validateInitResult, linkCliGlobally, LinkCliOutputSchema, unlinkCliGlobally, UnlinkCliOutputSchema, checkRepoStatus, CheckRepoStatusOutputSchema, enableTelemetry, disableTelemetry, getTelemetryStatus, uploadTelemetry, TelemetryUploadOutputSchema, runTest, TestRunOutputSchema, runTestService, TestServiceOutputSchema, runTestIntegration, TestIntegrationOutputSchema, runTestStatic, TestStaticOutputSchema, generateOwaspTop10Tests, TestOwaspGenerateOutputSchema, updateGoldenRecord, generateE2ETests, generateSecurityTests, generateUnitTests, generateApiTests, generateComponentTests, generateE2EScaffold, validateConfig, ValidateConfigOutputSchema, deploySchemaToProduction, WorkflowNotifyOutputSchema, devopsSync, workflowSync, validateInfrastructure, emitWorkflowValidateFailureCapsule, emitWorkflowAnnotations, writeWorkflowValidateStepSummary, exportWorkflowReportJson, WorkflowValidateInfrastructureOutputSchema, createSuccessEnvelopeSchema, CLI_CONTRACT_VERSION, runChecks, RunCheckOutputSchema, formatDuration as formatDuration$1, GITHUB_API, loadRunaConfig, getClassificationForProfile, loadRunaConfigOrThrow, recordSchemaAudit, RecordSchemaAuditOutputSchema, createBackup, CreateBackupOutputSchema, listBackups, ListBackupsOutputSchema, getBackupMetadata, restoreBackup, RestoreBackupOutputSchema, deleteBackup, DeleteBackupOutputSchema, detectSchemaNames, SUPABASE_SYSTEM_SCHEMAS, dbSeedApply, writeDbSeedStepSummary, DbSeedApplyOutputSchema, emitDbSeedFailureCapsule, syncEnvironment, EnvSyncOutputSchema, detectDatabasePackage, findProjectRoot as findProjectRoot$1, TelemetryEnableOutputSchema, TelemetryDisableOutputSchema, TelemetryStatusOutputSchema, workflowNotify, DevOpsSyncOutputSchema, WorkflowSyncOutputSchema, formatCLIError, getStatusIcon as getStatusIcon$1, findWorkspaceRoot as findWorkspaceRoot$1, checkExtensionConfig, UpgradeTransaction, readRunaVersion, syncTemplates, SyncOutputSchema, DATABASE_PACKAGE_CANDIDATES, ErrorEnvelopeSchema, preCheckSync, findConflictFiles, TestUnitGenOutputSchema, TestE2EGenerateOutputSchema, TestSecurityGenOutputSchema, TestApiGenOutputSchema, TestComponentGenOutputSchema } from '@runa-ai/runa';
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import fs9, { mkdir, writeFile, appendFile, readFile, rm, stat, realpath, cp, readdir, lstat } from 'fs/promises';
|
|
@@ -33,7 +33,7 @@ import { createJiti } from 'jiti';
|
|
|
33
33
|
import ora from 'ora';
|
|
34
34
|
import { stdout, stdin } from 'process';
|
|
35
35
|
import * as readline from 'readline/promises';
|
|
36
|
-
import { clearInjectionRegistry, clearUnifiedRegistry, postProcessRegistries, isPageFile, collectPageInfo, isLayoutFile, collectLayoutInfo, isApiRouteFile, collectApiRouteInfo, isMiddlewareFile, collectAuthBoundaries, hasMachineDefinition, collectMachineDefinition, getInjectionRegistry, buildManifest, getAllMachineDefinitions, generateSelectorTypeScript, getUnifiedRegistry, buildMachineLinks,
|
|
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 = () =>
|
|
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
|
|
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 ?
|
|
126
|
-
const dbPort = dbUrl ?
|
|
127
|
-
const studioPort = studioUrl ?
|
|
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 {
|
|
353
|
+
return {
|
|
354
|
+
api: apiPort,
|
|
355
|
+
db: dbPort,
|
|
356
|
+
studio: studioPort ?? apiPort + 2
|
|
357
|
+
};
|
|
134
358
|
}
|
|
135
359
|
function getSupabaseAccessPoints(projectRoot) {
|
|
136
|
-
const ports =
|
|
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:
|
|
139
|
-
api:
|
|
140
|
-
db:
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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/") ? "." :
|
|
779
|
-
const fullPath = dbPath === "." ? configDir :
|
|
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
|
-
|
|
793
|
-
|
|
794
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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.
|
|
1164
|
+
CLI_VERSION = "0.5.52";
|
|
933
1165
|
HAS_ADMIN_COMMAND = false;
|
|
934
1166
|
}
|
|
935
1167
|
});
|
|
@@ -1325,7 +1557,7 @@ var init_dependency_analyzer = __esm({
|
|
|
1325
1557
|
name = "DependencyAnalyzer";
|
|
1326
1558
|
categories = ["dependency"];
|
|
1327
1559
|
async analyze(options) {
|
|
1328
|
-
const packageJsonPath =
|
|
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 =
|
|
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 =
|
|
3090
|
-
const resolvedBoundary =
|
|
3091
|
-
const relative9 =
|
|
3092
|
-
return !relative9.startsWith("..") && !
|
|
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 =
|
|
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 =
|
|
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 =
|
|
3401
|
+
const normalized = path11__default.normalize(filePath);
|
|
3170
3402
|
return normalized.replace(/\\/g, "/");
|
|
3171
3403
|
}
|
|
3172
3404
|
function normalizeRuleId(ruleId) {
|
|
@@ -5329,7 +5561,7 @@ function pipeToSharedLog(params) {
|
|
|
5329
5561
|
}
|
|
5330
5562
|
async function ensureRunaTmpDir(cwd) {
|
|
5331
5563
|
const root = cwd ?? process.cwd();
|
|
5332
|
-
const dir =
|
|
5564
|
+
const dir = path11__default.join(root, ".runa", "tmp");
|
|
5333
5565
|
await mkdir(dir, { recursive: true });
|
|
5334
5566
|
return dir;
|
|
5335
5567
|
}
|
|
@@ -5354,7 +5586,7 @@ var buildActor = fromPromise(
|
|
|
5354
5586
|
const { repoRoot, tmpDir, hasTurbo, e2e, env: env2 = process.env } = input3;
|
|
5355
5587
|
const startTime = Date.now();
|
|
5356
5588
|
try {
|
|
5357
|
-
const fullTmpDir =
|
|
5589
|
+
const fullTmpDir = path11__default.join(repoRoot, tmpDir);
|
|
5358
5590
|
await mkdir(fullTmpDir, { recursive: true });
|
|
5359
5591
|
const buildEnv = { ...env2 };
|
|
5360
5592
|
if (e2e) {
|
|
@@ -5363,7 +5595,7 @@ var buildActor = fromPromise(
|
|
|
5363
5595
|
buildEnv.TURBO_FORCE = "true";
|
|
5364
5596
|
console.log(" E2E mode enabled: NEXT_PUBLIC_E2E_TEST=true, TURBO_FORCE=true");
|
|
5365
5597
|
}
|
|
5366
|
-
const hasApps = existsSync(
|
|
5598
|
+
const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
|
|
5367
5599
|
let args;
|
|
5368
5600
|
if (hasTurbo) {
|
|
5369
5601
|
args = hasApps ? ["turbo", "run", "build", "--filter=./apps/*", "--filter=./packages/*"] : ["turbo", "run", "build"];
|
|
@@ -5376,7 +5608,7 @@ var buildActor = fromPromise(
|
|
|
5376
5608
|
label: "build",
|
|
5377
5609
|
command: "pnpm",
|
|
5378
5610
|
args,
|
|
5379
|
-
logFile:
|
|
5611
|
+
logFile: path11__default.join(fullTmpDir, "build.log")
|
|
5380
5612
|
});
|
|
5381
5613
|
return {
|
|
5382
5614
|
passed: true,
|
|
@@ -5615,7 +5847,7 @@ function deleteIfExists(fullPath, displayPath, verbose) {
|
|
|
5615
5847
|
function deleteRootDirectories(repoRoot, dirs, verbose) {
|
|
5616
5848
|
const deleted = [];
|
|
5617
5849
|
for (const dir of dirs) {
|
|
5618
|
-
const fullPath =
|
|
5850
|
+
const fullPath = path11__default.join(repoRoot, dir);
|
|
5619
5851
|
if (deleteIfExists(fullPath, dir, verbose)) {
|
|
5620
5852
|
deleted.push(dir);
|
|
5621
5853
|
}
|
|
@@ -5626,13 +5858,13 @@ function cleanMonorepoPackages(repoRoot, dirs, verbose) {
|
|
|
5626
5858
|
const deleted = [];
|
|
5627
5859
|
const subdirs = ["apps", "packages"];
|
|
5628
5860
|
for (const subdir of subdirs) {
|
|
5629
|
-
const subdirPath =
|
|
5861
|
+
const subdirPath = path11__default.join(repoRoot, subdir);
|
|
5630
5862
|
if (!existsSync(subdirPath)) continue;
|
|
5631
5863
|
const entries = __require("fs").readdirSync(subdirPath, { withFileTypes: true });
|
|
5632
5864
|
for (const entry of entries) {
|
|
5633
5865
|
if (!entry.isDirectory()) continue;
|
|
5634
5866
|
for (const dir of dirs) {
|
|
5635
|
-
const targetPath =
|
|
5867
|
+
const targetPath = path11__default.join(subdirPath, entry.name, dir);
|
|
5636
5868
|
const displayPath = `${subdir}/${entry.name}/${dir}`;
|
|
5637
5869
|
if (deleteIfExists(targetPath, displayPath, verbose)) {
|
|
5638
5870
|
deleted.push(displayPath);
|
|
@@ -5651,7 +5883,7 @@ var cleanActor = fromPromise(
|
|
|
5651
5883
|
async ({ input: input3 }) => {
|
|
5652
5884
|
const { repoRoot, tmpDir, verbose = false } = input3;
|
|
5653
5885
|
try {
|
|
5654
|
-
await mkdir(
|
|
5886
|
+
await mkdir(path11__default.join(repoRoot, tmpDir), { recursive: true });
|
|
5655
5887
|
if (verbose) {
|
|
5656
5888
|
console.log("Cleaning build caches...");
|
|
5657
5889
|
}
|
|
@@ -5673,7 +5905,7 @@ var freshActor = fromPromise(
|
|
|
5673
5905
|
async ({ input: input3 }) => {
|
|
5674
5906
|
const { repoRoot, tmpDir, verbose = false } = input3;
|
|
5675
5907
|
try {
|
|
5676
|
-
await mkdir(
|
|
5908
|
+
await mkdir(path11__default.join(repoRoot, tmpDir), { recursive: true });
|
|
5677
5909
|
if (verbose) {
|
|
5678
5910
|
console.log("Fresh install: cleaning all caches and node_modules...");
|
|
5679
5911
|
}
|
|
@@ -5745,7 +5977,7 @@ var dbSyncActor = fromPromise(
|
|
|
5745
5977
|
const { repoRoot, tmpDir, env: env2 = process.env } = input3;
|
|
5746
5978
|
const startTime = Date.now();
|
|
5747
5979
|
try {
|
|
5748
|
-
const fullTmpDir =
|
|
5980
|
+
const fullTmpDir = path11__default.join(repoRoot, tmpDir);
|
|
5749
5981
|
await mkdir(fullTmpDir, { recursive: true });
|
|
5750
5982
|
await runLogged({
|
|
5751
5983
|
cwd: repoRoot,
|
|
@@ -5753,7 +5985,7 @@ var dbSyncActor = fromPromise(
|
|
|
5753
5985
|
label: "db-sync",
|
|
5754
5986
|
command: "pnpm",
|
|
5755
5987
|
args: ["exec", "runa", "db", "sync", "--auto-approve"],
|
|
5756
|
-
logFile:
|
|
5988
|
+
logFile: path11__default.join(fullTmpDir, "db-sync.log")
|
|
5757
5989
|
});
|
|
5758
5990
|
return {
|
|
5759
5991
|
passed: true,
|
|
@@ -5789,7 +6021,7 @@ var manifestActor = fromPromise(
|
|
|
5789
6021
|
const { repoRoot, tmpDir, env: env2 = process.env } = input3;
|
|
5790
6022
|
const startTime = Date.now();
|
|
5791
6023
|
try {
|
|
5792
|
-
const fullTmpDir =
|
|
6024
|
+
const fullTmpDir = path11__default.join(repoRoot, tmpDir);
|
|
5793
6025
|
await mkdir(fullTmpDir, { recursive: true });
|
|
5794
6026
|
await runLogged({
|
|
5795
6027
|
cwd: repoRoot,
|
|
@@ -5797,7 +6029,7 @@ var manifestActor = fromPromise(
|
|
|
5797
6029
|
label: "manifest",
|
|
5798
6030
|
command: "pnpm",
|
|
5799
6031
|
args: ["exec", "runa", "manifest"],
|
|
5800
|
-
logFile:
|
|
6032
|
+
logFile: path11__default.join(fullTmpDir, "manifest.log")
|
|
5801
6033
|
});
|
|
5802
6034
|
return {
|
|
5803
6035
|
passed: true,
|
|
@@ -6061,7 +6293,7 @@ function buildOutput(typeCheckPassed, lintPassed, typeCheckDurationMs, lintDurat
|
|
|
6061
6293
|
var staticChecksActor = fromPromise(
|
|
6062
6294
|
async ({ input: input3 }) => {
|
|
6063
6295
|
const { repoRoot, tmpDir, hasTurbo, env: env2 = process.env, skipTypes, skipLint } = input3;
|
|
6064
|
-
const fullTmpDir =
|
|
6296
|
+
const fullTmpDir = path11__default.join(repoRoot, tmpDir);
|
|
6065
6297
|
await mkdir(fullTmpDir, { recursive: true });
|
|
6066
6298
|
const startTime = Date.now();
|
|
6067
6299
|
const checksToRun = [];
|
|
@@ -6075,7 +6307,7 @@ var staticChecksActor = fromPromise(
|
|
|
6075
6307
|
label: "type-check",
|
|
6076
6308
|
command: cmd.command,
|
|
6077
6309
|
args: cmd.args,
|
|
6078
|
-
logFile:
|
|
6310
|
+
logFile: path11__default.join(fullTmpDir, "type-check.log")
|
|
6079
6311
|
})
|
|
6080
6312
|
);
|
|
6081
6313
|
checkOrder.push("type-check");
|
|
@@ -6089,7 +6321,7 @@ var staticChecksActor = fromPromise(
|
|
|
6089
6321
|
label: "lint",
|
|
6090
6322
|
command: cmd.command,
|
|
6091
6323
|
args: cmd.args,
|
|
6092
|
-
logFile:
|
|
6324
|
+
logFile: path11__default.join(fullTmpDir, "lint.log")
|
|
6093
6325
|
})
|
|
6094
6326
|
);
|
|
6095
6327
|
checkOrder.push("lint");
|
|
@@ -6133,14 +6365,14 @@ var validateActor = fromPromise(
|
|
|
6133
6365
|
let manifestsExist = true;
|
|
6134
6366
|
const buildOutputPaths = [
|
|
6135
6367
|
// Single app
|
|
6136
|
-
|
|
6137
|
-
|
|
6368
|
+
path11__default.join(repoRoot, ".next"),
|
|
6369
|
+
path11__default.join(repoRoot, "dist"),
|
|
6138
6370
|
// Monorepo apps
|
|
6139
|
-
|
|
6140
|
-
|
|
6371
|
+
path11__default.join(repoRoot, "apps", "web", ".next"),
|
|
6372
|
+
path11__default.join(repoRoot, "apps", "dashboard", ".next"),
|
|
6141
6373
|
// Packages
|
|
6142
|
-
|
|
6143
|
-
|
|
6374
|
+
path11__default.join(repoRoot, "packages", "cli", "dist"),
|
|
6375
|
+
path11__default.join(repoRoot, "packages", "sdk", "dist")
|
|
6144
6376
|
];
|
|
6145
6377
|
for (const outputPath of buildOutputPaths) {
|
|
6146
6378
|
if (existsSync(outputPath)) {
|
|
@@ -6154,7 +6386,7 @@ var validateActor = fromPromise(
|
|
|
6154
6386
|
);
|
|
6155
6387
|
}
|
|
6156
6388
|
if (!skipManifest) {
|
|
6157
|
-
const manifestPath =
|
|
6389
|
+
const manifestPath = path11__default.join(repoRoot, ".runa", "manifests", "manifest.json");
|
|
6158
6390
|
if (!existsSync(manifestPath)) {
|
|
6159
6391
|
manifestsExist = false;
|
|
6160
6392
|
warnings.push("No manifest.json found. E2E test generation may be affected.");
|
|
@@ -6213,35 +6445,35 @@ function isE2EMode({ context }) {
|
|
|
6213
6445
|
return context.input.e2e;
|
|
6214
6446
|
}
|
|
6215
6447
|
function detectDatabase(repoRoot) {
|
|
6216
|
-
const configPath =
|
|
6448
|
+
const configPath = path11__default.join(repoRoot, "runa.config.ts");
|
|
6217
6449
|
if (!existsSync(configPath)) {
|
|
6218
|
-
const jsConfigPath =
|
|
6450
|
+
const jsConfigPath = path11__default.join(repoRoot, "runa.config.js");
|
|
6219
6451
|
if (!existsSync(jsConfigPath)) {
|
|
6220
6452
|
return false;
|
|
6221
6453
|
}
|
|
6222
6454
|
}
|
|
6223
|
-
const supabaseDir =
|
|
6455
|
+
const supabaseDir = path11__default.join(repoRoot, "supabase");
|
|
6224
6456
|
if (existsSync(supabaseDir)) {
|
|
6225
6457
|
return true;
|
|
6226
6458
|
}
|
|
6227
|
-
const databasePkg =
|
|
6459
|
+
const databasePkg = path11__default.join(repoRoot, "packages", "database");
|
|
6228
6460
|
if (existsSync(databasePkg)) {
|
|
6229
6461
|
return true;
|
|
6230
6462
|
}
|
|
6231
6463
|
return false;
|
|
6232
6464
|
}
|
|
6233
6465
|
function detectManifestTask(repoRoot) {
|
|
6234
|
-
const runaConfigPath =
|
|
6466
|
+
const runaConfigPath = path11__default.join(repoRoot, "runa.config.ts");
|
|
6235
6467
|
if (existsSync(runaConfigPath)) {
|
|
6236
6468
|
return true;
|
|
6237
6469
|
}
|
|
6238
|
-
const rootPkgPath =
|
|
6470
|
+
const rootPkgPath = path11__default.join(repoRoot, "package.json");
|
|
6239
6471
|
if (hasXStateDependency(rootPkgPath)) {
|
|
6240
6472
|
return true;
|
|
6241
6473
|
}
|
|
6242
6474
|
const appDirs = ["apps/web", "apps/app", "apps/dashboard", "app"];
|
|
6243
6475
|
for (const appDir of appDirs) {
|
|
6244
|
-
const appPkgPath =
|
|
6476
|
+
const appPkgPath = path11__default.join(repoRoot, appDir, "package.json");
|
|
6245
6477
|
if (hasXStateDependency(appPkgPath)) {
|
|
6246
6478
|
return true;
|
|
6247
6479
|
}
|
|
@@ -6268,7 +6500,7 @@ function hasXStateDependency(pkgPath) {
|
|
|
6268
6500
|
}
|
|
6269
6501
|
}
|
|
6270
6502
|
function detectTurbo(repoRoot) {
|
|
6271
|
-
const turboJsonPath =
|
|
6503
|
+
const turboJsonPath = path11__default.join(repoRoot, "turbo.json");
|
|
6272
6504
|
return existsSync(turboJsonPath);
|
|
6273
6505
|
}
|
|
6274
6506
|
var guards = {
|
|
@@ -7276,15 +7508,15 @@ function printSummary(logger16, output3) {
|
|
|
7276
7508
|
}
|
|
7277
7509
|
}
|
|
7278
7510
|
function findRepoRoot(startDir) {
|
|
7279
|
-
const { existsSync:
|
|
7511
|
+
const { existsSync: existsSync52, readFileSync: readFileSync29 } = __require("fs");
|
|
7280
7512
|
const { join: join23, dirname: dirname5 } = __require("path");
|
|
7281
7513
|
let current = startDir;
|
|
7282
7514
|
while (current !== dirname5(current)) {
|
|
7283
|
-
if (
|
|
7515
|
+
if (existsSync52(join23(current, "turbo.json"))) {
|
|
7284
7516
|
return current;
|
|
7285
7517
|
}
|
|
7286
7518
|
const pkgPath = join23(current, "package.json");
|
|
7287
|
-
if (
|
|
7519
|
+
if (existsSync52(pkgPath)) {
|
|
7288
7520
|
try {
|
|
7289
7521
|
const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
|
|
7290
7522
|
if (pkg.workspaces) {
|
|
@@ -7527,42 +7759,42 @@ function resolvePolicy(_config, _repoKind) {
|
|
|
7527
7759
|
};
|
|
7528
7760
|
}
|
|
7529
7761
|
function detectRepoKind(repoRoot) {
|
|
7530
|
-
const hasApps = existsSync(
|
|
7531
|
-
const hasPackages = existsSync(
|
|
7532
|
-
const hasTurbo = existsSync(
|
|
7762
|
+
const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
|
|
7763
|
+
const hasPackages = existsSync(path11__default.join(repoRoot, "packages"));
|
|
7764
|
+
const hasTurbo = existsSync(path11__default.join(repoRoot, "turbo.json"));
|
|
7533
7765
|
if (hasApps || hasPackages || hasTurbo) {
|
|
7534
7766
|
return "monorepo";
|
|
7535
7767
|
}
|
|
7536
|
-
const hasSrc = existsSync(
|
|
7537
|
-
const hasApp = existsSync(
|
|
7768
|
+
const hasSrc = existsSync(path11__default.join(repoRoot, "src"));
|
|
7769
|
+
const hasApp = existsSync(path11__default.join(repoRoot, "app"));
|
|
7538
7770
|
if (hasSrc || hasApp) {
|
|
7539
7771
|
return "pj-repo";
|
|
7540
7772
|
}
|
|
7541
7773
|
return "unknown";
|
|
7542
7774
|
}
|
|
7543
7775
|
function hasKnownFrameworkConfig(dir) {
|
|
7544
|
-
if (existsSync(
|
|
7776
|
+
if (existsSync(path11__default.join(dir, "next.config.js")) || existsSync(path11__default.join(dir, "next.config.mjs")) || existsSync(path11__default.join(dir, "next.config.ts"))) {
|
|
7545
7777
|
return true;
|
|
7546
7778
|
}
|
|
7547
|
-
if (existsSync(
|
|
7779
|
+
if (existsSync(path11__default.join(dir, "vite.config.js")) || existsSync(path11__default.join(dir, "vite.config.ts"))) {
|
|
7548
7780
|
return true;
|
|
7549
7781
|
}
|
|
7550
|
-
if (existsSync(
|
|
7782
|
+
if (existsSync(path11__default.join(dir, "remix.config.js"))) {
|
|
7551
7783
|
return true;
|
|
7552
7784
|
}
|
|
7553
|
-
if (existsSync(
|
|
7785
|
+
if (existsSync(path11__default.join(dir, "astro.config.mjs")) || existsSync(path11__default.join(dir, "astro.config.ts"))) {
|
|
7554
7786
|
return true;
|
|
7555
7787
|
}
|
|
7556
|
-
if (existsSync(
|
|
7788
|
+
if (existsSync(path11__default.join(dir, "nuxt.config.js")) || existsSync(path11__default.join(dir, "nuxt.config.ts"))) {
|
|
7557
7789
|
return true;
|
|
7558
7790
|
}
|
|
7559
|
-
if (existsSync(
|
|
7791
|
+
if (existsSync(path11__default.join(dir, "svelte.config.js"))) {
|
|
7560
7792
|
return true;
|
|
7561
7793
|
}
|
|
7562
7794
|
return false;
|
|
7563
7795
|
}
|
|
7564
7796
|
function hasPackageJson(dir) {
|
|
7565
|
-
return existsSync(
|
|
7797
|
+
return existsSync(path11__default.join(dir, "package.json"));
|
|
7566
7798
|
}
|
|
7567
7799
|
var PORT_PATTERNS = [
|
|
7568
7800
|
/-p\s*([0-9]+)/i,
|
|
@@ -7582,7 +7814,7 @@ function extractPortFromScript(script) {
|
|
|
7582
7814
|
return null;
|
|
7583
7815
|
}
|
|
7584
7816
|
function readPortFromScripts(appDir) {
|
|
7585
|
-
const pkgPath =
|
|
7817
|
+
const pkgPath = path11__default.join(appDir, "package.json");
|
|
7586
7818
|
if (!existsSync(pkgPath)) return 3e3;
|
|
7587
7819
|
try {
|
|
7588
7820
|
const { readFileSync: readFileSync29 } = __require("fs");
|
|
@@ -7601,30 +7833,30 @@ function readPortFromScripts(appDir) {
|
|
|
7601
7833
|
return 3e3;
|
|
7602
7834
|
}
|
|
7603
7835
|
function findWebAppUnderApps(repoRoot) {
|
|
7604
|
-
const appsDir =
|
|
7836
|
+
const appsDir = path11__default.join(repoRoot, "apps");
|
|
7605
7837
|
if (!existsSync(appsDir)) return null;
|
|
7606
7838
|
try {
|
|
7607
7839
|
const { readdirSync: readdirSync12 } = __require("fs");
|
|
7608
7840
|
const entries = readdirSync12(appsDir, { withFileTypes: true });
|
|
7609
7841
|
const priority = ["web", "dashboard", "app", "frontend", "client"];
|
|
7610
7842
|
for (const name of priority) {
|
|
7611
|
-
const candidate =
|
|
7843
|
+
const candidate = path11__default.join(appsDir, name);
|
|
7612
7844
|
if (hasKnownFrameworkConfig(candidate)) return candidate;
|
|
7613
7845
|
}
|
|
7614
7846
|
for (const entry of entries) {
|
|
7615
7847
|
if (!entry.isDirectory()) continue;
|
|
7616
7848
|
if (priority.includes(entry.name)) continue;
|
|
7617
|
-
const candidate =
|
|
7849
|
+
const candidate = path11__default.join(appsDir, entry.name);
|
|
7618
7850
|
if (hasKnownFrameworkConfig(candidate)) return candidate;
|
|
7619
7851
|
}
|
|
7620
7852
|
for (const name of priority) {
|
|
7621
|
-
const candidate =
|
|
7853
|
+
const candidate = path11__default.join(appsDir, name);
|
|
7622
7854
|
if (hasPackageJson(candidate)) return candidate;
|
|
7623
7855
|
}
|
|
7624
7856
|
for (const entry of entries) {
|
|
7625
7857
|
if (!entry.isDirectory()) continue;
|
|
7626
7858
|
if (priority.includes(entry.name)) continue;
|
|
7627
|
-
const candidate =
|
|
7859
|
+
const candidate = path11__default.join(appsDir, entry.name);
|
|
7628
7860
|
if (hasPackageJson(candidate)) return candidate;
|
|
7629
7861
|
}
|
|
7630
7862
|
} catch {
|
|
@@ -7633,7 +7865,7 @@ function findWebAppUnderApps(repoRoot) {
|
|
|
7633
7865
|
}
|
|
7634
7866
|
function detectApp(repoRoot, configOverride) {
|
|
7635
7867
|
if (configOverride?.directory && configOverride.directory !== ".") {
|
|
7636
|
-
const configuredDir =
|
|
7868
|
+
const configuredDir = path11__default.join(repoRoot, configOverride.directory);
|
|
7637
7869
|
if (existsSync(configuredDir) && hasPackageJson(configuredDir)) {
|
|
7638
7870
|
return {
|
|
7639
7871
|
appDir: configuredDir,
|
|
@@ -7768,7 +8000,7 @@ function pipeChildOutputToLog(params) {
|
|
|
7768
8000
|
return { cleanup };
|
|
7769
8001
|
}
|
|
7770
8002
|
async function writeEnvLocal(params) {
|
|
7771
|
-
const filePath =
|
|
8003
|
+
const filePath = path11__default.join(params.appDir, ".env.local");
|
|
7772
8004
|
const content = `${Object.entries(params.values).map(([k, v]) => `${k}=${v}`).join("\n")}
|
|
7773
8005
|
`;
|
|
7774
8006
|
await writeFile(filePath, content, "utf-8");
|
|
@@ -7858,20 +8090,62 @@ function determineAppCommand(mode, isMonorepo2, rootScripts, appScripts, repoRoo
|
|
|
7858
8090
|
}
|
|
7859
8091
|
if (appHasCiScript || appHasDefaultScript) {
|
|
7860
8092
|
const scriptName = appHasCiScript ? ciScriptName : "start";
|
|
7861
|
-
const dirArgs2 = isMonorepo2 ? ["-C",
|
|
8093
|
+
const dirArgs2 = isMonorepo2 ? ["-C", path11__default.relative(repoRoot, appDir)] : [];
|
|
7862
8094
|
return { command: ["pnpm", ...dirArgs2, scriptName], useRootScript: false };
|
|
7863
8095
|
}
|
|
7864
|
-
const dirArgs = isMonorepo2 ? ["-C",
|
|
8096
|
+
const dirArgs = isMonorepo2 ? ["-C", path11__default.relative(repoRoot, appDir)] : [];
|
|
7865
8097
|
return {
|
|
7866
8098
|
command: ["pnpm", ...dirArgs, "exec", "next", nextCommand, "-p", String(port)],
|
|
7867
8099
|
useRootScript: false
|
|
7868
8100
|
};
|
|
7869
8101
|
}
|
|
8102
|
+
var NEXT_CRITICAL_FILES = ["routes-manifest.json", "build-manifest.json"];
|
|
8103
|
+
function cleanStaleNextDevState(appDir) {
|
|
8104
|
+
const nextDir = path11__default.join(appDir, ".next");
|
|
8105
|
+
if (!existsSync(nextDir)) {
|
|
8106
|
+
return { cleaned: false };
|
|
8107
|
+
}
|
|
8108
|
+
for (const file of NEXT_CRITICAL_FILES) {
|
|
8109
|
+
if (!existsSync(path11__default.join(nextDir, file))) {
|
|
8110
|
+
cleanNextDir(nextDir, `Missing ${file}`);
|
|
8111
|
+
return { cleaned: true, reason: `Missing ${file}` };
|
|
8112
|
+
}
|
|
8113
|
+
}
|
|
8114
|
+
const serverDir = path11__default.join(nextDir, "server");
|
|
8115
|
+
if (!existsSync(serverDir)) {
|
|
8116
|
+
try {
|
|
8117
|
+
const nextStat = statSync(nextDir);
|
|
8118
|
+
const ageHours = (Date.now() - nextStat.mtimeMs) / (1e3 * 60 * 60);
|
|
8119
|
+
if (ageHours > 1) {
|
|
8120
|
+
cleanNextDir(nextDir, "Stale .next without server directory");
|
|
8121
|
+
return { cleaned: true, reason: "Stale .next without server directory" };
|
|
8122
|
+
}
|
|
8123
|
+
} catch {
|
|
8124
|
+
}
|
|
8125
|
+
}
|
|
8126
|
+
return { cleaned: false };
|
|
8127
|
+
}
|
|
8128
|
+
function cleanNextDir(nextDir, reason) {
|
|
8129
|
+
console.log(`[runa] Stale .next detected: ${reason}`);
|
|
8130
|
+
console.log("[runa] Cleaning up .next directory...");
|
|
8131
|
+
try {
|
|
8132
|
+
rmSync(nextDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
8133
|
+
console.log("[runa] Cleanup complete");
|
|
8134
|
+
} catch {
|
|
8135
|
+
const staleDir = `${nextDir}-stale-${Date.now()}`;
|
|
8136
|
+
console.log(`[runa] Could not remove .next, quarantining to ${path11__default.basename(staleDir)}`);
|
|
8137
|
+
try {
|
|
8138
|
+
renameSync(nextDir, staleDir);
|
|
8139
|
+
} catch {
|
|
8140
|
+
console.warn("[runa] Failed to quarantine .next. Run: rm -rf .next");
|
|
8141
|
+
}
|
|
8142
|
+
}
|
|
8143
|
+
}
|
|
7870
8144
|
async function startAppBackground(params) {
|
|
7871
8145
|
const mode = params.mode ?? "start";
|
|
7872
8146
|
const isMonorepo2 = params.appDir !== params.repoRoot;
|
|
7873
|
-
const rootPkgPath =
|
|
7874
|
-
const appPkgPath =
|
|
8147
|
+
const rootPkgPath = path11__default.join(params.repoRoot, "package.json");
|
|
8148
|
+
const appPkgPath = path11__default.join(params.appDir, "package.json");
|
|
7875
8149
|
const rootScripts = await readPackageScripts(rootPkgPath);
|
|
7876
8150
|
const appScripts = isMonorepo2 ? await readPackageScripts(appPkgPath) : rootScripts;
|
|
7877
8151
|
const { command, useRootScript } = determineAppCommand(
|
|
@@ -7883,7 +8157,7 @@ async function startAppBackground(params) {
|
|
|
7883
8157
|
params.appDir,
|
|
7884
8158
|
params.port
|
|
7885
8159
|
);
|
|
7886
|
-
const appLog =
|
|
8160
|
+
const appLog = path11__default.join(params.tmpDir, "app.log");
|
|
7887
8161
|
const out = createWriteStream(appLog, { flags: "a" });
|
|
7888
8162
|
const commandStr = command.join(" ");
|
|
7889
8163
|
const modeLabel = mode === "dev" ? "development (hot reload)" : "production";
|
|
@@ -7892,7 +8166,7 @@ async function startAppBackground(params) {
|
|
|
7892
8166
|
`[runa] Mode: ${modeLabel}`,
|
|
7893
8167
|
`[runa] Command: ${commandStr}`,
|
|
7894
8168
|
`[runa] Working directory: ${params.repoRoot}`,
|
|
7895
|
-
`[runa] App directory: ${
|
|
8169
|
+
`[runa] App directory: ${path11__default.relative(params.repoRoot, params.appDir) || "."}`,
|
|
7896
8170
|
useRootScript ? "[runa] Using root package.json script" : "[runa] Using app package.json script",
|
|
7897
8171
|
"---",
|
|
7898
8172
|
""
|
|
@@ -7913,12 +8187,12 @@ async function startAppBackground(params) {
|
|
|
7913
8187
|
streamToTerminal: params.stream
|
|
7914
8188
|
});
|
|
7915
8189
|
const pid = child.pid ?? -1;
|
|
7916
|
-
await writeFile(
|
|
8190
|
+
await writeFile(path11__default.join(params.tmpDir, "app.pid"), `${pid}
|
|
7917
8191
|
`, "utf-8");
|
|
7918
8192
|
return { pid, cleanupStreams };
|
|
7919
8193
|
}
|
|
7920
8194
|
async function waitForAppReady(params) {
|
|
7921
|
-
const logFilePath = params.tmpDir ?
|
|
8195
|
+
const logFilePath = params.tmpDir ? path11__default.join(params.tmpDir, "app.log") : void 0;
|
|
7922
8196
|
await waitHttpOk({
|
|
7923
8197
|
url: `http://127.0.0.1:${params.port}/`,
|
|
7924
8198
|
timeoutSeconds: params.timeoutSeconds,
|
|
@@ -8058,8 +8332,9 @@ var e2eMeta2 = {
|
|
|
8058
8332
|
var appStartActor = fromPromise(
|
|
8059
8333
|
async ({ input: input3 }) => {
|
|
8060
8334
|
const { repoRoot, appDir, port, tmpDir, stream } = input3;
|
|
8061
|
-
const fullTmpDir =
|
|
8335
|
+
const fullTmpDir = path11__default.join(repoRoot, tmpDir);
|
|
8062
8336
|
await mkdir(fullTmpDir, { recursive: true });
|
|
8337
|
+
cleanStaleNextDevState(appDir);
|
|
8063
8338
|
const result = await startAppBackground({
|
|
8064
8339
|
repoRoot,
|
|
8065
8340
|
appDir,
|
|
@@ -8325,11 +8600,11 @@ function printSummary2(logger16, output3) {
|
|
|
8325
8600
|
}
|
|
8326
8601
|
function findRepoRoot2(startDir) {
|
|
8327
8602
|
let current = startDir;
|
|
8328
|
-
while (current !==
|
|
8329
|
-
if (existsSync(
|
|
8603
|
+
while (current !== path11__default.dirname(current)) {
|
|
8604
|
+
if (existsSync(path11__default.join(current, "turbo.json"))) {
|
|
8330
8605
|
return current;
|
|
8331
8606
|
}
|
|
8332
|
-
const pkgPath =
|
|
8607
|
+
const pkgPath = path11__default.join(current, "package.json");
|
|
8333
8608
|
if (existsSync(pkgPath)) {
|
|
8334
8609
|
try {
|
|
8335
8610
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
@@ -8339,7 +8614,7 @@ function findRepoRoot2(startDir) {
|
|
|
8339
8614
|
} catch {
|
|
8340
8615
|
}
|
|
8341
8616
|
}
|
|
8342
|
-
current =
|
|
8617
|
+
current = path11__default.dirname(current);
|
|
8343
8618
|
}
|
|
8344
8619
|
return startDir;
|
|
8345
8620
|
}
|
|
@@ -8526,19 +8801,19 @@ function isSupportedNodeEnv(value) {
|
|
|
8526
8801
|
function findProjectRoot(from) {
|
|
8527
8802
|
const workspaceRoot = findWorkspaceRoot(from);
|
|
8528
8803
|
if (workspaceRoot) return workspaceRoot;
|
|
8529
|
-
let current =
|
|
8530
|
-
const root =
|
|
8804
|
+
let current = path11__default.resolve(from);
|
|
8805
|
+
const root = path11__default.parse(current).root;
|
|
8531
8806
|
let depth = 0;
|
|
8532
8807
|
while (current !== root && depth < MAX_DIRECTORY_TRAVERSAL_DEPTH) {
|
|
8533
|
-
const hasGit = existsSync(
|
|
8534
|
-
const hasPackageJson2 = existsSync(
|
|
8808
|
+
const hasGit = existsSync(path11__default.join(current, ".git"));
|
|
8809
|
+
const hasPackageJson2 = existsSync(path11__default.join(current, "package.json"));
|
|
8535
8810
|
if (hasGit || hasPackageJson2) return current;
|
|
8536
|
-
const parent =
|
|
8811
|
+
const parent = path11__default.dirname(current);
|
|
8537
8812
|
if (parent === current) break;
|
|
8538
8813
|
current = parent;
|
|
8539
8814
|
depth++;
|
|
8540
8815
|
}
|
|
8541
|
-
return
|
|
8816
|
+
return path11__default.resolve(from);
|
|
8542
8817
|
}
|
|
8543
8818
|
function mapRunaEnvToVercelEnv(runaEnv) {
|
|
8544
8819
|
if (runaEnv === "preview") return "preview";
|
|
@@ -8579,7 +8854,7 @@ function loadEnvFiles(options = {}) {
|
|
|
8579
8854
|
const nodeEnv = resolveNodeEnv(options.nodeEnv);
|
|
8580
8855
|
const projectRoot = findProjectRoot(cwd);
|
|
8581
8856
|
const vercelEnv = options.vercelEnv ?? inferVercelEnv({ nodeEnv, runaEnv: options.runaEnv });
|
|
8582
|
-
const keysFile =
|
|
8857
|
+
const keysFile = path11__default.join(projectRoot, ".env.keys");
|
|
8583
8858
|
const baseFilePaths = buildBaseEnvFilePaths({ nodeEnv, vercelEnv });
|
|
8584
8859
|
const runaFilePaths = options.runaEnv ? buildRunaEnvFilePaths(options.runaEnv) : [];
|
|
8585
8860
|
const allRelPaths = [...baseFilePaths, ...runaFilePaths];
|
|
@@ -8589,7 +8864,7 @@ function loadEnvFiles(options = {}) {
|
|
|
8589
8864
|
const filePaths = [
|
|
8590
8865
|
keysFile,
|
|
8591
8866
|
// Load keys first
|
|
8592
|
-
...allRelPaths.map((rel) =>
|
|
8867
|
+
...allRelPaths.map((rel) => path11__default.join(projectRoot, rel)).filter(existsSync)
|
|
8593
8868
|
];
|
|
8594
8869
|
config({
|
|
8595
8870
|
path: filePaths,
|
|
@@ -8598,7 +8873,7 @@ function loadEnvFiles(options = {}) {
|
|
|
8598
8873
|
quiet: true
|
|
8599
8874
|
// Suppress dotenvx verbose output
|
|
8600
8875
|
});
|
|
8601
|
-
loadedFiles = allRelPaths.filter((rel) => existsSync(
|
|
8876
|
+
loadedFiles = allRelPaths.filter((rel) => existsSync(path11__default.join(projectRoot, rel)));
|
|
8602
8877
|
} else {
|
|
8603
8878
|
const targetEnv = { ...process.env };
|
|
8604
8879
|
loadedFiles = [
|
|
@@ -8673,8 +8948,8 @@ function buildRunaEnvFilePaths(runaEnv) {
|
|
|
8673
8948
|
function loadEnvFilesIntoTarget(params) {
|
|
8674
8949
|
const loadedFiles = [];
|
|
8675
8950
|
for (const relPath of params.relPaths) {
|
|
8676
|
-
const fullPath =
|
|
8677
|
-
const resolvedPath =
|
|
8951
|
+
const fullPath = path11__default.join(params.projectRoot, relPath);
|
|
8952
|
+
const resolvedPath = path11__default.resolve(fullPath);
|
|
8678
8953
|
if (!isPathContained(params.projectRoot, resolvedPath)) {
|
|
8679
8954
|
continue;
|
|
8680
8955
|
}
|
|
@@ -8942,7 +9217,7 @@ async function runTool(params) {
|
|
|
8942
9217
|
exitCode,
|
|
8943
9218
|
issueCount,
|
|
8944
9219
|
durationMs,
|
|
8945
|
-
outputPath:
|
|
9220
|
+
outputPath: path11__default.relative(process.cwd(), params.outputPath)
|
|
8946
9221
|
});
|
|
8947
9222
|
});
|
|
8948
9223
|
proc.on("error", async () => {
|
|
@@ -8961,7 +9236,7 @@ async function runTool(params) {
|
|
|
8961
9236
|
exitCode: -1,
|
|
8962
9237
|
issueCount: 0,
|
|
8963
9238
|
durationMs,
|
|
8964
|
-
outputPath:
|
|
9239
|
+
outputPath: path11__default.relative(process.cwd(), params.outputPath)
|
|
8965
9240
|
});
|
|
8966
9241
|
});
|
|
8967
9242
|
});
|
|
@@ -8993,7 +9268,7 @@ async function executeWorkflowCheck(params) {
|
|
|
8993
9268
|
label: params.label,
|
|
8994
9269
|
command: params.command,
|
|
8995
9270
|
args: params.args,
|
|
8996
|
-
outputPath:
|
|
9271
|
+
outputPath: path11__default.join(params.logDir, `${params.name}-output.txt`),
|
|
8997
9272
|
parseIssueCount: params.parseIssueCount
|
|
8998
9273
|
});
|
|
8999
9274
|
logCheckResult(result, params.isWarningOnly ?? false);
|
|
@@ -9065,7 +9340,7 @@ async function runCiChecks(options) {
|
|
|
9065
9340
|
const mode = options.mode === "github-actions" ? "github-actions" : "local";
|
|
9066
9341
|
const isCI3 = mode === "github-actions";
|
|
9067
9342
|
const workflowsChanged = options.workflowsChanged;
|
|
9068
|
-
const logDir =
|
|
9343
|
+
const logDir = path11__default.join(process.cwd(), ".runa", "tmp", "workflow");
|
|
9069
9344
|
await mkdir(logDir, { recursive: true });
|
|
9070
9345
|
console.log("");
|
|
9071
9346
|
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
@@ -9074,7 +9349,7 @@ async function runCiChecks(options) {
|
|
|
9074
9349
|
console.log("");
|
|
9075
9350
|
const results = await executeChecks(workflowsChanged, logDir);
|
|
9076
9351
|
const summary = buildChecksSummary(startedAt, workflowsChanged, results);
|
|
9077
|
-
const summaryPath =
|
|
9352
|
+
const summaryPath = path11__default.join(logDir, "checks-summary.json");
|
|
9078
9353
|
await writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
|
|
9079
9354
|
if (isCI3) {
|
|
9080
9355
|
await appendGithubStepSummary(buildStepSummaryMarkdown(summary));
|
|
@@ -9141,7 +9416,7 @@ function printFinalOutput(summary, summaryPath) {
|
|
|
9141
9416
|
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
9142
9417
|
console.log(`${summary.status === "failure" ? "\u274C" : "\u2705"} Workflow Checks: ${summary.status}`);
|
|
9143
9418
|
console.log(` Duration: ${formatDuration$1(summary.durationMs)}`);
|
|
9144
|
-
console.log(` Summary: ${
|
|
9419
|
+
console.log(` Summary: ${path11__default.relative(process.cwd(), summaryPath)}`);
|
|
9145
9420
|
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
9146
9421
|
}
|
|
9147
9422
|
var ciChecksCommand = new Command("checks").description("Run workflow checks (actionlint, zizmor)").option("--mode <mode>", "Execution mode (github-actions | local)", "local").option("--workflows-changed", "Indicate workflows have changed", false).action(runCiChecks);
|
|
@@ -9154,10 +9429,10 @@ init_esm_shims();
|
|
|
9154
9429
|
var CiConfigSchema = z.record(z.string(), z.unknown());
|
|
9155
9430
|
async function loadCiConfig(params) {
|
|
9156
9431
|
const override = typeof params.overridePath === "string" && params.overridePath.trim().length > 0 ? params.overridePath.trim() : null;
|
|
9157
|
-
const defaultPath =
|
|
9432
|
+
const defaultPath = path11__default.join(params.repoRoot, ".runa", "ci.config.json");
|
|
9158
9433
|
const resolvedPath = override ?? (existsSync(defaultPath) ? defaultPath : null);
|
|
9159
9434
|
if (!resolvedPath) return { configPath: null, config: null };
|
|
9160
|
-
const abs =
|
|
9435
|
+
const abs = path11__default.isAbsolute(resolvedPath) ? resolvedPath : path11__default.join(params.repoRoot, resolvedPath);
|
|
9161
9436
|
if (!existsSync(abs)) return { configPath: abs, config: null };
|
|
9162
9437
|
const raw = await readFile(abs, "utf-8");
|
|
9163
9438
|
const parsed = JSON.parse(raw);
|
|
@@ -9259,9 +9534,9 @@ var CiSummarySchema = z.object({
|
|
|
9259
9534
|
async function writeCiSummary(params) {
|
|
9260
9535
|
const cwd = params.cwd ?? process.cwd();
|
|
9261
9536
|
const parsed = CiSummarySchema.parse(params.summary);
|
|
9262
|
-
const dir =
|
|
9537
|
+
const dir = path11__default.join(cwd, ".runa", "tmp");
|
|
9263
9538
|
await mkdir(dir, { recursive: true });
|
|
9264
|
-
const filePath =
|
|
9539
|
+
const filePath = path11__default.join(dir, "ci-summary.json");
|
|
9265
9540
|
await writeFile(filePath, `${JSON.stringify(parsed, null, 2)}
|
|
9266
9541
|
`, "utf-8");
|
|
9267
9542
|
return filePath;
|
|
@@ -9510,12 +9785,12 @@ async function detectStack(repoRoot, tmpDir, productionDbUrlAdmin) {
|
|
|
9510
9785
|
label: "detect-stack",
|
|
9511
9786
|
command: "pnpm",
|
|
9512
9787
|
args: ["exec", "runa", "db", "detect-stack", "--quiet"],
|
|
9513
|
-
logFile:
|
|
9788
|
+
logFile: path11__default.join(tmpDir, "detect-stack.log")
|
|
9514
9789
|
});
|
|
9515
9790
|
return String(res.stdout ?? "").trim();
|
|
9516
9791
|
}
|
|
9517
9792
|
function checkIfInitialDeployment(repoRoot, productionDbUrl) {
|
|
9518
|
-
const schemasDir =
|
|
9793
|
+
const schemasDir = path11__default.join(repoRoot, "supabase", "schemas", "declarative");
|
|
9519
9794
|
let schemas;
|
|
9520
9795
|
try {
|
|
9521
9796
|
schemas = detectAppSchemas(schemasDir, false);
|
|
@@ -9581,9 +9856,9 @@ function checkIfInitialDeployment(repoRoot, productionDbUrl) {
|
|
|
9581
9856
|
}
|
|
9582
9857
|
}
|
|
9583
9858
|
async function showSchemaDiff(repoRoot, tmpDir) {
|
|
9584
|
-
const diffLog =
|
|
9859
|
+
const diffLog = path11__default.join(tmpDir, "schema-diff.log");
|
|
9585
9860
|
const safeEnv = getSafeEnv();
|
|
9586
|
-
const declarativeSqlPath =
|
|
9861
|
+
const declarativeSqlPath = path11__default.join(repoRoot, "supabase/schemas/declarative");
|
|
9587
9862
|
if (existsSync(declarativeSqlPath)) {
|
|
9588
9863
|
await runLogged({
|
|
9589
9864
|
cwd: repoRoot,
|
|
@@ -9597,8 +9872,8 @@ async function showSchemaDiff(repoRoot, tmpDir) {
|
|
|
9597
9872
|
}
|
|
9598
9873
|
const detected = detectDatabasePackage(repoRoot);
|
|
9599
9874
|
if (detected) {
|
|
9600
|
-
const schemaPath =
|
|
9601
|
-
if (existsSync(
|
|
9875
|
+
const schemaPath = path11__default.join(detected, "src", "schema");
|
|
9876
|
+
if (existsSync(path11__default.join(repoRoot, schemaPath))) {
|
|
9602
9877
|
await runLogged({
|
|
9603
9878
|
cwd: repoRoot,
|
|
9604
9879
|
env: safeEnv,
|
|
@@ -9611,8 +9886,8 @@ async function showSchemaDiff(repoRoot, tmpDir) {
|
|
|
9611
9886
|
}
|
|
9612
9887
|
}
|
|
9613
9888
|
for (const candidate of DATABASE_PACKAGE_CANDIDATES) {
|
|
9614
|
-
const candidatePath =
|
|
9615
|
-
if (existsSync(
|
|
9889
|
+
const candidatePath = path11__default.join("packages", candidate, "src", "schema");
|
|
9890
|
+
if (existsSync(path11__default.join(repoRoot, candidatePath))) {
|
|
9616
9891
|
await runLogged({
|
|
9617
9892
|
cwd: repoRoot,
|
|
9618
9893
|
env: safeEnv,
|
|
@@ -9624,7 +9899,7 @@ async function showSchemaDiff(repoRoot, tmpDir) {
|
|
|
9624
9899
|
return;
|
|
9625
9900
|
}
|
|
9626
9901
|
}
|
|
9627
|
-
if (existsSync(
|
|
9902
|
+
if (existsSync(path11__default.join(repoRoot, "src", "schema"))) {
|
|
9628
9903
|
await runLogged({
|
|
9629
9904
|
cwd: repoRoot,
|
|
9630
9905
|
env: safeEnv,
|
|
@@ -9636,7 +9911,7 @@ async function showSchemaDiff(repoRoot, tmpDir) {
|
|
|
9636
9911
|
}
|
|
9637
9912
|
}
|
|
9638
9913
|
async function detectRisks(repoRoot, tmpDir) {
|
|
9639
|
-
const logFile =
|
|
9914
|
+
const logFile = path11__default.join(tmpDir, "db-risks.log");
|
|
9640
9915
|
try {
|
|
9641
9916
|
const env2 = getFilteredEnv();
|
|
9642
9917
|
await runLogged({
|
|
@@ -9682,7 +9957,7 @@ async function snapshotCreate(repoRoot, tmpDir, productionDbUrlAdmin, commit) {
|
|
|
9682
9957
|
label: "snapshot create production",
|
|
9683
9958
|
command: "pnpm",
|
|
9684
9959
|
args: ["exec", "runa", "db", "snapshot", "create", "production", "--commit", commit],
|
|
9685
|
-
logFile:
|
|
9960
|
+
logFile: path11__default.join(tmpDir, "snapshot-create.log")
|
|
9686
9961
|
});
|
|
9687
9962
|
}
|
|
9688
9963
|
async function snapshotRestoreLatest(repoRoot, tmpDir, productionDbUrlAdmin) {
|
|
@@ -9695,7 +9970,7 @@ async function snapshotRestoreLatest(repoRoot, tmpDir, productionDbUrlAdmin) {
|
|
|
9695
9970
|
label: "snapshot restore production (latest)",
|
|
9696
9971
|
command: "pnpm",
|
|
9697
9972
|
args: ["exec", "runa", "db", "snapshot", "restore", "production", "--latest", "--auto-approve"],
|
|
9698
|
-
logFile:
|
|
9973
|
+
logFile: path11__default.join(tmpDir, "snapshot-restore.log")
|
|
9699
9974
|
});
|
|
9700
9975
|
}
|
|
9701
9976
|
function parseApplyLog(logContent) {
|
|
@@ -9759,7 +10034,7 @@ async function applyProductionSchema(repoRoot, tmpDir, productionDbUrlAdmin, pro
|
|
|
9759
10034
|
if (options?.maxLockWaitMs !== void 0) {
|
|
9760
10035
|
args.push("--max-lock-wait-ms", String(options.maxLockWaitMs));
|
|
9761
10036
|
}
|
|
9762
|
-
const logPath =
|
|
10037
|
+
const logPath = path11__default.join(tmpDir, "db-apply-production.log");
|
|
9763
10038
|
const startTime = Date.now();
|
|
9764
10039
|
await runLogged({
|
|
9765
10040
|
cwd: repoRoot,
|
|
@@ -9804,11 +10079,11 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
|
|
|
9804
10079
|
label: "git log (commit message)",
|
|
9805
10080
|
command: "git",
|
|
9806
10081
|
args: ["log", "-1", "--pretty=format:%s"],
|
|
9807
|
-
logFile:
|
|
10082
|
+
logFile: path11__default.join(tmpDir, "git-commit-message.log")
|
|
9808
10083
|
});
|
|
9809
10084
|
const commitMsg = String(msg.stdout ?? "").trim();
|
|
9810
10085
|
const schemaPaths = [];
|
|
9811
|
-
const declarativeSqlPath =
|
|
10086
|
+
const declarativeSqlPath = path11__default.join(repoRoot, "supabase/schemas/declarative");
|
|
9812
10087
|
if (existsSync(declarativeSqlPath)) {
|
|
9813
10088
|
schemaPaths.push("supabase/schemas/declarative/");
|
|
9814
10089
|
} else {
|
|
@@ -9828,7 +10103,7 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
|
|
|
9828
10103
|
label: "git diff (schema)",
|
|
9829
10104
|
command: "git",
|
|
9830
10105
|
args: ["diff", "origin/main", "HEAD", "--", ...schemaPaths],
|
|
9831
|
-
logFile:
|
|
10106
|
+
logFile: path11__default.join(tmpDir, "git-schema-diff.log")
|
|
9832
10107
|
});
|
|
9833
10108
|
const diffRaw = String(diff.stdout ?? "");
|
|
9834
10109
|
const diffLimited = diffRaw.length > 1e4 ? diffRaw.slice(0, 1e4) : diffRaw;
|
|
@@ -9857,7 +10132,7 @@ async function auditRecord(repoRoot, tmpDir, productionDbUrlAdmin, params) {
|
|
|
9857
10132
|
"--environment",
|
|
9858
10133
|
"production"
|
|
9859
10134
|
],
|
|
9860
|
-
logFile:
|
|
10135
|
+
logFile: path11__default.join(tmpDir, "db-audit-record.log")
|
|
9861
10136
|
});
|
|
9862
10137
|
}
|
|
9863
10138
|
async function notifyDeployment(repoRoot, tmpDir, params) {
|
|
@@ -9885,7 +10160,7 @@ async function notifyDeployment(repoRoot, tmpDir, params) {
|
|
|
9885
10160
|
"--type",
|
|
9886
10161
|
"production-schema"
|
|
9887
10162
|
],
|
|
9888
|
-
logFile:
|
|
10163
|
+
logFile: path11__default.join(tmpDir, "notify-deployment.log")
|
|
9889
10164
|
});
|
|
9890
10165
|
}
|
|
9891
10166
|
|
|
@@ -10247,7 +10522,7 @@ $$;
|
|
|
10247
10522
|
label: `repair timestamps (${params.labelPrefix})`,
|
|
10248
10523
|
command: "psql",
|
|
10249
10524
|
args: [...psql.args, "-v", "ON_ERROR_STOP=1", "-c", sql],
|
|
10250
|
-
logFile:
|
|
10525
|
+
logFile: path11__default.join(params.tmpDir, `timestamp-repair-${params.labelPrefix}.log`)
|
|
10251
10526
|
});
|
|
10252
10527
|
}
|
|
10253
10528
|
|
|
@@ -10679,7 +10954,7 @@ async function runCiProdApply(params) {
|
|
|
10679
10954
|
overridePath: params.options.config
|
|
10680
10955
|
});
|
|
10681
10956
|
if (cfg.configPath)
|
|
10682
|
-
params.summary.detected.configPath =
|
|
10957
|
+
params.summary.detected.configPath = path11__default.relative(params.repoRoot, cfg.configPath);
|
|
10683
10958
|
if (cfg.config) params.summary.detected.config = cfg.config;
|
|
10684
10959
|
requireCiAutoApprove({ mode: params.summary.mode, autoApprove: params.options.autoApprove });
|
|
10685
10960
|
const inputs = resolveProdApplyInputs();
|
|
@@ -10772,7 +11047,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
|
|
|
10772
11047
|
await appendGithubStepSummary(
|
|
10773
11048
|
buildCiProdApplyStepSummaryMarkdown({
|
|
10774
11049
|
summary,
|
|
10775
|
-
summaryPath:
|
|
11050
|
+
summaryPath: path11__default.relative(repoRoot, summaryPath)
|
|
10776
11051
|
})
|
|
10777
11052
|
);
|
|
10778
11053
|
if (summary.mode === "github-actions") {
|
|
@@ -10788,7 +11063,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
|
|
|
10788
11063
|
const summaryPath = await writeCiSummary({ summary });
|
|
10789
11064
|
logSection("Result");
|
|
10790
11065
|
console.log(`status: ${summary.status}`);
|
|
10791
|
-
console.log(`summary: ${
|
|
11066
|
+
console.log(`summary: ${path11__default.relative(repoRoot, summaryPath)}`);
|
|
10792
11067
|
logNextActions([
|
|
10793
11068
|
"Inspect .runa/tmp logs (db-apply-production.log, snapshot-*.log)",
|
|
10794
11069
|
"If rollback succeeded, database should be restored to pre-deploy snapshot"
|
|
@@ -10796,7 +11071,7 @@ var ciProdApplyCommand = new Command("prod-apply").description("Apply production
|
|
|
10796
11071
|
await appendGithubStepSummary(
|
|
10797
11072
|
buildCiProdApplyStepSummaryMarkdown({
|
|
10798
11073
|
summary,
|
|
10799
|
-
summaryPath:
|
|
11074
|
+
summaryPath: path11__default.relative(repoRoot, summaryPath)
|
|
10800
11075
|
})
|
|
10801
11076
|
);
|
|
10802
11077
|
await maybePostFailureComment({
|
|
@@ -10867,7 +11142,7 @@ function getChecks() {
|
|
|
10867
11142
|
}
|
|
10868
11143
|
async function runCheck(check, logDir) {
|
|
10869
11144
|
const startTime = Date.now();
|
|
10870
|
-
const logPath =
|
|
11145
|
+
const logPath = path11__default.join(logDir, `${check.name}.log`);
|
|
10871
11146
|
return new Promise((resolve12) => {
|
|
10872
11147
|
const proc = spawn(check.command, check.args, {
|
|
10873
11148
|
cwd: process.cwd(),
|
|
@@ -10897,7 +11172,7 @@ async function runCheck(check, logDir) {
|
|
|
10897
11172
|
status: exitCode === 0 ? "passed" : "failed",
|
|
10898
11173
|
exitCode,
|
|
10899
11174
|
durationMs,
|
|
10900
|
-
logPath:
|
|
11175
|
+
logPath: path11__default.relative(process.cwd(), logPath)
|
|
10901
11176
|
});
|
|
10902
11177
|
});
|
|
10903
11178
|
proc.on("error", async () => {
|
|
@@ -10912,7 +11187,7 @@ async function runCheck(check, logDir) {
|
|
|
10912
11187
|
status: "failed",
|
|
10913
11188
|
exitCode: 1,
|
|
10914
11189
|
durationMs,
|
|
10915
|
-
logPath:
|
|
11190
|
+
logPath: path11__default.relative(process.cwd(), logPath)
|
|
10916
11191
|
});
|
|
10917
11192
|
});
|
|
10918
11193
|
});
|
|
@@ -11040,19 +11315,19 @@ function printFinalStaticOutput(summary, summaryPath) {
|
|
|
11040
11315
|
console.log(`${summary.status === "success" ? "\u2705" : "\u274C"} Static Analysis: ${summary.status}`);
|
|
11041
11316
|
console.log(` Duration: ${formatDuration$1(summary.durationMs)}`);
|
|
11042
11317
|
console.log(` Passed: ${summary.passedCount}/${summary.checks.length}`);
|
|
11043
|
-
console.log(` Summary: ${
|
|
11318
|
+
console.log(` Summary: ${path11__default.relative(process.cwd(), summaryPath)}`);
|
|
11044
11319
|
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
11045
11320
|
}
|
|
11046
11321
|
async function runCiStatic(options) {
|
|
11047
11322
|
const startedAt = /* @__PURE__ */ new Date();
|
|
11048
11323
|
const isCI3 = options.mode === "github-actions";
|
|
11049
|
-
const logDir =
|
|
11324
|
+
const logDir = path11__default.join(process.cwd(), ".runa", "tmp", "workflow");
|
|
11050
11325
|
await mkdir(logDir, { recursive: true });
|
|
11051
11326
|
const checksToRun = getChecksToRun(options);
|
|
11052
11327
|
printStaticHeader(options);
|
|
11053
11328
|
const results = options.parallel ? await runChecksParallel(checksToRun, logDir) : await runChecksSequential(checksToRun, logDir);
|
|
11054
11329
|
const summary = buildStaticSummary(startedAt, results);
|
|
11055
|
-
const summaryPath =
|
|
11330
|
+
const summaryPath = path11__default.join(logDir, "static-summary.json");
|
|
11056
11331
|
await writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
|
|
11057
11332
|
if (isCI3) {
|
|
11058
11333
|
await appendGithubStepSummary(buildStepSummaryMarkdown2(summary));
|
|
@@ -11082,9 +11357,9 @@ var appBuildActor = fromPromise(
|
|
|
11082
11357
|
async ({ input: input3 }) => {
|
|
11083
11358
|
const { repoRoot, tmpDir, env: env2 = process.env } = input3;
|
|
11084
11359
|
try {
|
|
11085
|
-
const hasTurbo = existsSync(
|
|
11086
|
-
const hasApps = existsSync(
|
|
11087
|
-
const hasAppsWeb = existsSync(
|
|
11360
|
+
const hasTurbo = existsSync(path11__default.join(repoRoot, "turbo.json"));
|
|
11361
|
+
const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
|
|
11362
|
+
const hasAppsWeb = existsSync(path11__default.join(repoRoot, "apps", "web"));
|
|
11088
11363
|
const args = hasTurbo ? hasApps && !hasAppsWeb ? ["turbo", "run", "build", "--filter=./apps/*"] : ["turbo", "run", "build"] : ["build"];
|
|
11089
11364
|
await runLogged({
|
|
11090
11365
|
cwd: repoRoot,
|
|
@@ -11092,7 +11367,7 @@ var appBuildActor = fromPromise(
|
|
|
11092
11367
|
label: "build",
|
|
11093
11368
|
command: "pnpm",
|
|
11094
11369
|
args,
|
|
11095
|
-
logFile:
|
|
11370
|
+
logFile: path11__default.join(tmpDir, "build.log")
|
|
11096
11371
|
});
|
|
11097
11372
|
return { passed: true };
|
|
11098
11373
|
} catch (error) {
|
|
@@ -11108,14 +11383,14 @@ var appBuildActor = fromPromise(
|
|
|
11108
11383
|
init_esm_shims();
|
|
11109
11384
|
var APP_CANDIDATES = ["web", "dashboard", "app", "frontend", "client"];
|
|
11110
11385
|
function findExistingAppDirs(repoRoot) {
|
|
11111
|
-
const appsDir =
|
|
11386
|
+
const appsDir = path11__default.join(repoRoot, "apps");
|
|
11112
11387
|
if (!existsSync(appsDir)) return [];
|
|
11113
11388
|
try {
|
|
11114
11389
|
const entries = readdirSync(appsDir, { withFileTypes: true });
|
|
11115
11390
|
const found = [];
|
|
11116
11391
|
for (const entry of entries) {
|
|
11117
11392
|
if (!entry.isDirectory()) continue;
|
|
11118
|
-
const pkgJson =
|
|
11393
|
+
const pkgJson = path11__default.join(appsDir, entry.name, "package.json");
|
|
11119
11394
|
if (existsSync(pkgJson)) {
|
|
11120
11395
|
found.push(`apps/${entry.name}`);
|
|
11121
11396
|
}
|
|
@@ -11135,9 +11410,9 @@ function findExistingAppDirs(repoRoot) {
|
|
|
11135
11410
|
}
|
|
11136
11411
|
}
|
|
11137
11412
|
function validateAppDir(repoRoot, appDir) {
|
|
11138
|
-
const pkgJsonPath =
|
|
11413
|
+
const pkgJsonPath = path11__default.join(appDir, "package.json");
|
|
11139
11414
|
if (!existsSync(appDir)) {
|
|
11140
|
-
const relPath =
|
|
11415
|
+
const relPath = path11__default.relative(repoRoot, appDir) || ".";
|
|
11141
11416
|
const suggestions = findExistingAppDirs(repoRoot);
|
|
11142
11417
|
const errorParts = [`App directory not found: ${relPath}`];
|
|
11143
11418
|
if (suggestions.length > 0) {
|
|
@@ -11159,7 +11434,7 @@ function validateAppDir(repoRoot, appDir) {
|
|
|
11159
11434
|
return errorParts.join("\n");
|
|
11160
11435
|
}
|
|
11161
11436
|
if (!existsSync(pkgJsonPath)) {
|
|
11162
|
-
const relPath =
|
|
11437
|
+
const relPath = path11__default.relative(repoRoot, appDir) || ".";
|
|
11163
11438
|
return `No package.json found in app directory: ${relPath}`;
|
|
11164
11439
|
}
|
|
11165
11440
|
return null;
|
|
@@ -11216,9 +11491,9 @@ init_esm_shims();
|
|
|
11216
11491
|
async function runAppBuild(params) {
|
|
11217
11492
|
const { repoRoot, tmpDir, env: env2 } = params;
|
|
11218
11493
|
try {
|
|
11219
|
-
const hasTurbo = existsSync(
|
|
11220
|
-
const hasApps = existsSync(
|
|
11221
|
-
const hasAppsWeb = existsSync(
|
|
11494
|
+
const hasTurbo = existsSync(path11__default.join(repoRoot, "turbo.json"));
|
|
11495
|
+
const hasApps = existsSync(path11__default.join(repoRoot, "apps"));
|
|
11496
|
+
const hasAppsWeb = existsSync(path11__default.join(repoRoot, "apps", "web"));
|
|
11222
11497
|
const args = hasTurbo ? hasApps && !hasAppsWeb ? ["turbo", "run", "build", "--filter=./apps/*"] : ["turbo", "run", "build"] : ["build"];
|
|
11223
11498
|
await runLogged({
|
|
11224
11499
|
cwd: repoRoot,
|
|
@@ -11226,7 +11501,7 @@ async function runAppBuild(params) {
|
|
|
11226
11501
|
label: "build",
|
|
11227
11502
|
command: "pnpm",
|
|
11228
11503
|
args,
|
|
11229
|
-
logFile:
|
|
11504
|
+
logFile: path11__default.join(tmpDir, "build.log")
|
|
11230
11505
|
});
|
|
11231
11506
|
return { passed: true };
|
|
11232
11507
|
} catch (error) {
|
|
@@ -11245,7 +11520,7 @@ async function runManifestGenerate(params) {
|
|
|
11245
11520
|
label: "manifest:generate",
|
|
11246
11521
|
command: "pnpm",
|
|
11247
11522
|
args: ["manifest:generate"],
|
|
11248
|
-
logFile:
|
|
11523
|
+
logFile: path11__default.join(tmpDir, "manifest-generate.log")
|
|
11249
11524
|
});
|
|
11250
11525
|
return { generated: true };
|
|
11251
11526
|
} catch (error) {
|
|
@@ -11265,7 +11540,7 @@ async function runPlaywrightInstall(params) {
|
|
|
11265
11540
|
label: "playwright install",
|
|
11266
11541
|
command: "pnpm",
|
|
11267
11542
|
args,
|
|
11268
|
-
logFile:
|
|
11543
|
+
logFile: path11__default.join(tmpDir, "playwright-install.log")
|
|
11269
11544
|
});
|
|
11270
11545
|
return { installed: true };
|
|
11271
11546
|
} catch (error) {
|
|
@@ -11338,7 +11613,7 @@ var playwrightInstallActor = fromPromise(
|
|
|
11338
11613
|
label: "playwright install",
|
|
11339
11614
|
command: "pnpm",
|
|
11340
11615
|
args,
|
|
11341
|
-
logFile:
|
|
11616
|
+
logFile: path11__default.join(tmpDir, "playwright-install.log")
|
|
11342
11617
|
});
|
|
11343
11618
|
return { installed: true };
|
|
11344
11619
|
} catch (error) {
|
|
@@ -11362,7 +11637,7 @@ var staticChecksActor2 = fromPromise(
|
|
|
11362
11637
|
label: "type-check",
|
|
11363
11638
|
command: "pnpm",
|
|
11364
11639
|
args: ["type-check"],
|
|
11365
|
-
logFile:
|
|
11640
|
+
logFile: path11__default.join(tmpDir, "type-check.log")
|
|
11366
11641
|
}),
|
|
11367
11642
|
runLogged({
|
|
11368
11643
|
cwd: repoRoot,
|
|
@@ -11370,7 +11645,7 @@ var staticChecksActor2 = fromPromise(
|
|
|
11370
11645
|
label: "lint",
|
|
11371
11646
|
command: "pnpm",
|
|
11372
11647
|
args: ["lint"],
|
|
11373
|
-
logFile:
|
|
11648
|
+
logFile: path11__default.join(tmpDir, "lint.log")
|
|
11374
11649
|
})
|
|
11375
11650
|
]);
|
|
11376
11651
|
const typeCheckPassed = typeCheckResult.status === "fulfilled";
|
|
@@ -11521,7 +11796,7 @@ var applySeedsActor = fromPromise(
|
|
|
11521
11796
|
label: `db seed (${envArg})`,
|
|
11522
11797
|
command: "pnpm",
|
|
11523
11798
|
args: ["exec", "runa", "db", "seed", envArg, "--auto-approve"],
|
|
11524
|
-
logFile:
|
|
11799
|
+
logFile: path11__default.join(tmpDir, `ci-db-seed-${envArg}.log`)
|
|
11525
11800
|
});
|
|
11526
11801
|
return { applied: true };
|
|
11527
11802
|
} catch (error) {
|
|
@@ -11899,7 +12174,7 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
|
|
|
11899
12174
|
label: `probe pgtap (best-effort, ${params.label})`,
|
|
11900
12175
|
command: "psql",
|
|
11901
12176
|
args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", probeSql],
|
|
11902
|
-
logFile:
|
|
12177
|
+
logFile: path11__default.join(params.tmpDir, `pgtap-probe-${params.label}.log`)
|
|
11903
12178
|
}).catch(() => null);
|
|
11904
12179
|
const raw = String(probe?.stdout ?? "").trim();
|
|
11905
12180
|
const [availableRaw, installedRaw] = raw.split(",");
|
|
@@ -11914,11 +12189,11 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
|
|
|
11914
12189
|
label: `ensure pgtap (best-effort, ${params.label})`,
|
|
11915
12190
|
command: "psql",
|
|
11916
12191
|
args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-c", installSql],
|
|
11917
|
-
logFile:
|
|
12192
|
+
logFile: path11__default.join(params.tmpDir, `pgtap-ensure-${params.label}.log`)
|
|
11918
12193
|
}).catch(async (error) => {
|
|
11919
12194
|
try {
|
|
11920
12195
|
await writeFile(
|
|
11921
|
-
|
|
12196
|
+
path11__default.join(params.tmpDir, `pgtap-ensure-${params.label}.failed`),
|
|
11922
12197
|
`${error instanceof Error ? error.message : String(error)}
|
|
11923
12198
|
`,
|
|
11924
12199
|
"utf-8"
|
|
@@ -11932,7 +12207,7 @@ SELECT (SELECT available FROM a)::text || ',' || (SELECT installed FROM i)::text
|
|
|
11932
12207
|
label: `probe pgtap (best-effort, ${params.label}, after)`,
|
|
11933
12208
|
command: "psql",
|
|
11934
12209
|
args: [ddlUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", probeSql],
|
|
11935
|
-
logFile:
|
|
12210
|
+
logFile: path11__default.join(params.tmpDir, `pgtap-probe-${params.label}-after.log`)
|
|
11936
12211
|
}).catch(() => null);
|
|
11937
12212
|
const afterRaw = String(probeAfter?.stdout ?? "").trim();
|
|
11938
12213
|
const [availableAfterRaw, installedAfterRaw] = afterRaw.split(",");
|
|
@@ -12053,14 +12328,14 @@ function extractSqlFromSchemaChanges(fullOutput) {
|
|
|
12053
12328
|
return null;
|
|
12054
12329
|
}
|
|
12055
12330
|
function getIdempotentRoleNames(repoRoot) {
|
|
12056
|
-
const idempotentDir =
|
|
12331
|
+
const idempotentDir = path11__default.join(repoRoot, "supabase", "schemas", "idempotent");
|
|
12057
12332
|
const roles = [];
|
|
12058
12333
|
try {
|
|
12059
12334
|
const fs14 = __require("fs");
|
|
12060
12335
|
if (!fs14.existsSync(idempotentDir)) return [];
|
|
12061
12336
|
const files = fs14.readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
|
|
12062
12337
|
for (const file of files) {
|
|
12063
|
-
const content = fs14.readFileSync(
|
|
12338
|
+
const content = fs14.readFileSync(path11__default.join(idempotentDir, file), "utf-8");
|
|
12064
12339
|
const roleMatches = content.matchAll(/CREATE\s+ROLE\s+(\w+)\s+WITH/gi);
|
|
12065
12340
|
for (const match of roleMatches) {
|
|
12066
12341
|
if (match[1]) roles.push(match[1].toLowerCase());
|
|
@@ -12201,7 +12476,7 @@ var productionPreviewActor = fromPromise(
|
|
|
12201
12476
|
);
|
|
12202
12477
|
return buildSkipResult(!!productionUrl);
|
|
12203
12478
|
}
|
|
12204
|
-
const logFile =
|
|
12479
|
+
const logFile = path11__default.join(tmpDir, "ci-production-preview.log");
|
|
12205
12480
|
console.log("\u25B6 production preview (dry-run): runa db apply production --check");
|
|
12206
12481
|
try {
|
|
12207
12482
|
const result = await execa(
|
|
@@ -12291,7 +12566,7 @@ var resetDbActor = fromPromise(
|
|
|
12291
12566
|
label: "db reset (local)",
|
|
12292
12567
|
command: "npx",
|
|
12293
12568
|
args: ["supabase", "db", "reset", "--local"],
|
|
12294
|
-
logFile:
|
|
12569
|
+
logFile: path11__default.join(tmpDir, "ci-db-reset.log")
|
|
12295
12570
|
});
|
|
12296
12571
|
return { reset: true };
|
|
12297
12572
|
} catch (error) {
|
|
@@ -12307,8 +12582,8 @@ var resetDbActor = fromPromise(
|
|
|
12307
12582
|
init_esm_shims();
|
|
12308
12583
|
async function hasSetupRolesScript(repoRoot) {
|
|
12309
12584
|
const candidates = [
|
|
12310
|
-
|
|
12311
|
-
|
|
12585
|
+
path11__default.join(repoRoot, "packages", "database", "package.json"),
|
|
12586
|
+
path11__default.join(repoRoot, "package.json")
|
|
12312
12587
|
];
|
|
12313
12588
|
for (const pkgPath of candidates) {
|
|
12314
12589
|
if (!existsSync(pkgPath)) continue;
|
|
@@ -12346,7 +12621,7 @@ var setupRolesActor = fromPromise(
|
|
|
12346
12621
|
label: "db roles setup",
|
|
12347
12622
|
command: "pnpm",
|
|
12348
12623
|
args: ["db:setup-roles"],
|
|
12349
|
-
logFile:
|
|
12624
|
+
logFile: path11__default.join(tmpDir, "ci-db-roles-setup.log")
|
|
12350
12625
|
});
|
|
12351
12626
|
const stdout = String(result.stdout ?? "");
|
|
12352
12627
|
const appUrlMatch = stdout.match(/APP_DATABASE_URL=["']?([^"'\n]+)["']?/);
|
|
@@ -12459,14 +12734,14 @@ function getSchemaGitDiff(repoRoot) {
|
|
|
12459
12734
|
}
|
|
12460
12735
|
}
|
|
12461
12736
|
function getIdempotentRoleNames2(repoRoot) {
|
|
12462
|
-
const idempotentDir =
|
|
12737
|
+
const idempotentDir = path11__default.join(repoRoot, "supabase", "schemas", "idempotent");
|
|
12463
12738
|
const roles = [];
|
|
12464
12739
|
try {
|
|
12465
12740
|
const fs14 = __require("fs");
|
|
12466
12741
|
if (!fs14.existsSync(idempotentDir)) return [];
|
|
12467
12742
|
const files = fs14.readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
|
|
12468
12743
|
for (const file of files) {
|
|
12469
|
-
const content = fs14.readFileSync(
|
|
12744
|
+
const content = fs14.readFileSync(path11__default.join(idempotentDir, file), "utf-8");
|
|
12470
12745
|
const roleMatches = content.matchAll(/CREATE\s+ROLE\s+(\w+)\s+WITH/gi);
|
|
12471
12746
|
for (const match of roleMatches) {
|
|
12472
12747
|
if (match[1]) roles.push(match[1].toLowerCase());
|
|
@@ -12563,7 +12838,7 @@ var syncSchemaActor = fromPromise(
|
|
|
12563
12838
|
// Always verbose for full traceability
|
|
12564
12839
|
...skipCodegen ? ["--skip-codegen"] : []
|
|
12565
12840
|
];
|
|
12566
|
-
const logFile =
|
|
12841
|
+
const logFile = path11__default.join(tmpDir, `ci-db-${useDbApply ? "apply" : "sync"}-${envArg}.log`);
|
|
12567
12842
|
await runLogged({
|
|
12568
12843
|
cwd: repoRoot,
|
|
12569
12844
|
env: baseEnv,
|
|
@@ -12703,7 +12978,7 @@ async function startSupabaseLocal(params) {
|
|
|
12703
12978
|
label: "supabase start (local)",
|
|
12704
12979
|
command: "supabase",
|
|
12705
12980
|
args: ["start", "--exclude", exclude],
|
|
12706
|
-
logFile:
|
|
12981
|
+
logFile: path11__default.join(params.tmpDir, "supabase-start-local.log")
|
|
12707
12982
|
});
|
|
12708
12983
|
}
|
|
12709
12984
|
function getDefaultLocalSupabaseUrl(repoRoot) {
|
|
@@ -12731,7 +13006,7 @@ async function resolveLocalSupabaseEnv(params) {
|
|
|
12731
13006
|
label: "supabase status (json)",
|
|
12732
13007
|
command: "supabase",
|
|
12733
13008
|
args: ["status", "--output", "json"],
|
|
12734
|
-
logFile:
|
|
13009
|
+
logFile: path11__default.join(params.tmpDir, `supabase-status-${i + 1}.log`)
|
|
12735
13010
|
});
|
|
12736
13011
|
const parsed = JSON.parse(String(res.stdout ?? "{}"));
|
|
12737
13012
|
const out = z.object({
|
|
@@ -12851,7 +13126,7 @@ async function findFilesRecursive(params) {
|
|
|
12851
13126
|
continue;
|
|
12852
13127
|
}
|
|
12853
13128
|
for (const e of entries) {
|
|
12854
|
-
const p =
|
|
13129
|
+
const p = path11__default.join(dir, e.name);
|
|
12855
13130
|
if (e.isDirectory()) stack.push(p);
|
|
12856
13131
|
else if (e.isFile() && params.suffixes.some((s) => p.endsWith(s))) out.push(p);
|
|
12857
13132
|
}
|
|
@@ -12865,7 +13140,7 @@ async function queryScalar(params) {
|
|
|
12865
13140
|
label: `psql scalar (${params.logName})`,
|
|
12866
13141
|
command: "psql",
|
|
12867
13142
|
args: [params.databaseUrl, "-X", "-v", "ON_ERROR_STOP=1", "-q", "-t", "-A", "-c", params.sql],
|
|
12868
|
-
logFile:
|
|
13143
|
+
logFile: path11__default.join(params.tmpDir, `psql-${params.logName}.log`)
|
|
12869
13144
|
});
|
|
12870
13145
|
return String(res.stdout ?? "").trim();
|
|
12871
13146
|
}
|
|
@@ -12993,8 +13268,8 @@ function isPlaywrightIgnored(filePath) {
|
|
|
12993
13268
|
async function detectGeneratedE2eCapabilities(params) {
|
|
12994
13269
|
const caps = /* @__PURE__ */ new Set();
|
|
12995
13270
|
const diagnostics = {};
|
|
12996
|
-
const layer4Dir =
|
|
12997
|
-
const tmpDir =
|
|
13271
|
+
const layer4Dir = path11__default.join(params.repoRoot, ".runa", "tests", "layer4");
|
|
13272
|
+
const tmpDir = path11__default.join(params.repoRoot, ".runa", "tmp");
|
|
12998
13273
|
const hasLayer4Dir = await pathExists(layer4Dir);
|
|
12999
13274
|
const hasTmpDir = await pathExists(tmpDir);
|
|
13000
13275
|
if (!hasLayer4Dir && !hasTmpDir) {
|
|
@@ -13504,7 +13779,7 @@ init_esm_shims();
|
|
|
13504
13779
|
// src/commands/ci/utils/test-parallel.ts
|
|
13505
13780
|
init_esm_shims();
|
|
13506
13781
|
async function readLayerResult(tmpDir, layer) {
|
|
13507
|
-
const resultFile =
|
|
13782
|
+
const resultFile = path11__default.join(tmpDir, `vitest-layer${layer}-result.json`);
|
|
13508
13783
|
try {
|
|
13509
13784
|
const content = await readFile(resultFile, "utf-8");
|
|
13510
13785
|
return JSON.parse(content);
|
|
@@ -13622,8 +13897,8 @@ async function waitUntilAllFinished(params) {
|
|
|
13622
13897
|
async function runLayersInParallel(params) {
|
|
13623
13898
|
const spawned = [];
|
|
13624
13899
|
for (const layer of params.layers) {
|
|
13625
|
-
const logFile =
|
|
13626
|
-
const exitFile =
|
|
13900
|
+
const logFile = path11__default.join(params.tmpDir, `layer${layer}.log`);
|
|
13901
|
+
const exitFile = path11__default.join(params.tmpDir, `layer${layer}.exit`);
|
|
13627
13902
|
const proc = runLogged({
|
|
13628
13903
|
cwd: params.repoRoot,
|
|
13629
13904
|
env: {
|
|
@@ -13666,7 +13941,7 @@ async function runLayersInParallel(params) {
|
|
|
13666
13941
|
for (const p of spawned) {
|
|
13667
13942
|
const codeRaw = p.exitCode ?? await p.procPromise;
|
|
13668
13943
|
const code = Number.isNaN(codeRaw) ? 1 : codeRaw;
|
|
13669
|
-
const resultFile =
|
|
13944
|
+
const resultFile = path11__default.join(params.tmpDir, `vitest-layer${p.layer}-result.json`);
|
|
13670
13945
|
const wasKilled = killedLayerSet.has(p.layer);
|
|
13671
13946
|
const actualResult = waitResult.successMap.get(p.layer) ?? {
|
|
13672
13947
|
success: code === 0,
|
|
@@ -13681,9 +13956,9 @@ async function runLayersInParallel(params) {
|
|
|
13681
13956
|
skippedReason: actualResult.skippedReason,
|
|
13682
13957
|
killed: wasKilled,
|
|
13683
13958
|
killedBy: wasKilled ? failFastSource : void 0,
|
|
13684
|
-
logPath:
|
|
13685
|
-
exitPath:
|
|
13686
|
-
resultPath:
|
|
13959
|
+
logPath: path11__default.relative(params.repoRoot, p.logFile),
|
|
13960
|
+
exitPath: path11__default.relative(params.repoRoot, p.exitFile),
|
|
13961
|
+
resultPath: path11__default.relative(params.repoRoot, resultFile),
|
|
13687
13962
|
// Test count information
|
|
13688
13963
|
totalTests: actualResult.totalTests,
|
|
13689
13964
|
passedTests: actualResult.passedTests,
|
|
@@ -16979,13 +17254,20 @@ init_esm_shims();
|
|
|
16979
17254
|
// src/commands/db/utils/db-target.ts
|
|
16980
17255
|
init_esm_shims();
|
|
16981
17256
|
init_env();
|
|
16982
|
-
|
|
17257
|
+
init_local_supabase();
|
|
16983
17258
|
function getLocalDatabaseUrl() {
|
|
16984
|
-
|
|
16985
|
-
|
|
17259
|
+
return buildLocalDatabaseUrl(process.cwd());
|
|
17260
|
+
}
|
|
17261
|
+
function isLocalHostname(hostname) {
|
|
17262
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "host.docker.internal";
|
|
16986
17263
|
}
|
|
16987
17264
|
function isLocalDatabaseUrl(url) {
|
|
16988
|
-
|
|
17265
|
+
try {
|
|
17266
|
+
const parsed = new URL(url);
|
|
17267
|
+
return isLocalHostname(parsed.hostname);
|
|
17268
|
+
} catch {
|
|
17269
|
+
return false;
|
|
17270
|
+
}
|
|
16989
17271
|
}
|
|
16990
17272
|
function resolveDatabaseUrl(environment) {
|
|
16991
17273
|
switch (environment) {
|
|
@@ -18286,6 +18568,60 @@ function handleHazards(hazards, input3) {
|
|
|
18286
18568
|
);
|
|
18287
18569
|
}
|
|
18288
18570
|
}
|
|
18571
|
+
var TYPE_TO_EXTENSION = {
|
|
18572
|
+
geometry: "postgis",
|
|
18573
|
+
geography: "postgis",
|
|
18574
|
+
box2d: "postgis",
|
|
18575
|
+
box3d: "postgis",
|
|
18576
|
+
raster: "postgis_raster",
|
|
18577
|
+
vector: "vector",
|
|
18578
|
+
halfvec: "vector",
|
|
18579
|
+
sparsevec: "vector",
|
|
18580
|
+
cube: "cube",
|
|
18581
|
+
hstore: "hstore",
|
|
18582
|
+
ltree: "ltree",
|
|
18583
|
+
citext: "citext"
|
|
18584
|
+
};
|
|
18585
|
+
function detectMissingExtensionType(errorOutput) {
|
|
18586
|
+
const typePattern = /type ["']?(\w+)["']? does not exist/gi;
|
|
18587
|
+
const matches = [...errorOutput.matchAll(typePattern)];
|
|
18588
|
+
const missingTypes = [...new Set(matches.map((m) => m[1].toLowerCase()))];
|
|
18589
|
+
if (missingTypes.length === 0) {
|
|
18590
|
+
return { detected: false, missingTypes: [], suggestedExtensions: [] };
|
|
18591
|
+
}
|
|
18592
|
+
const extensions = /* @__PURE__ */ new Set();
|
|
18593
|
+
for (const type of missingTypes) {
|
|
18594
|
+
const ext = TYPE_TO_EXTENSION[type];
|
|
18595
|
+
if (ext) extensions.add(ext);
|
|
18596
|
+
}
|
|
18597
|
+
return {
|
|
18598
|
+
detected: true,
|
|
18599
|
+
missingTypes,
|
|
18600
|
+
suggestedExtensions: [...extensions]
|
|
18601
|
+
};
|
|
18602
|
+
}
|
|
18603
|
+
function formatExtensionErrorHint(detection) {
|
|
18604
|
+
if (!detection.detected) return "";
|
|
18605
|
+
const lines = [];
|
|
18606
|
+
lines.push("");
|
|
18607
|
+
lines.push("Missing extension type(s) detected:");
|
|
18608
|
+
for (const type of detection.missingTypes) {
|
|
18609
|
+
const ext = TYPE_TO_EXTENSION[type];
|
|
18610
|
+
lines.push(` type "${type}" \u2192 extension: ${ext ?? "unknown"}`);
|
|
18611
|
+
}
|
|
18612
|
+
if (detection.suggestedExtensions.length > 0) {
|
|
18613
|
+
lines.push("");
|
|
18614
|
+
lines.push("Fix 1: Add to supabase/schemas/idempotent/00_extensions.sql:");
|
|
18615
|
+
for (const ext of detection.suggestedExtensions) {
|
|
18616
|
+
lines.push(` CREATE EXTENSION IF NOT EXISTS ${ext};`);
|
|
18617
|
+
}
|
|
18618
|
+
const extList = detection.suggestedExtensions.map((e) => `'${e}'`).join(", ");
|
|
18619
|
+
lines.push("");
|
|
18620
|
+
lines.push("Fix 2: Configure shadow DB in runa.config.ts:");
|
|
18621
|
+
lines.push(` database: { pgSchemaDiff: { shadowDbExtensions: [${extList}] } }`);
|
|
18622
|
+
}
|
|
18623
|
+
return lines.join("\n");
|
|
18624
|
+
}
|
|
18289
18625
|
function executePgSchemaDiffPlan(dbUrl, schemasDir, includeSchemas, verbose, options) {
|
|
18290
18626
|
const planArgs = [
|
|
18291
18627
|
"plan",
|
|
@@ -18321,6 +18657,10 @@ function executePgSchemaDiffPlan(dbUrl, schemasDir, includeSchemas, verbose, opt
|
|
|
18321
18657
|
logger4.error(`Exit code: ${planResult.status}`);
|
|
18322
18658
|
logger4.error(`Signal: ${planResult.signal || "none"}`);
|
|
18323
18659
|
logger4.error(`Stderr: ${planStderr || "(empty)"}`);
|
|
18660
|
+
const extDetection = detectMissingExtensionType(planStderr || planOutput);
|
|
18661
|
+
if (extDetection.detected) {
|
|
18662
|
+
logger4.error(formatExtensionErrorHint(extDetection));
|
|
18663
|
+
}
|
|
18324
18664
|
throw new Error(
|
|
18325
18665
|
`pg-schema-diff plan failed (exit ${planResult.status}): ${planStderr || "(no output)"}`
|
|
18326
18666
|
);
|
|
@@ -18378,6 +18718,10 @@ async function executeApplyWithRetry(applyArgs, verbose, config) {
|
|
|
18378
18718
|
}
|
|
18379
18719
|
logger5.error("pg-schema-diff apply failed:");
|
|
18380
18720
|
logger5.error(errorOutput);
|
|
18721
|
+
const extDetection = detectMissingExtensionType(errorOutput);
|
|
18722
|
+
if (extDetection.detected) {
|
|
18723
|
+
logger5.error(formatExtensionErrorHint(extDetection));
|
|
18724
|
+
}
|
|
18381
18725
|
return {
|
|
18382
18726
|
success: false,
|
|
18383
18727
|
error: new Error(`pg-schema-diff apply failed: ${errorOutput}`),
|
|
@@ -19844,16 +20188,16 @@ var ERROR_MESSAGES2 = {
|
|
|
19844
20188
|
SCHEMA_NOT_FOUND: "Schema file not found"
|
|
19845
20189
|
};
|
|
19846
20190
|
function containsPathTraversal2(inputPath) {
|
|
19847
|
-
const normalized =
|
|
20191
|
+
const normalized = path11__default.normalize(inputPath);
|
|
19848
20192
|
return normalized.includes("..") || inputPath.includes("\0");
|
|
19849
20193
|
}
|
|
19850
20194
|
function isPathWithinBase(filePath, baseDir) {
|
|
19851
20195
|
try {
|
|
19852
|
-
const resolvedFile =
|
|
19853
|
-
const resolvedBase =
|
|
19854
|
-
const normalizedFile =
|
|
19855
|
-
const normalizedBase =
|
|
19856
|
-
return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase +
|
|
20196
|
+
const resolvedFile = path11__default.resolve(filePath);
|
|
20197
|
+
const resolvedBase = path11__default.resolve(baseDir);
|
|
20198
|
+
const normalizedFile = path11__default.normalize(resolvedFile);
|
|
20199
|
+
const normalizedBase = path11__default.normalize(resolvedBase);
|
|
20200
|
+
return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase + path11__default.sep);
|
|
19857
20201
|
} catch {
|
|
19858
20202
|
return false;
|
|
19859
20203
|
}
|
|
@@ -19862,13 +20206,13 @@ function validateSchemaPath(dbPackagePath, projectRoot = process.cwd()) {
|
|
|
19862
20206
|
if (containsPathTraversal2(dbPackagePath)) {
|
|
19863
20207
|
throw new Error(ERROR_MESSAGES2.PATH_TRAVERSAL);
|
|
19864
20208
|
}
|
|
19865
|
-
const schemaEntry =
|
|
19866
|
-
const absoluteSchemaPath =
|
|
20209
|
+
const schemaEntry = path11__default.join(dbPackagePath, "src", "schema", "index.ts");
|
|
20210
|
+
const absoluteSchemaPath = path11__default.resolve(projectRoot, schemaEntry);
|
|
19867
20211
|
let resolvedProjectRoot;
|
|
19868
20212
|
try {
|
|
19869
20213
|
resolvedProjectRoot = realpathSync(projectRoot);
|
|
19870
20214
|
} catch {
|
|
19871
|
-
resolvedProjectRoot =
|
|
20215
|
+
resolvedProjectRoot = path11__default.resolve(projectRoot);
|
|
19872
20216
|
}
|
|
19873
20217
|
if (!isPathWithinBase(absoluteSchemaPath, resolvedProjectRoot)) {
|
|
19874
20218
|
throw new Error(ERROR_MESSAGES2.PATH_TRAVERSAL);
|
|
@@ -20000,7 +20344,7 @@ function diffSchema(params) {
|
|
|
20000
20344
|
};
|
|
20001
20345
|
}
|
|
20002
20346
|
function extractTablesFromIdempotentSql(idempotentDir, projectRoot = process.cwd()) {
|
|
20003
|
-
const fullPath =
|
|
20347
|
+
const fullPath = path11__default.resolve(projectRoot, idempotentDir);
|
|
20004
20348
|
if (!existsSync(fullPath)) {
|
|
20005
20349
|
return [];
|
|
20006
20350
|
}
|
|
@@ -20009,7 +20353,7 @@ function extractTablesFromIdempotentSql(idempotentDir, projectRoot = process.cwd
|
|
|
20009
20353
|
try {
|
|
20010
20354
|
const files = readdirSync(fullPath).filter((f) => f.endsWith(".sql"));
|
|
20011
20355
|
for (const file of files) {
|
|
20012
|
-
const filePath =
|
|
20356
|
+
const filePath = path11__default.join(fullPath, file);
|
|
20013
20357
|
const content = readFileSync(filePath, "utf-8");
|
|
20014
20358
|
const contentWithoutComments = content.replace(/--.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
20015
20359
|
for (const match of contentWithoutComments.matchAll(createTablePattern)) {
|
|
@@ -20232,7 +20576,7 @@ async function validateGitHubOutputPath(filePath) {
|
|
|
20232
20576
|
if (!filePath || filePath.trim().length === 0) {
|
|
20233
20577
|
return { valid: false, resolvedPath: null, error: "Empty file path" };
|
|
20234
20578
|
}
|
|
20235
|
-
const normalizedPath =
|
|
20579
|
+
const normalizedPath = path11__default.normalize(filePath);
|
|
20236
20580
|
if (normalizedPath.includes("..")) {
|
|
20237
20581
|
return {
|
|
20238
20582
|
valid: false,
|
|
@@ -20240,7 +20584,7 @@ async function validateGitHubOutputPath(filePath) {
|
|
|
20240
20584
|
error: "Path traversal detected (..) in file path"
|
|
20241
20585
|
};
|
|
20242
20586
|
}
|
|
20243
|
-
const absolutePath =
|
|
20587
|
+
const absolutePath = path11__default.resolve(normalizedPath);
|
|
20244
20588
|
for (const forbidden of FORBIDDEN_PATHS) {
|
|
20245
20589
|
if (absolutePath.startsWith(forbidden) || absolutePath.includes(forbidden)) {
|
|
20246
20590
|
return {
|
|
@@ -20719,7 +21063,7 @@ async function analyzeSchemaChanges() {
|
|
|
20719
21063
|
try {
|
|
20720
21064
|
const { getDatabasePackagePath: getDatabasePackagePath2 } = await Promise.resolve().then(() => (init_config_loader(), config_loader_exports));
|
|
20721
21065
|
const dbPath = await getDatabasePackagePath2();
|
|
20722
|
-
const schemaPath =
|
|
21066
|
+
const schemaPath = path11__default.join(dbPath, "src/schema/");
|
|
20723
21067
|
const { stdout } = await execa("git", ["diff", "--cached", "--", schemaPath]);
|
|
20724
21068
|
const lines = stdout.split("\n");
|
|
20725
21069
|
return parseDiffLines(lines);
|
|
@@ -20998,7 +21342,7 @@ function categorizeRisks(risks) {
|
|
|
20998
21342
|
}
|
|
20999
21343
|
|
|
21000
21344
|
// src/commands/db/utils/preflight-check.ts
|
|
21001
|
-
|
|
21345
|
+
init_local_supabase();
|
|
21002
21346
|
init_config_loader();
|
|
21003
21347
|
function createInitialResult() {
|
|
21004
21348
|
return {
|
|
@@ -21052,7 +21396,7 @@ function runDatabasePackageChecks(result, logger16, step) {
|
|
|
21052
21396
|
logger16.error("Database package path is missing");
|
|
21053
21397
|
return null;
|
|
21054
21398
|
}
|
|
21055
|
-
logger16.success(`Found database package: ${
|
|
21399
|
+
logger16.success(`Found database package: ${path11__default.basename(dbPackagePath)}`);
|
|
21056
21400
|
logger16.step("Checking schema files", step.next());
|
|
21057
21401
|
const schemaCheck = checkSchemaFiles(dbPackagePath);
|
|
21058
21402
|
if (!schemaCheck.exists) {
|
|
@@ -21176,9 +21520,9 @@ ${stderr}`.toLowerCase();
|
|
|
21176
21520
|
}
|
|
21177
21521
|
}
|
|
21178
21522
|
async function testDatabaseConnection(projectRoot) {
|
|
21179
|
-
const
|
|
21180
|
-
const
|
|
21181
|
-
const
|
|
21523
|
+
const resolvedRoot = process.cwd();
|
|
21524
|
+
const connectionUrl = buildLocalDatabaseUrl(resolvedRoot);
|
|
21525
|
+
const dbPort = detectLocalSupabasePorts(resolvedRoot).db;
|
|
21182
21526
|
let sql = null;
|
|
21183
21527
|
try {
|
|
21184
21528
|
sql = postgres(connectionUrl, {
|
|
@@ -21200,12 +21544,12 @@ async function testDatabaseConnection(projectRoot) {
|
|
|
21200
21544
|
function checkDatabasePackage() {
|
|
21201
21545
|
const cwd = process.cwd();
|
|
21202
21546
|
const locations = [
|
|
21203
|
-
|
|
21204
|
-
|
|
21205
|
-
|
|
21547
|
+
path11__default.join(cwd, "packages", "database"),
|
|
21548
|
+
path11__default.join(cwd, "packages", "db"),
|
|
21549
|
+
path11__default.join(cwd, "db")
|
|
21206
21550
|
];
|
|
21207
21551
|
for (const location of locations) {
|
|
21208
|
-
const configPath =
|
|
21552
|
+
const configPath = path11__default.join(location, "drizzle.config.ts");
|
|
21209
21553
|
if (existsSync(configPath)) {
|
|
21210
21554
|
return { exists: true, path: location };
|
|
21211
21555
|
}
|
|
@@ -21250,7 +21594,7 @@ function countTsFilesRecursive(dir) {
|
|
|
21250
21594
|
try {
|
|
21251
21595
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
21252
21596
|
for (const entry of entries) {
|
|
21253
|
-
const fullPath =
|
|
21597
|
+
const fullPath = path11__default.join(dir, entry.name);
|
|
21254
21598
|
if (entry.isDirectory()) {
|
|
21255
21599
|
count += countTsFilesRecursive(fullPath);
|
|
21256
21600
|
} else if (entry.isFile() && entry.name.endsWith(".ts")) {
|
|
@@ -21262,7 +21606,7 @@ function countTsFilesRecursive(dir) {
|
|
|
21262
21606
|
return count;
|
|
21263
21607
|
}
|
|
21264
21608
|
function checkSchemaFiles(dbPackagePath) {
|
|
21265
|
-
const schemaDir =
|
|
21609
|
+
const schemaDir = path11__default.join(dbPackagePath, "src", "schema");
|
|
21266
21610
|
if (!existsSync(schemaDir)) {
|
|
21267
21611
|
return { exists: false, count: 0 };
|
|
21268
21612
|
}
|
|
@@ -21299,9 +21643,9 @@ async function runOrphanCheck(env2, dbPackagePath, result, logger16, step) {
|
|
|
21299
21643
|
logger16.step("Checking for orphaned database objects", step.next());
|
|
21300
21644
|
try {
|
|
21301
21645
|
const { expectedTables, expectedEnums } = await extractSchemaTablesAndEnums(dbPackagePath);
|
|
21302
|
-
const databaseUrl = tryResolveDatabaseUrl("local") ||
|
|
21646
|
+
const databaseUrl = tryResolveDatabaseUrl("local") || buildLocalDatabaseUrl(process.cwd());
|
|
21303
21647
|
const { dbTables, dbEnums } = await fetchDbTablesAndEnums(databaseUrl, {
|
|
21304
|
-
schemaDir:
|
|
21648
|
+
schemaDir: path11__default.join(dbPackagePath, "src", "schema")
|
|
21305
21649
|
});
|
|
21306
21650
|
let excludeFromOrphanDetection = [];
|
|
21307
21651
|
let idempotentSqlDir = "supabase/schemas/idempotent";
|
|
@@ -21339,61 +21683,43 @@ async function runOrphanCheck(env2, dbPackagePath, result, logger16, step) {
|
|
|
21339
21683
|
logger16.warn(`Orphan check skipped: ${message}`);
|
|
21340
21684
|
}
|
|
21341
21685
|
}
|
|
21342
|
-
function runExtensionConfigCheck(
|
|
21686
|
+
function runExtensionConfigCheck(_result, logger16, step) {
|
|
21343
21687
|
logger16.step("Checking PostgreSQL extension configuration", step.next());
|
|
21344
21688
|
try {
|
|
21345
21689
|
const extensionResult = checkExtensionConfig(process.cwd());
|
|
21346
|
-
if (extensionResult
|
|
21347
|
-
logger16.
|
|
21690
|
+
if (!extensionResult || typeof extensionResult !== "object") {
|
|
21691
|
+
logger16.warn("Extension config check returned invalid result");
|
|
21348
21692
|
return;
|
|
21349
21693
|
}
|
|
21350
|
-
|
|
21351
|
-
|
|
21352
|
-
|
|
21353
|
-
);
|
|
21694
|
+
const usedExtensions = extensionResult.usedExtensions ?? [];
|
|
21695
|
+
if (usedExtensions.length === 0) {
|
|
21696
|
+
logger16.success("No extensions detected in SQL files");
|
|
21354
21697
|
return;
|
|
21355
21698
|
}
|
|
21356
|
-
|
|
21357
|
-
|
|
21358
|
-
|
|
21359
|
-
|
|
21699
|
+
const sqlManaged = extensionResult.sqlManagedExtensions ?? [];
|
|
21700
|
+
const supabaseManaged = extensionResult.supabaseManagedExtensions ?? [];
|
|
21701
|
+
const parts = [];
|
|
21702
|
+
if (sqlManaged.length > 0) {
|
|
21703
|
+
parts.push(`${sqlManaged.length} SQL-managed`);
|
|
21360
21704
|
}
|
|
21361
|
-
if (
|
|
21362
|
-
|
|
21363
|
-
recordWarning(result, warning);
|
|
21364
|
-
}
|
|
21365
|
-
logger16.warn(
|
|
21366
|
-
`Missing ${extensionResult.missingExtensions.length} extension(s) in config.toml:`
|
|
21367
|
-
);
|
|
21368
|
-
for (const ext of extensionResult.missingExtensions) {
|
|
21369
|
-
const sqlFile = extensionResult.sqlFilePaths.get(ext);
|
|
21370
|
-
logger16.info(` \u2022 ${ext}${sqlFile ? ` (used in ${path10__default.basename(sqlFile)})` : ""}`);
|
|
21371
|
-
}
|
|
21372
|
-
logger16.info("");
|
|
21373
|
-
logger16.info(" To fix, add to supabase/config.toml:");
|
|
21374
|
-
logger16.info(" [db.extensions]");
|
|
21375
|
-
for (const ext of extensionResult.missingExtensions) {
|
|
21376
|
-
logger16.info(` ${ext} = "enabled"`);
|
|
21377
|
-
}
|
|
21378
|
-
logger16.info("");
|
|
21379
|
-
logger16.info(" Then restart Supabase: supabase stop && supabase start");
|
|
21380
|
-
logger16.info("");
|
|
21705
|
+
if (supabaseManaged.length > 0) {
|
|
21706
|
+
parts.push(`${supabaseManaged.length} Supabase-managed`);
|
|
21381
21707
|
}
|
|
21382
|
-
|
|
21383
|
-
|
|
21384
|
-
|
|
21385
|
-
|
|
21386
|
-
logger16.info(
|
|
21708
|
+
const summary = parts.join(", ");
|
|
21709
|
+
logger16.success(`${usedExtensions.length} extension(s) found (${summary})`);
|
|
21710
|
+
const notes = extensionResult.notes ?? [];
|
|
21711
|
+
for (const note of notes) {
|
|
21712
|
+
logger16.info(` ${note}`);
|
|
21387
21713
|
}
|
|
21388
21714
|
} catch (error) {
|
|
21389
21715
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
21390
|
-
logger16.warn(`Extension config check
|
|
21716
|
+
logger16.warn(`Extension config check failed: ${message}`);
|
|
21391
21717
|
}
|
|
21392
21718
|
}
|
|
21393
21719
|
async function runSqlSchemaRiskCheck(result, logger16, step) {
|
|
21394
21720
|
logger16.step("Checking SQL schema for risky patterns", step.next());
|
|
21395
21721
|
const cwd = process.cwd();
|
|
21396
|
-
const sqlDir =
|
|
21722
|
+
const sqlDir = path11__default.join(cwd, "supabase", "schemas", "declarative");
|
|
21397
21723
|
if (!existsSync(sqlDir)) {
|
|
21398
21724
|
logger16.success("No SQL schema directory found (supabase/schemas/declarative/)");
|
|
21399
21725
|
return;
|
|
@@ -21406,7 +21732,7 @@ async function runSqlSchemaRiskCheck(result, logger16, step) {
|
|
|
21406
21732
|
}
|
|
21407
21733
|
const allRisks = [];
|
|
21408
21734
|
for (const sqlFile of sqlFiles) {
|
|
21409
|
-
const filePath =
|
|
21735
|
+
const filePath = path11__default.join(sqlDir, sqlFile);
|
|
21410
21736
|
const risks = await detectSchemaRisks(filePath);
|
|
21411
21737
|
for (const risk of risks) {
|
|
21412
21738
|
allRisks.push({ ...risk, file: sqlFile });
|
|
@@ -23158,7 +23484,7 @@ async function checkPort(port) {
|
|
|
23158
23484
|
};
|
|
23159
23485
|
}
|
|
23160
23486
|
function detectSupabasePortsFromConfig() {
|
|
23161
|
-
const configPath =
|
|
23487
|
+
const configPath = path11__default.join(process.cwd(), "supabase", "config.toml");
|
|
23162
23488
|
const BASE_PORTS = { api: 54321, db: 54322, studio: 54323, inbucket: 54324 };
|
|
23163
23489
|
if (!existsSync(configPath)) {
|
|
23164
23490
|
return Object.values(BASE_PORTS);
|
|
@@ -23247,7 +23573,7 @@ var BASE_PORT = 54321;
|
|
|
23247
23573
|
var PORTS_PER_SLOT = 10;
|
|
23248
23574
|
var TOTAL_SLOTS = 100;
|
|
23249
23575
|
function calculatePortOffset(projectPath) {
|
|
23250
|
-
const normalizedPath =
|
|
23576
|
+
const normalizedPath = path11__default.resolve(projectPath);
|
|
23251
23577
|
const hash = createHash("md5").update(normalizedPath).digest("hex");
|
|
23252
23578
|
return parseInt(hash.slice(0, 8), 16) % TOTAL_SLOTS;
|
|
23253
23579
|
}
|
|
@@ -23268,7 +23594,7 @@ function getSupabasePorts(projectPath) {
|
|
|
23268
23594
|
}
|
|
23269
23595
|
function updateSupabaseConfigPorts(projectPath) {
|
|
23270
23596
|
const ports = getSupabasePorts(projectPath);
|
|
23271
|
-
const configPath =
|
|
23597
|
+
const configPath = path11__default.join(projectPath, "supabase", "config.toml");
|
|
23272
23598
|
if (!existsSync(configPath)) {
|
|
23273
23599
|
return { updated: false, ports, configPath };
|
|
23274
23600
|
}
|
|
@@ -23303,7 +23629,7 @@ function getPortAllocationSummary(projectPath) {
|
|
|
23303
23629
|
const ports = getSupabasePorts(projectPath);
|
|
23304
23630
|
const offset = calculatePortOffset(projectPath);
|
|
23305
23631
|
return [
|
|
23306
|
-
`Port allocation for: ${
|
|
23632
|
+
`Port allocation for: ${path11__default.basename(projectPath)}`,
|
|
23307
23633
|
` Slot: ${offset} (hash-based)`,
|
|
23308
23634
|
` API: ${ports.api}`,
|
|
23309
23635
|
` DB: ${ports.db}`,
|
|
@@ -23337,7 +23663,7 @@ function parseSeedPaths(configPath) {
|
|
|
23337
23663
|
}
|
|
23338
23664
|
}
|
|
23339
23665
|
async function applySeedFile(seedPath, dbUrl) {
|
|
23340
|
-
const supabaseDir =
|
|
23666
|
+
const supabaseDir = path11__default.join(process.cwd(), "supabase");
|
|
23341
23667
|
const absolutePath = resolveSafePath(supabaseDir, seedPath);
|
|
23342
23668
|
if (!existsSync(absolutePath)) {
|
|
23343
23669
|
return;
|
|
@@ -23348,12 +23674,12 @@ async function applySeedFile(seedPath, dbUrl) {
|
|
|
23348
23674
|
});
|
|
23349
23675
|
}
|
|
23350
23676
|
async function applySeeds2(configPath) {
|
|
23351
|
-
const configFile =
|
|
23677
|
+
const configFile = path11__default.join(process.cwd(), "supabase", "config.toml");
|
|
23352
23678
|
const seedPaths = parseSeedPaths(configFile);
|
|
23353
23679
|
if (seedPaths.length === 0) {
|
|
23354
23680
|
return;
|
|
23355
23681
|
}
|
|
23356
|
-
const supabaseDir =
|
|
23682
|
+
const supabaseDir = path11__default.join(process.cwd(), "supabase");
|
|
23357
23683
|
const safePaths = filterSafePaths(seedPaths, supabaseDir);
|
|
23358
23684
|
if (safePaths.length === 0) {
|
|
23359
23685
|
return;
|
|
@@ -23771,7 +24097,7 @@ var validateCommand = new Command("validate").description("Validate schema files
|
|
|
23771
24097
|
const logger16 = createCLILogger("db:validate");
|
|
23772
24098
|
try {
|
|
23773
24099
|
logger16.section("Schema Validation");
|
|
23774
|
-
const schemasPath =
|
|
24100
|
+
const schemasPath = path11__default.join(process.cwd(), "packages", "database", "src", "schema");
|
|
23775
24101
|
if (!existsSync(schemasPath)) {
|
|
23776
24102
|
throw new CLIError("Schema directory not found", "SCHEMA_DIR_NOT_FOUND", [
|
|
23777
24103
|
`Expected location: ${schemasPath}`,
|
|
@@ -23936,8 +24262,8 @@ var generateCommand = new Command("generate").description("Generate TypeScript t
|
|
|
23936
24262
|
var listCommand = new Command("list").description("List managed schemas from drizzle.config.ts").option("--sql", "Output as SQL-compatible string for IN clauses").option("--json", "Output as JSON array").action(async (options) => {
|
|
23937
24263
|
const logger16 = createCLILogger("db:schema:list");
|
|
23938
24264
|
try {
|
|
23939
|
-
const dbPackagePath =
|
|
23940
|
-
if (!existsSync(
|
|
24265
|
+
const dbPackagePath = path11__default.join(process.cwd(), "packages", "database");
|
|
24266
|
+
if (!existsSync(path11__default.join(dbPackagePath, "drizzle.config.ts"))) {
|
|
23941
24267
|
throw new CLIError("drizzle.config.ts not found", "CONFIG_NOT_FOUND", [
|
|
23942
24268
|
`Expected location: ${dbPackagePath}/drizzle.config.ts`,
|
|
23943
24269
|
"Ensure you are in the project root",
|
|
@@ -25176,7 +25502,7 @@ var testGenCommand = new Command("test:gen").description("Generate pgTAP behavio
|
|
|
25176
25502
|
const databaseUrl = options.db || process.env.DATABASE_URL || getLocalDbUrl();
|
|
25177
25503
|
const schemas = options.schemas ? options.schemas.split(",") : void 0;
|
|
25178
25504
|
const dbPackage = databasePaths.package();
|
|
25179
|
-
const defaultOutputPath =
|
|
25505
|
+
const defaultOutputPath = path11__default.join(dbPackage, "tests/00_behavior.generated.test.sql");
|
|
25180
25506
|
const outputPath = options.output || defaultOutputPath;
|
|
25181
25507
|
spinner.text = "Generating pgTAP behavior tests...";
|
|
25182
25508
|
const result = await dbGeneratePgTapTests({
|
|
@@ -26188,108 +26514,8 @@ async function getVercelRootDirectory() {
|
|
|
26188
26514
|
return info?.rootDirectory ?? null;
|
|
26189
26515
|
}
|
|
26190
26516
|
|
|
26191
|
-
// src/commands/env/constants/local-supabase.ts
|
|
26192
|
-
init_esm_shims();
|
|
26193
|
-
var DEFAULT_API_PORT = 54321;
|
|
26194
|
-
var DEFAULT_DB_PORT = 54322;
|
|
26195
|
-
function parsePortFromToml(content, section, key) {
|
|
26196
|
-
const sectionRegex = new RegExp(`\\[${section}\\]([\\s\\S]*?)(?=\\n\\[|$)`, "g");
|
|
26197
|
-
const sectionMatch = sectionRegex.exec(content);
|
|
26198
|
-
if (!sectionMatch) return null;
|
|
26199
|
-
const sectionContent = sectionMatch[1];
|
|
26200
|
-
const keyRegex = new RegExp(`^\\s*${key}\\s*=\\s*(\\d+)`, "m");
|
|
26201
|
-
const keyMatch = keyRegex.exec(sectionContent);
|
|
26202
|
-
if (!keyMatch) return null;
|
|
26203
|
-
const port = Number.parseInt(keyMatch[1], 10);
|
|
26204
|
-
return Number.isFinite(port) && port > 0 && port < 65536 ? port : null;
|
|
26205
|
-
}
|
|
26206
|
-
function readPortsFromConfigToml(projectRoot) {
|
|
26207
|
-
const configPath = path10__default.join(projectRoot, "supabase", "config.toml");
|
|
26208
|
-
try {
|
|
26209
|
-
const content = readFileSync(configPath, "utf-8");
|
|
26210
|
-
const apiPort = parsePortFromToml(content, "api", "port");
|
|
26211
|
-
const dbPort = parsePortFromToml(content, "db", "port");
|
|
26212
|
-
if (apiPort !== null || dbPort !== null) {
|
|
26213
|
-
return {
|
|
26214
|
-
api: apiPort ?? DEFAULT_API_PORT,
|
|
26215
|
-
db: dbPort ?? DEFAULT_DB_PORT
|
|
26216
|
-
};
|
|
26217
|
-
}
|
|
26218
|
-
return null;
|
|
26219
|
-
} catch {
|
|
26220
|
-
return null;
|
|
26221
|
-
}
|
|
26222
|
-
}
|
|
26223
|
-
function detectLocalSupabasePorts(projectRoot = process.cwd()) {
|
|
26224
|
-
const configPorts = readPortsFromConfigToml(projectRoot);
|
|
26225
|
-
if (configPorts) {
|
|
26226
|
-
return configPorts;
|
|
26227
|
-
}
|
|
26228
|
-
return {
|
|
26229
|
-
api: DEFAULT_API_PORT,
|
|
26230
|
-
db: DEFAULT_DB_PORT
|
|
26231
|
-
};
|
|
26232
|
-
}
|
|
26233
|
-
var LOCAL_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
|
|
26234
|
-
var LOCAL_SUPABASE_SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU";
|
|
26235
|
-
function buildLocalSupabaseUrl(projectRoot = process.cwd()) {
|
|
26236
|
-
const ports = detectLocalSupabasePorts(projectRoot);
|
|
26237
|
-
return `http://127.0.0.1:${ports.api}`;
|
|
26238
|
-
}
|
|
26239
|
-
function buildLocalDatabaseUrl(projectRoot = process.cwd()) {
|
|
26240
|
-
const ports = detectLocalSupabasePorts(projectRoot);
|
|
26241
|
-
return `postgresql://postgres:postgres@127.0.0.1:${ports.db}/postgres`;
|
|
26242
|
-
}
|
|
26243
|
-
function getLocalSupabaseEnvValues(projectRoot = process.cwd()) {
|
|
26244
|
-
const supabaseUrl = buildLocalSupabaseUrl(projectRoot);
|
|
26245
|
-
const databaseUrl = buildLocalDatabaseUrl(projectRoot);
|
|
26246
|
-
return {
|
|
26247
|
-
// Database URLs
|
|
26248
|
-
DATABASE_URL: databaseUrl,
|
|
26249
|
-
DATABASE_URL_ADMIN: databaseUrl,
|
|
26250
|
-
DATABASE_URL_SERVICE: databaseUrl,
|
|
26251
|
-
// Supabase URLs and keys
|
|
26252
|
-
NEXT_PUBLIC_SUPABASE_URL: supabaseUrl,
|
|
26253
|
-
NEXT_PUBLIC_SUPABASE_ANON_KEY: LOCAL_SUPABASE_ANON_KEY,
|
|
26254
|
-
SUPABASE_SERVICE_ROLE_KEY: LOCAL_SUPABASE_SERVICE_ROLE_KEY
|
|
26255
|
-
};
|
|
26256
|
-
}
|
|
26257
|
-
function getLocalValueDescriptions(projectRoot = process.cwd()) {
|
|
26258
|
-
const ports = detectLocalSupabasePorts(projectRoot);
|
|
26259
|
-
return {
|
|
26260
|
-
DATABASE_URL: `localhost:${ports.db} (PostgreSQL)`,
|
|
26261
|
-
DATABASE_URL_ADMIN: `localhost:${ports.db} (PostgreSQL)`,
|
|
26262
|
-
DATABASE_URL_SERVICE: `localhost:${ports.db} (PostgreSQL)`,
|
|
26263
|
-
NEXT_PUBLIC_SUPABASE_URL: `localhost:${ports.api} (Supabase API)`,
|
|
26264
|
-
NEXT_PUBLIC_SUPABASE_ANON_KEY: "local anon key (supabase-demo)",
|
|
26265
|
-
SUPABASE_SERVICE_ROLE_KEY: "local service key (supabase-demo)"
|
|
26266
|
-
};
|
|
26267
|
-
}
|
|
26268
|
-
var LOCAL_SUPABASE_ENV_VALUES = getLocalSupabaseEnvValues();
|
|
26269
|
-
getLocalValueDescriptions();
|
|
26270
|
-
function validateLocalhostValues(envValues) {
|
|
26271
|
-
const urlKeys = [
|
|
26272
|
-
"DATABASE_URL",
|
|
26273
|
-
"DATABASE_URL_ADMIN",
|
|
26274
|
-
"DATABASE_URL_SERVICE",
|
|
26275
|
-
"NEXT_PUBLIC_SUPABASE_URL"
|
|
26276
|
-
];
|
|
26277
|
-
const invalidEntries = [];
|
|
26278
|
-
for (const key of urlKeys) {
|
|
26279
|
-
const value = envValues[key];
|
|
26280
|
-
if (value && !value.includes("127.0.0.1") && !value.includes("localhost")) {
|
|
26281
|
-
invalidEntries.push(key);
|
|
26282
|
-
}
|
|
26283
|
-
}
|
|
26284
|
-
if (invalidEntries.length > 0) {
|
|
26285
|
-
throw new Error(
|
|
26286
|
-
`LOCAL_SUPABASE_ENV_VALUES safety check failed: The following keys do not point to localhost: ${invalidEntries.join(", ")}. This is a safety feature to prevent accidental production database connections during local development.`
|
|
26287
|
-
);
|
|
26288
|
-
}
|
|
26289
|
-
}
|
|
26290
|
-
validateLocalhostValues(LOCAL_SUPABASE_ENV_VALUES);
|
|
26291
|
-
|
|
26292
26517
|
// src/commands/env/commands/env-pull.ts
|
|
26518
|
+
init_local_supabase();
|
|
26293
26519
|
var ERROR_MESSAGES3 = {
|
|
26294
26520
|
INVALID_PATH: "Invalid working directory path",
|
|
26295
26521
|
PATH_TRAVERSAL: "Working directory path validation failed",
|
|
@@ -26321,16 +26547,16 @@ function sanitizeErrorMessage(message) {
|
|
|
26321
26547
|
return sanitized;
|
|
26322
26548
|
}
|
|
26323
26549
|
function containsPathTraversal3(inputPath) {
|
|
26324
|
-
const normalized =
|
|
26550
|
+
const normalized = path11__default.normalize(inputPath);
|
|
26325
26551
|
return normalized.includes("..") || inputPath.includes("\0");
|
|
26326
26552
|
}
|
|
26327
26553
|
function isPathWithinBase2(filePath, baseDir) {
|
|
26328
26554
|
try {
|
|
26329
|
-
const resolvedFile =
|
|
26330
|
-
const resolvedBase =
|
|
26331
|
-
const normalizedFile =
|
|
26332
|
-
const normalizedBase =
|
|
26333
|
-
return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase +
|
|
26555
|
+
const resolvedFile = path11__default.resolve(filePath);
|
|
26556
|
+
const resolvedBase = path11__default.resolve(baseDir);
|
|
26557
|
+
const normalizedFile = path11__default.normalize(resolvedFile);
|
|
26558
|
+
const normalizedBase = path11__default.normalize(resolvedBase);
|
|
26559
|
+
return normalizedFile === normalizedBase || normalizedFile.startsWith(normalizedBase + path11__default.sep);
|
|
26334
26560
|
} catch {
|
|
26335
26561
|
return false;
|
|
26336
26562
|
}
|
|
@@ -26339,12 +26565,12 @@ function validateCustomWorkingDir(cwdPath, projectRoot) {
|
|
|
26339
26565
|
if (containsPathTraversal3(cwdPath)) {
|
|
26340
26566
|
throw new CLIError(ERROR_MESSAGES3.PATH_TRAVERSAL, "ENV_PULL_PATH_TRAVERSAL");
|
|
26341
26567
|
}
|
|
26342
|
-
const absolutePath =
|
|
26568
|
+
const absolutePath = path11__default.isAbsolute(cwdPath) ? cwdPath : path11__default.resolve(projectRoot, cwdPath);
|
|
26343
26569
|
let resolvedProjectRoot;
|
|
26344
26570
|
try {
|
|
26345
26571
|
resolvedProjectRoot = realpathSync(projectRoot);
|
|
26346
26572
|
} catch {
|
|
26347
|
-
resolvedProjectRoot =
|
|
26573
|
+
resolvedProjectRoot = path11__default.resolve(projectRoot);
|
|
26348
26574
|
}
|
|
26349
26575
|
if (!isPathWithinBase2(absolutePath, resolvedProjectRoot)) {
|
|
26350
26576
|
throw new CLIError(ERROR_MESSAGES3.PATH_TRAVERSAL, "ENV_PULL_PATH_TRAVERSAL");
|
|
@@ -26371,6 +26597,27 @@ function validateAppDirectory2(appName, projectRoot) {
|
|
|
26371
26597
|
}
|
|
26372
26598
|
return appDir;
|
|
26373
26599
|
}
|
|
26600
|
+
var LOCAL_BOOTSTRAP_REQUIRED_KEYS = [
|
|
26601
|
+
"LOCAL_SUPABASE_HOST",
|
|
26602
|
+
"LOCAL_SUPABASE_API_PORT",
|
|
26603
|
+
"LOCAL_SUPABASE_DB_PORT"
|
|
26604
|
+
];
|
|
26605
|
+
function getMissingLocalBootstrapKeys(parsed) {
|
|
26606
|
+
return LOCAL_BOOTSTRAP_REQUIRED_KEYS.filter((key) => !(key in parsed));
|
|
26607
|
+
}
|
|
26608
|
+
function getLocalBootstrapStatusFromParsed(parsed) {
|
|
26609
|
+
const missing = getMissingLocalBootstrapKeys(parsed);
|
|
26610
|
+
return {
|
|
26611
|
+
status: missing.length === 0 ? "ok" : "partial",
|
|
26612
|
+
missing
|
|
26613
|
+
};
|
|
26614
|
+
}
|
|
26615
|
+
function missingLocalBootstrapReport() {
|
|
26616
|
+
return {
|
|
26617
|
+
status: "missing",
|
|
26618
|
+
missing: [...LOCAL_BOOTSTRAP_REQUIRED_KEYS]
|
|
26619
|
+
};
|
|
26620
|
+
}
|
|
26374
26621
|
var EnvPullOutputSchema = z.object({
|
|
26375
26622
|
results: z.array(
|
|
26376
26623
|
z.object({
|
|
@@ -26384,6 +26631,10 @@ var EnvPullOutputSchema = z.object({
|
|
|
26384
26631
|
totalPulled: z.number(),
|
|
26385
26632
|
totalFailed: z.number(),
|
|
26386
26633
|
totalEncrypted: z.number().optional(),
|
|
26634
|
+
localBootstrap: z.object({
|
|
26635
|
+
status: z.enum(["ok", "partial", "missing"]),
|
|
26636
|
+
missing: z.array(z.string())
|
|
26637
|
+
}).optional(),
|
|
26387
26638
|
/** Vercel Root Directory sync result */
|
|
26388
26639
|
vercelSync: z.object({
|
|
26389
26640
|
detected: z.boolean(),
|
|
@@ -26516,60 +26767,74 @@ function removePrivateKeysFromEnvFile(filePath) {
|
|
|
26516
26767
|
writeFileSync(filePath, `${newContent}
|
|
26517
26768
|
`, "utf-8");
|
|
26518
26769
|
}
|
|
26519
|
-
function replaceWithLocalValues(filePath, logger16, dryRun = false) {
|
|
26770
|
+
function replaceWithLocalValues(filePath, workDir, logger16, dryRun = false) {
|
|
26520
26771
|
if (!existsSync(filePath)) {
|
|
26521
26772
|
logger16.warn(" \u26A0\uFE0F .env.development not found (was pull successful?)");
|
|
26522
|
-
return;
|
|
26773
|
+
return missingLocalBootstrapReport();
|
|
26523
26774
|
}
|
|
26524
26775
|
const content = readFileSync(filePath, "utf-8");
|
|
26525
26776
|
if (!content.trim()) {
|
|
26526
26777
|
logger16.warn(" \u26A0\uFE0F .env.development is empty (no env vars in Vercel?)");
|
|
26527
|
-
return;
|
|
26778
|
+
return missingLocalBootstrapReport();
|
|
26528
26779
|
}
|
|
26529
26780
|
const parsed = parse(content);
|
|
26530
26781
|
if (Object.keys(parsed).length === 0) {
|
|
26531
26782
|
logger16.warn(" \u26A0\uFE0F No valid env vars found in .env.development (check syntax)");
|
|
26532
|
-
return;
|
|
26783
|
+
return missingLocalBootstrapReport();
|
|
26533
26784
|
}
|
|
26534
|
-
const
|
|
26535
|
-
const
|
|
26536
|
-
const localDescriptions = getLocalValueDescriptions(projectRoot);
|
|
26785
|
+
const localEnvValues = getLocalSupabaseEnvValues(workDir);
|
|
26786
|
+
const localDescriptions = getLocalValueDescriptions(workDir);
|
|
26537
26787
|
const replacementKeys = Object.keys(localEnvValues);
|
|
26538
26788
|
const replacedKeys = [];
|
|
26789
|
+
const hasAnySupabaseKey = Object.keys(parsed).some((key) => key.includes("SUPABASE") || key.includes("DATABASE_URL")) || replacementKeys.some((key) => key in parsed);
|
|
26539
26790
|
for (const key of replacementKeys) {
|
|
26540
|
-
if (key in parsed
|
|
26791
|
+
if (key in parsed || hasAnySupabaseKey) {
|
|
26541
26792
|
parsed[key] = localEnvValues[key];
|
|
26542
26793
|
replacedKeys.push(key);
|
|
26543
26794
|
}
|
|
26544
26795
|
}
|
|
26545
26796
|
if (replacedKeys.length === 0) {
|
|
26546
|
-
const
|
|
26797
|
+
const hasAnySupabaseKey2 = Object.keys(parsed).some(
|
|
26547
26798
|
(k) => k.includes("SUPABASE") || k.includes("DATABASE_URL")
|
|
26548
26799
|
);
|
|
26549
|
-
if (
|
|
26800
|
+
if (hasAnySupabaseKey2) {
|
|
26550
26801
|
logger16.warn(" \u26A0\uFE0F Found Supabase keys but none matched local replacement patterns");
|
|
26551
26802
|
} else {
|
|
26552
26803
|
logger16.info(" No Supabase variables found (may be expected for new projects)");
|
|
26553
26804
|
}
|
|
26554
|
-
return;
|
|
26805
|
+
return getLocalBootstrapStatusFromParsed(parsed);
|
|
26806
|
+
}
|
|
26807
|
+
const bootstrapStatus = getLocalBootstrapStatusFromParsed(parsed);
|
|
26808
|
+
if (bootstrapStatus.missing.length > 0) {
|
|
26809
|
+
logger16.warn(
|
|
26810
|
+
` \u26A0\uFE0F Some local bootstrap keys were not updated: ${bootstrapStatus.missing.join(", ")}`
|
|
26811
|
+
);
|
|
26555
26812
|
}
|
|
26813
|
+
const ensureRequired = bootstrapStatus.status === "ok";
|
|
26556
26814
|
const newContent = Object.entries(parsed).map(([key, value]) => `${key}=${formatEnvValue(value)}`).join("\n");
|
|
26557
26815
|
if (dryRun) {
|
|
26558
|
-
logger16.info(` \u{1F3E0} Would replace ${replacedKeys.length} variables with
|
|
26816
|
+
logger16.info(` \u{1F3E0} Would replace ${replacedKeys.length} variables with local values:`);
|
|
26559
26817
|
for (const key of replacedKeys) {
|
|
26560
26818
|
const description = localDescriptions[key] || "localhost";
|
|
26561
26819
|
logger16.info(` ${key} \u2192 ${description}`);
|
|
26562
26820
|
}
|
|
26821
|
+
logger16.info(
|
|
26822
|
+
` ${ensureRequired ? "\u2705" : "\u26A0\uFE0F"} Local bootstrap keys ready: ${ensureRequired ? "yes" : "partial"}`
|
|
26823
|
+
);
|
|
26563
26824
|
logger16.info(" (dry-run: no files modified)");
|
|
26564
|
-
return;
|
|
26825
|
+
return bootstrapStatus;
|
|
26565
26826
|
}
|
|
26566
26827
|
writeFileSync(filePath, `${newContent}
|
|
26567
26828
|
`, "utf-8");
|
|
26568
|
-
logger16.success(` \u{1F3E0} Replaced ${replacedKeys.length} variables with
|
|
26829
|
+
logger16.success(` \u{1F3E0} Replaced ${replacedKeys.length} variables with local values:`);
|
|
26569
26830
|
for (const key of replacedKeys) {
|
|
26570
26831
|
const description = localDescriptions[key] || "localhost";
|
|
26571
26832
|
logger16.info(` ${key} \u2192 ${description}`);
|
|
26572
26833
|
}
|
|
26834
|
+
logger16.info(
|
|
26835
|
+
` ${ensureRequired ? "\u2705" : "\u26A0\uFE0F"} Local bootstrap keys ready: ${ensureRequired ? "yes" : "partial"}`
|
|
26836
|
+
);
|
|
26837
|
+
return bootstrapStatus;
|
|
26573
26838
|
}
|
|
26574
26839
|
async function encryptFile2(workDir, filePath, logger16) {
|
|
26575
26840
|
if (!existsSync(filePath)) {
|
|
@@ -26801,13 +27066,20 @@ async function runEnvPullAction(options) {
|
|
|
26801
27066
|
}
|
|
26802
27067
|
logger16.info("");
|
|
26803
27068
|
const results = await pullAllEnvironments(workDir, environments, auth, logger16);
|
|
26804
|
-
|
|
27069
|
+
const shouldEvaluateLocalBootstrap = !options.productionAll && (!options.environment || options.environment === "development");
|
|
27070
|
+
let localBootstrap;
|
|
27071
|
+
if (shouldEvaluateLocalBootstrap) {
|
|
26805
27072
|
const devResult = results.find((r) => r.environment === "development" && r.success);
|
|
26806
27073
|
if (devResult) {
|
|
26807
27074
|
logger16.info("");
|
|
26808
27075
|
logger16.info("Applying local Supabase values to .env.development...");
|
|
26809
|
-
replaceWithLocalValues(devResult.outputPath, logger16, options.check);
|
|
27076
|
+
localBootstrap = replaceWithLocalValues(devResult.outputPath, workDir, logger16, options.check);
|
|
27077
|
+
} else {
|
|
27078
|
+
localBootstrap = missingLocalBootstrapReport();
|
|
27079
|
+
logger16.warn(" LOCAL_BOOTSTRAP: skipped (development env pull failed or missing)");
|
|
26810
27080
|
}
|
|
27081
|
+
} else {
|
|
27082
|
+
localBootstrap = void 0;
|
|
26811
27083
|
}
|
|
26812
27084
|
if (options.encrypt && !options.check) {
|
|
26813
27085
|
await encryptPulledFiles(workDir, results, logger16);
|
|
@@ -26828,6 +27100,7 @@ async function runEnvPullAction(options) {
|
|
|
26828
27100
|
totalPulled,
|
|
26829
27101
|
totalFailed,
|
|
26830
27102
|
totalEncrypted: options.encrypt ? totalEncrypted : void 0,
|
|
27103
|
+
localBootstrap,
|
|
26831
27104
|
vercelSync: vercelSyncResult
|
|
26832
27105
|
});
|
|
26833
27106
|
if (totalFailed > 0) {
|
|
@@ -28567,13 +28840,13 @@ z.object({
|
|
|
28567
28840
|
|
|
28568
28841
|
// src/commands/hotfix/metadata.ts
|
|
28569
28842
|
function getHotfixDir(targetDir) {
|
|
28570
|
-
return
|
|
28843
|
+
return path11__default.join(targetDir, ".runa", "hotfix");
|
|
28571
28844
|
}
|
|
28572
28845
|
function getCurrentFile(targetDir) {
|
|
28573
|
-
return
|
|
28846
|
+
return path11__default.join(getHotfixDir(targetDir), "current.json");
|
|
28574
28847
|
}
|
|
28575
28848
|
function getArchiveDir(targetDir) {
|
|
28576
|
-
return
|
|
28849
|
+
return path11__default.join(getHotfixDir(targetDir), "archive");
|
|
28577
28850
|
}
|
|
28578
28851
|
async function ensureHotfixDir(targetDir) {
|
|
28579
28852
|
await mkdir(getHotfixDir(targetDir), { recursive: true });
|
|
@@ -28583,7 +28856,7 @@ async function ensureArchiveDir(targetDir) {
|
|
|
28583
28856
|
}
|
|
28584
28857
|
async function getHotfixMetadata(input3 = {}) {
|
|
28585
28858
|
const parsed = GetHotfixInputSchema.parse(input3);
|
|
28586
|
-
const targetDir = parsed.targetDir ?
|
|
28859
|
+
const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
|
|
28587
28860
|
const currentFile = getCurrentFile(targetDir);
|
|
28588
28861
|
if (!existsSync(currentFile)) {
|
|
28589
28862
|
return null;
|
|
@@ -28593,7 +28866,7 @@ async function getHotfixMetadata(input3 = {}) {
|
|
|
28593
28866
|
}
|
|
28594
28867
|
async function createHotfixMetadata(input3) {
|
|
28595
28868
|
const parsed = CreateHotfixMetadataInputSchema.parse(input3);
|
|
28596
|
-
const targetDir = parsed.targetDir ?
|
|
28869
|
+
const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
|
|
28597
28870
|
await ensureHotfixDir(targetDir);
|
|
28598
28871
|
const metadata = {
|
|
28599
28872
|
branch: parsed.branch,
|
|
@@ -28610,7 +28883,7 @@ async function createHotfixMetadata(input3) {
|
|
|
28610
28883
|
}
|
|
28611
28884
|
async function updateHotfixStatus(input3) {
|
|
28612
28885
|
const parsed = UpdateHotfixInputSchema.parse(input3);
|
|
28613
|
-
const targetDir = parsed.targetDir ?
|
|
28886
|
+
const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
|
|
28614
28887
|
const current = await getHotfixMetadata({ targetDir });
|
|
28615
28888
|
if (!current) {
|
|
28616
28889
|
throw createError("HOTFIX_NOT_FOUND");
|
|
@@ -28627,13 +28900,13 @@ async function updateHotfixStatus(input3) {
|
|
|
28627
28900
|
return updated;
|
|
28628
28901
|
}
|
|
28629
28902
|
async function archiveHotfix(targetDir) {
|
|
28630
|
-
const dir = targetDir ?
|
|
28903
|
+
const dir = targetDir ? path11__default.resolve(targetDir) : process.cwd();
|
|
28631
28904
|
const current = await getHotfixMetadata({ targetDir: dir });
|
|
28632
28905
|
if (!current) {
|
|
28633
28906
|
throw createError("HOTFIX_NOT_FOUND");
|
|
28634
28907
|
}
|
|
28635
28908
|
await ensureArchiveDir(dir);
|
|
28636
|
-
const archiveFile =
|
|
28909
|
+
const archiveFile = path11__default.join(
|
|
28637
28910
|
getArchiveDir(dir),
|
|
28638
28911
|
`${current.branch.replace(/\//g, "-")}-${Date.now()}.json`
|
|
28639
28912
|
);
|
|
@@ -28649,7 +28922,7 @@ async function archiveHotfix(targetDir) {
|
|
|
28649
28922
|
return archived;
|
|
28650
28923
|
}
|
|
28651
28924
|
async function cancelHotfix(targetDir) {
|
|
28652
|
-
const dir = targetDir ?
|
|
28925
|
+
const dir = targetDir ? path11__default.resolve(targetDir) : process.cwd();
|
|
28653
28926
|
await updateHotfixStatus({
|
|
28654
28927
|
status: "cancelled",
|
|
28655
28928
|
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -28659,7 +28932,7 @@ async function cancelHotfix(targetDir) {
|
|
|
28659
28932
|
}
|
|
28660
28933
|
async function listArchivedHotfixes(input3 = {}) {
|
|
28661
28934
|
const parsed = ListArchivedHotfixesInputSchema.parse(input3);
|
|
28662
|
-
const targetDir = parsed.targetDir ?
|
|
28935
|
+
const targetDir = parsed.targetDir ? path11__default.resolve(parsed.targetDir) : process.cwd();
|
|
28663
28936
|
const archiveDir = getArchiveDir(targetDir);
|
|
28664
28937
|
if (!existsSync(archiveDir)) {
|
|
28665
28938
|
return { hotfixes: [] };
|
|
@@ -28668,7 +28941,7 @@ async function listArchivedHotfixes(input3 = {}) {
|
|
|
28668
28941
|
const hotfixes = [];
|
|
28669
28942
|
for (const file of files.filter((f) => f.endsWith(".json"))) {
|
|
28670
28943
|
try {
|
|
28671
|
-
const content = await readFile(
|
|
28944
|
+
const content = await readFile(path11__default.join(archiveDir, file), "utf-8");
|
|
28672
28945
|
hotfixes.push(HotfixMetadataSchema.parse(JSON.parse(content)));
|
|
28673
28946
|
} catch {
|
|
28674
28947
|
}
|
|
@@ -30168,13 +30441,13 @@ function validateVersion(version) {
|
|
|
30168
30441
|
}
|
|
30169
30442
|
}
|
|
30170
30443
|
function getCacheBase() {
|
|
30171
|
-
return
|
|
30444
|
+
return path11__default.join(os.homedir(), ".cache", "runa", "templates");
|
|
30172
30445
|
}
|
|
30173
30446
|
function getCacheDir(version) {
|
|
30174
30447
|
validateVersion(version);
|
|
30175
30448
|
const cacheBase = getCacheBase();
|
|
30176
|
-
const cacheDir =
|
|
30177
|
-
const resolvedCacheDir =
|
|
30449
|
+
const cacheDir = path11__default.join(cacheBase, version);
|
|
30450
|
+
const resolvedCacheDir = path11__default.resolve(cacheDir);
|
|
30178
30451
|
if (!isPathContained(cacheBase, resolvedCacheDir)) {
|
|
30179
30452
|
throw new CLIError(
|
|
30180
30453
|
"Security: cache directory would escape allowed location.",
|
|
@@ -30186,7 +30459,7 @@ function getCacheDir(version) {
|
|
|
30186
30459
|
}
|
|
30187
30460
|
function isCached(version) {
|
|
30188
30461
|
const cacheDir = getCacheDir(version);
|
|
30189
|
-
const templatesDir =
|
|
30462
|
+
const templatesDir = path11__default.join(cacheDir, "templates");
|
|
30190
30463
|
return fs5__default.existsSync(templatesDir);
|
|
30191
30464
|
}
|
|
30192
30465
|
var scopedAuthToken = null;
|
|
@@ -30237,13 +30510,13 @@ async function createTempPackageJson(tempDir, version) {
|
|
|
30237
30510
|
[TEMPLATES_PACKAGE_NAME]: version
|
|
30238
30511
|
}
|
|
30239
30512
|
};
|
|
30240
|
-
await writeFile(
|
|
30513
|
+
await writeFile(path11__default.join(tempDir, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
30241
30514
|
}
|
|
30242
30515
|
async function createTempNpmrc(tempDir) {
|
|
30243
30516
|
const npmrc = `@r06-dev:registry=${GITHUB_PACKAGES_REGISTRY}
|
|
30244
30517
|
//npm.pkg.github.com/:_authToken=\${NODE_AUTH_TOKEN}
|
|
30245
30518
|
`;
|
|
30246
|
-
await writeFile(
|
|
30519
|
+
await writeFile(path11__default.join(tempDir, ".npmrc"), npmrc);
|
|
30247
30520
|
}
|
|
30248
30521
|
async function installTemplates(tempDir, authToken, verbose) {
|
|
30249
30522
|
try {
|
|
@@ -30301,10 +30574,10 @@ async function installTemplates(tempDir, authToken, verbose) {
|
|
|
30301
30574
|
async function verifyNoSymlinks(dir, baseDir) {
|
|
30302
30575
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
30303
30576
|
for (const entry of entries) {
|
|
30304
|
-
const fullPath =
|
|
30577
|
+
const fullPath = path11__default.join(dir, entry.name);
|
|
30305
30578
|
const stats = await lstat(fullPath);
|
|
30306
30579
|
if (stats.isSymbolicLink()) {
|
|
30307
|
-
const relativePath =
|
|
30580
|
+
const relativePath = path11__default.relative(baseDir, fullPath);
|
|
30308
30581
|
throw new CLIError(
|
|
30309
30582
|
"Security: Symlink detected in template package.",
|
|
30310
30583
|
"SYMLINK_ATTACK_DETECTED",
|
|
@@ -30322,7 +30595,7 @@ async function verifyNoSymlinks(dir, baseDir) {
|
|
|
30322
30595
|
}
|
|
30323
30596
|
}
|
|
30324
30597
|
async function copyToCache(tempDir, cacheDir) {
|
|
30325
|
-
const sourceTemplates =
|
|
30598
|
+
const sourceTemplates = path11__default.join(tempDir, "node_modules", TEMPLATES_PACKAGE_NAME, "templates");
|
|
30326
30599
|
if (!fs5__default.existsSync(sourceTemplates)) {
|
|
30327
30600
|
throw new CLIError("Templates directory not found in package.", "TEMPLATES_DIR_NOT_FOUND", [
|
|
30328
30601
|
`Expected: ${sourceTemplates}`,
|
|
@@ -30332,7 +30605,7 @@ async function copyToCache(tempDir, cacheDir) {
|
|
|
30332
30605
|
}
|
|
30333
30606
|
await verifyNoSymlinks(sourceTemplates, sourceTemplates);
|
|
30334
30607
|
await mkdir(cacheDir, { recursive: true });
|
|
30335
|
-
const targetTemplates =
|
|
30608
|
+
const targetTemplates = path11__default.join(cacheDir, "templates");
|
|
30336
30609
|
await cp(sourceTemplates, targetTemplates, {
|
|
30337
30610
|
recursive: true,
|
|
30338
30611
|
dereference: false
|
|
@@ -30354,7 +30627,7 @@ async function fetchTemplates(options = {}) {
|
|
|
30354
30627
|
};
|
|
30355
30628
|
}
|
|
30356
30629
|
const cacheDir = getCacheDir(version);
|
|
30357
|
-
const templatesDir =
|
|
30630
|
+
const templatesDir = path11__default.join(cacheDir, "templates");
|
|
30358
30631
|
if (!fresh && isCached(version)) {
|
|
30359
30632
|
if (verbose) {
|
|
30360
30633
|
console.log(`Using cached templates v${version}: ${templatesDir}`);
|
|
@@ -30370,7 +30643,7 @@ async function fetchTemplates(options = {}) {
|
|
|
30370
30643
|
if (fresh && fs5__default.existsSync(cacheDir)) {
|
|
30371
30644
|
await rm(cacheDir, { recursive: true, force: true });
|
|
30372
30645
|
}
|
|
30373
|
-
const tempDir =
|
|
30646
|
+
const tempDir = path11__default.join(os.tmpdir(), `runa-templates-${Date.now()}`);
|
|
30374
30647
|
await mkdir(tempDir, { recursive: true });
|
|
30375
30648
|
try {
|
|
30376
30649
|
if (verbose) {
|
|
@@ -30398,11 +30671,11 @@ async function fetchTemplates(options = {}) {
|
|
|
30398
30671
|
}
|
|
30399
30672
|
var MAX_WORKSPACE_TRAVERSAL_DEPTH = 10;
|
|
30400
30673
|
function isLegitimateWorkspaceRoot(workspaceRoot) {
|
|
30401
|
-
const pnpmWorkspaceFile =
|
|
30674
|
+
const pnpmWorkspaceFile = path11__default.join(workspaceRoot, "pnpm-workspace.yaml");
|
|
30402
30675
|
if (!fs5__default.existsSync(pnpmWorkspaceFile)) {
|
|
30403
30676
|
return false;
|
|
30404
30677
|
}
|
|
30405
|
-
const rootPackageFile =
|
|
30678
|
+
const rootPackageFile = path11__default.join(workspaceRoot, "package.json");
|
|
30406
30679
|
if (!fs5__default.existsSync(rootPackageFile)) {
|
|
30407
30680
|
return false;
|
|
30408
30681
|
}
|
|
@@ -30416,24 +30689,24 @@ function isLegitimateWorkspaceRoot(workspaceRoot) {
|
|
|
30416
30689
|
}
|
|
30417
30690
|
}
|
|
30418
30691
|
function resolveWorkspaceTemplates() {
|
|
30419
|
-
let current =
|
|
30420
|
-
const root =
|
|
30692
|
+
let current = path11__default.resolve(process.cwd());
|
|
30693
|
+
const root = path11__default.parse(current).root;
|
|
30421
30694
|
let depth = 0;
|
|
30422
30695
|
while (current !== root && depth < MAX_WORKSPACE_TRAVERSAL_DEPTH) {
|
|
30423
30696
|
if (!isLegitimateWorkspaceRoot(current)) {
|
|
30424
|
-
current =
|
|
30697
|
+
current = path11__default.dirname(current);
|
|
30425
30698
|
depth++;
|
|
30426
30699
|
continue;
|
|
30427
30700
|
}
|
|
30428
|
-
const packagesTemplates =
|
|
30429
|
-
const normalizedTemplatesPath =
|
|
30430
|
-
if (!normalizedTemplatesPath.startsWith(current +
|
|
30431
|
-
current =
|
|
30701
|
+
const packagesTemplates = path11__default.join(current, "packages", "runa-templates", "templates");
|
|
30702
|
+
const normalizedTemplatesPath = path11__default.resolve(packagesTemplates);
|
|
30703
|
+
if (!normalizedTemplatesPath.startsWith(current + path11__default.sep)) {
|
|
30704
|
+
current = path11__default.dirname(current);
|
|
30432
30705
|
depth++;
|
|
30433
30706
|
continue;
|
|
30434
30707
|
}
|
|
30435
30708
|
if (fs5__default.existsSync(normalizedTemplatesPath)) {
|
|
30436
|
-
const markerFile =
|
|
30709
|
+
const markerFile = path11__default.join(current, "packages", "runa-templates", "package.json");
|
|
30437
30710
|
if (fs5__default.existsSync(markerFile)) {
|
|
30438
30711
|
try {
|
|
30439
30712
|
const pkg = JSON.parse(fs5__default.readFileSync(markerFile, "utf-8"));
|
|
@@ -30444,7 +30717,7 @@ function resolveWorkspaceTemplates() {
|
|
|
30444
30717
|
}
|
|
30445
30718
|
}
|
|
30446
30719
|
}
|
|
30447
|
-
current =
|
|
30720
|
+
current = path11__default.dirname(current);
|
|
30448
30721
|
depth++;
|
|
30449
30722
|
}
|
|
30450
30723
|
return void 0;
|
|
@@ -30453,9 +30726,9 @@ function resolveWorkspaceTemplates() {
|
|
|
30453
30726
|
// src/commands/init.ts
|
|
30454
30727
|
function checkZodVersion(_logger) {
|
|
30455
30728
|
const zodPaths = [
|
|
30456
|
-
|
|
30729
|
+
path11__default.join(process.cwd(), "node_modules", "zod", "package.json"),
|
|
30457
30730
|
// Check home directory node_modules (common source of conflicts)
|
|
30458
|
-
|
|
30731
|
+
path11__default.join(process.env.HOME ?? "", "node_modules", "zod", "package.json")
|
|
30459
30732
|
];
|
|
30460
30733
|
for (const zodPath of zodPaths) {
|
|
30461
30734
|
if (!fs5__default.existsSync(zodPath)) continue;
|
|
@@ -30469,7 +30742,7 @@ function checkZodVersion(_logger) {
|
|
|
30469
30742
|
"ZOD_VERSION_INCOMPATIBLE",
|
|
30470
30743
|
[
|
|
30471
30744
|
"runa SDK requires zod v4.x, but found zod v3.x",
|
|
30472
|
-
`Conflicting zod found at: ${
|
|
30745
|
+
`Conflicting zod found at: ${path11__default.dirname(zodPath)}`,
|
|
30473
30746
|
"",
|
|
30474
30747
|
"Solutions:",
|
|
30475
30748
|
"1. Run from a clean project directory without existing node_modules",
|
|
@@ -30721,7 +30994,7 @@ var initCommand = new Command("init").description("Initialize pj-repo with runa
|
|
|
30721
30994
|
try {
|
|
30722
30995
|
if (options.repairConfig) {
|
|
30723
30996
|
logger16.section("Repairing runa.config.ts");
|
|
30724
|
-
const projectName2 =
|
|
30997
|
+
const projectName2 = path11__default.basename(process.cwd());
|
|
30725
30998
|
const repairResult = repairRunaConfig(process.cwd(), projectName2);
|
|
30726
30999
|
if (repairResult.success) {
|
|
30727
31000
|
logger16.success("\u2705 Config file repaired successfully");
|
|
@@ -30772,7 +31045,7 @@ var initCommand = new Command("init").description("Initialize pj-repo with runa
|
|
|
30772
31045
|
existingConfig,
|
|
30773
31046
|
force: options.force === true
|
|
30774
31047
|
});
|
|
30775
|
-
const projectName =
|
|
31048
|
+
const projectName = path11__default.basename(process.cwd());
|
|
30776
31049
|
logger16.info(`Project: ${projectName}`);
|
|
30777
31050
|
logger16.step("Applying templates (SDK)", 1);
|
|
30778
31051
|
const result = await initProject({
|
|
@@ -30869,7 +31142,9 @@ var InjectTestAttrsInputSchema = z.object({
|
|
|
30869
31142
|
/** Manifest output directory */
|
|
30870
31143
|
manifestDir: z.string().default(".runa"),
|
|
30871
31144
|
/** Resolve Zod schemas to JSON Schema (v7+) for API contracts */
|
|
30872
|
-
resolveSchemas: z.boolean().default(false)
|
|
31145
|
+
resolveSchemas: z.boolean().default(false),
|
|
31146
|
+
/** Fail when heuristic fallback detection is used */
|
|
31147
|
+
strictDetect: z.boolean().default(false)
|
|
30873
31148
|
}).strict();
|
|
30874
31149
|
var FileChangeSchema = z.object({
|
|
30875
31150
|
filePath: z.string(),
|
|
@@ -30881,6 +31156,51 @@ var MachineWithoutE2EMetaSchema = z.object({
|
|
|
30881
31156
|
id: z.string(),
|
|
30882
31157
|
sourceFile: z.string()
|
|
30883
31158
|
});
|
|
31159
|
+
var DetectionScanSummarySchema = z.object({
|
|
31160
|
+
totalFiles: z.number().int().nonnegative(),
|
|
31161
|
+
filesWithMachineDefinitions: z.number().int().nonnegative(),
|
|
31162
|
+
filesWithMachineHooks: z.number().int().nonnegative(),
|
|
31163
|
+
filesWithJsxOnly: z.number().int().nonnegative()
|
|
31164
|
+
}).strict();
|
|
31165
|
+
var MachineResolutionDetailSchema = z.object({
|
|
31166
|
+
filePath: z.string(),
|
|
31167
|
+
machineRef: z.string(),
|
|
31168
|
+
resolvedId: z.string(),
|
|
31169
|
+
source: z.enum(["explicit", "import", "inline", "fallback"])
|
|
31170
|
+
}).strict();
|
|
31171
|
+
var DetectionDiagnosticsSchema = z.object({
|
|
31172
|
+
schemaVersion: z.literal(1),
|
|
31173
|
+
scan: DetectionScanSummarySchema,
|
|
31174
|
+
resolution: z.object({
|
|
31175
|
+
totalMachineUsages: z.number().int().nonnegative(),
|
|
31176
|
+
bySource: z.object({
|
|
31177
|
+
explicit: z.number().int().nonnegative(),
|
|
31178
|
+
import: z.number().int().nonnegative(),
|
|
31179
|
+
inline: z.number().int().nonnegative(),
|
|
31180
|
+
fallback: z.number().int().nonnegative()
|
|
31181
|
+
}).strict(),
|
|
31182
|
+
fallbackRate: z.number().min(0).max(1),
|
|
31183
|
+
fallbackExamples: z.array(MachineResolutionDetailSchema)
|
|
31184
|
+
}).strict(),
|
|
31185
|
+
coverage: z.object({
|
|
31186
|
+
totalManifestMachines: z.number().int().nonnegative(),
|
|
31187
|
+
linkedManifestMachines: z.number().int().nonnegative(),
|
|
31188
|
+
unlinkedManifestMachines: z.number().int().nonnegative(),
|
|
31189
|
+
machineLinkCoverage: z.number().min(0).max(1),
|
|
31190
|
+
unlinkedManifestMachineIds: z.array(z.string())
|
|
31191
|
+
}).strict(),
|
|
31192
|
+
warnings: z.array(
|
|
31193
|
+
z.object({
|
|
31194
|
+
severity: z.enum(["warning", "info", "hint"]),
|
|
31195
|
+
message: z.string()
|
|
31196
|
+
}).strict()
|
|
31197
|
+
)
|
|
31198
|
+
}).strict();
|
|
31199
|
+
var StrictDetectStatusSchema = z.object({
|
|
31200
|
+
enabled: z.literal(true),
|
|
31201
|
+
passed: z.boolean(),
|
|
31202
|
+
reasons: z.array(z.string())
|
|
31203
|
+
}).strict();
|
|
30884
31204
|
var InjectTestAttrsOutputSchema = z.object({
|
|
30885
31205
|
totalFiles: z.number(),
|
|
30886
31206
|
changedFiles: z.number(),
|
|
@@ -30892,17 +31212,98 @@ var InjectTestAttrsOutputSchema = z.object({
|
|
|
30892
31212
|
/** Number of machines in manifest */
|
|
30893
31213
|
manifestMachineCount: z.number().optional(),
|
|
30894
31214
|
/** Machines without meta.e2e annotation (opt-in warning) */
|
|
30895
|
-
machinesWithoutE2EMeta: z.array(MachineWithoutE2EMetaSchema).optional()
|
|
31215
|
+
machinesWithoutE2EMeta: z.array(MachineWithoutE2EMetaSchema).optional(),
|
|
31216
|
+
/** Structured diagnostics for detection quality */
|
|
31217
|
+
detectionDiagnostics: DetectionDiagnosticsSchema.optional(),
|
|
31218
|
+
/** Strict detection mode result */
|
|
31219
|
+
strictDetect: StrictDetectStatusSchema.optional()
|
|
30896
31220
|
}).strict();
|
|
30897
31221
|
|
|
30898
31222
|
// src/commands/inject-test-attrs/processor.ts
|
|
30899
31223
|
init_esm_shims();
|
|
30900
31224
|
|
|
31225
|
+
// src/commands/inject-test-attrs/detection-diagnostics.ts
|
|
31226
|
+
init_esm_shims();
|
|
31227
|
+
var MAX_EXAMPLES = 20;
|
|
31228
|
+
function normalizeMachineId(id) {
|
|
31229
|
+
return id.replace(/-([a-z])/g, (_, char) => char.toUpperCase()).replace(/Machine$/i, "").toLowerCase();
|
|
31230
|
+
}
|
|
31231
|
+
function buildDetectionDiagnostics(params) {
|
|
31232
|
+
const bySource = {
|
|
31233
|
+
explicit: 0,
|
|
31234
|
+
import: 0,
|
|
31235
|
+
inline: 0,
|
|
31236
|
+
fallback: 0
|
|
31237
|
+
};
|
|
31238
|
+
const fallbackExamples = [];
|
|
31239
|
+
for (const detail of params.resolutionDetails) {
|
|
31240
|
+
bySource[detail.source] += 1;
|
|
31241
|
+
if (detail.source === "fallback" && fallbackExamples.length < MAX_EXAMPLES) {
|
|
31242
|
+
fallbackExamples.push(detail);
|
|
31243
|
+
}
|
|
31244
|
+
}
|
|
31245
|
+
const linkedMachineIds = new Set(
|
|
31246
|
+
params.machineLinks.filter((link) => link.usedIn.length > 0).map((link) => normalizeMachineId(link.machineName))
|
|
31247
|
+
);
|
|
31248
|
+
const linkedManifestMachineIds = [];
|
|
31249
|
+
const unlinkedManifestMachineIds = [];
|
|
31250
|
+
for (const machineId of params.manifestMachineIds) {
|
|
31251
|
+
if (linkedMachineIds.has(normalizeMachineId(machineId))) {
|
|
31252
|
+
linkedManifestMachineIds.push(machineId);
|
|
31253
|
+
continue;
|
|
31254
|
+
}
|
|
31255
|
+
unlinkedManifestMachineIds.push(machineId);
|
|
31256
|
+
}
|
|
31257
|
+
const totalMachineUsages = params.resolutionDetails.length;
|
|
31258
|
+
const fallbackRate = totalMachineUsages > 0 ? bySource.fallback / totalMachineUsages : 0;
|
|
31259
|
+
const totalManifestMachines = params.manifestMachineIds.length;
|
|
31260
|
+
const linkedManifestMachines = linkedManifestMachineIds.length;
|
|
31261
|
+
const machineLinkCoverage = totalManifestMachines > 0 ? linkedManifestMachines / totalManifestMachines : 1;
|
|
31262
|
+
return {
|
|
31263
|
+
schemaVersion: 1,
|
|
31264
|
+
scan: params.scanSummary,
|
|
31265
|
+
resolution: {
|
|
31266
|
+
totalMachineUsages,
|
|
31267
|
+
bySource,
|
|
31268
|
+
fallbackRate,
|
|
31269
|
+
fallbackExamples
|
|
31270
|
+
},
|
|
31271
|
+
coverage: {
|
|
31272
|
+
totalManifestMachines,
|
|
31273
|
+
linkedManifestMachines,
|
|
31274
|
+
unlinkedManifestMachines: totalManifestMachines - linkedManifestMachines,
|
|
31275
|
+
machineLinkCoverage,
|
|
31276
|
+
unlinkedManifestMachineIds: unlinkedManifestMachineIds.slice(0, MAX_EXAMPLES)
|
|
31277
|
+
},
|
|
31278
|
+
warnings: params.warnings
|
|
31279
|
+
};
|
|
31280
|
+
}
|
|
31281
|
+
function evaluateStrictDetect(diagnostics) {
|
|
31282
|
+
const reasons = [];
|
|
31283
|
+
const fallbackCount = diagnostics.resolution.bySource.fallback;
|
|
31284
|
+
if (fallbackCount > 0) {
|
|
31285
|
+
reasons.push(`fallback machine resolution detected (${fallbackCount})`);
|
|
31286
|
+
}
|
|
31287
|
+
if (diagnostics.scan.filesWithMachineHooks > 0 && diagnostics.resolution.totalMachineUsages === 0) {
|
|
31288
|
+
reasons.push(
|
|
31289
|
+
`machine hooks were detected in ${diagnostics.scan.filesWithMachineHooks} files, but no machine usages were resolved`
|
|
31290
|
+
);
|
|
31291
|
+
}
|
|
31292
|
+
if (diagnostics.resolution.totalMachineUsages > 0 && diagnostics.coverage.totalManifestMachines > 0 && diagnostics.coverage.linkedManifestMachines === 0) {
|
|
31293
|
+
reasons.push("machine usages were detected, but no machines were linked to routes/pages");
|
|
31294
|
+
}
|
|
31295
|
+
return {
|
|
31296
|
+
enabled: true,
|
|
31297
|
+
passed: reasons.length === 0,
|
|
31298
|
+
reasons
|
|
31299
|
+
};
|
|
31300
|
+
}
|
|
31301
|
+
|
|
30901
31302
|
// src/commands/inject-test-attrs/formatter.ts
|
|
30902
31303
|
init_esm_shims();
|
|
30903
31304
|
async function formatFilesWithBiome(files, cwd) {
|
|
30904
31305
|
if (files.length === 0) return;
|
|
30905
|
-
const relativePaths = files.map((f) =>
|
|
31306
|
+
const relativePaths = files.map((f) => path11.relative(cwd, f));
|
|
30906
31307
|
try {
|
|
30907
31308
|
await execa("pnpm", ["exec", "biome", "format", "--write", ...relativePaths], {
|
|
30908
31309
|
cwd,
|
|
@@ -30994,7 +31395,8 @@ function emptyResult(filePath) {
|
|
|
30994
31395
|
changed: false,
|
|
30995
31396
|
actions: [],
|
|
30996
31397
|
fields: [],
|
|
30997
|
-
testIds: []
|
|
31398
|
+
testIds: [],
|
|
31399
|
+
resolutionDetails: []
|
|
30998
31400
|
};
|
|
30999
31401
|
}
|
|
31000
31402
|
function ensureDirectoryExists(dirPath) {
|
|
@@ -31004,7 +31406,7 @@ function ensureDirectoryExists(dirPath) {
|
|
|
31004
31406
|
}
|
|
31005
31407
|
function getGeneratorVersion() {
|
|
31006
31408
|
try {
|
|
31007
|
-
const pkgPath =
|
|
31409
|
+
const pkgPath = path11.resolve(__dirname$1, "../../../package.json");
|
|
31008
31410
|
if (fs5.existsSync(pkgPath)) {
|
|
31009
31411
|
const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
|
|
31010
31412
|
return pkg.version ?? "unknown";
|
|
@@ -31019,15 +31421,15 @@ function detectPlatform(repoRoot) {
|
|
|
31019
31421
|
const nextConfigPatterns = ["next.config.ts", "next.config.js", "next.config.mjs"];
|
|
31020
31422
|
for (const pattern of nextConfigPatterns) {
|
|
31021
31423
|
const paths = [
|
|
31022
|
-
|
|
31023
|
-
|
|
31024
|
-
|
|
31424
|
+
path11.join(repoRoot, pattern),
|
|
31425
|
+
path11.join(repoRoot, "apps", "web", pattern),
|
|
31426
|
+
path11.join(repoRoot, "apps", "dashboard", pattern)
|
|
31025
31427
|
];
|
|
31026
31428
|
if (paths.some((p) => fs5.existsSync(p))) {
|
|
31027
31429
|
return "nextjs";
|
|
31028
31430
|
}
|
|
31029
31431
|
}
|
|
31030
|
-
const appJsonPath =
|
|
31432
|
+
const appJsonPath = path11.join(repoRoot, "app.json");
|
|
31031
31433
|
if (fs5.existsSync(appJsonPath)) {
|
|
31032
31434
|
try {
|
|
31033
31435
|
const appJson = JSON.parse(fs5.readFileSync(appJsonPath, "utf-8"));
|
|
@@ -31037,7 +31439,7 @@ function detectPlatform(repoRoot) {
|
|
|
31037
31439
|
} catch {
|
|
31038
31440
|
}
|
|
31039
31441
|
}
|
|
31040
|
-
if (fs5.existsSync(
|
|
31442
|
+
if (fs5.existsSync(path11.join(repoRoot, "expo.json"))) {
|
|
31041
31443
|
return "expo";
|
|
31042
31444
|
}
|
|
31043
31445
|
const electronPatterns = [
|
|
@@ -31046,56 +31448,38 @@ function detectPlatform(repoRoot) {
|
|
|
31046
31448
|
"electron.vite.config.ts",
|
|
31047
31449
|
"electron.vite.config.js"
|
|
31048
31450
|
];
|
|
31049
|
-
if (electronPatterns.some((p) => fs5.existsSync(
|
|
31451
|
+
if (electronPatterns.some((p) => fs5.existsSync(path11.join(repoRoot, p)))) {
|
|
31050
31452
|
return "electron";
|
|
31051
31453
|
}
|
|
31052
31454
|
return "unknown";
|
|
31053
31455
|
}
|
|
31054
|
-
function
|
|
31055
|
-
|
|
31056
|
-
|
|
31057
|
-
|
|
31058
|
-
|
|
31059
|
-
|
|
31060
|
-
|
|
31061
|
-
|
|
31062
|
-
const routesDir = path10.join(appsDir, app.name, "routes");
|
|
31063
|
-
if (fs5.existsSync(routesDir)) {
|
|
31064
|
-
const files = fs5.readdirSync(routesDir);
|
|
31065
|
-
const hasRouteFiles = files.some(
|
|
31066
|
-
(f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.endsWith(".spec.ts")
|
|
31067
|
-
);
|
|
31068
|
-
if (hasRouteFiles) {
|
|
31069
|
-
possibleDirs.push(`apps/${app.name}/routes`);
|
|
31070
|
-
}
|
|
31071
|
-
}
|
|
31072
|
-
}
|
|
31073
|
-
}
|
|
31074
|
-
} catch {
|
|
31075
|
-
}
|
|
31456
|
+
function hasHonoRouteFiles(dir) {
|
|
31457
|
+
try {
|
|
31458
|
+
const files = fs5.readdirSync(dir);
|
|
31459
|
+
return files.some(
|
|
31460
|
+
(file) => file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".spec.ts")
|
|
31461
|
+
);
|
|
31462
|
+
} catch {
|
|
31463
|
+
return false;
|
|
31076
31464
|
}
|
|
31077
|
-
|
|
31078
|
-
|
|
31079
|
-
|
|
31080
|
-
|
|
31081
|
-
|
|
31082
|
-
|
|
31083
|
-
|
|
31084
|
-
|
|
31085
|
-
|
|
31086
|
-
|
|
31087
|
-
|
|
31088
|
-
);
|
|
31089
|
-
if (hasRouteFiles) {
|
|
31090
|
-
possibleDirs.push(`packages/${pkg.name}/routes`);
|
|
31091
|
-
}
|
|
31092
|
-
}
|
|
31093
|
-
}
|
|
31094
|
-
}
|
|
31095
|
-
} catch {
|
|
31096
|
-
}
|
|
31465
|
+
}
|
|
31466
|
+
function collectRouteDirsInScope(repoRoot, scope) {
|
|
31467
|
+
const scopeDir = path11.join(repoRoot, scope);
|
|
31468
|
+
if (!fs5.existsSync(scopeDir)) {
|
|
31469
|
+
return [];
|
|
31470
|
+
}
|
|
31471
|
+
try {
|
|
31472
|
+
const entries = fs5.readdirSync(scopeDir, { withFileTypes: true });
|
|
31473
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((entryName) => hasHonoRouteFiles(path11.join(scopeDir, entryName, "routes"))).map((entryName) => `${scope}/${entryName}/routes`);
|
|
31474
|
+
} catch {
|
|
31475
|
+
return [];
|
|
31097
31476
|
}
|
|
31098
|
-
|
|
31477
|
+
}
|
|
31478
|
+
function findPossibleHonoDirs(repoRoot) {
|
|
31479
|
+
return [
|
|
31480
|
+
...collectRouteDirsInScope(repoRoot, "apps"),
|
|
31481
|
+
...collectRouteDirsInScope(repoRoot, "packages")
|
|
31482
|
+
];
|
|
31099
31483
|
}
|
|
31100
31484
|
function collectManifestWarnings(repoRoot, platform, apiContracts, machinesWithoutE2EMeta, totalMachines) {
|
|
31101
31485
|
const warnings = [];
|
|
@@ -31146,15 +31530,18 @@ function printManifestWarnings(warnings, verbose) {
|
|
|
31146
31530
|
for (const detail of warning.details) {
|
|
31147
31531
|
console.log(detail);
|
|
31148
31532
|
}
|
|
31149
|
-
if (warning.details.length < warning._totalCount) {
|
|
31150
|
-
console.log(` ... and more`);
|
|
31151
|
-
}
|
|
31152
31533
|
}
|
|
31153
31534
|
if (warning.fix) {
|
|
31154
31535
|
console.log(` \u2192 ${warning.fix}`);
|
|
31155
31536
|
}
|
|
31156
31537
|
}
|
|
31157
31538
|
}
|
|
31539
|
+
function toDetectionWarnings(warnings) {
|
|
31540
|
+
return warnings.map((warning) => ({
|
|
31541
|
+
severity: warning.severity,
|
|
31542
|
+
message: warning.message
|
|
31543
|
+
}));
|
|
31544
|
+
}
|
|
31158
31545
|
function normalizeToCanonicalId(id) {
|
|
31159
31546
|
return id.replace(/-([a-z])/g, (_, c) => c.toUpperCase()).replace(/Machine$/i, "");
|
|
31160
31547
|
}
|
|
@@ -31242,7 +31629,7 @@ async function analyzeHonoRoutes(repoRoot, verbose, resolveSchemas = false) {
|
|
|
31242
31629
|
return { apiContracts: [], schemasResolved: false };
|
|
31243
31630
|
}
|
|
31244
31631
|
if (verbose) {
|
|
31245
|
-
console.log(` Analyzing Hono routes in: ${
|
|
31632
|
+
console.log(` Analyzing Hono routes in: ${path11.relative(repoRoot, routesPath)}`);
|
|
31246
31633
|
if (resolveSchemas) {
|
|
31247
31634
|
console.log(" Schema resolution enabled (--resolve-schemas)");
|
|
31248
31635
|
}
|
|
@@ -31288,7 +31675,7 @@ async function analyzeHonoRoutes(repoRoot, verbose, resolveSchemas = false) {
|
|
|
31288
31675
|
return { apiContracts: [], schemasResolved: false };
|
|
31289
31676
|
}
|
|
31290
31677
|
}
|
|
31291
|
-
async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSchemas = false) {
|
|
31678
|
+
async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSchemas = false, diagnosticsInput) {
|
|
31292
31679
|
const registry = getInjectionRegistry();
|
|
31293
31680
|
const generatorVersion = getGeneratorVersion();
|
|
31294
31681
|
const e2eManifest = buildManifest(registry, generatorVersion);
|
|
@@ -31302,18 +31689,18 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
|
|
|
31302
31689
|
}
|
|
31303
31690
|
const definitionMap = buildDefinitionMap(machineDefinitions);
|
|
31304
31691
|
const enhancedMachines = buildEnhancedMachines(e2eManifest, definitionMap, machineDefinitions);
|
|
31305
|
-
const absoluteManifestDir =
|
|
31692
|
+
const absoluteManifestDir = path11.isAbsolute(manifestDir) ? manifestDir : path11.join(repoRoot, manifestDir);
|
|
31306
31693
|
if (!isPathContained(repoRoot, absoluteManifestDir)) {
|
|
31307
31694
|
throw new Error(
|
|
31308
31695
|
`Security error: Manifest directory '${manifestDir}' would escape the project root. The --manifest-dir must be a relative path within the project directory.`
|
|
31309
31696
|
);
|
|
31310
31697
|
}
|
|
31311
31698
|
ensureDirectoryExists(absoluteManifestDir);
|
|
31312
|
-
const generatedDir =
|
|
31699
|
+
const generatedDir = path11.join(absoluteManifestDir, "generated");
|
|
31313
31700
|
ensureDirectoryExists(generatedDir);
|
|
31314
|
-
const manifestsDir =
|
|
31701
|
+
const manifestsDir = path11.join(absoluteManifestDir, "manifests");
|
|
31315
31702
|
ensureDirectoryExists(manifestsDir);
|
|
31316
|
-
const tsPath =
|
|
31703
|
+
const tsPath = path11.join(generatedDir, "selectors.ts");
|
|
31317
31704
|
await fs5.promises.writeFile(tsPath, generateSelectorTypeScript(e2eManifest), "utf-8");
|
|
31318
31705
|
const unifiedRegistry = getUnifiedRegistry();
|
|
31319
31706
|
const machineLinks = buildMachineLinks();
|
|
@@ -31328,6 +31715,29 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
|
|
|
31328
31715
|
const jstOffset = 9 * 60 * 60 * 1e3;
|
|
31329
31716
|
const jst = new Date(now.getTime() + jstOffset);
|
|
31330
31717
|
const generatedAtJST = `${jst.getUTCFullYear()}-${String(jst.getUTCMonth() + 1).padStart(2, "0")}-${String(jst.getUTCDate()).padStart(2, "0")}T${String(jst.getUTCHours()).padStart(2, "0")}:${String(jst.getUTCMinutes()).padStart(2, "0")}:${String(jst.getUTCSeconds()).padStart(2, "0")}+09:00`;
|
|
31718
|
+
const machinesWithoutE2EMeta = machineDefinitions.filter(
|
|
31719
|
+
(def) => !def.hasE2EMeta && typeof def.id === "string"
|
|
31720
|
+
).map((def) => ({ id: def.id, sourceFile: def.sourceFile }));
|
|
31721
|
+
const warnings = collectManifestWarnings(
|
|
31722
|
+
repoRoot,
|
|
31723
|
+
platform,
|
|
31724
|
+
apiContracts,
|
|
31725
|
+
machinesWithoutE2EMeta,
|
|
31726
|
+
machineDefinitions.length
|
|
31727
|
+
);
|
|
31728
|
+
printManifestWarnings(warnings, verbose);
|
|
31729
|
+
const detectionDiagnostics = buildDetectionDiagnostics({
|
|
31730
|
+
scanSummary: diagnosticsInput?.scanSummary ?? {
|
|
31731
|
+
totalFiles: 0,
|
|
31732
|
+
filesWithMachineDefinitions: 0,
|
|
31733
|
+
filesWithMachineHooks: 0,
|
|
31734
|
+
filesWithJsxOnly: 0
|
|
31735
|
+
},
|
|
31736
|
+
resolutionDetails: diagnosticsInput?.resolutionDetails ?? [],
|
|
31737
|
+
manifestMachineIds: Object.keys(enhancedMachines),
|
|
31738
|
+
machineLinks,
|
|
31739
|
+
warnings: toDetectionWarnings(warnings)
|
|
31740
|
+
});
|
|
31331
31741
|
const unifiedManifest = {
|
|
31332
31742
|
version: manifestVersion,
|
|
31333
31743
|
generatedAt: generatedAtJST,
|
|
@@ -31340,17 +31750,15 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
|
|
|
31340
31750
|
authBoundaries: unifiedRegistry.authBoundaries,
|
|
31341
31751
|
machineDefinitions: unifiedRegistry.machineDefinitions,
|
|
31342
31752
|
machineLinks,
|
|
31343
|
-
apiContracts
|
|
31753
|
+
apiContracts,
|
|
31754
|
+
detectionDiagnostics
|
|
31344
31755
|
};
|
|
31345
|
-
const manifestPath =
|
|
31756
|
+
const manifestPath = path11.join(manifestsDir, "manifest.json");
|
|
31346
31757
|
await fs5.promises.writeFile(manifestPath, JSON.stringify(unifiedManifest, null, 2), "utf-8");
|
|
31347
|
-
const machinesWithoutE2EMeta = machineDefinitions.filter(
|
|
31348
|
-
(def) => !def.hasE2EMeta && typeof def.id === "string"
|
|
31349
|
-
).map((def) => ({ id: def.id, sourceFile: def.sourceFile }));
|
|
31350
31758
|
if (verbose) {
|
|
31351
|
-
console.log(`Generated selectors: ${
|
|
31759
|
+
console.log(`Generated selectors: ${path11.relative(repoRoot, tsPath)}`);
|
|
31352
31760
|
console.log(
|
|
31353
|
-
`Generated manifest: ${
|
|
31761
|
+
`Generated manifest: ${path11.relative(repoRoot, manifestPath)} (v${manifestVersion})`
|
|
31354
31762
|
);
|
|
31355
31763
|
console.log(` Platform: ${platform}`);
|
|
31356
31764
|
console.log(` Machine definitions: ${machineDefinitions.length}`);
|
|
@@ -31364,19 +31772,15 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
|
|
|
31364
31772
|
` API contracts: ${apiContracts.length}${schemasResolved ? " (with schemas)" : ""}`
|
|
31365
31773
|
);
|
|
31366
31774
|
console.log(` Machine links: ${machineLinks.length}`);
|
|
31775
|
+
console.log(
|
|
31776
|
+
` Detection: fallback=${detectionDiagnostics.resolution.bySource.fallback}, linkCoverage=${(detectionDiagnostics.coverage.machineLinkCoverage * 100).toFixed(1)}%`
|
|
31777
|
+
);
|
|
31367
31778
|
}
|
|
31368
|
-
const warnings = collectManifestWarnings(
|
|
31369
|
-
repoRoot,
|
|
31370
|
-
platform,
|
|
31371
|
-
apiContracts,
|
|
31372
|
-
machinesWithoutE2EMeta,
|
|
31373
|
-
machineDefinitions.length
|
|
31374
|
-
);
|
|
31375
|
-
printManifestWarnings(warnings, verbose);
|
|
31376
31779
|
return {
|
|
31377
|
-
manifestPath:
|
|
31780
|
+
manifestPath: path11.relative(repoRoot, tsPath),
|
|
31378
31781
|
machineCount: Object.keys(enhancedMachines).length,
|
|
31379
|
-
machinesWithoutE2EMeta
|
|
31782
|
+
machinesWithoutE2EMeta,
|
|
31783
|
+
detectionDiagnostics
|
|
31380
31784
|
};
|
|
31381
31785
|
}
|
|
31382
31786
|
|
|
@@ -31408,7 +31812,7 @@ function registerExistingInjections(machineIds, attrs, sourceFile) {
|
|
|
31408
31812
|
}
|
|
31409
31813
|
async function preprocessFile(filePath, repoRoot, options) {
|
|
31410
31814
|
let code = await fs5.promises.readFile(filePath, "utf-8");
|
|
31411
|
-
const relativePath =
|
|
31815
|
+
const relativePath = path11.relative(repoRoot, filePath);
|
|
31412
31816
|
collectRouteInfo(relativePath, code, options.verbose);
|
|
31413
31817
|
const hasMarker = code.includes(CLI_INJECTION_MARKER);
|
|
31414
31818
|
if (hasMarker && options.force) {
|
|
@@ -31439,14 +31843,15 @@ async function preprocessFile(filePath, repoRoot, options) {
|
|
|
31439
31843
|
injectedCount: 0,
|
|
31440
31844
|
machineIds,
|
|
31441
31845
|
changed: false,
|
|
31442
|
-
...attrs
|
|
31846
|
+
...attrs,
|
|
31847
|
+
resolutionDetails: []
|
|
31443
31848
|
}
|
|
31444
31849
|
};
|
|
31445
31850
|
}
|
|
31446
31851
|
return { code, hasMarker: false, skipped: false };
|
|
31447
31852
|
}
|
|
31448
31853
|
function transformAndRegister(filePath, code, repoRoot, options) {
|
|
31449
|
-
const relativePath =
|
|
31854
|
+
const relativePath = path11.relative(repoRoot, filePath);
|
|
31450
31855
|
const readAndParseFile = createReadAndParseFile(options.verbose);
|
|
31451
31856
|
const resolveImportPath = createResolveImportPath();
|
|
31452
31857
|
try {
|
|
@@ -31462,6 +31867,14 @@ function transformAndRegister(filePath, code, repoRoot, options) {
|
|
|
31462
31867
|
const transformedCode = markerComment + result.code;
|
|
31463
31868
|
const { actions, fields, testIds } = extractInjectedAttributes(transformedCode);
|
|
31464
31869
|
const machineIds = [...result.resolvedIds.values()];
|
|
31870
|
+
const resultWithResolution = result;
|
|
31871
|
+
const rawResolutionDetails = Array.isArray(resultWithResolution.resolutionDetails) ? resultWithResolution.resolutionDetails : [];
|
|
31872
|
+
const resolutionDetails = rawResolutionDetails.map((detail) => ({
|
|
31873
|
+
filePath: relativePath,
|
|
31874
|
+
machineRef: detail.machineRef,
|
|
31875
|
+
resolvedId: detail.resolvedId,
|
|
31876
|
+
source: detail.source
|
|
31877
|
+
}));
|
|
31465
31878
|
registerExistingInjections(machineIds, { actions, fields, testIds }, relativePath);
|
|
31466
31879
|
return {
|
|
31467
31880
|
filePath,
|
|
@@ -31471,7 +31884,8 @@ function transformAndRegister(filePath, code, repoRoot, options) {
|
|
|
31471
31884
|
transformedCode,
|
|
31472
31885
|
actions,
|
|
31473
31886
|
fields,
|
|
31474
|
-
testIds
|
|
31887
|
+
testIds,
|
|
31888
|
+
resolutionDetails
|
|
31475
31889
|
};
|
|
31476
31890
|
} catch (error) {
|
|
31477
31891
|
if (options.verbose) {
|
|
@@ -31492,7 +31906,7 @@ async function processFileForChildInjection(filePath, repoRoot, options) {
|
|
|
31492
31906
|
if (prep.skipped && prep.skipResult) return prep.skipResult;
|
|
31493
31907
|
const result = transformAndRegister(filePath, prep.code, repoRoot, options);
|
|
31494
31908
|
if (options.verbose && result.changed && result.injectedCount > 0) {
|
|
31495
|
-
const relativePath =
|
|
31909
|
+
const relativePath = path11.relative(repoRoot, filePath);
|
|
31496
31910
|
console.log(
|
|
31497
31911
|
` [child] Injected ${result.injectedCount} attrs in ${relativePath} (actions: ${result.actions.join(", ")})`
|
|
31498
31912
|
);
|
|
@@ -31512,7 +31926,7 @@ async function handleChangedFile(result, check, repoRoot, verbose, state2) {
|
|
|
31512
31926
|
await fs5.promises.writeFile(result.filePath, result.transformedCode, "utf-8");
|
|
31513
31927
|
state2.filesToFormat.push(result.filePath);
|
|
31514
31928
|
if (verbose) {
|
|
31515
|
-
const relativePath =
|
|
31929
|
+
const relativePath = path11.relative(repoRoot, result.filePath);
|
|
31516
31930
|
console.log(` Injected ${result.injectedCount} attrs in ${relativePath}`);
|
|
31517
31931
|
}
|
|
31518
31932
|
}
|
|
@@ -31523,6 +31937,60 @@ async function formatChangedFiles(filesToFormat, repoRoot, verbose) {
|
|
|
31523
31937
|
}
|
|
31524
31938
|
await formatFilesWithBiome(filesToFormat, repoRoot);
|
|
31525
31939
|
}
|
|
31940
|
+
function createScanSummary(params) {
|
|
31941
|
+
return {
|
|
31942
|
+
totalFiles: params.files.length,
|
|
31943
|
+
filesWithMachineDefinitions: params.withMachineDefinitions.length,
|
|
31944
|
+
filesWithMachineHooks: params.withMachineHooks.length,
|
|
31945
|
+
filesWithJsxOnly: params.withJsxOnly.length
|
|
31946
|
+
};
|
|
31947
|
+
}
|
|
31948
|
+
async function resolveManifestArtifacts(params) {
|
|
31949
|
+
let manifestPath;
|
|
31950
|
+
let manifestMachineCount;
|
|
31951
|
+
let machinesWithoutE2EMeta;
|
|
31952
|
+
let detectionDiagnostics;
|
|
31953
|
+
if (params.manifest && !params.check) {
|
|
31954
|
+
const diagnosticsInput = {
|
|
31955
|
+
scanSummary: params.scanSummary,
|
|
31956
|
+
resolutionDetails: params.resolutionDetails
|
|
31957
|
+
};
|
|
31958
|
+
const manifestResult = await generateManifestFiles(
|
|
31959
|
+
params.manifestDir,
|
|
31960
|
+
params.repoRoot,
|
|
31961
|
+
params.verbose,
|
|
31962
|
+
params.resolveSchemas,
|
|
31963
|
+
diagnosticsInput
|
|
31964
|
+
);
|
|
31965
|
+
manifestPath = manifestResult.manifestPath;
|
|
31966
|
+
manifestMachineCount = manifestResult.machineCount;
|
|
31967
|
+
machinesWithoutE2EMeta = manifestResult.machinesWithoutE2EMeta;
|
|
31968
|
+
detectionDiagnostics = manifestResult.detectionDiagnostics;
|
|
31969
|
+
} else if (params.manifest && params.check) {
|
|
31970
|
+
const warnings = [];
|
|
31971
|
+
detectionDiagnostics = buildDetectionDiagnostics({
|
|
31972
|
+
scanSummary: params.scanSummary,
|
|
31973
|
+
resolutionDetails: params.resolutionDetails,
|
|
31974
|
+
manifestMachineIds: [],
|
|
31975
|
+
machineLinks: [],
|
|
31976
|
+
warnings
|
|
31977
|
+
});
|
|
31978
|
+
}
|
|
31979
|
+
const strictDetectStatus = params.strictDetect ? detectionDiagnostics ? evaluateStrictDetect(detectionDiagnostics) : {
|
|
31980
|
+
enabled: true,
|
|
31981
|
+
passed: false,
|
|
31982
|
+
reasons: [
|
|
31983
|
+
"strict detect requires manifest diagnostics, but diagnostics were unavailable"
|
|
31984
|
+
]
|
|
31985
|
+
} : void 0;
|
|
31986
|
+
return {
|
|
31987
|
+
manifestPath,
|
|
31988
|
+
manifestMachineCount,
|
|
31989
|
+
machinesWithoutE2EMeta,
|
|
31990
|
+
detectionDiagnostics,
|
|
31991
|
+
strictDetectStatus
|
|
31992
|
+
};
|
|
31993
|
+
}
|
|
31526
31994
|
function mightContainMachineDefinition(code) {
|
|
31527
31995
|
return code.includes("createMachine");
|
|
31528
31996
|
}
|
|
@@ -31546,13 +32014,34 @@ async function categorizeFiles(files) {
|
|
|
31546
32014
|
return { withMachineDefinitions, withMachineHooks, withJsxOnly };
|
|
31547
32015
|
}
|
|
31548
32016
|
async function processFiles(options) {
|
|
31549
|
-
const {
|
|
32017
|
+
const {
|
|
32018
|
+
repoRoot,
|
|
32019
|
+
check,
|
|
32020
|
+
verbose,
|
|
32021
|
+
include,
|
|
32022
|
+
exclude,
|
|
32023
|
+
manifest,
|
|
32024
|
+
manifestDir,
|
|
32025
|
+
resolveSchemas,
|
|
32026
|
+
strictDetect
|
|
32027
|
+
} = options;
|
|
31550
32028
|
clearInjectionRegistry();
|
|
31551
32029
|
clearUnifiedRegistry();
|
|
31552
32030
|
const files = await discoverFiles(repoRoot, include, exclude);
|
|
31553
32031
|
if (verbose) console.log(`Found ${files.length} files to process`);
|
|
31554
|
-
const state2 = {
|
|
32032
|
+
const state2 = {
|
|
32033
|
+
changes: [],
|
|
32034
|
+
filesToFormat: [],
|
|
32035
|
+
totalInjections: 0,
|
|
32036
|
+
resolutionDetails: []
|
|
32037
|
+
};
|
|
31555
32038
|
const { withMachineDefinitions, withMachineHooks, withJsxOnly } = await categorizeFiles(files);
|
|
32039
|
+
const scanSummary = createScanSummary({
|
|
32040
|
+
files,
|
|
32041
|
+
withMachineDefinitions,
|
|
32042
|
+
withMachineHooks,
|
|
32043
|
+
withJsxOnly
|
|
32044
|
+
});
|
|
31556
32045
|
if (verbose) {
|
|
31557
32046
|
console.log(` Files with machine definitions: ${withMachineDefinitions.length}`);
|
|
31558
32047
|
console.log(` Files with machine hooks: ${withMachineHooks.length}`);
|
|
@@ -31562,46 +32051,50 @@ async function processFiles(options) {
|
|
|
31562
32051
|
for (const filePath of withMachineDefinitions) {
|
|
31563
32052
|
try {
|
|
31564
32053
|
const code = await fs5.promises.readFile(filePath, "utf-8");
|
|
31565
|
-
const relativePath =
|
|
32054
|
+
const relativePath = path11.relative(repoRoot, filePath);
|
|
31566
32055
|
collectRouteInfo(relativePath, code, verbose);
|
|
31567
32056
|
} catch {
|
|
31568
32057
|
}
|
|
31569
32058
|
}
|
|
31570
32059
|
for (const filePath of withMachineHooks) {
|
|
31571
32060
|
const result = await processFile(filePath, repoRoot, processOpts);
|
|
32061
|
+
state2.resolutionDetails.push(...result.resolutionDetails);
|
|
31572
32062
|
await handleChangedFile(result, check, repoRoot, verbose, state2);
|
|
31573
32063
|
}
|
|
31574
32064
|
for (const filePath of withJsxOnly) {
|
|
31575
32065
|
const result = await processFileForChildInjection(filePath, repoRoot, processOpts);
|
|
32066
|
+
state2.resolutionDetails.push(...result.resolutionDetails);
|
|
31576
32067
|
await handleChangedFile(result, check, repoRoot, verbose, state2);
|
|
31577
32068
|
}
|
|
31578
32069
|
if (!check) {
|
|
31579
32070
|
await formatChangedFiles(state2.filesToFormat, repoRoot, verbose);
|
|
31580
32071
|
}
|
|
31581
32072
|
postProcessRegistries();
|
|
31582
|
-
|
|
31583
|
-
|
|
31584
|
-
|
|
31585
|
-
|
|
31586
|
-
|
|
31587
|
-
|
|
31588
|
-
|
|
31589
|
-
|
|
31590
|
-
|
|
31591
|
-
|
|
31592
|
-
|
|
31593
|
-
|
|
31594
|
-
|
|
31595
|
-
|
|
32073
|
+
const manifestArtifacts = await resolveManifestArtifacts({
|
|
32074
|
+
manifest,
|
|
32075
|
+
check,
|
|
32076
|
+
manifestDir,
|
|
32077
|
+
repoRoot,
|
|
32078
|
+
verbose,
|
|
32079
|
+
resolveSchemas: resolveSchemas ?? false,
|
|
32080
|
+
strictDetect: strictDetect ?? false,
|
|
32081
|
+
scanSummary,
|
|
32082
|
+
resolutionDetails: state2.resolutionDetails
|
|
32083
|
+
});
|
|
32084
|
+
const hasCheckFailure = check && state2.changes.length > 0;
|
|
32085
|
+
const hasStrictDetectFailure = manifestArtifacts.strictDetectStatus?.passed === false;
|
|
32086
|
+
const exitCode = hasCheckFailure || hasStrictDetectFailure ? 1 : 0;
|
|
31596
32087
|
return {
|
|
31597
32088
|
totalFiles: files.length,
|
|
31598
32089
|
changedFiles: state2.changes.length,
|
|
31599
32090
|
totalInjections: state2.totalInjections,
|
|
31600
32091
|
changes: state2.changes,
|
|
31601
|
-
exitCode
|
|
31602
|
-
manifestPath,
|
|
31603
|
-
manifestMachineCount,
|
|
31604
|
-
machinesWithoutE2EMeta
|
|
32092
|
+
exitCode,
|
|
32093
|
+
manifestPath: manifestArtifacts.manifestPath,
|
|
32094
|
+
manifestMachineCount: manifestArtifacts.manifestMachineCount,
|
|
32095
|
+
machinesWithoutE2EMeta: manifestArtifacts.machinesWithoutE2EMeta,
|
|
32096
|
+
detectionDiagnostics: manifestArtifacts.detectionDiagnostics,
|
|
32097
|
+
strictDetect: manifestArtifacts.strictDetectStatus
|
|
31605
32098
|
};
|
|
31606
32099
|
}
|
|
31607
32100
|
|
|
@@ -31661,6 +32154,35 @@ function logMachinesWithoutE2EMeta(result, logger16) {
|
|
|
31661
32154
|
logger16.info(" }");
|
|
31662
32155
|
logger16.info(" See: .claude/rules/xstate-design.md#meta.e2e");
|
|
31663
32156
|
}
|
|
32157
|
+
function logDetectionDiagnostics(result, logger16) {
|
|
32158
|
+
if (!result.detectionDiagnostics) return;
|
|
32159
|
+
const diagnostics = result.detectionDiagnostics;
|
|
32160
|
+
const fallbackCount = diagnostics.resolution.bySource.fallback;
|
|
32161
|
+
const fallbackRate = (diagnostics.resolution.fallbackRate * 100).toFixed(1);
|
|
32162
|
+
const coverage = (diagnostics.coverage.machineLinkCoverage * 100).toFixed(1);
|
|
32163
|
+
logger16.info("");
|
|
32164
|
+
logger16.info(
|
|
32165
|
+
`Detection diagnostics: usages=${diagnostics.resolution.totalMachineUsages}, fallback=${fallbackCount} (${fallbackRate}%), linkCoverage=${coverage}%`
|
|
32166
|
+
);
|
|
32167
|
+
if (fallbackCount > 0) {
|
|
32168
|
+
for (const item of diagnostics.resolution.fallbackExamples.slice(0, 5)) {
|
|
32169
|
+
logger16.warn(
|
|
32170
|
+
` fallback: ${item.filePath} :: ${item.machineRef} -> ${item.resolvedId} (${item.source})`
|
|
32171
|
+
);
|
|
32172
|
+
}
|
|
32173
|
+
}
|
|
32174
|
+
}
|
|
32175
|
+
function logStrictDetect(result, logger16) {
|
|
32176
|
+
if (!result.strictDetect) return;
|
|
32177
|
+
if (result.strictDetect.passed) {
|
|
32178
|
+
logger16.success("Strict detect passed (no fallback resolution)");
|
|
32179
|
+
return;
|
|
32180
|
+
}
|
|
32181
|
+
logger16.error("Strict detect failed");
|
|
32182
|
+
for (const reason of result.strictDetect.reasons) {
|
|
32183
|
+
logger16.error(` - ${reason}`);
|
|
32184
|
+
}
|
|
32185
|
+
}
|
|
31664
32186
|
async function injectTestAttrsAction(rawOptions, command) {
|
|
31665
32187
|
const logger16 = createCLILogger("manifest");
|
|
31666
32188
|
const parseResult = InjectTestAttrsInputSchema.safeParse(rawOptions);
|
|
@@ -31671,6 +32193,20 @@ async function injectTestAttrsAction(rawOptions, command) {
|
|
|
31671
32193
|
]);
|
|
31672
32194
|
}
|
|
31673
32195
|
const options = parseResult.data;
|
|
32196
|
+
if (options.strictDetect && options.check) {
|
|
32197
|
+
throw new CLIError(
|
|
32198
|
+
"--strict-detect cannot be used with --check",
|
|
32199
|
+
"STRICT_DETECT_CHECK_UNSUPPORTED",
|
|
32200
|
+
["Run without --check to evaluate strict detection against manifest diagnostics"]
|
|
32201
|
+
);
|
|
32202
|
+
}
|
|
32203
|
+
if (options.strictDetect && !options.manifest) {
|
|
32204
|
+
throw new CLIError(
|
|
32205
|
+
"--strict-detect requires manifest generation",
|
|
32206
|
+
"STRICT_DETECT_MANIFEST_REQUIRED",
|
|
32207
|
+
["Remove --no-manifest, or disable --strict-detect"]
|
|
32208
|
+
);
|
|
32209
|
+
}
|
|
31674
32210
|
const repoRoot = findProjectRoot$1() ?? process.cwd();
|
|
31675
32211
|
if (!options.check) {
|
|
31676
32212
|
logger16.section("Generating manifest (manifest.json)");
|
|
@@ -31689,6 +32225,8 @@ async function injectTestAttrsAction(rawOptions, command) {
|
|
|
31689
32225
|
logResultSummary(result, options, logger16);
|
|
31690
32226
|
logManifestInfo(result, logger16);
|
|
31691
32227
|
logMachinesWithoutE2EMeta(result, logger16);
|
|
32228
|
+
logDetectionDiagnostics(result, logger16);
|
|
32229
|
+
logStrictDetect(result, logger16);
|
|
31692
32230
|
emitJsonSuccess(command, InjectTestAttrsOutputSchema, result);
|
|
31693
32231
|
if (result.exitCode !== 0) {
|
|
31694
32232
|
process.exit(result.exitCode);
|
|
@@ -31708,7 +32246,7 @@ var injectTestAttrsCommand = new Command("inject-test-attrs").description("Injec
|
|
|
31708
32246
|
"**/*.test.*",
|
|
31709
32247
|
"**/*.spec.*",
|
|
31710
32248
|
"**/*.stories.*"
|
|
31711
|
-
]).option("--no-manifest", "Skip E2E selector manifest generation").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").action(async (rawOptions) => {
|
|
32249
|
+
]).option("--no-manifest", "Skip E2E selector manifest generation").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").option("--strict-detect", "Fail when fallback machine detection is used (for deterministic CI)").action(async (rawOptions) => {
|
|
31712
32250
|
await injectTestAttrsAction(rawOptions, injectTestAttrsCommand);
|
|
31713
32251
|
});
|
|
31714
32252
|
|
|
@@ -31772,7 +32310,7 @@ var manifestCommand = new Command("manifest").description("Generate E2E manifest
|
|
|
31772
32310
|
"**/*.test.*",
|
|
31773
32311
|
"**/*.spec.*",
|
|
31774
32312
|
"**/*.stories.*"
|
|
31775
|
-
]).option("--no-manifest", "Skip manifest file generation (attributes only)").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").action(async (options) => {
|
|
32313
|
+
]).option("--no-manifest", "Skip manifest file generation (attributes only)").option("--manifest-dir <dir>", "Output directory for manifest files", ".runa").option("--strict-detect", "Fail when fallback machine detection is used (for deterministic CI)").action(async (options) => {
|
|
31776
32314
|
await injectTestAttrsAction(options, manifestCommand);
|
|
31777
32315
|
});
|
|
31778
32316
|
|
|
@@ -31831,7 +32369,7 @@ function assertNodeAuthToken(options) {
|
|
|
31831
32369
|
}
|
|
31832
32370
|
}
|
|
31833
32371
|
function getPackageVersion(packagePath) {
|
|
31834
|
-
const packageJsonPath =
|
|
32372
|
+
const packageJsonPath = path11__default.join(packagePath, "package.json");
|
|
31835
32373
|
if (!existsSync(packageJsonPath)) {
|
|
31836
32374
|
throw new CLIError(`package.json not found at ${packagePath}`, "PACKAGE_NOT_FOUND");
|
|
31837
32375
|
}
|
|
@@ -31850,7 +32388,7 @@ function resolveWorkspaceDependencies(workspaceRoot, packages, logger16) {
|
|
|
31850
32388
|
const sdkPackage = packages.find((p) => p.name === "SDK");
|
|
31851
32389
|
const xstatePluginPackage = packages.find((p) => p.name === "xstate-test-plugin");
|
|
31852
32390
|
if (!sdkPackage) return;
|
|
31853
|
-
const cliPackagePath =
|
|
32391
|
+
const cliPackagePath = path11__default.join(workspaceRoot, "packages", "cli", "package.json");
|
|
31854
32392
|
if (!existsSync(cliPackagePath)) return;
|
|
31855
32393
|
let content = readFileSync(cliPackagePath, "utf-8");
|
|
31856
32394
|
let updated = false;
|
|
@@ -31879,7 +32417,7 @@ function resolveWorkspaceDependencies(workspaceRoot, packages, logger16) {
|
|
|
31879
32417
|
}
|
|
31880
32418
|
}
|
|
31881
32419
|
function restoreWorkspaceDependencies(workspaceRoot) {
|
|
31882
|
-
const cliPackagePath =
|
|
32420
|
+
const cliPackagePath = path11__default.join(workspaceRoot, "packages", "cli", "package.json");
|
|
31883
32421
|
if (!existsSync(cliPackagePath)) return;
|
|
31884
32422
|
let content = readFileSync(cliPackagePath, "utf-8");
|
|
31885
32423
|
content = content.replace(/"@runa-ai\/runa": "\^[\d.]+"/, '"@runa-ai/runa": "workspace:*"');
|
|
@@ -31991,7 +32529,7 @@ function collectPackageInfo(workspaceRoot, logger16, stepNum) {
|
|
|
31991
32529
|
logger16.step("Collecting package info", stepNum);
|
|
31992
32530
|
const packages = [];
|
|
31993
32531
|
for (const pkgConfig of PUBLISHABLE_PACKAGES) {
|
|
31994
|
-
const pkgPath =
|
|
32532
|
+
const pkgPath = path11__default.join(workspaceRoot, "packages", pkgConfig.dir);
|
|
31995
32533
|
const version = getPackageVersion(pkgPath);
|
|
31996
32534
|
const exists = checkVersionExists(pkgConfig.publishName, version);
|
|
31997
32535
|
packages.push({
|
|
@@ -33380,8 +33918,8 @@ var compareActor = fromPromise(async ({ input: input3 }) => {
|
|
|
33380
33918
|
const result = compareBothFiles(
|
|
33381
33919
|
runaRelPath,
|
|
33382
33920
|
templateRelPath,
|
|
33383
|
-
|
|
33384
|
-
|
|
33921
|
+
path11.join(repoRoot, runaRelPath),
|
|
33922
|
+
path11.join(templateDir, templateRelPath),
|
|
33385
33923
|
runaFile.category,
|
|
33386
33924
|
options.diff ?? false
|
|
33387
33925
|
);
|
|
@@ -33832,7 +34370,7 @@ var discoverActor = fromPromise(async ({ input: input3 }) => {
|
|
|
33832
34370
|
const runaPattern = rule.runa;
|
|
33833
34371
|
const runaFiles = await globFiles(repoRoot, runaPattern);
|
|
33834
34372
|
for (const file of runaFiles) {
|
|
33835
|
-
const relativePath =
|
|
34373
|
+
const relativePath = path11.relative(repoRoot, file.absolutePath);
|
|
33836
34374
|
const key = generateComparisonKey(relativePath, false);
|
|
33837
34375
|
inventory.runaFiles.set(relativePath, {
|
|
33838
34376
|
...file,
|
|
@@ -33846,7 +34384,7 @@ var discoverActor = fromPromise(async ({ input: input3 }) => {
|
|
|
33846
34384
|
const templatePattern = rule.template;
|
|
33847
34385
|
const templateFiles = await globFiles(templateDir, templatePattern);
|
|
33848
34386
|
for (const file of templateFiles) {
|
|
33849
|
-
const relativePath =
|
|
34387
|
+
const relativePath = path11.relative(templateDir, file.absolutePath);
|
|
33850
34388
|
const key = generateComparisonKey(relativePath, true);
|
|
33851
34389
|
inventory.templateFiles.set(relativePath, {
|
|
33852
34390
|
...file,
|
|
@@ -33895,7 +34433,7 @@ async function matchDoubleWildcard(ctx, entries) {
|
|
|
33895
34433
|
await walkAndMatch({ ...ctx, partIndex: ctx.partIndex + 1 });
|
|
33896
34434
|
for (const entry of entries) {
|
|
33897
34435
|
if (entry.isDirectory()) {
|
|
33898
|
-
const subDir =
|
|
34436
|
+
const subDir = path11.join(ctx.currentDir, entry.name);
|
|
33899
34437
|
await walkAndMatch({ ...ctx, currentDir: subDir });
|
|
33900
34438
|
}
|
|
33901
34439
|
}
|
|
@@ -33904,7 +34442,7 @@ async function matchSingleWildcard(ctx, entries, pattern, isLastPart) {
|
|
|
33904
34442
|
const regex = patternToRegex(pattern);
|
|
33905
34443
|
for (const entry of entries) {
|
|
33906
34444
|
if (regex.test(entry.name)) {
|
|
33907
|
-
const entryPath =
|
|
34445
|
+
const entryPath = path11.join(ctx.currentDir, entry.name);
|
|
33908
34446
|
await processEntry(ctx, entryPath, entry.isFile(), entry.isDirectory(), isLastPart);
|
|
33909
34447
|
}
|
|
33910
34448
|
}
|
|
@@ -33914,14 +34452,14 @@ async function matchBraceExpansion(ctx, entries, pattern, isLastPart) {
|
|
|
33914
34452
|
for (const option of options) {
|
|
33915
34453
|
for (const entry of entries) {
|
|
33916
34454
|
if (entry.name === option) {
|
|
33917
|
-
const entryPath =
|
|
34455
|
+
const entryPath = path11.join(ctx.currentDir, entry.name);
|
|
33918
34456
|
await processEntry(ctx, entryPath, entry.isFile(), entry.isDirectory(), isLastPart);
|
|
33919
34457
|
}
|
|
33920
34458
|
}
|
|
33921
34459
|
}
|
|
33922
34460
|
}
|
|
33923
34461
|
async function matchLiteral(ctx, pattern, isLastPart) {
|
|
33924
|
-
const entryPath =
|
|
34462
|
+
const entryPath = path11.join(ctx.currentDir, pattern);
|
|
33925
34463
|
if (!fs5.existsSync(entryPath)) return;
|
|
33926
34464
|
const stats = fs5.statSync(entryPath);
|
|
33927
34465
|
await processEntry(ctx, entryPath, stats.isFile(), stats.isDirectory(), isLastPart);
|
|
@@ -34446,15 +34984,15 @@ function printActionsNeeded(logger16, actions) {
|
|
|
34446
34984
|
);
|
|
34447
34985
|
}
|
|
34448
34986
|
function findRepoRoot3(startDir) {
|
|
34449
|
-
const { existsSync:
|
|
34987
|
+
const { existsSync: existsSync52, readFileSync: readFileSync29 } = __require("fs");
|
|
34450
34988
|
const { join: join23, dirname: dirname5 } = __require("path");
|
|
34451
34989
|
let current = startDir;
|
|
34452
34990
|
while (current !== dirname5(current)) {
|
|
34453
|
-
if (
|
|
34991
|
+
if (existsSync52(join23(current, "turbo.json"))) {
|
|
34454
34992
|
return current;
|
|
34455
34993
|
}
|
|
34456
34994
|
const pkgPath = join23(current, "package.json");
|
|
34457
|
-
if (
|
|
34995
|
+
if (existsSync52(pkgPath)) {
|
|
34458
34996
|
try {
|
|
34459
34997
|
const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
|
|
34460
34998
|
if (pkg.workspaces) {
|
|
@@ -34522,10 +35060,10 @@ function generateReportOutput(output3, isJsonMode) {
|
|
|
34522
35060
|
};
|
|
34523
35061
|
}
|
|
34524
35062
|
function validateRunaRepo(repoRoot) {
|
|
34525
|
-
const { existsSync:
|
|
35063
|
+
const { existsSync: existsSync52 } = __require("fs");
|
|
34526
35064
|
const { join: join23 } = __require("path");
|
|
34527
35065
|
const templateDir = join23(repoRoot, "packages/runa-templates/templates");
|
|
34528
|
-
if (!
|
|
35066
|
+
if (!existsSync52(templateDir)) {
|
|
34529
35067
|
throw new CLIError("template-check is a runa-repo only command", "NOT_RUNA_REPO", [
|
|
34530
35068
|
"This command compares runa-repo with pj-repo templates",
|
|
34531
35069
|
"It should only be run in the runa repository",
|
|
@@ -34627,11 +35165,29 @@ init_esm_shims();
|
|
|
34627
35165
|
|
|
34628
35166
|
// src/commands/test/commands/test.ts
|
|
34629
35167
|
init_esm_shims();
|
|
35168
|
+
function resolveEffectiveRequireManifest(options) {
|
|
35169
|
+
if (options.requireManifest && options.allowManifestFallback) {
|
|
35170
|
+
throw new CLIError(
|
|
35171
|
+
"--require-manifest and --allow-manifest-fallback are mutually exclusive",
|
|
35172
|
+
"TEST_MANIFEST_FLAGS_EXCLUSIVE",
|
|
35173
|
+
["Use strict mode (default) OR explicitly allow fallback, but not both"]
|
|
35174
|
+
);
|
|
35175
|
+
}
|
|
35176
|
+
if (options.allowManifestFallback) return false;
|
|
35177
|
+
return options.requireManifest;
|
|
35178
|
+
}
|
|
34630
35179
|
var testCommand = new Command("test").description("Run tests (compat). Prefer: test:layer0..4 or test:static/service/integration.").option("--layer <number>", "Run specific layer (0-4)").option("--from <number>", "Run from layer N to 4").option("--to <number>", "Run from layer 0 to N").option("--ci", "CI mode (fail fast, no interactive)").option("--verbose", "Verbose output").option("--record", "Record test results to database", true).option(
|
|
34631
35180
|
"--report-json <path>",
|
|
34632
35181
|
"Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
|
|
34633
|
-
).option("--generate", "Generate tests from XState before running (integration)").option("--advanced", "Generate advanced tests (integration)").option("--auto", "Zero-config auto-generation (integration)").option("--base-url <url>", "Override base URL (integration)").option("--changed", "Run only impacted layers based on git diff (service)").option("--base <ref>", "Base ref for --changed (service)").option("--skip-missing", "Skip layers with missing dependencies instead of failing").
|
|
35182
|
+
).option("--generate", "Generate tests from XState before running (integration)").option("--advanced", "Generate advanced tests (integration)").option("--auto", "Zero-config auto-generation (integration)").option("--base-url <url>", "Override base URL (integration)").option("--changed", "Run only impacted layers based on git diff (service)").option("--base <ref>", "Base ref for --changed (service)").option("--skip-missing", "Skip layers with missing dependencies instead of failing").option(
|
|
35183
|
+
"--require-manifest",
|
|
35184
|
+
"Require manifest to be present and valid for Layer 3/4 tests (strict behavior)"
|
|
35185
|
+
).option(
|
|
35186
|
+
"--allow-manifest-fallback",
|
|
35187
|
+
"Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
|
|
35188
|
+
).action(async (options) => {
|
|
34634
35189
|
try {
|
|
35190
|
+
const effectiveRequireManifest = resolveEffectiveRequireManifest(options);
|
|
34635
35191
|
const output3 = await runTest({
|
|
34636
35192
|
layer: options.layer !== void 0 ? Number.parseInt(options.layer, 10) : void 0,
|
|
34637
35193
|
from: options.from !== void 0 ? Number.parseInt(options.from, 10) : void 0,
|
|
@@ -34646,7 +35202,8 @@ var testCommand = new Command("test").description("Run tests (compat). Prefer: t
|
|
|
34646
35202
|
baseUrl: options.baseUrl,
|
|
34647
35203
|
changed: options.changed,
|
|
34648
35204
|
base: options.base,
|
|
34649
|
-
skipMissing: options.skipMissing
|
|
35205
|
+
skipMissing: options.skipMissing,
|
|
35206
|
+
requireManifest: effectiveRequireManifest
|
|
34650
35207
|
});
|
|
34651
35208
|
emitJsonSuccess(testCommand, TestRunOutputSchema, output3);
|
|
34652
35209
|
} catch (error) {
|
|
@@ -34744,11 +35301,29 @@ var testApiCommand = new Command("test:api").description("Run Layer 3: API tests
|
|
|
34744
35301
|
|
|
34745
35302
|
// src/commands/test/commands/test-e2e.ts
|
|
34746
35303
|
init_esm_shims();
|
|
35304
|
+
function resolveEffectiveRequireManifest2(options) {
|
|
35305
|
+
if (options.requireManifest && options.allowManifestFallback) {
|
|
35306
|
+
throw new CLIError(
|
|
35307
|
+
"--require-manifest and --allow-manifest-fallback are mutually exclusive",
|
|
35308
|
+
"TEST_E2E_MANIFEST_FLAGS_EXCLUSIVE",
|
|
35309
|
+
["Use strict mode (default) OR explicitly allow fallback, but not both"]
|
|
35310
|
+
);
|
|
35311
|
+
}
|
|
35312
|
+
if (options.allowManifestFallback) return false;
|
|
35313
|
+
return options.requireManifest;
|
|
35314
|
+
}
|
|
34747
35315
|
var testE2ECommand = new Command("test:e2e").description("Run Layer 4: E2E tests (Playwright) - Requires browser").option("--generate", "Generate tests from XState before running").option("--advanced", "Generate advanced tests (context-aware, guards, invariants, etc.)").option("--auto", "Zero-config auto-generation (implementation-driven)").option("--ci", "CI mode (fail fast, no interactive)").option("--record", "Record test results to database", true).option("--base-url <url>", "Explicit base URL for E2E (disables auto dev server start)").option(
|
|
35316
|
+
"--require-manifest",
|
|
35317
|
+
"Require manifest to be present and valid (strict behavior; enabled by default for Layer 4)"
|
|
35318
|
+
).option(
|
|
35319
|
+
"--allow-manifest-fallback",
|
|
35320
|
+
"Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
|
|
35321
|
+
).option(
|
|
34748
35322
|
"--report-json <path>",
|
|
34749
35323
|
"Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
|
|
34750
35324
|
).option("--verbose", "Verbose output (full error details, environment info)").action(async (options) => {
|
|
34751
35325
|
try {
|
|
35326
|
+
const effectiveRequireManifest = resolveEffectiveRequireManifest2(options);
|
|
34752
35327
|
const output3 = await runTestIntegration({
|
|
34753
35328
|
ci: options.ci ?? false,
|
|
34754
35329
|
record: options.record,
|
|
@@ -34758,6 +35333,7 @@ var testE2ECommand = new Command("test:e2e").description("Run Layer 4: E2E tests
|
|
|
34758
35333
|
advanced: options.advanced,
|
|
34759
35334
|
auto: options.auto,
|
|
34760
35335
|
baseUrl: options.baseUrl,
|
|
35336
|
+
requireManifest: effectiveRequireManifest,
|
|
34761
35337
|
invokedAs: "runa test:e2e"
|
|
34762
35338
|
});
|
|
34763
35339
|
emitJsonSuccess(testE2ECommand, TestIntegrationOutputSchema, output3);
|
|
@@ -34778,8 +35354,15 @@ var testE2ECommand = new Command("test:e2e").description("Run Layer 4: E2E tests
|
|
|
34778
35354
|
);
|
|
34779
35355
|
}
|
|
34780
35356
|
});
|
|
34781
|
-
var testBrowserCommand = new Command("test:browser").description("Run Layer 4: Browser tests (Playwright E2E) - Alias for test:e2e").option("--generate", "Generate tests from XState before running").option("--advanced", "Generate advanced tests").option("--auto", "Zero-config auto-generation").option("--ci", "CI mode (fail fast, no interactive)").option("--record", "Record test results to database", true).option("--base-url <url>", "Explicit base URL for E2E").option(
|
|
35357
|
+
var testBrowserCommand = new Command("test:browser").description("Run Layer 4: Browser tests (Playwright E2E) - Alias for test:e2e").option("--generate", "Generate tests from XState before running").option("--advanced", "Generate advanced tests").option("--auto", "Zero-config auto-generation").option("--ci", "CI mode (fail fast, no interactive)").option("--record", "Record test results to database", true).option("--base-url <url>", "Explicit base URL for E2E").option(
|
|
35358
|
+
"--require-manifest",
|
|
35359
|
+
"Require manifest to be present and valid (strict behavior; enabled by default for Layer 4)"
|
|
35360
|
+
).option(
|
|
35361
|
+
"--allow-manifest-fallback",
|
|
35362
|
+
"Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
|
|
35363
|
+
).option("--report-json <path>", "Export test report as JSON").option("--verbose", "Verbose output").action(async (options) => {
|
|
34782
35364
|
try {
|
|
35365
|
+
const effectiveRequireManifest = resolveEffectiveRequireManifest2(options);
|
|
34783
35366
|
const output3 = await runTestIntegration({
|
|
34784
35367
|
ci: options.ci ?? false,
|
|
34785
35368
|
record: options.record,
|
|
@@ -34789,6 +35372,7 @@ var testBrowserCommand = new Command("test:browser").description("Run Layer 4: B
|
|
|
34789
35372
|
advanced: options.advanced,
|
|
34790
35373
|
auto: options.auto,
|
|
34791
35374
|
baseUrl: options.baseUrl,
|
|
35375
|
+
requireManifest: effectiveRequireManifest,
|
|
34792
35376
|
invokedAs: "runa test:browser"
|
|
34793
35377
|
});
|
|
34794
35378
|
emitJsonSuccess(testBrowserCommand, TestIntegrationOutputSchema, output3);
|
|
@@ -34861,11 +35445,29 @@ var testLintCommand = new Command("test:lint").description("Run Layer 0: Lint (t
|
|
|
34861
35445
|
|
|
34862
35446
|
// src/commands/test/commands/test-integration.ts
|
|
34863
35447
|
init_esm_shims();
|
|
35448
|
+
function resolveEffectiveRequireManifest3(options) {
|
|
35449
|
+
if (options.requireManifest && options.allowManifestFallback) {
|
|
35450
|
+
throw new CLIError(
|
|
35451
|
+
"--require-manifest and --allow-manifest-fallback are mutually exclusive",
|
|
35452
|
+
"TEST_INTEGRATION_MANIFEST_FLAGS_EXCLUSIVE",
|
|
35453
|
+
["Use strict mode (default) OR explicitly allow fallback, but not both"]
|
|
35454
|
+
);
|
|
35455
|
+
}
|
|
35456
|
+
if (options.allowManifestFallback) return false;
|
|
35457
|
+
return options.requireManifest;
|
|
35458
|
+
}
|
|
34864
35459
|
var testIntegrationCommand = new Command("test:integration").description("Run Layer 4: Integration tests (E2E) with auto-generation").option("--generate", "Generate tests from XState before running").option("--advanced", "Generate advanced tests (context-aware, guards, invariants, etc.)").option("--auto", "Zero-config auto-generation (implementation-driven)").option("--ci", "CI mode (fail fast, no interactive)").option("--record", "Record test results to database", true).option("--base-url <url>", "Explicit base URL for E2E/Security (disables auto dev server start)").option(
|
|
35460
|
+
"--require-manifest",
|
|
35461
|
+
"Require manifest to be present and valid (strict behavior; enabled by default for Layer 4)"
|
|
35462
|
+
).option(
|
|
35463
|
+
"--allow-manifest-fallback",
|
|
35464
|
+
"Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
|
|
35465
|
+
).option(
|
|
34865
35466
|
"--report-json <path>",
|
|
34866
35467
|
"Export test report as JSON. If <path> is a bare filename, it will be written under .runa/tmp/."
|
|
34867
35468
|
).option("--verbose", "Verbose output (full error details, environment info)").action(async (options) => {
|
|
34868
35469
|
try {
|
|
35470
|
+
const effectiveRequireManifest = resolveEffectiveRequireManifest3(options);
|
|
34869
35471
|
const output3 = await runTestIntegration({
|
|
34870
35472
|
ci: options.ci ?? false,
|
|
34871
35473
|
record: options.record,
|
|
@@ -34875,6 +35477,7 @@ var testIntegrationCommand = new Command("test:integration").description("Run La
|
|
|
34875
35477
|
advanced: options.advanced,
|
|
34876
35478
|
auto: options.auto,
|
|
34877
35479
|
baseUrl: options.baseUrl,
|
|
35480
|
+
requireManifest: effectiveRequireManifest,
|
|
34878
35481
|
invokedAs: "runa test:integration"
|
|
34879
35482
|
});
|
|
34880
35483
|
emitJsonSuccess(testIntegrationCommand, TestIntegrationOutputSchema, output3);
|
|
@@ -34920,7 +35523,7 @@ function injectTestAttrsIfLayer4(layer, options) {
|
|
|
34920
35523
|
"Run `runa inject-test-attrs` manually to see detailed errors",
|
|
34921
35524
|
"Ensure XState machines exist in your project",
|
|
34922
35525
|
"Check that machines have valid meta.e2e definitions",
|
|
34923
|
-
"Or
|
|
35526
|
+
"Or pass --allow-manifest-fallback to continue with fallback behavior"
|
|
34924
35527
|
],
|
|
34925
35528
|
error instanceof Error ? error : void 0
|
|
34926
35529
|
);
|
|
@@ -34930,10 +35533,17 @@ function injectTestAttrsIfLayer4(layer, options) {
|
|
|
34930
35533
|
}
|
|
34931
35534
|
}
|
|
34932
35535
|
}
|
|
35536
|
+
function resolveEffectiveRequireManifest4(layer, options) {
|
|
35537
|
+
if (options.allowManifestFallback) return false;
|
|
35538
|
+
if (options.requireManifest !== void 0) return options.requireManifest;
|
|
35539
|
+
if (layer === 4 && process.env.RUNA_LAYER4_ALLOW_MANIFEST_FALLBACK !== "true") return true;
|
|
35540
|
+
return void 0;
|
|
35541
|
+
}
|
|
34933
35542
|
async function runSingleLayer(params) {
|
|
35543
|
+
const effectiveRequireManifest = resolveEffectiveRequireManifest4(params.layer, params.options);
|
|
34934
35544
|
injectTestAttrsIfLayer4(params.layer, {
|
|
34935
35545
|
verbose: params.options.verbose,
|
|
34936
|
-
requireManifest:
|
|
35546
|
+
requireManifest: effectiveRequireManifest
|
|
34937
35547
|
});
|
|
34938
35548
|
try {
|
|
34939
35549
|
const output3 = await runTest({
|
|
@@ -34950,7 +35560,7 @@ async function runSingleLayer(params) {
|
|
|
34950
35560
|
reviewSnapshots: params.options.reviewSnapshots,
|
|
34951
35561
|
forceRegenerate: params.options.force,
|
|
34952
35562
|
skipGeneration: params.options.skipGeneration,
|
|
34953
|
-
requireManifest:
|
|
35563
|
+
requireManifest: effectiveRequireManifest,
|
|
34954
35564
|
invokedAs: `runa test:layer${params.layer}`
|
|
34955
35565
|
});
|
|
34956
35566
|
emitJsonSuccess(params.cmd, TestRunOutputSchema, output3);
|
|
@@ -34984,6 +35594,13 @@ function validateGenerationFlags(layer, opts) {
|
|
|
34984
35594
|
["Use --auto (implementation-driven) OR --generate/--advanced (XState-driven)"]
|
|
34985
35595
|
);
|
|
34986
35596
|
}
|
|
35597
|
+
if (layer === 4 && opts.requireManifest && opts.allowManifestFallback) {
|
|
35598
|
+
throw new CLIError(
|
|
35599
|
+
"--require-manifest and --allow-manifest-fallback are mutually exclusive",
|
|
35600
|
+
"TEST_LAYER_MANIFEST_FLAGS_EXCLUSIVE",
|
|
35601
|
+
["Use strict mode (default) OR explicitly allow fallback, but not both"]
|
|
35602
|
+
);
|
|
35603
|
+
}
|
|
34987
35604
|
}
|
|
34988
35605
|
function validateSnapshotFlags(opts) {
|
|
34989
35606
|
if (opts.reviewSnapshots && opts.ci) {
|
|
@@ -35022,6 +35639,9 @@ function createLayerCommand(layer) {
|
|
|
35022
35639
|
cmd.option("--generate", "Generate tests from XState before running (Layer 4)").option("--advanced", "Generate advanced tests (requires --generate)").option("--auto", "Zero-config auto-generation (implementation-driven)").option("--update-snapshots", "Update visual baselines (Layer 4)").option("--filter <pattern>", 'Filter tests by pattern (e.g., "checkout-*")').option("--review-snapshots", "Interactive review of changed visual snapshots (Layer 4)").option("--force", "Force regenerate all tests, bypassing cache").option(
|
|
35023
35640
|
"--require-manifest",
|
|
35024
35641
|
"Require manifest to be present and valid (fail if missing or stale)"
|
|
35642
|
+
).option(
|
|
35643
|
+
"--allow-manifest-fallback",
|
|
35644
|
+
"Allow fallback behavior when manifest is missing/invalid (disables Layer 4 strict default)"
|
|
35025
35645
|
);
|
|
35026
35646
|
}
|
|
35027
35647
|
return cmd;
|
|
@@ -36870,8 +37490,8 @@ var logger13 = createCLILogger("watch");
|
|
|
36870
37490
|
function addFallbackSchemaPatterns(patterns) {
|
|
36871
37491
|
const detected = detectDatabasePackage(process.cwd());
|
|
36872
37492
|
if (detected) {
|
|
36873
|
-
patterns.push(
|
|
36874
|
-
patterns.push(
|
|
37493
|
+
patterns.push(path11__default.join(detected, "src/schema/**/*.ts"));
|
|
37494
|
+
patterns.push(path11__default.join(detected, "sql/**/*.sql"));
|
|
36875
37495
|
return;
|
|
36876
37496
|
}
|
|
36877
37497
|
for (const candidate of DATABASE_PACKAGE_CANDIDATES) {
|
|
@@ -36885,8 +37505,8 @@ async function buildSchemaPatterns() {
|
|
|
36885
37505
|
const patterns = ["supabase/schemas/**/*.sql"];
|
|
36886
37506
|
try {
|
|
36887
37507
|
const dbPackagePath = await getDatabasePackagePath();
|
|
36888
|
-
patterns.push(
|
|
36889
|
-
patterns.push(
|
|
37508
|
+
patterns.push(path11__default.join(dbPackagePath, "src/schema/**/*.ts"));
|
|
37509
|
+
patterns.push(path11__default.join(dbPackagePath, "sql/**/*.sql"));
|
|
36890
37510
|
} catch {
|
|
36891
37511
|
addFallbackSchemaPatterns(patterns);
|
|
36892
37512
|
}
|