@runa-ai/runa-cli 0.5.41 → 0.5.43
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/machine/actors/db/collect-schema-stats.d.ts +7 -5
- package/dist/commands/ci/machine/actors/db/collect-schema-stats.d.ts.map +1 -1
- package/dist/commands/ci/machine/actors/db/index.d.ts +1 -1
- package/dist/commands/ci/machine/actors/db/index.d.ts.map +1 -1
- package/dist/commands/ci/machine/actors/db/schema-stats.d.ts +63 -23
- package/dist/commands/ci/machine/actors/db/schema-stats.d.ts.map +1 -1
- package/dist/commands/ci/machine/commands/machine-runner.d.ts.map +1 -1
- package/dist/commands/ci/machine/contract.d.ts +5 -0
- package/dist/commands/ci/machine/contract.d.ts.map +1 -1
- package/dist/commands/ci/machine/formatters/sections/final-comment.d.ts.map +1 -1
- package/dist/commands/ci/machine/formatters/sections/schema-matrix.d.ts +1 -0
- package/dist/commands/ci/machine/formatters/sections/schema-matrix.d.ts.map +1 -1
- package/dist/commands/ci/machine/guards.d.ts.map +1 -1
- package/dist/commands/ci/machine/helpers.d.ts +2 -1
- package/dist/commands/ci/machine/helpers.d.ts.map +1 -1
- package/dist/commands/ci/machine/machine.d.ts +1 -1
- package/dist/commands/ci/machine/machine.d.ts.map +1 -1
- package/dist/commands/ci/utils/test-parallel.d.ts +4 -0
- package/dist/commands/ci/utils/test-parallel.d.ts.map +1 -1
- package/dist/commands/db/commands/db-sync.d.ts.map +1 -1
- package/dist/commands/db/utils/import-impact-analyzer.d.ts +40 -0
- package/dist/commands/db/utils/import-impact-analyzer.d.ts.map +1 -0
- package/dist/constants/versions.d.ts +1 -1
- package/dist/index.js +524 -265
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,11 +4,11 @@ import * as path10 from 'path';
|
|
|
4
4
|
import path10__default, { join, dirname, resolve, relative, basename, sep, isAbsolute, normalize } from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { execSync, spawnSync, execFileSync, exec, spawn } from 'child_process';
|
|
7
|
-
import * as
|
|
8
|
-
import
|
|
7
|
+
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';
|
|
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, DATABASE_PACKAGE_CANDIDATES, getStatusIcon as getStatusIcon$1, findWorkspaceRoot as findWorkspaceRoot$1, checkExtensionConfig, UpgradeTransaction, readRunaVersion, syncTemplates, SyncOutputSchema, ErrorEnvelopeSchema, preCheckSync, findConflictFiles, TestUnitGenOutputSchema, TestE2EGenerateOutputSchema, TestSecurityGenOutputSchema, TestApiGenOutputSchema, TestComponentGenOutputSchema } from '@runa-ai/runa';
|
|
10
10
|
import { z } from 'zod';
|
|
11
|
-
import
|
|
11
|
+
import fs9, { mkdir, writeFile, appendFile, readFile, rm, stat, realpath, cp, readdir, lstat } from 'fs/promises';
|
|
12
12
|
import { promisify } from 'util';
|
|
13
13
|
import { glob } from 'glob';
|
|
14
14
|
import { Project, Node, SyntaxKind } from 'ts-morph';
|
|
@@ -925,7 +925,7 @@ var CLI_VERSION, HAS_ADMIN_COMMAND;
|
|
|
925
925
|
var init_version = __esm({
|
|
926
926
|
"src/version.ts"() {
|
|
927
927
|
init_esm_shims();
|
|
928
|
-
CLI_VERSION = "0.5.
|
|
928
|
+
CLI_VERSION = "0.5.43";
|
|
929
929
|
HAS_ADMIN_COMMAND = false;
|
|
930
930
|
}
|
|
931
931
|
});
|
|
@@ -1323,7 +1323,7 @@ var init_dependency_analyzer = __esm({
|
|
|
1323
1323
|
async analyze(options) {
|
|
1324
1324
|
const packageJsonPath = path10__default.join(options.rootDir, "package.json");
|
|
1325
1325
|
try {
|
|
1326
|
-
await
|
|
1326
|
+
await fs9.access(packageJsonPath);
|
|
1327
1327
|
} catch {
|
|
1328
1328
|
return [];
|
|
1329
1329
|
}
|
|
@@ -1356,7 +1356,7 @@ var init_dependency_analyzer = __esm({
|
|
|
1356
1356
|
}
|
|
1357
1357
|
async checkTyposquatting(packageJsonPath) {
|
|
1358
1358
|
try {
|
|
1359
|
-
const content = await
|
|
1359
|
+
const content = await fs9.readFile(packageJsonPath, "utf-8");
|
|
1360
1360
|
const packageJson = JSON.parse(content);
|
|
1361
1361
|
const allDeps = {
|
|
1362
1362
|
...packageJson.dependencies || {},
|
|
@@ -1534,7 +1534,7 @@ function createPolicyFromMatch(match, content, filePath) {
|
|
|
1534
1534
|
};
|
|
1535
1535
|
}
|
|
1536
1536
|
async function parseSqlFileForPolicies(filePath) {
|
|
1537
|
-
const content = await
|
|
1537
|
+
const content = await fs9.readFile(filePath, "utf-8");
|
|
1538
1538
|
const matches = findPolicyMatches(content);
|
|
1539
1539
|
return matches.map((match) => createPolicyFromMatch(match, content, filePath));
|
|
1540
1540
|
}
|
|
@@ -2019,11 +2019,11 @@ function scanLineForSecrets(line, lineNumber, filePath) {
|
|
|
2019
2019
|
return findings;
|
|
2020
2020
|
}
|
|
2021
2021
|
async function scanFileForSecrets(filePath) {
|
|
2022
|
-
const stats = await
|
|
2023
|
-
if (stats.size >
|
|
2022
|
+
const stats = await fs9.stat(filePath);
|
|
2023
|
+
if (stats.size > MAX_FILE_SIZE2) {
|
|
2024
2024
|
return [];
|
|
2025
2025
|
}
|
|
2026
|
-
const content = await
|
|
2026
|
+
const content = await fs9.readFile(filePath, "utf-8");
|
|
2027
2027
|
const lines = content.split("\n");
|
|
2028
2028
|
const findings = [];
|
|
2029
2029
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -2098,13 +2098,13 @@ function isMultiLineFalsePositive(blockContent, lines, startLine) {
|
|
|
2098
2098
|
}
|
|
2099
2099
|
return false;
|
|
2100
2100
|
}
|
|
2101
|
-
var MAX_LINE_LENGTH,
|
|
2101
|
+
var MAX_LINE_LENGTH, MAX_FILE_SIZE2, SECRET_PATTERNS, BASE64_SECRET_INDICATORS, EXCLUDED_PATTERNS, MULTILINE_PATTERNS, SecretAnalyzer;
|
|
2102
2102
|
var init_secret_analyzer = __esm({
|
|
2103
2103
|
"src/internal/vuln-checker/analyzers/secret-analyzer.ts"() {
|
|
2104
2104
|
init_esm_shims();
|
|
2105
2105
|
init_constants2();
|
|
2106
2106
|
MAX_LINE_LENGTH = 2e3;
|
|
2107
|
-
|
|
2107
|
+
MAX_FILE_SIZE2 = 1024 * 1024;
|
|
2108
2108
|
SECRET_PATTERNS = [
|
|
2109
2109
|
// AWS
|
|
2110
2110
|
{
|
|
@@ -3053,8 +3053,8 @@ function isPathWithinBoundary(filePath, boundaryDir) {
|
|
|
3053
3053
|
try {
|
|
3054
3054
|
const resolvedFile = path10__default.resolve(filePath);
|
|
3055
3055
|
const resolvedBoundary = path10__default.resolve(boundaryDir);
|
|
3056
|
-
const
|
|
3057
|
-
return !
|
|
3056
|
+
const relative9 = path10__default.relative(resolvedBoundary, resolvedFile);
|
|
3057
|
+
return !relative9.startsWith("..") && !path10__default.isAbsolute(relative9);
|
|
3058
3058
|
} catch {
|
|
3059
3059
|
return false;
|
|
3060
3060
|
}
|
|
@@ -3088,7 +3088,7 @@ var init_path_validation = __esm({
|
|
|
3088
3088
|
async function loadConfig(configPath, rootDir) {
|
|
3089
3089
|
const fullPath = resolvePathWithinBoundary(configPath, rootDir);
|
|
3090
3090
|
try {
|
|
3091
|
-
const content = await
|
|
3091
|
+
const content = await fs9.readFile(fullPath, "utf-8");
|
|
3092
3092
|
if (fullPath.endsWith(".yml") || fullPath.endsWith(".yaml")) {
|
|
3093
3093
|
return yaml.load(content, { schema: yaml.JSON_SCHEMA });
|
|
3094
3094
|
}
|
|
@@ -3103,7 +3103,7 @@ async function loadConfig(configPath, rootDir) {
|
|
|
3103
3103
|
async function loadIgnores(ignorePath, rootDir) {
|
|
3104
3104
|
const fullPath = resolvePathWithinBoundary(ignorePath, rootDir);
|
|
3105
3105
|
try {
|
|
3106
|
-
const content = await
|
|
3106
|
+
const content = await fs9.readFile(fullPath, "utf-8");
|
|
3107
3107
|
let parsed;
|
|
3108
3108
|
if (fullPath.endsWith(".yml") || fullPath.endsWith(".yaml")) {
|
|
3109
3109
|
parsed = yaml.load(content, { schema: yaml.JSON_SCHEMA });
|
|
@@ -3178,7 +3178,7 @@ function createAnnotationPatterns() {
|
|
|
3178
3178
|
async function parseInlineAnnotations(filePath) {
|
|
3179
3179
|
const annotations = [];
|
|
3180
3180
|
try {
|
|
3181
|
-
const content = await
|
|
3181
|
+
const content = await fs9.readFile(filePath, "utf-8");
|
|
3182
3182
|
const lines = content.split("\n");
|
|
3183
3183
|
for (let i = 0; i < lines.length; i++) {
|
|
3184
3184
|
const line = lines[i];
|
|
@@ -7220,17 +7220,17 @@ function printSummary(logger16, output3) {
|
|
|
7220
7220
|
}
|
|
7221
7221
|
}
|
|
7222
7222
|
function findRepoRoot(startDir) {
|
|
7223
|
-
const { existsSync:
|
|
7224
|
-
const { join:
|
|
7223
|
+
const { existsSync: existsSync51, readFileSync: readFileSync29 } = __require("fs");
|
|
7224
|
+
const { join: join23, dirname: dirname5 } = __require("path");
|
|
7225
7225
|
let current = startDir;
|
|
7226
7226
|
while (current !== dirname5(current)) {
|
|
7227
|
-
if (
|
|
7227
|
+
if (existsSync51(join23(current, "turbo.json"))) {
|
|
7228
7228
|
return current;
|
|
7229
7229
|
}
|
|
7230
|
-
const pkgPath =
|
|
7231
|
-
if (
|
|
7230
|
+
const pkgPath = join23(current, "package.json");
|
|
7231
|
+
if (existsSync51(pkgPath)) {
|
|
7232
7232
|
try {
|
|
7233
|
-
const pkg = JSON.parse(
|
|
7233
|
+
const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
|
|
7234
7234
|
if (pkg.workspaces) {
|
|
7235
7235
|
return current;
|
|
7236
7236
|
}
|
|
@@ -7527,8 +7527,8 @@ function readPortFromScripts(appDir) {
|
|
|
7527
7527
|
const pkgPath = path10__default.join(appDir, "package.json");
|
|
7528
7528
|
if (!existsSync(pkgPath)) return 3e3;
|
|
7529
7529
|
try {
|
|
7530
|
-
const { readFileSync:
|
|
7531
|
-
const raw =
|
|
7530
|
+
const { readFileSync: readFileSync29 } = __require("fs");
|
|
7531
|
+
const raw = readFileSync29(pkgPath, "utf-8");
|
|
7532
7532
|
const parsed = JSON.parse(raw);
|
|
7533
7533
|
const scripts = parsed.scripts;
|
|
7534
7534
|
for (const key of ["start:ci", "start", "dev"]) {
|
|
@@ -7546,8 +7546,8 @@ function findWebAppUnderApps(repoRoot) {
|
|
|
7546
7546
|
const appsDir = path10__default.join(repoRoot, "apps");
|
|
7547
7547
|
if (!existsSync(appsDir)) return null;
|
|
7548
7548
|
try {
|
|
7549
|
-
const { readdirSync:
|
|
7550
|
-
const entries =
|
|
7549
|
+
const { readdirSync: readdirSync12 } = __require("fs");
|
|
7550
|
+
const entries = readdirSync12(appsDir, { withFileTypes: true });
|
|
7551
7551
|
const priority = ["web", "dashboard", "app", "frontend", "client"];
|
|
7552
7552
|
for (const name of priority) {
|
|
7553
7553
|
const candidate = path10__default.join(appsDir, name);
|
|
@@ -9559,8 +9559,8 @@ async function detectRisks(repoRoot, tmpDir) {
|
|
|
9559
9559
|
} catch (error) {
|
|
9560
9560
|
let logContent = "";
|
|
9561
9561
|
try {
|
|
9562
|
-
const { readFileSync:
|
|
9563
|
-
logContent =
|
|
9562
|
+
const { readFileSync: readFileSync29 } = await import('fs');
|
|
9563
|
+
logContent = readFileSync29(logFile, "utf-8");
|
|
9564
9564
|
} catch {
|
|
9565
9565
|
}
|
|
9566
9566
|
const isInitialDeployment = logContent.includes("No common ancestor") || logContent.includes("INITIAL DEPLOYMENT");
|
|
@@ -9688,8 +9688,8 @@ async function applyProductionSchema(repoRoot, tmpDir, productionDbUrlAdmin, pro
|
|
|
9688
9688
|
const totalMs = Date.now() - startTime;
|
|
9689
9689
|
let logContent = "";
|
|
9690
9690
|
try {
|
|
9691
|
-
const { readFileSync:
|
|
9692
|
-
logContent =
|
|
9691
|
+
const { readFileSync: readFileSync29 } = await import('fs');
|
|
9692
|
+
logContent = readFileSync29(logPath, "utf-8");
|
|
9693
9693
|
} catch {
|
|
9694
9694
|
}
|
|
9695
9695
|
const parsed = parseApplyLog(logContent);
|
|
@@ -11398,98 +11398,32 @@ init_esm_shims();
|
|
|
11398
11398
|
|
|
11399
11399
|
// src/commands/ci/machine/actors/db/schema-stats.ts
|
|
11400
11400
|
init_esm_shims();
|
|
11401
|
-
var
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11412
|
-
|
|
11413
|
-
|
|
11414
|
-
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
|
|
11418
|
-
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
11422
|
-
|
|
11423
|
-
|
|
11424
|
-
|
|
11425
|
-
|
|
11426
|
-
|
|
11427
|
-
schemas[schemaName] = { tables: 0, functions: 0, policies: 0, indexes: 0, triggers: 0 };
|
|
11428
|
-
}
|
|
11429
|
-
}
|
|
11430
|
-
function parseLocalSqlFile(content, schemas, total) {
|
|
11431
|
-
const cleanContent = content.replace(/--.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
11432
|
-
const tableRegex = new RegExp(
|
|
11433
|
-
`CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?${SCHEMA_TABLE_PATTERN}`,
|
|
11434
|
-
"gi"
|
|
11435
|
-
);
|
|
11436
|
-
for (const match of cleanContent.matchAll(tableRegex)) {
|
|
11437
|
-
const schemaName = extractIdentifier(match[1], match[2]);
|
|
11438
|
-
ensureSchema(schemas, schemaName, EXCLUDED_SCHEMAS_FOR_LOCAL);
|
|
11439
|
-
if (schemas[schemaName]) {
|
|
11440
|
-
schemas[schemaName].tables++;
|
|
11441
|
-
total.tables++;
|
|
11442
|
-
}
|
|
11443
|
-
}
|
|
11444
|
-
const functionRegex = new RegExp(
|
|
11445
|
-
`CREATE\\s+(?:OR\\s+REPLACE\\s+)?FUNCTION\\s+${SCHEMA_TABLE_PATTERN}`,
|
|
11446
|
-
"gi"
|
|
11447
|
-
);
|
|
11448
|
-
for (const match of cleanContent.matchAll(functionRegex)) {
|
|
11449
|
-
const schemaName = extractIdentifier(match[1], match[2]);
|
|
11450
|
-
ensureSchema(schemas, schemaName, EXCLUDED_SCHEMAS_FOR_LOCAL);
|
|
11451
|
-
if (schemas[schemaName]) {
|
|
11452
|
-
schemas[schemaName].functions++;
|
|
11453
|
-
total.functions++;
|
|
11454
|
-
}
|
|
11455
|
-
}
|
|
11456
|
-
const policyRegex = new RegExp(
|
|
11457
|
-
`CREATE\\s+POLICY\\s+(?:"[^"]+"|'[^']+'|\\S+)\\s+ON\\s+${SCHEMA_TABLE_PATTERN}`,
|
|
11458
|
-
"gi"
|
|
11459
|
-
);
|
|
11460
|
-
for (const match of cleanContent.matchAll(policyRegex)) {
|
|
11461
|
-
const schemaName = extractIdentifier(match[1], match[2]);
|
|
11462
|
-
ensureSchema(schemas, schemaName, EXCLUDED_SCHEMAS_FOR_LOCAL);
|
|
11463
|
-
if (schemas[schemaName]) {
|
|
11464
|
-
schemas[schemaName].policies++;
|
|
11465
|
-
total.policies++;
|
|
11466
|
-
}
|
|
11467
|
-
}
|
|
11468
|
-
const indexRegex = new RegExp(
|
|
11469
|
-
`CREATE\\s+(?:UNIQUE\\s+)?INDEX\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:CONCURRENTLY\\s+)?${IDENT_PATTERN}\\s+ON\\s+${SCHEMA_TABLE_PATTERN}`,
|
|
11470
|
-
"gi"
|
|
11471
|
-
);
|
|
11472
|
-
for (const match of cleanContent.matchAll(indexRegex)) {
|
|
11473
|
-
const schemaName = extractIdentifier(match[3], match[4]);
|
|
11474
|
-
ensureSchema(schemas, schemaName, EXCLUDED_SCHEMAS_FOR_LOCAL);
|
|
11475
|
-
if (schemas[schemaName]) {
|
|
11476
|
-
schemas[schemaName].indexes++;
|
|
11477
|
-
total.indexes++;
|
|
11478
|
-
}
|
|
11479
|
-
}
|
|
11480
|
-
const triggerRegex = new RegExp(
|
|
11481
|
-
`CREATE\\s+TRIGGER\\s+${IDENT_PATTERN}[\\s\\S]*?ON\\s+${SCHEMA_TABLE_PATTERN}`,
|
|
11482
|
-
"gi"
|
|
11483
|
-
);
|
|
11484
|
-
for (const match of cleanContent.matchAll(triggerRegex)) {
|
|
11485
|
-
const schemaName = extractIdentifier(match[3], match[4]);
|
|
11486
|
-
ensureSchema(schemas, schemaName, EXCLUDED_SCHEMAS_FOR_LOCAL);
|
|
11487
|
-
if (schemas[schemaName]) {
|
|
11488
|
-
schemas[schemaName].triggers++;
|
|
11489
|
-
total.triggers++;
|
|
11490
|
-
}
|
|
11491
|
-
}
|
|
11492
|
-
}
|
|
11401
|
+
var EXCLUDED_SCHEMAS2 = [
|
|
11402
|
+
// PostgreSQL system schemas
|
|
11403
|
+
"pg_catalog",
|
|
11404
|
+
"pg_toast",
|
|
11405
|
+
"information_schema",
|
|
11406
|
+
// Supabase managed schemas (vary by Supabase version)
|
|
11407
|
+
"auth",
|
|
11408
|
+
"storage",
|
|
11409
|
+
"realtime",
|
|
11410
|
+
"_realtime",
|
|
11411
|
+
// Supabase realtime internal schema
|
|
11412
|
+
"supabase_functions",
|
|
11413
|
+
"supabase_migrations",
|
|
11414
|
+
"vault",
|
|
11415
|
+
"pgsodium",
|
|
11416
|
+
"pgsodium_masks",
|
|
11417
|
+
"graphql",
|
|
11418
|
+
"graphql_public",
|
|
11419
|
+
"extensions",
|
|
11420
|
+
// PostgREST
|
|
11421
|
+
"net",
|
|
11422
|
+
// Cron
|
|
11423
|
+
"cron",
|
|
11424
|
+
// pgTAP test schema (test-only, should not exist in production)
|
|
11425
|
+
"tests"
|
|
11426
|
+
];
|
|
11493
11427
|
function processQueryResult(result, schemas, total, field) {
|
|
11494
11428
|
for (const row of result) {
|
|
11495
11429
|
const schemaName = row.schemaname;
|
|
@@ -11564,16 +11498,53 @@ async function executeSchemaQueries(sql, schemaList, schemas, total) {
|
|
|
11564
11498
|
`;
|
|
11565
11499
|
processQueryResult(triggersResult, schemas, total, "triggers");
|
|
11566
11500
|
}
|
|
11567
|
-
async function
|
|
11501
|
+
async function getDetailedIndexList(sql, schemaList) {
|
|
11502
|
+
const result = await sql`
|
|
11503
|
+
SELECT
|
|
11504
|
+
n.nspname as schema,
|
|
11505
|
+
i.relname as name,
|
|
11506
|
+
t.relname as table,
|
|
11507
|
+
idx.indisunique as is_unique,
|
|
11508
|
+
idx.indpred IS NOT NULL as is_partial,
|
|
11509
|
+
CASE
|
|
11510
|
+
WHEN idx.indpred IS NOT NULL
|
|
11511
|
+
THEN pg_get_expr(idx.indpred, idx.indrelid, true)
|
|
11512
|
+
ELSE NULL
|
|
11513
|
+
END as where_clause
|
|
11514
|
+
FROM pg_index idx
|
|
11515
|
+
JOIN pg_class i ON i.oid = idx.indexrelid
|
|
11516
|
+
JOIN pg_class t ON t.oid = idx.indrelid
|
|
11517
|
+
JOIN pg_namespace n ON n.oid = i.relnamespace
|
|
11518
|
+
WHERE n.nspname IN (${sql.unsafe(schemaList)})
|
|
11519
|
+
AND NOT EXISTS (
|
|
11520
|
+
SELECT 1 FROM pg_constraint c
|
|
11521
|
+
WHERE c.conindid = idx.indexrelid
|
|
11522
|
+
)
|
|
11523
|
+
ORDER BY n.nspname, t.relname, i.relname
|
|
11524
|
+
`;
|
|
11525
|
+
return result.map((row) => ({
|
|
11526
|
+
schema: row.schema,
|
|
11527
|
+
name: row.name,
|
|
11528
|
+
table: row.table,
|
|
11529
|
+
isUnique: row.is_unique,
|
|
11530
|
+
isPartial: row.is_partial,
|
|
11531
|
+
whereClause: row.where_clause || void 0
|
|
11532
|
+
}));
|
|
11533
|
+
}
|
|
11534
|
+
async function getUserSchemas(sql) {
|
|
11535
|
+
const excludeList = EXCLUDED_SCHEMAS2.map((s) => `'${s}'`).join(", ");
|
|
11536
|
+
const result = await sql`
|
|
11537
|
+
SELECT nspname
|
|
11538
|
+
FROM pg_namespace
|
|
11539
|
+
WHERE nspname NOT IN (${sql.unsafe(excludeList)})
|
|
11540
|
+
AND nspname NOT LIKE 'pg_%'
|
|
11541
|
+
ORDER BY nspname
|
|
11542
|
+
`;
|
|
11543
|
+
return result.map((row) => row.nspname);
|
|
11544
|
+
}
|
|
11545
|
+
async function getDbSchemaStats(databaseUrl) {
|
|
11568
11546
|
const schemas = {};
|
|
11569
11547
|
const total = { tables: 0, functions: 0, policies: 0, indexes: 0, triggers: 0 };
|
|
11570
|
-
if (targetSchemas.length === 0) {
|
|
11571
|
-
return { schemas, total };
|
|
11572
|
-
}
|
|
11573
|
-
for (const schemaName of targetSchemas) {
|
|
11574
|
-
schemas[schemaName] = { tables: 0, functions: 0, policies: 0, indexes: 0, triggers: 0 };
|
|
11575
|
-
}
|
|
11576
|
-
const schemaList = targetSchemas.map((s) => `'${s}'`).join(", ");
|
|
11577
11548
|
let sql = null;
|
|
11578
11549
|
const isRemoteSupabase = databaseUrl.includes(".supabase.co");
|
|
11579
11550
|
try {
|
|
@@ -11584,7 +11555,17 @@ async function getDbSchemaStats(databaseUrl, targetSchemas) {
|
|
|
11584
11555
|
// Supabase production requires SSL; local Docker does not
|
|
11585
11556
|
...isRemoteSupabase && { ssl: "require" }
|
|
11586
11557
|
});
|
|
11558
|
+
const userSchemas = await getUserSchemas(sql);
|
|
11559
|
+
if (userSchemas.length === 0) {
|
|
11560
|
+
return { schemas, total };
|
|
11561
|
+
}
|
|
11562
|
+
for (const schemaName of userSchemas) {
|
|
11563
|
+
schemas[schemaName] = { tables: 0, functions: 0, policies: 0, indexes: 0, triggers: 0 };
|
|
11564
|
+
}
|
|
11565
|
+
const schemaList = userSchemas.map((s) => `'${s}'`).join(", ");
|
|
11587
11566
|
await executeSchemaQueries(sql, schemaList, schemas, total);
|
|
11567
|
+
const indexList = await getDetailedIndexList(sql, schemaList);
|
|
11568
|
+
return { schemas, total, indexList };
|
|
11588
11569
|
} catch (error) {
|
|
11589
11570
|
console.warn(`[schema-stats] Could not query database: ${error}`);
|
|
11590
11571
|
} finally {
|
|
@@ -11637,39 +11618,73 @@ function hasDisplayedStatsDiff(a, b) {
|
|
|
11637
11618
|
function getActiveSchemas(stats) {
|
|
11638
11619
|
return Object.entries(stats.schemas).filter(([_, s]) => s.tables > 0 || s.functions > 0 || s.policies > 0).map(([name]) => name).sort();
|
|
11639
11620
|
}
|
|
11621
|
+
function compareIndexLists(reference, target) {
|
|
11622
|
+
const refIndexes = reference.indexList || [];
|
|
11623
|
+
const targetIndexes = target.indexList || [];
|
|
11624
|
+
const refKeys = new Set(refIndexes.map((i) => `${i.schema}.${i.name}`));
|
|
11625
|
+
const targetKeys = new Set(targetIndexes.map((i) => `${i.schema}.${i.name}`));
|
|
11626
|
+
const missing = refIndexes.filter((i) => !targetKeys.has(`${i.schema}.${i.name}`));
|
|
11627
|
+
const extra = targetIndexes.filter((i) => !refKeys.has(`${i.schema}.${i.name}`));
|
|
11628
|
+
return { missing, extra };
|
|
11629
|
+
}
|
|
11630
|
+
function formatIndexInfo(index) {
|
|
11631
|
+
const qualifiedName = `${index.schema}.${index.name}`;
|
|
11632
|
+
const tags = [];
|
|
11633
|
+
if (index.isUnique) tags.push("unique");
|
|
11634
|
+
if (index.isPartial) tags.push("partial");
|
|
11635
|
+
const tagStr = tags.length > 0 ? ` (${tags.join(", ")})` : "";
|
|
11636
|
+
return `${qualifiedName}${tagStr}`;
|
|
11637
|
+
}
|
|
11638
|
+
function hasIndexDiff(diff) {
|
|
11639
|
+
return diff.missing.length > 0 || diff.extra.length > 0;
|
|
11640
|
+
}
|
|
11640
11641
|
|
|
11641
11642
|
// src/commands/ci/machine/actors/db/collect-schema-stats.ts
|
|
11643
|
+
function emptyStats() {
|
|
11644
|
+
return {
|
|
11645
|
+
schemas: {},
|
|
11646
|
+
total: { tables: 0, functions: 0, policies: 0, indexes: 0, triggers: 0 }
|
|
11647
|
+
};
|
|
11648
|
+
}
|
|
11642
11649
|
var collectSchemaStatsActor = fromPromise(
|
|
11643
11650
|
async ({ input: input3 }) => {
|
|
11644
|
-
const {
|
|
11645
|
-
console.log("[schema-stats] Collecting schema statistics...");
|
|
11646
|
-
|
|
11647
|
-
|
|
11648
|
-
|
|
11649
|
-
|
|
11650
|
-
|
|
11651
|
-
|
|
11652
|
-
|
|
11651
|
+
const { localDbUrl, ciDbUrl, queryProduction } = input3;
|
|
11652
|
+
console.log("[schema-stats] Collecting schema statistics (DB query mode)...");
|
|
11653
|
+
let local = emptyStats();
|
|
11654
|
+
if (localDbUrl) {
|
|
11655
|
+
console.log("[schema-stats] Querying local database...");
|
|
11656
|
+
try {
|
|
11657
|
+
local = await getDbSchemaStats(localDbUrl);
|
|
11658
|
+
const schemas = Object.keys(local.schemas);
|
|
11659
|
+
console.log(
|
|
11660
|
+
`[schema-stats] Local: ${local.total.tables}T ${local.total.functions}F ${local.total.policies}P (schemas: ${schemas.join(", ")})`
|
|
11661
|
+
);
|
|
11662
|
+
} catch (error) {
|
|
11663
|
+
console.warn(`[schema-stats] Failed to query local database: ${error}`);
|
|
11664
|
+
}
|
|
11665
|
+
} else {
|
|
11666
|
+
console.log("[schema-stats] No local database URL, skipping local stats");
|
|
11667
|
+
}
|
|
11668
|
+
let ci = emptyStats();
|
|
11653
11669
|
if (ciDbUrl) {
|
|
11654
11670
|
console.log("[schema-stats] Querying CI database...");
|
|
11655
11671
|
try {
|
|
11656
|
-
ci = await getDbSchemaStats(ciDbUrl
|
|
11672
|
+
ci = await getDbSchemaStats(ciDbUrl);
|
|
11657
11673
|
console.log(
|
|
11658
11674
|
`[schema-stats] CI: ${ci.total.tables}T ${ci.total.functions}F ${ci.total.policies}P`
|
|
11659
11675
|
);
|
|
11660
11676
|
} catch (error) {
|
|
11661
11677
|
console.warn(`[schema-stats] Failed to query CI database: ${error}`);
|
|
11662
|
-
ci = local;
|
|
11663
11678
|
}
|
|
11664
11679
|
} else {
|
|
11665
|
-
console.log("[schema-stats] No CI database URL,
|
|
11680
|
+
console.log("[schema-stats] No CI database URL, skipping CI stats");
|
|
11666
11681
|
}
|
|
11667
11682
|
let production = null;
|
|
11668
11683
|
const productionUrl = process.env.GH_DATABASE_URL_ADMIN || process.env.GH_DATABASE_URL;
|
|
11669
11684
|
if (queryProduction && productionUrl) {
|
|
11670
11685
|
console.log("[schema-stats] Querying production database...");
|
|
11671
11686
|
try {
|
|
11672
|
-
production = await getDbSchemaStats(productionUrl
|
|
11687
|
+
production = await getDbSchemaStats(productionUrl);
|
|
11673
11688
|
console.log(
|
|
11674
11689
|
`[schema-stats] Production: ${production.total.tables}T ${production.total.functions}F ${production.total.policies}P`
|
|
11675
11690
|
);
|
|
@@ -11902,11 +11917,11 @@ function getIdempotentRoleNames(repoRoot) {
|
|
|
11902
11917
|
const idempotentDir = path10__default.join(repoRoot, "supabase", "schemas", "idempotent");
|
|
11903
11918
|
const roles = [];
|
|
11904
11919
|
try {
|
|
11905
|
-
const
|
|
11906
|
-
if (!
|
|
11907
|
-
const files =
|
|
11920
|
+
const fs14 = __require("fs");
|
|
11921
|
+
if (!fs14.existsSync(idempotentDir)) return [];
|
|
11922
|
+
const files = fs14.readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
|
|
11908
11923
|
for (const file of files) {
|
|
11909
|
-
const content =
|
|
11924
|
+
const content = fs14.readFileSync(path10__default.join(idempotentDir, file), "utf-8");
|
|
11910
11925
|
const roleMatches = content.matchAll(/CREATE\s+ROLE\s+(\w+)\s+WITH/gi);
|
|
11911
11926
|
for (const match of roleMatches) {
|
|
11912
11927
|
if (match[1]) roles.push(match[1].toLowerCase());
|
|
@@ -12016,8 +12031,8 @@ function isCommandSuccess(exitCode, fullOutput) {
|
|
|
12016
12031
|
}
|
|
12017
12032
|
async function writeLogFile(logFile, content) {
|
|
12018
12033
|
try {
|
|
12019
|
-
const
|
|
12020
|
-
await
|
|
12034
|
+
const fs14 = await import('fs/promises');
|
|
12035
|
+
await fs14.writeFile(logFile, content);
|
|
12021
12036
|
console.log(`[DEBUG] productionPreviewActor: wrote log to ${logFile}`);
|
|
12022
12037
|
} catch {
|
|
12023
12038
|
}
|
|
@@ -12308,11 +12323,11 @@ function getIdempotentRoleNames2(repoRoot) {
|
|
|
12308
12323
|
const idempotentDir = path10__default.join(repoRoot, "supabase", "schemas", "idempotent");
|
|
12309
12324
|
const roles = [];
|
|
12310
12325
|
try {
|
|
12311
|
-
const
|
|
12312
|
-
if (!
|
|
12313
|
-
const files =
|
|
12326
|
+
const fs14 = __require("fs");
|
|
12327
|
+
if (!fs14.existsSync(idempotentDir)) return [];
|
|
12328
|
+
const files = fs14.readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
|
|
12314
12329
|
for (const file of files) {
|
|
12315
|
-
const content =
|
|
12330
|
+
const content = fs14.readFileSync(path10__default.join(idempotentDir, file), "utf-8");
|
|
12316
12331
|
const roleMatches = content.matchAll(/CREATE\s+ROLE\s+(\w+)\s+WITH/gi);
|
|
12317
12332
|
for (const match of roleMatches) {
|
|
12318
12333
|
if (match[1]) roles.push(match[1].toLowerCase());
|
|
@@ -13448,16 +13463,22 @@ async function waitUntilAllFinished(params) {
|
|
|
13448
13463
|
` ${statusIcon} layer${finished.p.layer} finished (exit=${finished.code}, success=${actualResult.success}${mismatchNote}), remaining=${remaining.size}`
|
|
13449
13464
|
);
|
|
13450
13465
|
if (params.failFast && !actualResult.success && !actualResult.skipped) {
|
|
13466
|
+
const killedLayers = Array.from(remaining).map((p) => p.layer);
|
|
13451
13467
|
killAllSafe(Array.from(remaining));
|
|
13452
|
-
|
|
13453
|
-
|
|
13454
|
-
|
|
13468
|
+
clearTimeout(timeoutId);
|
|
13469
|
+
return {
|
|
13470
|
+
successMap,
|
|
13471
|
+
failFast: {
|
|
13472
|
+
failedLayer: finished.p.layer,
|
|
13473
|
+
killedLayers
|
|
13474
|
+
}
|
|
13475
|
+
};
|
|
13455
13476
|
}
|
|
13456
13477
|
}
|
|
13457
13478
|
} finally {
|
|
13458
13479
|
clearTimeout(timeoutId);
|
|
13459
13480
|
}
|
|
13460
|
-
return successMap;
|
|
13481
|
+
return { successMap };
|
|
13461
13482
|
}
|
|
13462
13483
|
async function runLayersInParallel(params) {
|
|
13463
13484
|
const spawned = [];
|
|
@@ -13493,29 +13514,34 @@ async function runLayersInParallel(params) {
|
|
|
13493
13514
|
kill: () => proc.kill("SIGTERM")
|
|
13494
13515
|
});
|
|
13495
13516
|
}
|
|
13496
|
-
const
|
|
13517
|
+
const waitResult = await waitUntilAllFinished({
|
|
13497
13518
|
spawned,
|
|
13498
13519
|
tmpDir: params.tmpDir,
|
|
13499
13520
|
failFast: params.failFast,
|
|
13500
13521
|
maxWaitSeconds: params.maxWaitSeconds,
|
|
13501
13522
|
progressIntervalSeconds: params.progressIntervalSeconds
|
|
13502
13523
|
});
|
|
13524
|
+
const killedLayerSet = new Set(waitResult.failFast?.killedLayers ?? []);
|
|
13525
|
+
const failFastSource = waitResult.failFast?.failedLayer;
|
|
13503
13526
|
const results = [];
|
|
13504
13527
|
for (const p of spawned) {
|
|
13505
13528
|
const codeRaw = p.exitCode ?? await p.procPromise;
|
|
13506
13529
|
const code = Number.isNaN(codeRaw) ? 1 : codeRaw;
|
|
13507
13530
|
const resultFile = path10__default.join(params.tmpDir, `vitest-layer${p.layer}-result.json`);
|
|
13508
|
-
const
|
|
13531
|
+
const wasKilled = killedLayerSet.has(p.layer);
|
|
13532
|
+
const actualResult = waitResult.successMap.get(p.layer) ?? {
|
|
13509
13533
|
success: code === 0,
|
|
13510
13534
|
exitCodeMismatch: false
|
|
13511
13535
|
};
|
|
13512
13536
|
results.push({
|
|
13513
13537
|
layer: p.layer,
|
|
13514
13538
|
exitCode: code,
|
|
13515
|
-
success: actualResult.success,
|
|
13539
|
+
success: wasKilled ? false : actualResult.success,
|
|
13516
13540
|
exitCodeMismatch: actualResult.exitCodeMismatch,
|
|
13517
13541
|
skipped: actualResult.skipped,
|
|
13518
13542
|
skippedReason: actualResult.skippedReason,
|
|
13543
|
+
killed: wasKilled,
|
|
13544
|
+
killedBy: wasKilled ? failFastSource : void 0,
|
|
13519
13545
|
logPath: path10__default.relative(params.repoRoot, p.logFile),
|
|
13520
13546
|
exitPath: path10__default.relative(params.repoRoot, p.exitFile),
|
|
13521
13547
|
resultPath: path10__default.relative(params.repoRoot, resultFile),
|
|
@@ -13755,7 +13781,7 @@ function formatSkippedLayers(layerSkipReasons, originalSelectedLayers) {
|
|
|
13755
13781
|
|
|
13756
13782
|
// src/commands/ci/machine/formatters/sections/schema-matrix.ts
|
|
13757
13783
|
init_esm_shims();
|
|
13758
|
-
function
|
|
13784
|
+
function emptyStats2() {
|
|
13759
13785
|
return { tables: 0, functions: 0, policies: 0, indexes: 0, triggers: 0 };
|
|
13760
13786
|
}
|
|
13761
13787
|
function formatLocalCell(stats) {
|
|
@@ -13802,8 +13828,8 @@ function getSortedActiveSchemas(schemaStats) {
|
|
|
13802
13828
|
function generateSchemaTableRows(schemaStats, sortedSchemas, hasProduction) {
|
|
13803
13829
|
const lines = [];
|
|
13804
13830
|
for (const schemaName of sortedSchemas) {
|
|
13805
|
-
const localStats = schemaStats.local.schemas[schemaName] ??
|
|
13806
|
-
const ciStats = schemaStats.ci.schemas[schemaName] ??
|
|
13831
|
+
const localStats = schemaStats.local.schemas[schemaName] ?? emptyStats2();
|
|
13832
|
+
const ciStats = schemaStats.ci.schemas[schemaName] ?? emptyStats2();
|
|
13807
13833
|
const prodStats = schemaStats.production?.schemas[schemaName] ?? null;
|
|
13808
13834
|
const localCell = formatLocalCell(localStats);
|
|
13809
13835
|
const ciCell = formatCiCellWithDiff(ciStats, localStats);
|
|
@@ -13827,6 +13853,28 @@ function generateSchemaMatrixSummary(localTotal, ciTotal, prodTotal) {
|
|
|
13827
13853
|
}
|
|
13828
13854
|
return parts.join(" ");
|
|
13829
13855
|
}
|
|
13856
|
+
function generateIndexDiffSection(schemaStats) {
|
|
13857
|
+
if (!schemaStats.production) return [];
|
|
13858
|
+
const diff = compareIndexLists(schemaStats.local, schemaStats.production);
|
|
13859
|
+
if (!hasIndexDiff(diff)) return [];
|
|
13860
|
+
const lines = [];
|
|
13861
|
+
if (diff.missing.length > 0) {
|
|
13862
|
+
lines.push("");
|
|
13863
|
+
lines.push("> \u26A0\uFE0F **\u672C\u756A\u306B\u4E0D\u8DB3\u3057\u3066\u3044\u308B\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9:**");
|
|
13864
|
+
for (const idx of diff.missing) {
|
|
13865
|
+
const whereInfo = idx.whereClause ? ` WHERE ${idx.whereClause}` : "";
|
|
13866
|
+
lines.push(`> - \`${formatIndexInfo(idx)}\` on \`${idx.table}\`${whereInfo}`);
|
|
13867
|
+
}
|
|
13868
|
+
}
|
|
13869
|
+
if (diff.extra.length > 0) {
|
|
13870
|
+
lines.push("");
|
|
13871
|
+
lines.push("> \u{1F4DD} **\u672C\u756A\u306B\u4F59\u5206\u306A\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9:**");
|
|
13872
|
+
for (const idx of diff.extra) {
|
|
13873
|
+
lines.push(`> - \`${formatIndexInfo(idx)}\` on \`${idx.table}\``);
|
|
13874
|
+
}
|
|
13875
|
+
}
|
|
13876
|
+
return lines;
|
|
13877
|
+
}
|
|
13830
13878
|
function formatSchemaMatrix(schemaStats, gitDiff) {
|
|
13831
13879
|
if (!schemaStats) {
|
|
13832
13880
|
return ["### \u30B9\u30AD\u30FC\u30DE\u72B6\u6CC1", "", "_\u30B9\u30AD\u30FC\u30DE\u7D71\u8A08\u60C5\u5831\u304C\u5229\u7528\u3067\u304D\u307E\u305B\u3093_", ""];
|
|
@@ -13846,6 +13894,7 @@ function formatSchemaMatrix(schemaStats, gitDiff) {
|
|
|
13846
13894
|
const prodTotalCell = production ? formatProdTotalCellWithDiff(production.total, local.total) : null;
|
|
13847
13895
|
const totalRow = hasProduction ? `| **Total** | ${localTotalCell} | ${ciTotalCell} | ${prodTotalCell ?? "n/a"} |` : `| **Total** | ${localTotalCell} | ${ciTotalCell} |`;
|
|
13848
13896
|
const summary = generateSchemaMatrixSummary(local.total, ci.total, production?.total ?? null);
|
|
13897
|
+
const indexDiffSection = generateIndexDiffSection(schemaStats);
|
|
13849
13898
|
return [
|
|
13850
13899
|
header,
|
|
13851
13900
|
"",
|
|
@@ -13854,6 +13903,7 @@ function formatSchemaMatrix(schemaStats, gitDiff) {
|
|
|
13854
13903
|
totalRow,
|
|
13855
13904
|
"",
|
|
13856
13905
|
summary,
|
|
13906
|
+
...indexDiffSection,
|
|
13857
13907
|
"",
|
|
13858
13908
|
"<sub>T=\u30C6\u30FC\u30D6\u30EB F=\u95A2\u6570 P=\u30DD\u30EA\u30B7\u30FC I=\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 Tr=\u30C8\u30EA\u30AC\u30FC</sub>",
|
|
13859
13909
|
""
|
|
@@ -13951,7 +14001,7 @@ function generatePreviewDetails(prodPreview) {
|
|
|
13951
14001
|
""
|
|
13952
14002
|
];
|
|
13953
14003
|
}
|
|
13954
|
-
function generateProductionPreviewSection(prodPreview, schemaDrift) {
|
|
14004
|
+
function generateProductionPreviewSection(prodPreview, schemaDrift, schemaStats) {
|
|
13955
14005
|
if (!prodPreview?.executed) {
|
|
13956
14006
|
if (schemaDrift?.gitDiff?.filesChanged?.length) {
|
|
13957
14007
|
return [
|
|
@@ -13978,18 +14028,37 @@ function generateProductionPreviewSection(prodPreview, schemaDrift) {
|
|
|
13978
14028
|
}
|
|
13979
14029
|
return lines;
|
|
13980
14030
|
}
|
|
14031
|
+
if (schemaStats?.local && schemaStats?.production) {
|
|
14032
|
+
const indexDiff = compareIndexLists(schemaStats.local, schemaStats.production);
|
|
14033
|
+
if (hasIndexDiff(indexDiff)) {
|
|
14034
|
+
const missingCount = indexDiff.missing.length;
|
|
14035
|
+
const extraCount = indexDiff.extra.length;
|
|
14036
|
+
const diffParts = [];
|
|
14037
|
+
if (missingCount > 0) diffParts.push(`${missingCount}\u4EF6\u4E0D\u8DB3`);
|
|
14038
|
+
if (extraCount > 0) diffParts.push(`${extraCount}\u4EF6\u4F59\u5206`);
|
|
14039
|
+
return [
|
|
14040
|
+
`> \u26A0\uFE0F **\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u5DEE\u5206\u691C\u51FA** (${diffParts.join(", ")})`,
|
|
14041
|
+
">",
|
|
14042
|
+
"> pg-schema-diff \u3067\u306F\u691C\u51FA\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F\u304C\u3001\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u306E\u5DEE\u5206\u304C\u3042\u308A\u307E\u3059\u3002",
|
|
14043
|
+
"> \u30B9\u30AD\u30FC\u30DE\u30DE\u30C8\u30EA\u30C3\u30AF\u30B9\u306E\u8A73\u7D30\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
14044
|
+
""
|
|
14045
|
+
];
|
|
14046
|
+
}
|
|
14047
|
+
}
|
|
13981
14048
|
return ["**\u672C\u756A\u30D7\u30EC\u30D3\u30E5\u30FC**: \u2705 \u672C\u756A\u306B\u9069\u7528\u3059\u308B\u30B9\u30AD\u30FC\u30DE\u5909\u66F4\u306F\u3042\u308A\u307E\u305B\u3093", ""];
|
|
13982
14049
|
}
|
|
13983
|
-
function generateDeploySection(exitCode, layerResults, gitBranchName, productionPreview, schemaDrift, env2) {
|
|
14050
|
+
function generateDeploySection(exitCode, layerResults, gitBranchName, productionPreview, schemaDrift, schemaStats, env2) {
|
|
13984
14051
|
if (!checkIfDeployable(exitCode, layerResults)) return [];
|
|
13985
14052
|
const deployWorkflowUrl = env2.repository ? `${env2.serverUrl}/${env2.repository}/actions/workflows/deploy-db.yml` : null;
|
|
13986
|
-
const
|
|
14053
|
+
const hasPgSchemaDiffChanges = productionPreview?.hasChanges === true;
|
|
14054
|
+
const hasIndexChanges = schemaStats?.local && schemaStats?.production ? hasIndexDiff(compareIndexLists(schemaStats.local, schemaStats.production)) : false;
|
|
14055
|
+
const hasSchemaChanges = hasPgSchemaDiffChanges || hasIndexChanges;
|
|
13987
14056
|
const headerEmoji = hasSchemaChanges ? "\u{1F6A8}" : "\u{1F680}";
|
|
13988
14057
|
const headerText = hasSchemaChanges ? "\u672C\u756A\u30C7\u30D7\u30ED\u30A4 (\u30B9\u30AD\u30FC\u30DE\u5909\u66F4\u3042\u308A!)" : "\u672C\u756A\u30C7\u30D7\u30ED\u30A4";
|
|
13989
14058
|
const lines = ["---", "", `### ${headerEmoji} ${headerText}`, ""];
|
|
13990
14059
|
if (exitCode !== 0)
|
|
13991
14060
|
lines.push("> **\u6CE8**: Layer 4 (E2E) \u306F\u5931\u6557\u3057\u307E\u3057\u305F\u304C\u3001\u30B9\u30AD\u30FC\u30DE\u5909\u66F4\u306F\u30C7\u30D7\u30ED\u30A4\u53EF\u80FD\u3067\u3059\u3002", "");
|
|
13992
|
-
lines.push(...generateProductionPreviewSection(productionPreview, schemaDrift));
|
|
14061
|
+
lines.push(...generateProductionPreviewSection(productionPreview, schemaDrift, schemaStats));
|
|
13993
14062
|
if (deployWorkflowUrl) {
|
|
13994
14063
|
const buttonText = hasSchemaChanges ? "\u26A1 \u30B9\u30AD\u30FC\u30DE\u5909\u66F4\u3092\u672C\u756A\u306B\u30C7\u30D7\u30ED\u30A4" : "\u25B6\uFE0F \u672C\u756A\u306B\u30C7\u30D7\u30ED\u30A4";
|
|
13995
14064
|
lines.push(
|
|
@@ -14034,6 +14103,7 @@ function generateIntermediateCommentBody(input3) {
|
|
|
14034
14103
|
gitBranchName,
|
|
14035
14104
|
productionPreview,
|
|
14036
14105
|
schemaDrift,
|
|
14106
|
+
input3.schemaStats ?? null,
|
|
14037
14107
|
env2
|
|
14038
14108
|
),
|
|
14039
14109
|
"<sub>\u{1F916} RUNA CI \u751F\u6210 (\u4E2D\u9593\u66F4\u65B0)</sub>"
|
|
@@ -14064,6 +14134,7 @@ function generateCommentBody(input3) {
|
|
|
14064
14134
|
gitBranchName,
|
|
14065
14135
|
input3.productionPreview,
|
|
14066
14136
|
schemaDrift,
|
|
14137
|
+
input3.schemaStats ?? null,
|
|
14067
14138
|
env2
|
|
14068
14139
|
),
|
|
14069
14140
|
"<sub>\u{1F916} RUNA CI \u751F\u6210</sub>"
|
|
@@ -14525,7 +14596,7 @@ function hasError(context) {
|
|
|
14525
14596
|
function allTestsPassed(context) {
|
|
14526
14597
|
if (!context.testsRun) return false;
|
|
14527
14598
|
for (const result of Object.values(context.layerResults)) {
|
|
14528
|
-
if (result.status === "failed") return false;
|
|
14599
|
+
if (result.status === "failed" || result.status === "killed") return false;
|
|
14529
14600
|
}
|
|
14530
14601
|
return true;
|
|
14531
14602
|
}
|
|
@@ -14553,7 +14624,9 @@ function convertLayerResults(results) {
|
|
|
14553
14624
|
const layerResults = {};
|
|
14554
14625
|
for (const r of results) {
|
|
14555
14626
|
let status;
|
|
14556
|
-
if (r.
|
|
14627
|
+
if (r.killed) {
|
|
14628
|
+
status = "killed";
|
|
14629
|
+
} else if (r.skipped) {
|
|
14557
14630
|
status = "skipped";
|
|
14558
14631
|
} else {
|
|
14559
14632
|
status = r.success ? "passed" : "failed";
|
|
@@ -15108,7 +15181,8 @@ ${generateProgressCommentBody(progressInput)}`;
|
|
|
15108
15181
|
invoke: {
|
|
15109
15182
|
src: "collectSchemaStats",
|
|
15110
15183
|
input: ({ context }) => ({
|
|
15111
|
-
|
|
15184
|
+
// In CI mode, local and CI both use the Docker Supabase
|
|
15185
|
+
localDbUrl: context.supabase?.databaseUrlRaw ?? null,
|
|
15112
15186
|
ciDbUrl: context.supabase?.databaseUrlRaw ?? null,
|
|
15113
15187
|
// Query production only in ci-pr modes
|
|
15114
15188
|
queryProduction: context.mode !== "ci-local"
|
|
@@ -16107,11 +16181,36 @@ async function runCiMachine(input3, logger16, onStateChange) {
|
|
|
16107
16181
|
}
|
|
16108
16182
|
function formatLayerResults2(layers) {
|
|
16109
16183
|
const passed = Object.values(layers).filter((r) => r.status === "passed").length;
|
|
16110
|
-
const failed = Object.values(layers).filter(
|
|
16184
|
+
const failed = Object.values(layers).filter(
|
|
16185
|
+
(r) => r.status === "failed" || r.status === "killed"
|
|
16186
|
+
).length;
|
|
16111
16187
|
const lines = [];
|
|
16112
16188
|
for (const [layer, result] of Object.entries(layers)) {
|
|
16113
|
-
|
|
16114
|
-
|
|
16189
|
+
let icon;
|
|
16190
|
+
let statusText;
|
|
16191
|
+
switch (result.status) {
|
|
16192
|
+
case "passed":
|
|
16193
|
+
icon = "\u2705";
|
|
16194
|
+
statusText = "PASSED";
|
|
16195
|
+
break;
|
|
16196
|
+
case "failed":
|
|
16197
|
+
icon = "\u274C";
|
|
16198
|
+
statusText = "FAILED";
|
|
16199
|
+
break;
|
|
16200
|
+
case "killed":
|
|
16201
|
+
icon = "\u23F9\uFE0F";
|
|
16202
|
+
statusText = "KILLED (fail-fast)";
|
|
16203
|
+
break;
|
|
16204
|
+
case "skipped":
|
|
16205
|
+
icon = "\u23ED\uFE0F";
|
|
16206
|
+
statusText = "SKIPPED";
|
|
16207
|
+
break;
|
|
16208
|
+
case "timeout":
|
|
16209
|
+
icon = "\u23F1\uFE0F";
|
|
16210
|
+
statusText = "TIMEOUT";
|
|
16211
|
+
break;
|
|
16212
|
+
}
|
|
16213
|
+
lines.push(` Layer ${layer}: ${icon} ${statusText}`);
|
|
16115
16214
|
}
|
|
16116
16215
|
return { passed, failed, lines };
|
|
16117
16216
|
}
|
|
@@ -16299,7 +16398,7 @@ var CiPhaseSchema = z.enum(["all", "test"]);
|
|
|
16299
16398
|
var CiDbModeSchema = z.enum(["auto", "local"]);
|
|
16300
16399
|
var RepoKindSchema = z.enum(["monorepo", "pj-repo", "unknown"]);
|
|
16301
16400
|
var StepStatusSchema = z.enum(["passed", "failed", "skipped", "timeout"]);
|
|
16302
|
-
var LayerStatusSchema = z.enum(["passed", "failed", "skipped", "timeout"]);
|
|
16401
|
+
var LayerStatusSchema = z.enum(["passed", "failed", "skipped", "timeout", "killed"]);
|
|
16303
16402
|
z.object({
|
|
16304
16403
|
// === Command ===
|
|
16305
16404
|
/** CLI command: 'local' for ci local, 'pr' for ci pr */
|
|
@@ -16735,8 +16834,8 @@ function getGitHubEventAction() {
|
|
|
16735
16834
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
16736
16835
|
if (!eventPath) return void 0;
|
|
16737
16836
|
try {
|
|
16738
|
-
const
|
|
16739
|
-
const eventPayload = JSON.parse(
|
|
16837
|
+
const fs14 = __require("fs");
|
|
16838
|
+
const eventPayload = JSON.parse(fs14.readFileSync(eventPath, "utf-8"));
|
|
16740
16839
|
return eventPayload.action;
|
|
16741
16840
|
} catch {
|
|
16742
16841
|
return void 0;
|
|
@@ -24722,6 +24821,157 @@ statsCommand.command("reset").description("Reset query statistics").option("--en
|
|
|
24722
24821
|
// src/commands/db/commands/db-sync.ts
|
|
24723
24822
|
init_esm_shims();
|
|
24724
24823
|
init_config_loader();
|
|
24824
|
+
|
|
24825
|
+
// src/commands/db/utils/import-impact-analyzer.ts
|
|
24826
|
+
init_esm_shims();
|
|
24827
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
24828
|
+
"node_modules",
|
|
24829
|
+
".git",
|
|
24830
|
+
"dist",
|
|
24831
|
+
"build",
|
|
24832
|
+
".next",
|
|
24833
|
+
".runa",
|
|
24834
|
+
"coverage",
|
|
24835
|
+
"__snapshots__"
|
|
24836
|
+
]);
|
|
24837
|
+
var MAX_FILE_SIZE = 1024 * 1024;
|
|
24838
|
+
var SCHEMA_IMPORT_PATTERNS = [
|
|
24839
|
+
/from\s+['"]@runa-ai\/runa-database\/schema['"]/,
|
|
24840
|
+
/from\s+['"]@runa\/database\/schema['"]/,
|
|
24841
|
+
/from\s+['"]@runa\/database['"]/,
|
|
24842
|
+
/from\s+['"].*\/database\/src\/schema['"]/,
|
|
24843
|
+
/from\s+['"].*\/packages\/database\/src\/schema['"]/
|
|
24844
|
+
];
|
|
24845
|
+
function findTsFiles(dir, files = []) {
|
|
24846
|
+
if (!existsSync(dir)) return files;
|
|
24847
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
24848
|
+
for (const entry of entries) {
|
|
24849
|
+
const fullPath = join(dir, entry.name);
|
|
24850
|
+
if (entry.isDirectory()) {
|
|
24851
|
+
if (!SKIP_DIRS.has(entry.name)) {
|
|
24852
|
+
findTsFiles(fullPath, files);
|
|
24853
|
+
}
|
|
24854
|
+
} else if (entry.isFile()) {
|
|
24855
|
+
if (/\.(ts|tsx)$/.test(entry.name) && !entry.name.endsWith(".d.ts")) {
|
|
24856
|
+
files.push(fullPath);
|
|
24857
|
+
}
|
|
24858
|
+
}
|
|
24859
|
+
}
|
|
24860
|
+
return files;
|
|
24861
|
+
}
|
|
24862
|
+
function extractSchemaImports(filePath, rootDir) {
|
|
24863
|
+
const imports = [];
|
|
24864
|
+
try {
|
|
24865
|
+
const stats = statSync(filePath);
|
|
24866
|
+
if (stats.size > MAX_FILE_SIZE) {
|
|
24867
|
+
return imports;
|
|
24868
|
+
}
|
|
24869
|
+
const content = readFileSync(filePath, "utf-8");
|
|
24870
|
+
const lines = content.split("\n");
|
|
24871
|
+
for (let i = 0; i < lines.length; i++) {
|
|
24872
|
+
const line = lines[i];
|
|
24873
|
+
const isSchemaImport = SCHEMA_IMPORT_PATTERNS.some((pattern) => pattern.test(line));
|
|
24874
|
+
if (!isSchemaImport) continue;
|
|
24875
|
+
const sourceMatch = line.match(/from\s+['"]([^'"]+)['"]/);
|
|
24876
|
+
if (!sourceMatch) continue;
|
|
24877
|
+
const source = sourceMatch[1];
|
|
24878
|
+
const namedMatch = line.match(/import\s*\{([^}]+)\}/);
|
|
24879
|
+
if (namedMatch) {
|
|
24880
|
+
const symbols = namedMatch[1].split(",").map((s) => {
|
|
24881
|
+
const parts = s.trim().split(/\s+as\s+/);
|
|
24882
|
+
return parts[0].trim();
|
|
24883
|
+
});
|
|
24884
|
+
for (const symbol of symbols) {
|
|
24885
|
+
if (symbol) {
|
|
24886
|
+
imports.push({
|
|
24887
|
+
file: relative(rootDir, filePath),
|
|
24888
|
+
line: i + 1,
|
|
24889
|
+
symbol,
|
|
24890
|
+
source
|
|
24891
|
+
});
|
|
24892
|
+
}
|
|
24893
|
+
}
|
|
24894
|
+
}
|
|
24895
|
+
const namespaceMatch = line.match(/import\s+\*\s+as\s+(\w+)/);
|
|
24896
|
+
if (namespaceMatch) {
|
|
24897
|
+
imports.push({
|
|
24898
|
+
file: relative(rootDir, filePath),
|
|
24899
|
+
line: i + 1,
|
|
24900
|
+
symbol: `* as ${namespaceMatch[1]}`,
|
|
24901
|
+
source
|
|
24902
|
+
});
|
|
24903
|
+
}
|
|
24904
|
+
const typeMatch = line.match(/import\s+type\s*\{([^}]+)\}/);
|
|
24905
|
+
if (typeMatch) {
|
|
24906
|
+
const symbols = typeMatch[1].split(",").map(
|
|
24907
|
+
(s) => s.trim().split(/\s+as\s+/)[0].trim()
|
|
24908
|
+
);
|
|
24909
|
+
for (const symbol of symbols) {
|
|
24910
|
+
if (symbol) {
|
|
24911
|
+
imports.push({
|
|
24912
|
+
file: relative(rootDir, filePath),
|
|
24913
|
+
line: i + 1,
|
|
24914
|
+
symbol: `type ${symbol}`,
|
|
24915
|
+
source
|
|
24916
|
+
});
|
|
24917
|
+
}
|
|
24918
|
+
}
|
|
24919
|
+
}
|
|
24920
|
+
}
|
|
24921
|
+
} catch {
|
|
24922
|
+
}
|
|
24923
|
+
return imports;
|
|
24924
|
+
}
|
|
24925
|
+
function analyzeImportImpact(rootDir) {
|
|
24926
|
+
const symbolUsage = /* @__PURE__ */ new Map();
|
|
24927
|
+
const tsFiles = findTsFiles(rootDir);
|
|
24928
|
+
let filesWithImports = 0;
|
|
24929
|
+
for (const file of tsFiles) {
|
|
24930
|
+
const imports = extractSchemaImports(file, rootDir);
|
|
24931
|
+
if (imports.length > 0) {
|
|
24932
|
+
filesWithImports++;
|
|
24933
|
+
}
|
|
24934
|
+
for (const imp of imports) {
|
|
24935
|
+
const existing = symbolUsage.get(imp.symbol) ?? [];
|
|
24936
|
+
existing.push(imp);
|
|
24937
|
+
symbolUsage.set(imp.symbol, existing);
|
|
24938
|
+
}
|
|
24939
|
+
}
|
|
24940
|
+
return {
|
|
24941
|
+
symbolUsage,
|
|
24942
|
+
totalFilesScanned: tsFiles.length,
|
|
24943
|
+
filesWithImports
|
|
24944
|
+
};
|
|
24945
|
+
}
|
|
24946
|
+
function formatImportImpactReport(report, changedSymbols) {
|
|
24947
|
+
const lines = [];
|
|
24948
|
+
lines.push("\u{1F4CA} Schema Import Impact Analysis");
|
|
24949
|
+
lines.push(` Files scanned: ${report.totalFilesScanned}`);
|
|
24950
|
+
lines.push(` Files with schema imports: ${report.filesWithImports}`);
|
|
24951
|
+
lines.push("");
|
|
24952
|
+
const symbolsToShow = Array.from(report.symbolUsage.keys()).sort();
|
|
24953
|
+
if (symbolsToShow.length === 0) {
|
|
24954
|
+
lines.push(" No schema imports found.");
|
|
24955
|
+
return lines;
|
|
24956
|
+
}
|
|
24957
|
+
for (const symbol of symbolsToShow) {
|
|
24958
|
+
const refs = report.symbolUsage.get(symbol);
|
|
24959
|
+
if (!refs || refs.length === 0) continue;
|
|
24960
|
+
lines.push(` ${symbol}:`);
|
|
24961
|
+
for (const ref of refs) {
|
|
24962
|
+
lines.push(` \u2022 ${ref.file}:${ref.line}`);
|
|
24963
|
+
}
|
|
24964
|
+
lines.push("");
|
|
24965
|
+
}
|
|
24966
|
+
const totalRefs = Array.from(report.symbolUsage.values()).reduce(
|
|
24967
|
+
(sum, refs) => sum + refs.length,
|
|
24968
|
+
0
|
|
24969
|
+
);
|
|
24970
|
+
lines.push(` Total: ${report.symbolUsage.size} symbols, ${totalRefs} references`);
|
|
24971
|
+
return lines;
|
|
24972
|
+
}
|
|
24973
|
+
|
|
24974
|
+
// src/commands/db/commands/db-sync.ts
|
|
24725
24975
|
function printList(title, items, logger16) {
|
|
24726
24976
|
if (items.length === 0) return;
|
|
24727
24977
|
logger16.warn(`
|
|
@@ -24834,6 +25084,14 @@ async function runSyncAction(env2, options) {
|
|
|
24834
25084
|
return;
|
|
24835
25085
|
}
|
|
24836
25086
|
logHumanSyncReport({ logger: logger16, expectedTables, expectedEnums, dbTables, dbEnums, diff });
|
|
25087
|
+
if (options.showImportImpact) {
|
|
25088
|
+
logger16.info("");
|
|
25089
|
+
const report = analyzeImportImpact(process.cwd());
|
|
25090
|
+
const lines = formatImportImpactReport(report);
|
|
25091
|
+
for (const line of lines) {
|
|
25092
|
+
logger16.info(line);
|
|
25093
|
+
}
|
|
25094
|
+
}
|
|
24837
25095
|
if (countSyncIssues(diff) === 0) return;
|
|
24838
25096
|
throw new CLIError("Database schema is out of sync", "DB_SCHEMA_OUT_OF_SYNC", [
|
|
24839
25097
|
"Review the diff output above",
|
|
@@ -24854,7 +25112,7 @@ async function runSyncAction(env2, options) {
|
|
|
24854
25112
|
);
|
|
24855
25113
|
}
|
|
24856
25114
|
}
|
|
24857
|
-
var checkCommand2 = new Command("check").description("Compare TypeScript schema (Drizzle) vs target database (tables/enums)").argument("[env]", "Environment: local, preview, main, or production", "local").option("--json", "Output diff as JSON").action(async (env2, options) => await runSyncAction(env2, options));
|
|
25115
|
+
var checkCommand2 = new Command("check").description("Compare TypeScript schema (Drizzle) vs target database (tables/enums)").argument("[env]", "Environment: local, preview, main, or production", "local").option("--json", "Output diff as JSON").option("--show-import-impact", "Analyze which files import schema tables").action(async (env2, options) => await runSyncAction(env2, options));
|
|
24858
25116
|
|
|
24859
25117
|
// src/commands/db/commands/db-test.ts
|
|
24860
25118
|
init_esm_shims();
|
|
@@ -27303,7 +27561,8 @@ async function setVercelEnvVar(linkedDir, key, value, overwrite, logger16) {
|
|
|
27303
27561
|
proc.stderr?.on("data", (data) => {
|
|
27304
27562
|
stderr += data.toString();
|
|
27305
27563
|
});
|
|
27306
|
-
proc.stdin?.write(value
|
|
27564
|
+
proc.stdin?.write(`${value}
|
|
27565
|
+
`);
|
|
27307
27566
|
proc.stdin?.end();
|
|
27308
27567
|
proc.on("close", (code) => {
|
|
27309
27568
|
if (code === 0) {
|
|
@@ -29766,7 +30025,7 @@ init_esm_shims();
|
|
|
29766
30025
|
|
|
29767
30026
|
// src/constants/versions.ts
|
|
29768
30027
|
init_esm_shims();
|
|
29769
|
-
var COMPATIBLE_TEMPLATES_VERSION = "0.5.
|
|
30028
|
+
var COMPATIBLE_TEMPLATES_VERSION = "0.5.43";
|
|
29770
30029
|
var TEMPLATES_PACKAGE_NAME = "@r06-dev/runa-templates";
|
|
29771
30030
|
var GITHUB_PACKAGES_REGISTRY = "https://npm.pkg.github.com";
|
|
29772
30031
|
|
|
@@ -29819,7 +30078,7 @@ function getCacheDir(version) {
|
|
|
29819
30078
|
function isCached(version) {
|
|
29820
30079
|
const cacheDir = getCacheDir(version);
|
|
29821
30080
|
const templatesDir = path10__default.join(cacheDir, "templates");
|
|
29822
|
-
return
|
|
30081
|
+
return fs5__default.existsSync(templatesDir);
|
|
29823
30082
|
}
|
|
29824
30083
|
var scopedAuthToken = null;
|
|
29825
30084
|
var tokenWasAutoDetected = false;
|
|
@@ -29955,7 +30214,7 @@ async function verifyNoSymlinks(dir, baseDir) {
|
|
|
29955
30214
|
}
|
|
29956
30215
|
async function copyToCache(tempDir, cacheDir) {
|
|
29957
30216
|
const sourceTemplates = path10__default.join(tempDir, "node_modules", TEMPLATES_PACKAGE_NAME, "templates");
|
|
29958
|
-
if (!
|
|
30217
|
+
if (!fs5__default.existsSync(sourceTemplates)) {
|
|
29959
30218
|
throw new CLIError("Templates directory not found in package.", "TEMPLATES_DIR_NOT_FOUND", [
|
|
29960
30219
|
`Expected: ${sourceTemplates}`,
|
|
29961
30220
|
"The templates package may be corrupted.",
|
|
@@ -29999,7 +30258,7 @@ async function fetchTemplates(options = {}) {
|
|
|
29999
30258
|
}
|
|
30000
30259
|
const authToken = await getAuthToken();
|
|
30001
30260
|
try {
|
|
30002
|
-
if (fresh &&
|
|
30261
|
+
if (fresh && fs5__default.existsSync(cacheDir)) {
|
|
30003
30262
|
await rm(cacheDir, { recursive: true, force: true });
|
|
30004
30263
|
}
|
|
30005
30264
|
const tempDir = path10__default.join(os.tmpdir(), `runa-templates-${Date.now()}`);
|
|
@@ -30031,15 +30290,15 @@ async function fetchTemplates(options = {}) {
|
|
|
30031
30290
|
var MAX_WORKSPACE_TRAVERSAL_DEPTH = 10;
|
|
30032
30291
|
function isLegitimateWorkspaceRoot(workspaceRoot) {
|
|
30033
30292
|
const pnpmWorkspaceFile = path10__default.join(workspaceRoot, "pnpm-workspace.yaml");
|
|
30034
|
-
if (!
|
|
30293
|
+
if (!fs5__default.existsSync(pnpmWorkspaceFile)) {
|
|
30035
30294
|
return false;
|
|
30036
30295
|
}
|
|
30037
30296
|
const rootPackageFile = path10__default.join(workspaceRoot, "package.json");
|
|
30038
|
-
if (!
|
|
30297
|
+
if (!fs5__default.existsSync(rootPackageFile)) {
|
|
30039
30298
|
return false;
|
|
30040
30299
|
}
|
|
30041
30300
|
try {
|
|
30042
|
-
const rootPkg = JSON.parse(
|
|
30301
|
+
const rootPkg = JSON.parse(fs5__default.readFileSync(rootPackageFile, "utf-8"));
|
|
30043
30302
|
const hasWorkspaces = Array.isArray(rootPkg.workspaces) && rootPkg.workspaces.length > 0;
|
|
30044
30303
|
const hasExpectedName = rootPkg.name === "runa" || rootPkg.name === "@r06-dev/runa";
|
|
30045
30304
|
return hasWorkspaces || hasExpectedName;
|
|
@@ -30064,11 +30323,11 @@ function resolveWorkspaceTemplates() {
|
|
|
30064
30323
|
depth++;
|
|
30065
30324
|
continue;
|
|
30066
30325
|
}
|
|
30067
|
-
if (
|
|
30326
|
+
if (fs5__default.existsSync(normalizedTemplatesPath)) {
|
|
30068
30327
|
const markerFile = path10__default.join(current, "packages", "runa-templates", "package.json");
|
|
30069
|
-
if (
|
|
30328
|
+
if (fs5__default.existsSync(markerFile)) {
|
|
30070
30329
|
try {
|
|
30071
|
-
const pkg = JSON.parse(
|
|
30330
|
+
const pkg = JSON.parse(fs5__default.readFileSync(markerFile, "utf-8"));
|
|
30072
30331
|
if (pkg.name === "@r06-dev/runa-templates") {
|
|
30073
30332
|
return normalizedTemplatesPath;
|
|
30074
30333
|
}
|
|
@@ -30090,9 +30349,9 @@ function checkZodVersion(_logger) {
|
|
|
30090
30349
|
path10__default.join(process.env.HOME ?? "", "node_modules", "zod", "package.json")
|
|
30091
30350
|
];
|
|
30092
30351
|
for (const zodPath of zodPaths) {
|
|
30093
|
-
if (!
|
|
30352
|
+
if (!fs5__default.existsSync(zodPath)) continue;
|
|
30094
30353
|
try {
|
|
30095
|
-
const raw =
|
|
30354
|
+
const raw = fs5__default.readFileSync(zodPath, "utf-8");
|
|
30096
30355
|
const pkg = JSON.parse(raw);
|
|
30097
30356
|
const version = pkg.version ?? "";
|
|
30098
30357
|
if (version.startsWith("3.")) {
|
|
@@ -30630,15 +30889,15 @@ function emptyResult(filePath) {
|
|
|
30630
30889
|
};
|
|
30631
30890
|
}
|
|
30632
30891
|
function ensureDirectoryExists(dirPath) {
|
|
30633
|
-
if (!
|
|
30634
|
-
|
|
30892
|
+
if (!fs5.existsSync(dirPath)) {
|
|
30893
|
+
fs5.mkdirSync(dirPath, { recursive: true });
|
|
30635
30894
|
}
|
|
30636
30895
|
}
|
|
30637
30896
|
function getGeneratorVersion() {
|
|
30638
30897
|
try {
|
|
30639
30898
|
const pkgPath = path10.resolve(__dirname$1, "../../../package.json");
|
|
30640
|
-
if (
|
|
30641
|
-
const pkg = JSON.parse(
|
|
30899
|
+
if (fs5.existsSync(pkgPath)) {
|
|
30900
|
+
const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
|
|
30642
30901
|
return pkg.version ?? "unknown";
|
|
30643
30902
|
}
|
|
30644
30903
|
} catch {
|
|
@@ -30655,21 +30914,21 @@ function detectPlatform(repoRoot) {
|
|
|
30655
30914
|
path10.join(repoRoot, "apps", "web", pattern),
|
|
30656
30915
|
path10.join(repoRoot, "apps", "dashboard", pattern)
|
|
30657
30916
|
];
|
|
30658
|
-
if (paths.some((p) =>
|
|
30917
|
+
if (paths.some((p) => fs5.existsSync(p))) {
|
|
30659
30918
|
return "nextjs";
|
|
30660
30919
|
}
|
|
30661
30920
|
}
|
|
30662
30921
|
const appJsonPath = path10.join(repoRoot, "app.json");
|
|
30663
|
-
if (
|
|
30922
|
+
if (fs5.existsSync(appJsonPath)) {
|
|
30664
30923
|
try {
|
|
30665
|
-
const appJson = JSON.parse(
|
|
30924
|
+
const appJson = JSON.parse(fs5.readFileSync(appJsonPath, "utf-8"));
|
|
30666
30925
|
if (appJson.expo) {
|
|
30667
30926
|
return "expo";
|
|
30668
30927
|
}
|
|
30669
30928
|
} catch {
|
|
30670
30929
|
}
|
|
30671
30930
|
}
|
|
30672
|
-
if (
|
|
30931
|
+
if (fs5.existsSync(path10.join(repoRoot, "expo.json"))) {
|
|
30673
30932
|
return "expo";
|
|
30674
30933
|
}
|
|
30675
30934
|
const electronPatterns = [
|
|
@@ -30678,7 +30937,7 @@ function detectPlatform(repoRoot) {
|
|
|
30678
30937
|
"electron.vite.config.ts",
|
|
30679
30938
|
"electron.vite.config.js"
|
|
30680
30939
|
];
|
|
30681
|
-
if (electronPatterns.some((p) =>
|
|
30940
|
+
if (electronPatterns.some((p) => fs5.existsSync(path10.join(repoRoot, p)))) {
|
|
30682
30941
|
return "electron";
|
|
30683
30942
|
}
|
|
30684
30943
|
return "unknown";
|
|
@@ -30686,14 +30945,14 @@ function detectPlatform(repoRoot) {
|
|
|
30686
30945
|
function findPossibleHonoDirs(repoRoot) {
|
|
30687
30946
|
const possibleDirs = [];
|
|
30688
30947
|
const appsDir = path10.join(repoRoot, "apps");
|
|
30689
|
-
if (
|
|
30948
|
+
if (fs5.existsSync(appsDir)) {
|
|
30690
30949
|
try {
|
|
30691
|
-
const apps =
|
|
30950
|
+
const apps = fs5.readdirSync(appsDir, { withFileTypes: true });
|
|
30692
30951
|
for (const app of apps) {
|
|
30693
30952
|
if (app.isDirectory()) {
|
|
30694
30953
|
const routesDir = path10.join(appsDir, app.name, "routes");
|
|
30695
|
-
if (
|
|
30696
|
-
const files =
|
|
30954
|
+
if (fs5.existsSync(routesDir)) {
|
|
30955
|
+
const files = fs5.readdirSync(routesDir);
|
|
30697
30956
|
const hasRouteFiles = files.some(
|
|
30698
30957
|
(f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.endsWith(".spec.ts")
|
|
30699
30958
|
);
|
|
@@ -30707,14 +30966,14 @@ function findPossibleHonoDirs(repoRoot) {
|
|
|
30707
30966
|
}
|
|
30708
30967
|
}
|
|
30709
30968
|
const packagesDir = path10.join(repoRoot, "packages");
|
|
30710
|
-
if (
|
|
30969
|
+
if (fs5.existsSync(packagesDir)) {
|
|
30711
30970
|
try {
|
|
30712
|
-
const packages =
|
|
30971
|
+
const packages = fs5.readdirSync(packagesDir, { withFileTypes: true });
|
|
30713
30972
|
for (const pkg of packages) {
|
|
30714
30973
|
if (pkg.isDirectory()) {
|
|
30715
30974
|
const routesDir = path10.join(packagesDir, pkg.name, "routes");
|
|
30716
|
-
if (
|
|
30717
|
-
const files =
|
|
30975
|
+
if (fs5.existsSync(routesDir)) {
|
|
30976
|
+
const files = fs5.readdirSync(routesDir);
|
|
30718
30977
|
const hasRouteFiles = files.some(
|
|
30719
30978
|
(f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.endsWith(".spec.ts")
|
|
30720
30979
|
);
|
|
@@ -30804,7 +31063,7 @@ function buildDefinitionMap(definitions) {
|
|
|
30804
31063
|
function buildEnhancedMachines(e2eManifest, definitionMap, machineDefinitions) {
|
|
30805
31064
|
const enhanced = {};
|
|
30806
31065
|
const normalizedIdToCanonical = /* @__PURE__ */ new Map();
|
|
30807
|
-
const isMachineFile = (
|
|
31066
|
+
const isMachineFile = (path63) => path63.includes("machine.ts") || path63.includes("machines/") || path63.includes(".machine.ts") || path63.includes("/machine/");
|
|
30808
31067
|
const addMachine = (id, sourceFile, entryBuilder) => {
|
|
30809
31068
|
const normalizedId = normalizeToCanonicalId(id).toLowerCase();
|
|
30810
31069
|
const existingCanonical = normalizedIdToCanonical.get(normalizedId);
|
|
@@ -30946,7 +31205,7 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
|
|
|
30946
31205
|
const manifestsDir = path10.join(absoluteManifestDir, "manifests");
|
|
30947
31206
|
ensureDirectoryExists(manifestsDir);
|
|
30948
31207
|
const tsPath = path10.join(generatedDir, "selectors.ts");
|
|
30949
|
-
await
|
|
31208
|
+
await fs5.promises.writeFile(tsPath, generateSelectorTypeScript(e2eManifest), "utf-8");
|
|
30950
31209
|
const unifiedRegistry = getUnifiedRegistry();
|
|
30951
31210
|
const machineLinks = buildMachineLinks();
|
|
30952
31211
|
const { apiContracts, schemasResolved } = await analyzeHonoRoutes(
|
|
@@ -30975,7 +31234,7 @@ async function generateManifestFiles(manifestDir, repoRoot, verbose, resolveSche
|
|
|
30975
31234
|
apiContracts
|
|
30976
31235
|
};
|
|
30977
31236
|
const manifestPath = path10.join(manifestsDir, "manifest.json");
|
|
30978
|
-
await
|
|
31237
|
+
await fs5.promises.writeFile(manifestPath, JSON.stringify(unifiedManifest, null, 2), "utf-8");
|
|
30979
31238
|
const machinesWithoutE2EMeta = machineDefinitions.filter(
|
|
30980
31239
|
(def) => !def.hasE2EMeta && typeof def.id === "string"
|
|
30981
31240
|
).map((def) => ({ id: def.id, sourceFile: def.sourceFile }));
|
|
@@ -31039,7 +31298,7 @@ function registerExistingInjections(machineIds, attrs, sourceFile) {
|
|
|
31039
31298
|
}
|
|
31040
31299
|
}
|
|
31041
31300
|
async function preprocessFile(filePath, repoRoot, options) {
|
|
31042
|
-
let code = await
|
|
31301
|
+
let code = await fs5.promises.readFile(filePath, "utf-8");
|
|
31043
31302
|
const relativePath = path10.relative(repoRoot, filePath);
|
|
31044
31303
|
collectRouteInfo(relativePath, code, options.verbose);
|
|
31045
31304
|
const hasMarker = code.includes(CLI_INJECTION_MARKER);
|
|
@@ -31141,7 +31400,7 @@ async function handleChangedFile(result, check, repoRoot, verbose, state2) {
|
|
|
31141
31400
|
});
|
|
31142
31401
|
state2.totalInjections += result.injectedCount;
|
|
31143
31402
|
if (check) return;
|
|
31144
|
-
await
|
|
31403
|
+
await fs5.promises.writeFile(result.filePath, result.transformedCode, "utf-8");
|
|
31145
31404
|
state2.filesToFormat.push(result.filePath);
|
|
31146
31405
|
if (verbose) {
|
|
31147
31406
|
const relativePath = path10.relative(repoRoot, result.filePath);
|
|
@@ -31164,7 +31423,7 @@ async function categorizeFiles(files) {
|
|
|
31164
31423
|
const withJsxOnly = [];
|
|
31165
31424
|
for (const filePath of files) {
|
|
31166
31425
|
try {
|
|
31167
|
-
const code = await
|
|
31426
|
+
const code = await fs5.promises.readFile(filePath, "utf-8");
|
|
31168
31427
|
if (mightContainMachineHooks(code)) {
|
|
31169
31428
|
withMachineHooks.push(filePath);
|
|
31170
31429
|
} else if (mightContainJsx(code)) {
|
|
@@ -31193,7 +31452,7 @@ async function processFiles(options) {
|
|
|
31193
31452
|
const processOpts = { verbose, force: options.force ?? false };
|
|
31194
31453
|
for (const filePath of withMachineDefinitions) {
|
|
31195
31454
|
try {
|
|
31196
|
-
const code = await
|
|
31455
|
+
const code = await fs5.promises.readFile(filePath, "utf-8");
|
|
31197
31456
|
const relativePath = path10.relative(repoRoot, filePath);
|
|
31198
31457
|
collectRouteInfo(relativePath, code, verbose);
|
|
31199
31458
|
} catch {
|
|
@@ -32922,8 +33181,8 @@ function formatLineDiff(diff) {
|
|
|
32922
33181
|
|
|
32923
33182
|
// src/commands/template-check/actors/compare.ts
|
|
32924
33183
|
function compareBothFiles(runaRelPath, templateRelPath, runaAbsPath, templateAbsPath, category, includeDiff) {
|
|
32925
|
-
const runaContent =
|
|
32926
|
-
const templateContent =
|
|
33184
|
+
const runaContent = fs5.readFileSync(runaAbsPath, "utf-8");
|
|
33185
|
+
const templateContent = fs5.readFileSync(templateAbsPath, "utf-8");
|
|
32927
33186
|
const comparison = compareFiles(runaContent, templateContent);
|
|
32928
33187
|
let status;
|
|
32929
33188
|
if (comparison.identical) {
|
|
@@ -33400,9 +33659,9 @@ var PATH_MAPPING_RULES = [
|
|
|
33400
33659
|
category: "prompts"
|
|
33401
33660
|
}
|
|
33402
33661
|
];
|
|
33403
|
-
function getCategoryForPath(
|
|
33662
|
+
function getCategoryForPath(path63) {
|
|
33404
33663
|
for (const rule of PATH_MAPPING_RULES) {
|
|
33405
|
-
if (matchGlobPattern(
|
|
33664
|
+
if (matchGlobPattern(path63, rule.runa) || matchGlobPattern(path63, rule.template)) {
|
|
33406
33665
|
return rule.category;
|
|
33407
33666
|
}
|
|
33408
33667
|
}
|
|
@@ -33422,17 +33681,17 @@ function applyReverseRename(normalized, rule, isTemplate) {
|
|
|
33422
33681
|
}
|
|
33423
33682
|
return normalized;
|
|
33424
33683
|
}
|
|
33425
|
-
function generateComparisonKey(
|
|
33426
|
-
let normalized = isTemplate ? normalizeTemplatePath(
|
|
33684
|
+
function generateComparisonKey(path63, isTemplate) {
|
|
33685
|
+
let normalized = isTemplate ? normalizeTemplatePath(path63) : path63;
|
|
33427
33686
|
for (const rule of PATH_MAPPING_RULES) {
|
|
33428
33687
|
normalized = applyReverseRename(normalized, rule, isTemplate);
|
|
33429
33688
|
}
|
|
33430
33689
|
return normalized;
|
|
33431
33690
|
}
|
|
33432
|
-
function matchGlobPattern(
|
|
33691
|
+
function matchGlobPattern(path63, pattern) {
|
|
33433
33692
|
const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<DOUBLE_STAR>>").replace(/\*/g, "([^/]*)").replace(/<<DOUBLE_STAR>>/g, "(.*)");
|
|
33434
33693
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
33435
|
-
const match =
|
|
33694
|
+
const match = path63.match(regex);
|
|
33436
33695
|
if (match) {
|
|
33437
33696
|
const subPath = match[1] ?? "";
|
|
33438
33697
|
return { matched: true, subPath };
|
|
@@ -33496,7 +33755,7 @@ async function globFiles(baseDir, pattern) {
|
|
|
33496
33755
|
return results;
|
|
33497
33756
|
}
|
|
33498
33757
|
function addFileResult(entryPath, fullPattern, results) {
|
|
33499
|
-
const stats =
|
|
33758
|
+
const stats = fs5.statSync(entryPath);
|
|
33500
33759
|
results.push({
|
|
33501
33760
|
absolutePath: entryPath,
|
|
33502
33761
|
size: stats.size,
|
|
@@ -33543,16 +33802,16 @@ async function matchBraceExpansion(ctx, entries, pattern, isLastPart) {
|
|
|
33543
33802
|
}
|
|
33544
33803
|
async function matchLiteral(ctx, pattern, isLastPart) {
|
|
33545
33804
|
const entryPath = path10.join(ctx.currentDir, pattern);
|
|
33546
|
-
if (!
|
|
33547
|
-
const stats =
|
|
33805
|
+
if (!fs5.existsSync(entryPath)) return;
|
|
33806
|
+
const stats = fs5.statSync(entryPath);
|
|
33548
33807
|
await processEntry(ctx, entryPath, stats.isFile(), stats.isDirectory(), isLastPart);
|
|
33549
33808
|
}
|
|
33550
33809
|
async function walkAndMatch(ctx) {
|
|
33551
33810
|
if (ctx.partIndex >= ctx.patternParts.length) return;
|
|
33552
|
-
if (!
|
|
33811
|
+
if (!fs5.existsSync(ctx.currentDir)) return;
|
|
33553
33812
|
const currentPattern = ctx.patternParts[ctx.partIndex];
|
|
33554
33813
|
const isLastPart = ctx.partIndex === ctx.patternParts.length - 1;
|
|
33555
|
-
const entries =
|
|
33814
|
+
const entries = fs5.readdirSync(ctx.currentDir, { withFileTypes: true });
|
|
33556
33815
|
if (currentPattern === "**") {
|
|
33557
33816
|
await matchDoubleWildcard(ctx, entries);
|
|
33558
33817
|
} else if (currentPattern.includes("*")) {
|
|
@@ -34067,17 +34326,17 @@ function printActionsNeeded(logger16, actions) {
|
|
|
34067
34326
|
);
|
|
34068
34327
|
}
|
|
34069
34328
|
function findRepoRoot3(startDir) {
|
|
34070
|
-
const { existsSync:
|
|
34071
|
-
const { join:
|
|
34329
|
+
const { existsSync: existsSync51, readFileSync: readFileSync29 } = __require("fs");
|
|
34330
|
+
const { join: join23, dirname: dirname5 } = __require("path");
|
|
34072
34331
|
let current = startDir;
|
|
34073
34332
|
while (current !== dirname5(current)) {
|
|
34074
|
-
if (
|
|
34333
|
+
if (existsSync51(join23(current, "turbo.json"))) {
|
|
34075
34334
|
return current;
|
|
34076
34335
|
}
|
|
34077
|
-
const pkgPath =
|
|
34078
|
-
if (
|
|
34336
|
+
const pkgPath = join23(current, "package.json");
|
|
34337
|
+
if (existsSync51(pkgPath)) {
|
|
34079
34338
|
try {
|
|
34080
|
-
const pkg = JSON.parse(
|
|
34339
|
+
const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
|
|
34081
34340
|
if (pkg.workspaces) {
|
|
34082
34341
|
return current;
|
|
34083
34342
|
}
|
|
@@ -34143,10 +34402,10 @@ function generateReportOutput(output3, isJsonMode) {
|
|
|
34143
34402
|
};
|
|
34144
34403
|
}
|
|
34145
34404
|
function validateRunaRepo(repoRoot) {
|
|
34146
|
-
const { existsSync:
|
|
34147
|
-
const { join:
|
|
34148
|
-
const templateDir =
|
|
34149
|
-
if (!
|
|
34405
|
+
const { existsSync: existsSync51 } = __require("fs");
|
|
34406
|
+
const { join: join23 } = __require("path");
|
|
34407
|
+
const templateDir = join23(repoRoot, "packages/runa-templates/templates");
|
|
34408
|
+
if (!existsSync51(templateDir)) {
|
|
34150
34409
|
throw new CLIError("template-check is a runa-repo only command", "NOT_RUNA_REPO", [
|
|
34151
34410
|
"This command compares runa-repo with pj-repo templates",
|
|
34152
34411
|
"It should only be run in the runa repository",
|
|
@@ -35379,8 +35638,8 @@ async function runVerification(logger16) {
|
|
|
35379
35638
|
return allPassed;
|
|
35380
35639
|
}
|
|
35381
35640
|
async function findWorkspacesWithSdkPackages(rootDir, packageNames) {
|
|
35382
|
-
const
|
|
35383
|
-
const
|
|
35641
|
+
const fs14 = await import('fs/promises');
|
|
35642
|
+
const path63 = await import('path');
|
|
35384
35643
|
const { glob: glob8 } = await import('glob');
|
|
35385
35644
|
const result = [];
|
|
35386
35645
|
const packageJsonPaths = await glob8("**/package.json", {
|
|
@@ -35389,9 +35648,9 @@ async function findWorkspacesWithSdkPackages(rootDir, packageNames) {
|
|
|
35389
35648
|
// Exclude root
|
|
35390
35649
|
});
|
|
35391
35650
|
for (const relPath of packageJsonPaths) {
|
|
35392
|
-
const fullPath =
|
|
35651
|
+
const fullPath = path63.join(rootDir, relPath);
|
|
35393
35652
|
try {
|
|
35394
|
-
const content = await
|
|
35653
|
+
const content = await fs14.readFile(fullPath, "utf-8");
|
|
35395
35654
|
const pkg = JSON.parse(content);
|
|
35396
35655
|
let hasAnySdkPackage = false;
|
|
35397
35656
|
for (const pkgName of packageNames) {
|
|
@@ -35402,7 +35661,7 @@ async function findWorkspacesWithSdkPackages(rootDir, packageNames) {
|
|
|
35402
35661
|
}
|
|
35403
35662
|
if (hasAnySdkPackage) {
|
|
35404
35663
|
result.push({
|
|
35405
|
-
dir:
|
|
35664
|
+
dir: path63.dirname(fullPath),
|
|
35406
35665
|
packages: packageNames
|
|
35407
35666
|
// All packages, not just found ones
|
|
35408
35667
|
});
|
|
@@ -36045,7 +36304,7 @@ var SchemaWatcher = class {
|
|
|
36045
36304
|
persistent: true,
|
|
36046
36305
|
ignoreInitial: true
|
|
36047
36306
|
});
|
|
36048
|
-
this.watcher.on("add", (
|
|
36307
|
+
this.watcher.on("add", (path63) => this.handleFileEvent("add", path63)).on("change", (path63) => this.handleFileEvent("change", path63)).on("unlink", (path63) => this.handleFileEvent("unlink", path63)).on("error", (error) => this.handleError(error));
|
|
36049
36308
|
this.logger.success("\u2705 Schema watcher started");
|
|
36050
36309
|
this.logger.info(chalk.dim(" Press Ctrl+C to stop\n"));
|
|
36051
36310
|
}
|
|
@@ -36066,23 +36325,23 @@ var SchemaWatcher = class {
|
|
|
36066
36325
|
/**
|
|
36067
36326
|
* Handle file system events with debouncing
|
|
36068
36327
|
*/
|
|
36069
|
-
handleFileEvent(type,
|
|
36070
|
-
const existingTimer = this.debounceTimers.get(
|
|
36328
|
+
handleFileEvent(type, path63) {
|
|
36329
|
+
const existingTimer = this.debounceTimers.get(path63);
|
|
36071
36330
|
if (existingTimer) {
|
|
36072
36331
|
clearTimeout(existingTimer);
|
|
36073
36332
|
}
|
|
36074
36333
|
const timer = setTimeout(() => {
|
|
36075
|
-
this.processFileEvent({ type, path:
|
|
36076
|
-
this.debounceTimers.delete(
|
|
36334
|
+
this.processFileEvent({ type, path: path63, timestamp: /* @__PURE__ */ new Date() });
|
|
36335
|
+
this.debounceTimers.delete(path63);
|
|
36077
36336
|
}, this.options.debounceMs);
|
|
36078
|
-
this.debounceTimers.set(
|
|
36337
|
+
this.debounceTimers.set(path63, timer);
|
|
36079
36338
|
}
|
|
36080
36339
|
/**
|
|
36081
36340
|
* Process file system event
|
|
36082
36341
|
*/
|
|
36083
36342
|
async processFileEvent(event) {
|
|
36084
|
-
const { type, path:
|
|
36085
|
-
const fileName =
|
|
36343
|
+
const { type, path: path63 } = event;
|
|
36344
|
+
const fileName = path63.split("/").pop() || path63;
|
|
36086
36345
|
switch (type) {
|
|
36087
36346
|
case "add":
|
|
36088
36347
|
this.logger.info(chalk.green(`\u2795 Added: ${fileName}`));
|
|
@@ -36095,19 +36354,19 @@ var SchemaWatcher = class {
|
|
|
36095
36354
|
return;
|
|
36096
36355
|
}
|
|
36097
36356
|
if (this.options.autoValidate) {
|
|
36098
|
-
await this.validateFile(
|
|
36357
|
+
await this.validateFile(path63);
|
|
36099
36358
|
}
|
|
36100
36359
|
}
|
|
36101
36360
|
/**
|
|
36102
36361
|
* Validate schema file
|
|
36103
36362
|
*/
|
|
36104
|
-
async validateFile(
|
|
36363
|
+
async validateFile(path63) {
|
|
36105
36364
|
try {
|
|
36106
36365
|
this.logger.info(chalk.dim(" Validating..."));
|
|
36107
|
-
const validationResult = await validateSchemaFile(
|
|
36366
|
+
const validationResult = await validateSchemaFile(path63);
|
|
36108
36367
|
if (validationResult.isValid) {
|
|
36109
36368
|
this.logger.success(chalk.green(" \u2713 Validation passed"));
|
|
36110
|
-
const risks = await detectSchemaRisks(
|
|
36369
|
+
const risks = await detectSchemaRisks(path63);
|
|
36111
36370
|
if (risks.length > 0) {
|
|
36112
36371
|
this.logger.warn(` \u26A0\uFE0F ${risks.length} risk(s) detected`);
|
|
36113
36372
|
for (const risk of risks) {
|
|
@@ -36122,7 +36381,7 @@ var SchemaWatcher = class {
|
|
|
36122
36381
|
if (this.options.notifyOnError) {
|
|
36123
36382
|
await notifyDesktop({
|
|
36124
36383
|
title: "Schema Validation Failed",
|
|
36125
|
-
message: `${validationResult.errors.length} error(s) in ${
|
|
36384
|
+
message: `${validationResult.errors.length} error(s) in ${path63.split("/").pop()}`,
|
|
36126
36385
|
type: "error"
|
|
36127
36386
|
});
|
|
36128
36387
|
}
|
|
@@ -36341,7 +36600,7 @@ var TestWatcher = class {
|
|
|
36341
36600
|
persistent: true,
|
|
36342
36601
|
ignoreInitial: true
|
|
36343
36602
|
});
|
|
36344
|
-
this.watcher.on("add", (
|
|
36603
|
+
this.watcher.on("add", (path63) => this.handleFileEvent("add", path63)).on("change", (path63) => this.handleFileEvent("change", path63)).on("unlink", (path63) => this.handleFileEvent("unlink", path63)).on("error", (error) => this.handleError(error));
|
|
36345
36604
|
this.logger.success("\u2705 Test watcher started");
|
|
36346
36605
|
this.logger.info(chalk.dim(" Press Ctrl+C to stop\n"));
|
|
36347
36606
|
}
|
|
@@ -36362,26 +36621,26 @@ var TestWatcher = class {
|
|
|
36362
36621
|
/**
|
|
36363
36622
|
* Handle file system events with debouncing
|
|
36364
36623
|
*/
|
|
36365
|
-
handleFileEvent(type,
|
|
36366
|
-
const existingTimer = this.debounceTimers.get(
|
|
36624
|
+
handleFileEvent(type, path63) {
|
|
36625
|
+
const existingTimer = this.debounceTimers.get(path63);
|
|
36367
36626
|
if (existingTimer) {
|
|
36368
36627
|
clearTimeout(existingTimer);
|
|
36369
36628
|
}
|
|
36370
36629
|
const timer = setTimeout(() => {
|
|
36371
|
-
this.processFileEvent(type,
|
|
36372
|
-
this.debounceTimers.delete(
|
|
36630
|
+
this.processFileEvent(type, path63);
|
|
36631
|
+
this.debounceTimers.delete(path63);
|
|
36373
36632
|
}, this.options.debounceMs);
|
|
36374
|
-
this.debounceTimers.set(
|
|
36633
|
+
this.debounceTimers.set(path63, timer);
|
|
36375
36634
|
}
|
|
36376
36635
|
/**
|
|
36377
36636
|
* Process file system event
|
|
36378
36637
|
*/
|
|
36379
|
-
async processFileEvent(type,
|
|
36638
|
+
async processFileEvent(type, path63) {
|
|
36380
36639
|
if (this.isRunning) {
|
|
36381
36640
|
this.logger.warn(chalk.yellow("\u23F3 Tests already running, skipping..."));
|
|
36382
36641
|
return;
|
|
36383
36642
|
}
|
|
36384
|
-
const fileName =
|
|
36643
|
+
const fileName = path63.split("/").pop() || path63;
|
|
36385
36644
|
switch (type) {
|
|
36386
36645
|
case "add":
|
|
36387
36646
|
this.logger.info(chalk.green(`\u2795 Test added: ${fileName}`));
|
|
@@ -36394,7 +36653,7 @@ var TestWatcher = class {
|
|
|
36394
36653
|
return;
|
|
36395
36654
|
}
|
|
36396
36655
|
if (this.options.autoRun) {
|
|
36397
|
-
await this.runTests(
|
|
36656
|
+
await this.runTests(path63);
|
|
36398
36657
|
}
|
|
36399
36658
|
}
|
|
36400
36659
|
/**
|