@runa-ai/runa-cli 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/{chunk-Y5ANTCKE.js → chunk-EZ46JIEO.js} +5 -2
  2. package/dist/{chunk-ZWDWFMOX.js → chunk-HWR5NUUZ.js} +24 -3
  3. package/dist/{chunk-OXQISY3J.js → chunk-IR7SA2ME.js} +1 -1
  4. package/dist/{chunk-QDOR3GTD.js → chunk-LCJNIHZY.js} +82 -14
  5. package/dist/{chunk-JQXOVCOP.js → chunk-NIS77243.js} +8 -5
  6. package/dist/{chunk-URWDB7YL.js → chunk-O3M7A73M.js} +58 -2
  7. package/dist/{chunk-PAWNJA3N.js → chunk-XFXGFUAM.js} +1 -1
  8. package/dist/{chunk-IEKYTCYA.js → chunk-YTQS2O4H.js} +59 -0
  9. package/dist/{ci-FLTJ2UXB.js → ci-6XYG7XNX.js} +5 -5
  10. package/dist/{cli-THEA6T7N.js → cli-2XL3VESS.js} +14 -14
  11. package/dist/commands/build/contract.d.ts +2 -2
  12. package/dist/commands/build/machine.d.ts +6 -6
  13. package/dist/commands/ci/commands/ci-prod-types.d.ts +1 -1
  14. package/dist/commands/ci/machine/contract.d.ts +10 -10
  15. package/dist/commands/ci/machine/machine.d.ts +3 -3
  16. package/dist/commands/ci/utils/ci-summary.d.ts +3 -3
  17. package/dist/commands/db/apply/contract.d.ts +1 -1
  18. package/dist/commands/db/apply/helpers/pg-schema-diff-helpers.d.ts +6 -0
  19. package/dist/commands/db/apply/helpers/planner-artifact.d.ts +1 -1
  20. package/dist/commands/db/commands/db-preview-profile.d.ts +1 -1
  21. package/dist/commands/db/commands/db-sync/production-precheck.d.ts +0 -8
  22. package/dist/commands/db/preflight/contract.d.ts +1 -1
  23. package/dist/commands/db/sync/contract.d.ts +5 -5
  24. package/dist/commands/db/sync/machine.d.ts +2 -2
  25. package/dist/commands/db/sync/schema-guardrail-graph-guidance.d.ts +18 -1
  26. package/dist/commands/db/sync/schema-guardrail-graph-metadata.d.ts +1 -7
  27. package/dist/commands/db/sync/schema-guardrail-graph-nodes.d.ts +1 -1
  28. package/dist/commands/db/sync/schema-guardrail-graph-sql-helpers.d.ts +1 -1
  29. package/dist/commands/db/sync/schema-guardrail-types.d.ts +4 -2
  30. package/dist/commands/db/utils/changed-files-detector.d.ts +21 -0
  31. package/dist/commands/db/utils/duplicate-function-ownership-allowlist.d.ts +13 -0
  32. package/dist/commands/db/utils/schema-sync.d.ts +12 -0
  33. package/dist/commands/db/utils/sql-boundary-parser.d.ts +13 -0
  34. package/dist/commands/db/utils/sql-file-collector.d.ts +2 -0
  35. package/dist/commands/upgrade.d.ts +36 -0
  36. package/dist/constants/versions.d.ts +9 -0
  37. package/dist/{db-IDKQ44VX.js → db-4AGPISOW.js} +1560 -1006
  38. package/dist/{dev-LGSMDFJN.js → dev-QR55VDNZ.js} +1 -1
  39. package/dist/{error-handler-YRQWRDEF.js → error-handler-XUQOP4TU.js} +1 -2
  40. package/dist/{hotfix-RJIAPLAM.js → hotfix-JYHDY2M6.js} +1 -2
  41. package/dist/index.js +4 -4
  42. package/dist/{init-2O6ODG5Z.js → init-4UAWYY75.js} +1 -1
  43. package/dist/{license-OB7GVJQ2.js → license-M6ODBV4X.js} +140 -154
  44. package/dist/pg-schema-diff-helpers-JZO4GAQG.js +7 -0
  45. package/dist/{risk-detector-S7XQF4I2.js → risk-detector-GDDLISVE.js} +1 -1
  46. package/dist/{risk-detector-core-TGFKWHRS.js → risk-detector-core-YI3M6INI.js} +1 -1
  47. package/dist/{risk-detector-plpgsql-O32TUR34.js → risk-detector-plpgsql-4GWEQXUG.js} +1 -1
  48. package/dist/{template-check-VNNQQXCX.js → template-check-D35F2GDP.js} +4 -0
  49. package/dist/{upgrade-QZKEI3NJ.js → upgrade-X7P6WRD5.js} +190 -20
  50. package/dist/utils/license/index.d.ts +15 -24
  51. package/dist/utils/license/types.d.ts +3 -4
  52. package/dist/utils/template-access.d.ts +20 -0
  53. package/dist/utils/template-fetcher.d.ts +10 -7
  54. package/dist/{vuln-check-JRPMUHLF.js → vuln-check-LMDYYJUE.js} +1 -1
  55. package/dist/{vuln-checker-Q7LSHUHJ.js → vuln-checker-NHXLNZRM.js} +1 -1
  56. package/dist/{watch-RFVCEQLH.js → watch-4RHXVCQ3.js} +1 -1
  57. package/package.json +3 -3
  58. package/dist/chunk-ZZOXM6Q4.js +0 -8
  59. package/dist/pg-schema-diff-helpers-7377FS2D.js +0 -7
@@ -512,10 +512,13 @@ function buildExecuteExpressionInfo(body, statementStartOffset, state) {
512
512
  }
513
513
  function parseExecuteExpressionAt(body, statementStartOffset) {
514
514
  const indexCursor = skipWhitespace(body, statementStartOffset + 7);
515
- if (isQuoteBoundary(body, indexCursor, "ON")) {
515
+ const ignoredKeyword = ["ON", "FUNCTION", "PROCEDURE"].find(
516
+ (keyword) => isQuoteBoundary(body, indexCursor, keyword)
517
+ );
518
+ if (ignoredKeyword) {
516
519
  return {
517
520
  info: null,
518
- nextCursor: Math.max(indexCursor + 2, statementStartOffset + 1)
521
+ nextCursor: Math.max(indexCursor + ignoredKeyword.length, statementStartOffset + 1)
519
522
  };
520
523
  }
521
524
  const state = {
@@ -2,10 +2,10 @@
2
2
  import { createRequire } from 'module';
3
3
  import { blankDollarQuotedBodies, stripSqlComments, psqlSyncQuery, parsePostgresUrl, buildPsqlArgs, buildPsqlEnv } from './chunk-A6A7JIRD.js';
4
4
  import { init_esm_shims } from './chunk-VRXHCR5K.js';
5
+ import { existsSync, readdirSync, readFileSync } from 'fs';
5
6
  import path from 'path';
6
7
  import { execFileSync, spawnSync, spawn } from 'child_process';
7
8
  import { createCLILogger } from '@runa-ai/runa';
8
- import { existsSync, readdirSync, readFileSync } from 'fs';
9
9
 
10
10
  createRequire(import.meta.url);
11
11
 
@@ -473,6 +473,7 @@ function collectWarningsForStatement(statement, file, line, knownFunctionNames)
473
473
 
474
474
  // src/commands/db/utils/sql-boundary-parser.ts
475
475
  init_esm_shims();
476
+ var ALLOW_DYNAMIC_SQL_ANNOTATION = /--\s*runa:allow-dynamic-sql\b/;
476
477
  var DOLLAR_QUOTE_PATTERN = /^\$([A-Za-z_][A-Za-z0-9_]*)?\$/;
477
478
  function countNewlines2(text) {
478
479
  let count = 0;
@@ -1204,6 +1205,20 @@ function detectMissingExtensionType(errorOutput) {
1204
1205
  suggestedExtensions: [...extensions]
1205
1206
  };
1206
1207
  }
1208
+ function detectExtensionFilePath() {
1209
+ const defaultPath = "supabase/schemas/idempotent/00_extensions.sql";
1210
+ const idempotentDir = path.join(process.cwd(), "supabase", "schemas", "idempotent");
1211
+ if (!existsSync(idempotentDir)) return defaultPath;
1212
+ try {
1213
+ const files = readdirSync(idempotentDir).filter((f) => f.endsWith(".sql"));
1214
+ const extensionFile = files.find((f) => /extension/i.test(f));
1215
+ if (extensionFile) {
1216
+ return path.posix.join("supabase", "schemas", "idempotent", extensionFile);
1217
+ }
1218
+ } catch {
1219
+ }
1220
+ return defaultPath;
1221
+ }
1207
1222
  function formatExtensionErrorHint(detection) {
1208
1223
  if (!detection.detected) return "";
1209
1224
  const lines = [];
@@ -1214,8 +1229,14 @@ function formatExtensionErrorHint(detection) {
1214
1229
  lines.push(` type "${type}" \u2192 extension: ${ext ?? "unknown"}`);
1215
1230
  }
1216
1231
  if (detection.suggestedExtensions.length > 0) {
1232
+ const extensionFile = detectExtensionFilePath();
1233
+ const fileExists = existsSync(path.join(process.cwd(), extensionFile));
1217
1234
  lines.push("");
1218
- lines.push("Fix 1: Add to supabase/schemas/idempotent/00_extensions.sql:");
1235
+ if (fileExists) {
1236
+ lines.push(`Fix 1: Add to ${extensionFile}:`);
1237
+ } else {
1238
+ lines.push(`Fix 1: Create ${extensionFile} (or add to your existing extension file):`);
1239
+ }
1219
1240
  for (const ext of detection.suggestedExtensions) {
1220
1241
  lines.push(` CREATE EXTENSION IF NOT EXISTS ${ext};`);
1221
1242
  }
@@ -1511,4 +1532,4 @@ function executePgSchemaDiffPlan(dbUrl, schemasDir, includeSchemas, verbose, opt
1511
1532
  throw new Error("pg-schema-diff plan failed after all retries");
1512
1533
  }
1513
1534
 
1514
- export { DB_APPLY_CHECK_MODE_CONTRACT_NOTE, FUNCTION_DEFINITION_RE, HAZARD_REGEX, MAX_DETAILED_DECLARATIVE_WARNINGS, PG_SCHEMA_DIFF_APPLY_TIMEOUT_MS, PUBLIC_SCHEMA, STATEMENT_IDX_REGEX, analyzeDeclarativeDependencyContract, blankQuotedStrings, buildIdleConnectionCleanupSql, collectSqlFiles, countNewlines, detectDropTableStatements, detectMissingExtensionType, detectMissingQualifiedFunction, detectPartitionPrivilegeError, detectPgSchemaDiffVersion, executePgSchemaDiffPlan, extractDdlObject, extractFirstDollarBody, formatDeclarativeDependencyBoundaryHint, formatDeclarativeDependencyViolation, formatDeclarativeDependencyWarning, formatExtensionErrorHint, formatPartitionPrivilegeHint, freeConnectionSlotsForPgSchemaDiff, hasUnparsedHazardHints, isNonDdlMaintenanceStatement, isNonSchemaOperation, parseSqlFilename, sanitizeExecutableCode, sanitizeExecutableCodePreserveStrings, shouldReviewUnknownDeclarativeDdl, shouldReviewUnknownIdempotentDdl, splitSqlStatements, startConnectionCleanupDaemon, stopConnectionCleanupDaemon, summarizeDeclarativeDependencyWarnings, verifyDatabaseConnection, verifyPgSchemaDiffBinary };
1535
+ export { ALLOW_DYNAMIC_SQL_ANNOTATION, DB_APPLY_CHECK_MODE_CONTRACT_NOTE, FUNCTION_DEFINITION_RE, HAZARD_REGEX, MAX_DETAILED_DECLARATIVE_WARNINGS, PG_SCHEMA_DIFF_APPLY_TIMEOUT_MS, PUBLIC_SCHEMA, STATEMENT_IDX_REGEX, analyzeDeclarativeDependencyContract, blankQuotedStrings, buildIdleConnectionCleanupSql, collectSqlFiles, countNewlines, detectDropTableStatements, detectExtensionFilePath, detectMissingExtensionType, detectMissingQualifiedFunction, detectPartitionPrivilegeError, detectPgSchemaDiffVersion, executePgSchemaDiffPlan, extractDdlObject, extractFirstDollarBody, formatDeclarativeDependencyBoundaryHint, formatDeclarativeDependencyViolation, formatDeclarativeDependencyWarning, formatExtensionErrorHint, formatPartitionPrivilegeHint, freeConnectionSlotsForPgSchemaDiff, hasUnparsedHazardHints, isNonDdlMaintenanceStatement, isNonSchemaOperation, parseSqlFilename, sanitizeExecutableCode, sanitizeExecutableCodePreserveStrings, shouldReviewUnknownDeclarativeDdl, shouldReviewUnknownIdempotentDdl, splitSqlStatements, startConnectionCleanupDaemon, stopConnectionCleanupDaemon, summarizeDeclarativeDependencyWarnings, verifyDatabaseConnection, verifyPgSchemaDiffBinary };
@@ -6,7 +6,7 @@ createRequire(import.meta.url);
6
6
 
7
7
  // src/version.ts
8
8
  init_esm_shims();
9
- var CLI_VERSION = "0.10.0";
9
+ var CLI_VERSION = "0.10.2";
10
10
  var HAS_ADMIN_COMMAND = false;
11
11
 
12
12
  export { CLI_VERSION, HAS_ADMIN_COMMAND };
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module';
3
3
  import { resolveDatabaseUrl, resolveDatabaseTarget } from './chunk-WGRVAGSR.js';
4
- import { verifyPgSchemaDiffBinary, verifyDatabaseConnection, freeConnectionSlotsForPgSchemaDiff, executePgSchemaDiffPlan, detectDropTableStatements, analyzeDeclarativeDependencyContract, DB_APPLY_CHECK_MODE_CONTRACT_NOTE, formatDeclarativeDependencyViolation, summarizeDeclarativeDependencyWarnings, MAX_DETAILED_DECLARATIVE_WARNINGS, formatDeclarativeDependencyWarning, detectPgSchemaDiffVersion, STATEMENT_IDX_REGEX, hasUnparsedHazardHints, collectSqlFiles, splitSqlStatements, PG_SCHEMA_DIFF_APPLY_TIMEOUT_MS, HAZARD_REGEX, PUBLIC_SCHEMA, FUNCTION_DEFINITION_RE } from './chunk-ZWDWFMOX.js';
5
- import { splitPlpgsqlStatementsWithOffsets, extractExecuteExpressions, extractStaticSqlFromExpression } from './chunk-Y5ANTCKE.js';
4
+ import { verifyPgSchemaDiffBinary, verifyDatabaseConnection, freeConnectionSlotsForPgSchemaDiff, executePgSchemaDiffPlan, detectDropTableStatements, analyzeDeclarativeDependencyContract, DB_APPLY_CHECK_MODE_CONTRACT_NOTE, formatDeclarativeDependencyViolation, summarizeDeclarativeDependencyWarnings, MAX_DETAILED_DECLARATIVE_WARNINGS, formatDeclarativeDependencyWarning, detectPgSchemaDiffVersion, STATEMENT_IDX_REGEX, hasUnparsedHazardHints, collectSqlFiles, splitSqlStatements, PG_SCHEMA_DIFF_APPLY_TIMEOUT_MS, HAZARD_REGEX, PUBLIC_SCHEMA, FUNCTION_DEFINITION_RE } from './chunk-HWR5NUUZ.js';
5
+ import { splitPlpgsqlStatementsWithOffsets, extractExecuteExpressions, extractStaticSqlFromExpression } from './chunk-EZ46JIEO.js';
6
6
  import { loadEnvFiles } from './chunk-IWVXI5O4.js';
7
- import { CLI_VERSION } from './chunk-OXQISY3J.js';
8
- import { generateTablesManifest } from './chunk-URWDB7YL.js';
7
+ import { CLI_VERSION } from './chunk-IR7SA2ME.js';
8
+ import { generateTablesManifest } from './chunk-O3M7A73M.js';
9
9
  import { parsePostgresUrl, buildPsqlEnv, buildPsqlArgs, stripSqlComments, psqlSyncQuery, blankDollarQuotedBodies, psqlSyncBatch, psqlSyncFile } from './chunk-A6A7JIRD.js';
10
10
  import { init_local_supabase, buildLocalDatabaseUrl } from './chunk-QSEF4T3Y.js';
11
11
  import { emitJsonSuccess } from './chunk-KE6QJBZG.js';
@@ -2309,7 +2309,7 @@ function extractQualifiedNameAfterKeyword(sql, keywordPattern) {
2309
2309
  const rest = sql.slice(keywordMatch.index + keywordMatch[0].length);
2310
2310
  const nameMatch = rest.match(/^\s*["']?([A-Za-z_]\w*)["']?\s*\.\s*["']?([A-Za-z_]\w*)["']?/);
2311
2311
  if (!nameMatch) return null;
2312
- return `${nameMatch[1].replace(/"/g, "").toLowerCase()}.${nameMatch[2].replace(/"/g, "").toLowerCase()}`;
2312
+ return `${nameMatch[1]?.replace(/"/g, "").toLowerCase()}.${nameMatch[2]?.replace(/"/g, "").toLowerCase()}`;
2313
2313
  }
2314
2314
  function extractFkReferences(sql) {
2315
2315
  const refs = /* @__PURE__ */ new Set();
@@ -2317,7 +2317,7 @@ function extractFkReferences(sql) {
2317
2317
  /REFERENCES\s+["']?([A-Za-z_]\w*)["']?\s*\.\s*["']?([A-Za-z_]\w*)["']?\s*\(/gi
2318
2318
  )) {
2319
2319
  refs.add(
2320
- `${match[1].replace(/"/g, "").toLowerCase()}.${match[2].replace(/"/g, "").toLowerCase()}`
2320
+ `${match[1]?.replace(/"/g, "").toLowerCase()}.${match[2]?.replace(/"/g, "").toLowerCase()}`
2321
2321
  );
2322
2322
  }
2323
2323
  return [...refs];
@@ -2327,12 +2327,12 @@ function extractRelationRefsFromBody(sql) {
2327
2327
  for (const m of sql.matchAll(
2328
2328
  /\bFROM\s+["']?([A-Za-z_]\w*)["']?\s*\.\s*["']?([A-Za-z_]\w*)["']?/gi
2329
2329
  )) {
2330
- refs.add(`${m[1].replace(/"/g, "").toLowerCase()}.${m[2].replace(/"/g, "").toLowerCase()}`);
2330
+ refs.add(`${m[1]?.replace(/"/g, "").toLowerCase()}.${m[2]?.replace(/"/g, "").toLowerCase()}`);
2331
2331
  }
2332
2332
  for (const m of sql.matchAll(
2333
2333
  /["']?([A-Za-z_]\w*)["']?\s*\.\s*["']?([A-Za-z_]\w*)["']?\s*%ROWTYPE/gi
2334
2334
  )) {
2335
- refs.add(`${m[1].replace(/"/g, "").toLowerCase()}.${m[2].replace(/"/g, "").toLowerCase()}`);
2335
+ refs.add(`${m[1]?.replace(/"/g, "").toLowerCase()}.${m[2]?.replace(/"/g, "").toLowerCase()}`);
2336
2336
  }
2337
2337
  return [...refs];
2338
2338
  }
@@ -2404,7 +2404,7 @@ function analyzeWithRegexFallback(strippedSql) {
2404
2404
  const match = strippedSql.match(
2405
2405
  /(?:CREATE|ALTER|DROP)\s+POLICY\s+.*?\bON\s+["']?([A-Za-z_]\w*)["']?\s*\.\s*["']?([A-Za-z_]\w*)["']?/i
2406
2406
  );
2407
- const key = match ? `${match[1].replace(/"/g, "").toLowerCase()}.${match[2].replace(/"/g, "").toLowerCase()}` : null;
2407
+ const key = match ? `${match[1]?.replace(/"/g, "").toLowerCase()}.${match[2]?.replace(/"/g, "").toLowerCase()}` : null;
2408
2408
  return {
2409
2409
  ...buildBaseStatementAnalysis(strippedSql, "relation"),
2410
2410
  targetKey: key,
@@ -2565,7 +2565,7 @@ function stabilizeAnalyzedPlanOrder(analyzedPlan) {
2565
2565
  const groupedStatements = /* @__PURE__ */ new Set();
2566
2566
  const deferredTriggerStatements = [];
2567
2567
  const createdFunctionKeys = new Set(
2568
- analyzedPlan.statements.filter((s) => s.objectKind === "function" && s.targetFunctionKey).map((s) => s.targetFunctionKey.toLowerCase())
2568
+ analyzedPlan.statements.filter((s) => s.objectKind === "function" && s.targetFunctionKey).map((s) => s.targetFunctionKey?.toLowerCase())
2569
2569
  );
2570
2570
  for (const statement of analyzedPlan.statements) {
2571
2571
  if (statement.phase === 50 && statement.functionDependencies.some((fn) => createdFunctionKeys.has(fn.toLowerCase()))) {
@@ -3322,7 +3322,30 @@ async function createShadowDbWithExtensions(config) {
3322
3322
  // Extensions like PostGIS can take time
3323
3323
  });
3324
3324
  if (extResult.status !== 0) {
3325
- logger7.warn(`Some extensions failed to install: ${extResult.stderr}`);
3325
+ const stderr = extResult.stderr?.trim() ?? "";
3326
+ logger7.error(`Shadow DB extension installation failed: ${stderr}`);
3327
+ logger7.error("Configured extensions may not be available in the target PostgreSQL server.");
3328
+ logger7.error("Check that the extensions are installed on the server:");
3329
+ for (const ext of extensions) {
3330
+ logger7.error(` SELECT * FROM pg_available_extensions WHERE name = '${ext}';`);
3331
+ }
3332
+ logger7.error(
3333
+ "If running locally with Supabase, ensure extensions are enabled in the dashboard."
3334
+ );
3335
+ }
3336
+ const verifyResult = psqlSyncQuery({
3337
+ databaseUrl: shadowDsn,
3338
+ sql: `SELECT extname FROM pg_extension WHERE extname = ANY(ARRAY[${extensions.map((e) => `'${e}'`).join(",")}])`,
3339
+ timeout: 1e4
3340
+ });
3341
+ if (verifyResult.status === 0) {
3342
+ const installed = (verifyResult.stdout ?? "").split("\n").map((l) => l.trim()).filter(Boolean);
3343
+ const missing = extensions.filter((ext) => !installed.includes(ext));
3344
+ if (missing.length > 0) {
3345
+ logger7.warn(
3346
+ `Shadow DB missing extensions: ${missing.join(", ")}. pg-schema-diff may fail on extension-defined types (geometry, vector, etc.).`
3347
+ );
3348
+ }
3326
3349
  }
3327
3350
  bootstrapShadowDbSchemaPrerequisites(sourceDbUrl, shadowDsn);
3328
3351
  logger7.debug(`Shadow database ready with extensions: ${extensions.join(", ")}`);
@@ -5176,7 +5199,7 @@ function logIdempotentRiskSummary(summary) {
5176
5199
  async function detectIdempotentRiskSummary(schemasDir, files, verbose) {
5177
5200
  const summary = emptyRiskSummary();
5178
5201
  try {
5179
- const { detectSchemaRisks } = await import('./risk-detector-S7XQF4I2.js');
5202
+ const { detectSchemaRisks } = await import('./risk-detector-GDDLISVE.js');
5180
5203
  for (const file of files) {
5181
5204
  const filePath = join(schemasDir, file);
5182
5205
  const risks = await detectSchemaRisks(filePath);
@@ -7203,11 +7226,54 @@ async function applyWithRetry(params) {
7203
7226
  retryWaitMs: result.totalWaitMs
7204
7227
  };
7205
7228
  }
7229
+ function autoDetectRequiredExtensions(targetDir) {
7230
+ const EXTENSION_TYPE_KEYWORDS = {
7231
+ geometry: "postgis",
7232
+ geography: "postgis",
7233
+ box2d: "postgis",
7234
+ box3d: "postgis",
7235
+ raster: "postgis_raster",
7236
+ vector: "vector",
7237
+ halfvec: "vector",
7238
+ sparsevec: "vector",
7239
+ citext: "citext",
7240
+ hstore: "hstore",
7241
+ ltree: "ltree"
7242
+ };
7243
+ const declarativeDir = join(targetDir, "supabase", "schemas", "declarative");
7244
+ if (!existsSync(declarativeDir)) return [];
7245
+ const detected = /* @__PURE__ */ new Set();
7246
+ try {
7247
+ const files = readdirSync(declarativeDir).filter((f) => f.endsWith(".sql"));
7248
+ for (const file of files) {
7249
+ const content = readFileSync(join(declarativeDir, file), "utf-8").toLowerCase();
7250
+ for (const [typeName, extName] of Object.entries(EXTENSION_TYPE_KEYWORDS)) {
7251
+ if (content.includes(typeName)) {
7252
+ detected.add(extName);
7253
+ }
7254
+ }
7255
+ }
7256
+ } catch {
7257
+ }
7258
+ return [...detected].sort();
7259
+ }
7260
+ function resolveEffectiveShadowExtensions(configured, targetDir, verbose) {
7261
+ if (configured && configured.length > 0) return configured;
7262
+ const autoDetected = autoDetectRequiredExtensions(targetDir);
7263
+ if (autoDetected.length > 0 && verbose) {
7264
+ logger13.debug(`Auto-detected shadow DB extensions from SQL: ${autoDetected.join(", ")}`);
7265
+ }
7266
+ return autoDetected.length > 0 ? autoDetected : void 0;
7267
+ }
7206
7268
  function loadPgSchemaDiffConfigState(targetDir, verbose) {
7207
7269
  try {
7208
7270
  const config = loadRunaConfig(targetDir);
7209
7271
  return {
7210
- shadowExtensions: config.database?.pgSchemaDiff?.shadowDbExtensions,
7272
+ shadowExtensions: resolveEffectiveShadowExtensions(
7273
+ config.database?.pgSchemaDiff?.shadowDbExtensions,
7274
+ targetDir,
7275
+ verbose
7276
+ ),
7211
7277
  configExclusions: config.database?.pgSchemaDiff?.excludeFromOrphanDetection ? [...config.database.pgSchemaDiff.excludeFromOrphanDetection] : void 0,
7212
7278
  schemaCheckExclusions: config.database?.pgSchemaDiff?.excludeFromSchemaCheck ? [...config.database.pgSchemaDiff.excludeFromSchemaCheck] : void 0
7213
7279
  };
@@ -7215,7 +7281,9 @@ function loadPgSchemaDiffConfigState(targetDir, verbose) {
7215
7281
  if (verbose) {
7216
7282
  logger13.debug("Could not load runa.config.ts - continuing without extension support");
7217
7283
  }
7218
- return {};
7284
+ return {
7285
+ shadowExtensions: resolveEffectiveShadowExtensions(void 0, targetDir, verbose)
7286
+ };
7219
7287
  }
7220
7288
  }
7221
7289
  function createPrefilterState(schemasDir, verbose, configExclusions) {
@@ -132,12 +132,12 @@ var ERROR_CATALOG = {
132
132
  LICENSE_UNAUTHORIZED: {
133
133
  code: "ERR_RUNA_LICENSE_UNAUTHORIZED",
134
134
  exitCode: EXIT_CODES.AUTH_ERROR,
135
- title: "CI access not authorized",
136
- template: 'Organization "{owner}" is not authorized to use runa CI',
135
+ title: "Legacy CI access policy denied command",
136
+ template: 'Legacy CI access policy denied runa execution for "{owner}"',
137
137
  suggestions: [
138
- "Install GitHub App: https://github.com/apps/runa-app",
139
- "Contact runa admin for approval",
140
- "Local development is not affected"
138
+ "Upgrade to the latest @runa-ai/runa-cli",
139
+ "Public runa CLI/SDK/plugin commands should not require CI allowlist approval",
140
+ "Template operations use separate repository-access checks"
141
141
  ],
142
142
  docUrl: "https://runa.dev/docs/errors/license-unauthorized"
143
143
  },
@@ -571,4 +571,7 @@ function interpolateTemplate(template, params) {
571
571
  });
572
572
  }
573
573
 
574
+ // src/errors/index.ts
575
+ init_esm_shims();
576
+
574
577
  export { ERROR_CATALOG, createError };
@@ -231,6 +231,32 @@ function extractTablesFromIdempotentSql(idempotentDir, projectRoot = process.cwd
231
231
  }
232
232
  return [...new Set(tables)].sort();
233
233
  }
234
+ function extractDynamicTablePatternsFromIdempotentSql(idempotentDir, projectRoot = process.cwd()) {
235
+ const fullPath = path.resolve(projectRoot, idempotentDir);
236
+ if (!existsSync(fullPath)) {
237
+ return [];
238
+ }
239
+ const patterns = [];
240
+ const prefixInFormat = /EXECUTE\s+format\s*\(\s*'CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:"?([a-zA-Z_][a-zA-Z0-9_]*)"?\.)?([a-zA-Z_][a-zA-Z0-9_]*)%[sI]/gi;
241
+ try {
242
+ const files = readdirSync(fullPath).filter((f) => f.endsWith(".sql"));
243
+ for (const file of files) {
244
+ const filePath = path.join(fullPath, file);
245
+ const content = readFileSync(filePath, "utf-8");
246
+ const cleaned = content.replace(/--.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
247
+ for (const match of cleaned.matchAll(prefixInFormat)) {
248
+ const schema = match[1] || "public";
249
+ const prefix = match[2];
250
+ if (prefix && prefix.length >= 2) {
251
+ patterns.push(`${schema}.${prefix}*`);
252
+ }
253
+ }
254
+ }
255
+ } catch {
256
+ return [];
257
+ }
258
+ return [...new Set(patterns)].sort();
259
+ }
234
260
 
235
261
  // src/commands/db/utils/table-registry.ts
236
262
  init_esm_shims();
@@ -1686,8 +1712,16 @@ function resolveSourceConfig(projectRoot, options) {
1686
1712
  }
1687
1713
  } catch {
1688
1714
  }
1715
+ const resolvedIdempotentDir = isAbsolute(idempotentSqlDir) ? idempotentSqlDir : join(projectRoot, idempotentSqlDir);
1716
+ const dynamicPatterns = extractDynamicTablePatternsFromIdempotentSql(
1717
+ resolvedIdempotentDir,
1718
+ projectRoot
1719
+ );
1720
+ for (const pattern of dynamicPatterns) {
1721
+ exclusions.add(pattern);
1722
+ }
1689
1723
  return {
1690
- idempotentSqlDir: isAbsolute(idempotentSqlDir) ? idempotentSqlDir : join(projectRoot, idempotentSqlDir),
1724
+ idempotentSqlDir: resolvedIdempotentDir,
1691
1725
  excludeFromOrphanDetection: [...exclusions].sort((a, b) => a.localeCompare(b))
1692
1726
  };
1693
1727
  }
@@ -1918,9 +1952,31 @@ async function generateTablesManifest(projectRoot, options = {}) {
1918
1952
  }
1919
1953
  writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}
1920
1954
  `);
1955
+ validateManifestSourceFiles(manifest, projectRoot);
1921
1956
  logManifestSummary(manifest, mappingResult.conflicts);
1922
1957
  return manifest;
1923
1958
  }
1959
+ function validateManifestSourceFiles(manifest, projectRoot) {
1960
+ const staleEntries = [];
1961
+ for (const table of manifest.tables) {
1962
+ if (!table.sourceFile) continue;
1963
+ const absolutePath = join(projectRoot, table.sourceFile);
1964
+ if (!existsSync(absolutePath)) {
1965
+ staleEntries.push({ table: table.qualifiedName, sourceFile: table.sourceFile });
1966
+ }
1967
+ }
1968
+ if (staleEntries.length === 0) return;
1969
+ console.warn(
1970
+ `[tables-manifest] warn: ${staleEntries.length} table(s) reference non-existent sourceFile:`
1971
+ );
1972
+ for (const entry of staleEntries.slice(0, 5)) {
1973
+ console.warn(` ${entry.table} \u2192 ${entry.sourceFile} (file not found)`);
1974
+ }
1975
+ if (staleEntries.length > 5) {
1976
+ console.warn(` ... and ${staleEntries.length - 5} more`);
1977
+ }
1978
+ console.warn(" \u2192 If files were moved, re-run `runa db sync` to update sourceFile references.");
1979
+ }
1924
1980
  function logManifestSummary(manifest, conflicts) {
1925
1981
  const tableCount = manifest.tables.length;
1926
1982
  const schemas = [...new Set(manifest.tables.map((t) => t.schema))];
@@ -1975,4 +2031,4 @@ function logManifestSummary(manifest, conflicts) {
1975
2031
  console.log(" Path: .runa/manifests/tables.json\n");
1976
2032
  }
1977
2033
 
1978
- export { buildTablePatternMatcher, diffSchema, extractSchemaTablesAndEnums, extractTablesFromIdempotentSql, fetchDbTablesAndEnums, generateTablesManifest, getSqlParserUtils };
2034
+ export { buildTablePatternMatcher, diffSchema, extractDynamicTablePatternsFromIdempotentSql, extractSchemaTablesAndEnums, extractTablesFromIdempotentSql, fetchDbTablesAndEnums, generateTablesManifest, getSqlParserUtils };
@@ -9,7 +9,7 @@ init_esm_shims();
9
9
  var riskDetectorModulePromise = null;
10
10
  async function loadRiskDetectorModule() {
11
11
  if (!riskDetectorModulePromise) {
12
- riskDetectorModulePromise = import('./risk-detector-core-TGFKWHRS.js').catch((error) => {
12
+ riskDetectorModulePromise = import('./risk-detector-core-YI3M6INI.js').catch((error) => {
13
13
  riskDetectorModulePromise = null;
14
14
  throw error;
15
15
  });
@@ -19,6 +19,64 @@ init_esm_shims();
19
19
  var COMPATIBLE_TEMPLATES_VERSION = "0.7.3";
20
20
  var TEMPLATES_PACKAGE_NAME = "@r06-dev/runa-templates";
21
21
  var GITHUB_PACKAGES_REGISTRY = "https://npm.pkg.github.com";
22
+ var TEMPLATES_SOURCE_REPOSITORY = "r06-dev/runa";
23
+ var TEMPLATES_SOURCE_REPOSITORY_API_URL = `https://api.github.com/repos/${TEMPLATES_SOURCE_REPOSITORY}`;
24
+
25
+ // src/utils/template-access.ts
26
+ init_esm_shims();
27
+ var TEMPLATE_ACCESS_TIMEOUT_MS = 5e3;
28
+ var TEMPLATE_ACCESS_USER_AGENT = "runa-cli/template-access-check";
29
+ async function hasRepoAccessWithToken(token) {
30
+ const controller = new AbortController();
31
+ const timeoutId = setTimeout(() => controller.abort(), TEMPLATE_ACCESS_TIMEOUT_MS);
32
+ try {
33
+ const response = await fetch(TEMPLATES_SOURCE_REPOSITORY_API_URL, {
34
+ method: "GET",
35
+ headers: {
36
+ Authorization: `Bearer ${token}`,
37
+ Accept: "application/vnd.github+json",
38
+ "User-Agent": TEMPLATE_ACCESS_USER_AGENT
39
+ },
40
+ signal: controller.signal
41
+ });
42
+ return response.ok;
43
+ } catch {
44
+ return false;
45
+ } finally {
46
+ clearTimeout(timeoutId);
47
+ }
48
+ }
49
+ async function hasRepoAccessWithGh() {
50
+ try {
51
+ const result = await secureGh(["api", `repos/${TEMPLATES_SOURCE_REPOSITORY}`, "--silent"], {
52
+ reject: false,
53
+ timeout: TEMPLATE_ACCESS_TIMEOUT_MS,
54
+ stdio: "pipe"
55
+ });
56
+ return result.exitCode === 0;
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+ async function verifyTemplateRepoAccess() {
62
+ const explicitToken = process.env.NODE_AUTH_TOKEN?.trim();
63
+ if (explicitToken && await hasRepoAccessWithToken(explicitToken)) {
64
+ return;
65
+ }
66
+ if (await hasRepoAccessWithGh()) {
67
+ return;
68
+ }
69
+ throw new CLIError(
70
+ `Template operations require access to ${TEMPLATES_SOURCE_REPOSITORY}.`,
71
+ "TEMPLATE_REPO_ACCESS_REQUIRED",
72
+ [
73
+ `Use a GitHub account that can access https://github.com/${TEMPLATES_SOURCE_REPOSITORY}`,
74
+ "Authenticate with GitHub CLI: gh auth login",
75
+ "Or export NODE_AUTH_TOKEN from an authorized account",
76
+ "Normal runa CLI/SDK/plugin commands do not require this access"
77
+ ]
78
+ );
79
+ }
22
80
 
23
81
  // src/utils/template-fetcher.ts
24
82
  var SAFE_VERSION_PATTERN = /^[a-zA-Z0-9._-]+$/;
@@ -273,6 +331,7 @@ async function fetchTemplates(options = {}) {
273
331
  const version = options.version ?? COMPATIBLE_TEMPLATES_VERSION;
274
332
  const fresh = options.fresh ?? false;
275
333
  const verbose = options.verbose ?? false;
334
+ await verifyTemplateRepoAccess();
276
335
  const workspaceResult = getWorkspaceTemplatesResult(resolveWorkspaceTemplates(), verbose);
277
336
  if (workspaceResult) {
278
337
  return workspaceResult;
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module';
3
- import { normalizeDatabaseUrlForDdl, parseBoolish, enhanceConnectionError, isIdempotentRoleHazard, detectAppSchemas, formatSchemasForSql, getDbPlanArtifactPath, runDbApply } from './chunk-QDOR3GTD.js';
3
+ import { normalizeDatabaseUrlForDdl, parseBoolish, enhanceConnectionError, isIdempotentRoleHazard, detectAppSchemas, formatSchemasForSql, getDbPlanArtifactPath, runDbApply } from './chunk-LCJNIHZY.js';
4
4
  import './chunk-WGRVAGSR.js';
5
- import './chunk-ZWDWFMOX.js';
5
+ import './chunk-HWR5NUUZ.js';
6
6
  import './chunk-UHDAYPHH.js';
7
- import './chunk-Y5ANTCKE.js';
7
+ import './chunk-EZ46JIEO.js';
8
8
  import './chunk-IWVXI5O4.js';
9
- import './chunk-OXQISY3J.js';
9
+ import './chunk-IR7SA2ME.js';
10
10
  import './chunk-B7C7CLW2.js';
11
11
  import './chunk-QDF7QXBL.js';
12
12
  import { getSnapshotStateName, getSnapshotStatePaths, isSnapshotComplete } from './chunk-XVNDDHAF.js';
13
13
  import { createInitialSummary, resolveMode, appendGithubStepSummary, buildCiProdApplyStepSummaryMarkdown, setSummaryErrorFromUnknown, writeEnvLocal, startAppBackground, waitForAppReady, executePrSetupBase, createErrorOutput, requireCiAutoApprove, resolveProdApplyInputs, parseIntOr, classifyCiProdApplyError, addGithubMask } from './chunk-EXR4J2JT.js';
14
- import './chunk-URWDB7YL.js';
14
+ import './chunk-O3M7A73M.js';
15
15
  import { parsePostgresUrl, buildPsqlArgs, buildPsqlEnv, psqlSyncQuery } from './chunk-A6A7JIRD.js';
16
16
  import { ensureRunaTmpDir, runLogged } from './chunk-ELXXQIGW.js';
17
17
  import { createMachineStateChangeLogger } from './chunk-5FT3F36G.js';
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from 'module';
3
3
  import { enableNonInteractiveMode } from './chunk-6Y3LAUGL.js';
4
4
  import { getRequestedCommandNameFromArgv } from './chunk-UWWSAPDR.js';
5
- import { CLI_VERSION, HAS_ADMIN_COMMAND } from './chunk-OXQISY3J.js';
5
+ import { CLI_VERSION, HAS_ADMIN_COMMAND } from './chunk-IR7SA2ME.js';
6
6
  import { emitDefaultSuccessIfNeeded } from './chunk-WJXC4MVY.js';
7
7
  import { parseOutputFormat, setOutputFormat, getOutputFormatFromEnv } from './chunk-HKUWEGUX.js';
8
8
  import { init_esm_shims } from './chunk-VRXHCR5K.js';
@@ -145,7 +145,7 @@ function isTestCommand(requested) {
145
145
  async function registerProjectLifecycleCommands(program, requested, loadAllCommands) {
146
146
  if (!loadAllCommands && requested) {
147
147
  if (requested === "init") {
148
- const { initCommand: initCommand2 } = await import('./init-2O6ODG5Z.js');
148
+ const { initCommand: initCommand2 } = await import('./init-4UAWYY75.js');
149
149
  program.addCommand(initCommand2);
150
150
  return;
151
151
  }
@@ -155,7 +155,7 @@ async function registerProjectLifecycleCommands(program, requested, loadAllComma
155
155
  return;
156
156
  }
157
157
  if (requested === "upgrade") {
158
- const { upgradeCommand: upgradeCommand2 } = await import('./upgrade-QZKEI3NJ.js');
158
+ const { upgradeCommand: upgradeCommand2 } = await import('./upgrade-X7P6WRD5.js');
159
159
  program.addCommand(upgradeCommand2);
160
160
  return;
161
161
  }
@@ -170,7 +170,7 @@ async function registerProjectLifecycleCommands(program, requested, loadAllComma
170
170
  return;
171
171
  }
172
172
  if (requested === "dev") {
173
- const { devCommand: devCommand2 } = await import('./dev-LGSMDFJN.js');
173
+ const { devCommand: devCommand2 } = await import('./dev-QR55VDNZ.js');
174
174
  program.addCommand(devCommand2);
175
175
  return;
176
176
  }
@@ -183,12 +183,12 @@ async function registerProjectLifecycleCommands(program, requested, loadAllComma
183
183
  { buildCommand },
184
184
  { devCommand }
185
185
  ] = await Promise.all([
186
- import('./init-2O6ODG5Z.js'),
186
+ import('./init-4UAWYY75.js'),
187
187
  import('./prepare-32DOVHTE.js'),
188
- import('./upgrade-QZKEI3NJ.js'),
188
+ import('./upgrade-X7P6WRD5.js'),
189
189
  import('./validate-CAAW4Y44.js'),
190
190
  import('./build-P2A6345N.js'),
191
- import('./dev-LGSMDFJN.js')
191
+ import('./dev-QR55VDNZ.js')
192
192
  ]);
193
193
  program.addCommand(initCommand);
194
194
  program.addCommand(prepareCommand);
@@ -462,11 +462,11 @@ async function registerFocusedStatusUtilityCommand(program, requested) {
462
462
  return false;
463
463
  }
464
464
  async function registerCiCommand(program) {
465
- const { ciCommand } = await import('./ci-FLTJ2UXB.js');
465
+ const { ciCommand } = await import('./ci-6XYG7XNX.js');
466
466
  program.addCommand(ciCommand);
467
467
  }
468
468
  async function registerDbCommand(program) {
469
- const { dbCommand } = await import('./db-IDKQ44VX.js');
469
+ const { dbCommand } = await import('./db-4AGPISOW.js');
470
470
  program.addCommand(dbCommand);
471
471
  }
472
472
  async function registerServicesCommand(program) {
@@ -478,7 +478,7 @@ async function registerEnvCommand(program) {
478
478
  program.addCommand(envCommand);
479
479
  }
480
480
  async function registerHotfixCommand(program) {
481
- const { hotfixCommand } = await import('./hotfix-RJIAPLAM.js');
481
+ const { hotfixCommand } = await import('./hotfix-JYHDY2M6.js');
482
482
  program.addCommand(hotfixCommand);
483
483
  }
484
484
  async function registerSdkCommand(program) {
@@ -490,7 +490,7 @@ async function registerUiCommand(program) {
490
490
  program.addCommand(uiCommand);
491
491
  }
492
492
  async function registerWatchCommand(program) {
493
- const { watchCommand } = await import('./watch-RFVCEQLH.js');
493
+ const { watchCommand } = await import('./watch-4RHXVCQ3.js');
494
494
  program.addCommand(watchCommand);
495
495
  }
496
496
  async function registerWorkflowCommand(program) {
@@ -498,11 +498,11 @@ async function registerWorkflowCommand(program) {
498
498
  program.addCommand(workflowCommand);
499
499
  }
500
500
  async function registerVulnCheckCommand(program) {
501
- const { vulnCheckCommand } = await import('./vuln-check-JRPMUHLF.js');
501
+ const { vulnCheckCommand } = await import('./vuln-check-LMDYYJUE.js');
502
502
  program.addCommand(vulnCheckCommand);
503
503
  }
504
504
  async function registerTemplateCheckCommand(program) {
505
- const { templateCheckCommand } = await import('./template-check-VNNQQXCX.js');
505
+ const { templateCheckCommand } = await import('./template-check-D35F2GDP.js');
506
506
  program.addCommand(templateCheckCommand);
507
507
  }
508
508
  async function registerSessionCommands(program) {
@@ -708,7 +708,7 @@ async function executeProgram(program) {
708
708
  if (!isHelpOrVersion && shouldRunRuntimeBootstrap(argv)) {
709
709
  const [{ loadEnvFiles }, { enforceLicenseInCI }] = await Promise.all([
710
710
  import('./env-files-ONBC47I6.js'),
711
- import('./license-OB7GVJQ2.js')
711
+ import('./license-M6ODBV4X.js')
712
712
  ]);
713
713
  loadEnvFiles({
714
714
  silent: true
@@ -21,9 +21,9 @@ import { z } from 'zod';
21
21
  export declare const BuildPhaseSchema: z.ZodEnum<{
22
22
  db: "db";
23
23
  build: "build";
24
+ manifest: "manifest";
24
25
  lint: "lint";
25
26
  types: "types";
26
- manifest: "manifest";
27
27
  }>;
28
28
  export type BuildPhase = z.infer<typeof BuildPhaseSchema>;
29
29
  /** Valid build phases for --only option */
@@ -44,9 +44,9 @@ export declare const BuildInputSchema: z.ZodObject<{
44
44
  only: z.ZodOptional<z.ZodArray<z.ZodEnum<{
45
45
  db: "db";
46
46
  build: "build";
47
+ manifest: "manifest";
47
48
  lint: "lint";
48
49
  types: "types";
49
- manifest: "manifest";
50
50
  }>>>;
51
51
  }, z.core.$strict>;
52
52
  export type BuildInput = z.infer<typeof BuildInputSchema>;