@thelogicatelier/sylva 1.0.12 → 1.0.13

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.
@@ -83,21 +83,24 @@ async function braveSearch(query, options) {
83
83
  });
84
84
  if (!response.ok) {
85
85
  const statusText = response.statusText || "Unknown error";
86
+ const errorMsg = `HTTP ${response.status} (${statusText})`;
86
87
  if (response.status === 401 || response.status === 403) {
87
88
  console.warn(`❌ Brave Search API authentication failed (HTTP ${response.status}: ${statusText}).\n` +
88
89
  ` Your BRAVE_API_KEY may be invalid or expired.\n` +
89
90
  ` Get a valid key at: https://brave.com/search/api/\n` +
90
91
  ` Framework detection still works — only web doc references are affected.`);
92
+ throw new Error(`Authentication failed ${errorMsg}. Valid API key required.`);
91
93
  }
92
94
  else if (response.status === 429) {
93
95
  console.warn(`⚠️ Brave Search API rate limit exceeded (HTTP 429).\n` +
94
96
  ` Query: "${query}"\n` +
95
97
  ` Wait a moment and retry, or check your Brave API plan limits.`);
98
+ throw new Error(`Rate limit exceeded ${errorMsg}.`);
96
99
  }
97
100
  else {
98
101
  console.warn(`⚠️ Brave Search API returned HTTP ${response.status} (${statusText}) for query: "${query}"`);
102
+ throw new Error(`Brave Search API error: ${errorMsg}`);
99
103
  }
100
- return [];
101
104
  }
102
105
  const data = (await response.json());
103
106
  const webResults = data.web?.results || [];
@@ -120,10 +123,10 @@ async function braveSearch(query, options) {
120
123
  console.warn(`⚠️ Brave Search network error for query "${query}": ${errMsg}\n` +
121
124
  ` Check your internet connection. Framework detection is unaffected.`);
122
125
  }
123
- else {
126
+ else if (!errMsg.includes("HTTP")) {
124
127
  console.warn(`⚠️ Brave Search failed for query "${query}": ${errMsg}`);
125
128
  }
126
- return [];
129
+ throw error;
127
130
  }
128
131
  }
129
132
  /**
@@ -3,6 +3,7 @@
3
3
  * Deterministic — no LLM involvement.
4
4
  */
5
5
  import { Signal, StackInfo, ArchitectureModel, VersionInfo } from "./types";
6
+ /** Confidence scoring rules */
6
7
  /**
7
8
  * Detect stacks from signals.
8
9
  * Groups signals by frameworkId and scores confidence.
@@ -8,37 +8,8 @@ exports.detectStacks = detectStacks;
8
8
  exports.detectArchitecture = detectArchitecture;
9
9
  exports.formatVersionForDisplay = formatVersionForDisplay;
10
10
  const versionResolver_1 = require("./versionResolver");
11
+ const constants_1 = require("../constants");
11
12
  /** Confidence scoring rules */
12
- const CONFIDENCE_SCORES = {
13
- orchestrator: 95,
14
- angular: 85,
15
- react: 80,
16
- nextjs: 85,
17
- vue: 80,
18
- nuxt: 85,
19
- svelte: 80,
20
- sveltekit: 85,
21
- express: 75,
22
- nestjs: 85,
23
- fastify: 75,
24
- django: 85,
25
- flask: 75,
26
- fastapi: 80,
27
- "spring-boot": 90,
28
- spring: 80,
29
- "java-maven": 70,
30
- "java-gradle": 70,
31
- dotnet: 80,
32
- "aspnet-core": 85,
33
- go: 80,
34
- rust: 80,
35
- "actix-web": 85,
36
- axum: 85,
37
- nodejs: 60,
38
- python: 60,
39
- typescript: 65,
40
- docker: 50,
41
- };
42
13
  /**
43
14
  * Detect stacks from signals.
44
15
  * Groups signals by frameworkId and scores confidence.
@@ -55,7 +26,8 @@ function detectStacks(signals) {
55
26
  signal.kind === "cron" ||
56
27
  signal.kind === "hook" ||
57
28
  signal.kind === "skill" ||
58
- signal.kind === "plugin")
29
+ signal.kind === "plugin" ||
30
+ signal.kind === "integration")
59
31
  continue;
60
32
  if (!grouped.has(signal.frameworkId)) {
61
33
  grouped.set(signal.frameworkId, []);
@@ -65,7 +37,7 @@ function detectStacks(signals) {
65
37
  const stacks = [];
66
38
  for (const [frameworkId, frameworkSignals] of grouped) {
67
39
  const frameworkName = frameworkSignals[0].frameworkName;
68
- const confidence = CONFIDENCE_SCORES[frameworkId] || 50;
40
+ const confidence = constants_1.CONFIDENCE_SCORES[frameworkId] || 50;
69
41
  const version = (0, versionResolver_1.resolveVersion)(frameworkSignals);
70
42
  // Determine rootPath — use the shallowest signal's scope
71
43
  const rootPaths = frameworkSignals.map((s) => s.scope.pathRoot).filter(Boolean);
@@ -46,6 +46,7 @@ const manifestParsers_1 = require("./manifestParsers");
46
46
  const versionResolver_1 = require("./versionResolver");
47
47
  const detector_1 = require("./detector");
48
48
  const webGrounding_1 = require("./webGrounding");
49
+ const sourceScanner_1 = require("./sourceScanner");
49
50
  /**
50
51
  * The ARCHITECTURE CONSTRAINTS block injected into LLM context.
51
52
  * This is authoritative and must not be overridden by the model.
@@ -82,6 +83,15 @@ function buildConstraintsBlock(stacks, resolvedVersions, hasOrchestrator, signal
82
83
  if (hasOrchestrator) {
83
84
  appendOpenClawConstraints(lines, signals);
84
85
  }
86
+ // External Integrations (source code scanner)
87
+ const integrations = signals.filter((s) => s.kind === "integration");
88
+ if (integrations.length > 0) {
89
+ lines.push("", "EXTERNAL INTEGRATIONS (Discovered in Source Code):");
90
+ for (const sig of integrations) {
91
+ lines.push(` - ${sig.frameworkName}`);
92
+ lines.push(` Evidence: ${sig.evidence.reason} [${sig.evidence.file}]`);
93
+ }
94
+ }
85
95
  lines.push("=== END ARCHITECTURE CONSTRAINTS ===");
86
96
  return lines.join("\n");
87
97
  }
@@ -311,8 +321,16 @@ async function runAwareness(repoPath, repoName) {
311
321
  }
312
322
  // Step 2: Parse all manifests into signals
313
323
  console.log(" → Parsing manifests...");
314
- const signals = (0, manifestParsers_1.parseAllManifests)(manifests);
315
- console.log(` → Generated ${signals.length} signal(s)`);
324
+ const manifestSignals = (0, manifestParsers_1.parseAllManifests)(manifests);
325
+ console.log(` → Generated ${manifestSignals.length} signal(s) from manifests`);
326
+ // Step 2.5: Scan source code for external integrations
327
+ console.log(" → Scanning source code for external integrations...");
328
+ const integrationSignals = (0, sourceScanner_1.scanSourceFiles)(repoPath);
329
+ if (integrationSignals.length > 0) {
330
+ console.log(` → Discovered ${integrationSignals.length} integration(s) in source code`);
331
+ }
332
+ // Merge all signals
333
+ const signals = [...manifestSignals, ...integrationSignals];
316
334
  // Step 3: Resolve versions
317
335
  console.log(" → Resolving versions...");
318
336
  const resolvedVersions = (0, versionResolver_1.resolveAllVersions)(signals);
@@ -40,16 +40,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
40
40
  exports.parseGoMod = parseGoMod;
41
41
  const fs = __importStar(require("fs"));
42
42
  const path = __importStar(require("path"));
43
- /** Known Go frameworks/libraries */
44
- const GO_FRAMEWORKS = [
45
- { module: "github.com/gin-gonic/gin", frameworkId: "gin", frameworkName: "Gin" },
46
- { module: "github.com/labstack/echo", frameworkId: "echo", frameworkName: "Echo" },
47
- { module: "github.com/gofiber/fiber", frameworkId: "fiber", frameworkName: "Fiber" },
48
- { module: "github.com/gorilla/mux", frameworkId: "gorilla-mux", frameworkName: "Gorilla Mux" },
49
- { module: "gorm.io/gorm", frameworkId: "gorm", frameworkName: "GORM" },
50
- { module: "github.com/stretchr/testify", frameworkId: "testify", frameworkName: "Testify" },
51
- { module: "google.golang.org/grpc", frameworkId: "grpc-go", frameworkName: "gRPC-Go" },
52
- ];
43
+ const constants_1 = require("../../constants");
53
44
  /**
54
45
  * Parse go.mod
55
46
  */
@@ -117,7 +108,7 @@ function parseGoMod(manifest) {
117
108
  continue;
118
109
  const modulePath = match[1];
119
110
  const version = match[2];
120
- const framework = GO_FRAMEWORKS.find((f) => modulePath.startsWith(f.module));
111
+ const framework = constants_1.GO_FRAMEWORKS.find((f) => modulePath.startsWith(f.module));
121
112
  if (framework) {
122
113
  signals.push({
123
114
  kind: "framework",
@@ -41,25 +41,7 @@ exports.parsePomXml = parsePomXml;
41
41
  exports.parseBuildGradle = parseBuildGradle;
42
42
  const fs = __importStar(require("fs"));
43
43
  const path = __importStar(require("path"));
44
- /** Known Java frameworks */
45
- const JAVA_FRAMEWORKS = [
46
- {
47
- groupArtifact: "org.springframework.boot",
48
- frameworkId: "spring-boot",
49
- frameworkName: "Spring Boot",
50
- },
51
- {
52
- groupArtifact: "org.springframework",
53
- frameworkId: "spring",
54
- frameworkName: "Spring Framework",
55
- },
56
- { groupArtifact: "io.quarkus", frameworkId: "quarkus", frameworkName: "Quarkus" },
57
- { groupArtifact: "io.micronaut", frameworkId: "micronaut", frameworkName: "Micronaut" },
58
- { groupArtifact: "org.hibernate", frameworkId: "hibernate", frameworkName: "Hibernate" },
59
- { groupArtifact: "junit", frameworkId: "junit", frameworkName: "JUnit" },
60
- { groupArtifact: "org.junit", frameworkId: "junit5", frameworkName: "JUnit 5" },
61
- { groupArtifact: "org.apache.kafka", frameworkId: "kafka", frameworkName: "Apache Kafka" },
62
- ];
44
+ const constants_1 = require("../../constants");
63
45
  /**
64
46
  * Parse pom.xml (Maven)
65
47
  */
@@ -108,7 +90,7 @@ function parsePomXml(manifest) {
108
90
  if (parentMatch) {
109
91
  const parentGroup = parentMatch[1];
110
92
  const parentVersion = parentMatch[2];
111
- const framework = JAVA_FRAMEWORKS.find((f) => parentGroup.includes(f.groupArtifact));
93
+ const framework = constants_1.JAVA_FRAMEWORKS.find((f) => parentGroup.includes(f.groupArtifact));
112
94
  if (framework) {
113
95
  const resolvedVersion = parentVersion.startsWith("${")
114
96
  ? properties[parentVersion.slice(2, -1)]
@@ -141,7 +123,7 @@ function parsePomXml(manifest) {
141
123
  const groupId = depMatch[1];
142
124
  const artifactId = depMatch[2];
143
125
  const version = depMatch[3];
144
- const framework = JAVA_FRAMEWORKS.find((f) => groupId.includes(f.groupArtifact));
126
+ const framework = constants_1.JAVA_FRAMEWORKS.find((f) => groupId.includes(f.groupArtifact));
145
127
  if (framework) {
146
128
  let versionInfo;
147
129
  if (version) {
@@ -223,7 +205,7 @@ function parseBuildGradle(manifest) {
223
205
  while ((m = depRegex.exec(content)) !== null) {
224
206
  const groupId = m[1];
225
207
  const version = m[3];
226
- const framework = JAVA_FRAMEWORKS.find((f) => groupId.includes(f.groupArtifact));
208
+ const framework = constants_1.JAVA_FRAMEWORKS.find((f) => groupId.includes(f.groupArtifact));
227
209
  if (framework) {
228
210
  signals.push({
229
211
  kind: "framework",
@@ -41,29 +41,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
41
41
  exports.parsePackageJson = parsePackageJson;
42
42
  const fs = __importStar(require("fs"));
43
43
  const path = __importStar(require("path"));
44
- /** Framework detection rules: dep name patterns → framework info */
45
- const FRAMEWORK_DETECTION_RULES = [
46
- { depPattern: "@angular/core", frameworkId: "angular", frameworkName: "Angular" },
47
- { depPattern: "react", frameworkId: "react", frameworkName: "React" },
48
- { depPattern: "react-dom", frameworkId: "react-dom", frameworkName: "React DOM" },
49
- { depPattern: "next", frameworkId: "nextjs", frameworkName: "Next.js" },
50
- { depPattern: "vue", frameworkId: "vue", frameworkName: "Vue.js" },
51
- { depPattern: "nuxt", frameworkId: "nuxt", frameworkName: "Nuxt" },
52
- { depPattern: "@sveltejs/kit", frameworkId: "sveltekit", frameworkName: "SvelteKit" },
53
- { depPattern: "svelte", frameworkId: "svelte", frameworkName: "Svelte" },
54
- { depPattern: "express", frameworkId: "express", frameworkName: "Express" },
55
- { depPattern: "@nestjs/core", frameworkId: "nestjs", frameworkName: "NestJS" },
56
- { depPattern: "fastify", frameworkId: "fastify", frameworkName: "Fastify" },
57
- { depPattern: "koa", frameworkId: "koa", frameworkName: "Koa" },
58
- { depPattern: "typescript", frameworkId: "typescript", frameworkName: "TypeScript" },
59
- { depPattern: "@ax-llm/ax", frameworkId: "ax-llm", frameworkName: "Ax-LLM" },
60
- { depPattern: "electron", frameworkId: "electron", frameworkName: "Electron" },
61
- { depPattern: "react-native", frameworkId: "react-native", frameworkName: "React Native" },
62
- { depPattern: "tailwindcss", frameworkId: "tailwindcss", frameworkName: "Tailwind CSS" },
63
- { depPattern: "vite", frameworkId: "vite", frameworkName: "Vite" },
64
- { depPattern: "webpack", frameworkId: "webpack", frameworkName: "Webpack" },
65
- { depPattern: "esbuild", frameworkId: "esbuild", frameworkName: "esbuild" },
66
- ];
44
+ const constants_1 = require("../../constants");
67
45
  /**
68
46
  * Determine version certainty from a semver-like string.
69
47
  */
@@ -126,7 +104,7 @@ function parsePackageJson(manifest) {
126
104
  scope: { pathRoot: rootPath },
127
105
  });
128
106
  // Detect frameworks from dependencies
129
- for (const rule of FRAMEWORK_DETECTION_RULES) {
107
+ for (const rule of constants_1.NPM_FRAMEWORKS) {
130
108
  const depName = typeof rule.depPattern === "string" ? rule.depPattern : undefined;
131
109
  let matchedDep;
132
110
  let matchedVersion;
@@ -43,23 +43,7 @@ exports.parsePipfile = parsePipfile;
43
43
  exports.parseSetupCfg = parseSetupCfg;
44
44
  const fs = __importStar(require("fs"));
45
45
  const path = __importStar(require("path"));
46
- /** Known Python frameworks and their detection patterns */
47
- const PYTHON_FRAMEWORKS = [
48
- { pkg: "django", frameworkId: "django", frameworkName: "Django" },
49
- { pkg: "flask", frameworkId: "flask", frameworkName: "Flask" },
50
- { pkg: "fastapi", frameworkId: "fastapi", frameworkName: "FastAPI" },
51
- { pkg: "uvicorn", frameworkId: "uvicorn", frameworkName: "Uvicorn" },
52
- { pkg: "starlette", frameworkId: "starlette", frameworkName: "Starlette" },
53
- { pkg: "celery", frameworkId: "celery", frameworkName: "Celery" },
54
- { pkg: "sqlalchemy", frameworkId: "sqlalchemy", frameworkName: "SQLAlchemy" },
55
- { pkg: "pandas", frameworkId: "pandas", frameworkName: "Pandas" },
56
- { pkg: "numpy", frameworkId: "numpy", frameworkName: "NumPy" },
57
- { pkg: "tensorflow", frameworkId: "tensorflow", frameworkName: "TensorFlow" },
58
- { pkg: "torch", frameworkId: "pytorch", frameworkName: "PyTorch" },
59
- { pkg: "scikit-learn", frameworkId: "scikit-learn", frameworkName: "scikit-learn" },
60
- { pkg: "pytest", frameworkId: "pytest", frameworkName: "pytest" },
61
- { pkg: "gunicorn", frameworkId: "gunicorn", frameworkName: "Gunicorn" },
62
- ];
46
+ const constants_1 = require("../../constants");
63
47
  function parsePythonVersion(versionSpec, sourceFile, pkgName) {
64
48
  if (!versionSpec || versionSpec.trim() === "") {
65
49
  return { certainty: "unknown", sourceFile, notes: `No version for ${pkgName}` };
@@ -110,7 +94,7 @@ function parseRequirementsTxt(manifest) {
110
94
  continue;
111
95
  const pkgName = match[1].toLowerCase();
112
96
  const versionSpec = match[2] || "";
113
- const framework = PYTHON_FRAMEWORKS.find((f) => f.pkg === pkgName);
97
+ const framework = constants_1.PYTHON_FRAMEWORKS.find((f) => f.pkg === pkgName);
114
98
  if (framework) {
115
99
  const versionInfo = parsePythonVersion(versionSpec, manifest.relativePath, pkgName);
116
100
  signals.push({
@@ -179,7 +163,7 @@ function parsePyprojectToml(manifest) {
179
163
  if (simpleMatch) {
180
164
  const pkgName = simpleMatch[1].toLowerCase();
181
165
  const versionSpec = simpleMatch[2];
182
- const framework = PYTHON_FRAMEWORKS.find((f) => f.pkg === pkgName);
166
+ const framework = constants_1.PYTHON_FRAMEWORKS.find((f) => f.pkg === pkgName);
183
167
  if (framework) {
184
168
  const isPinned = /^\d+\.\d+/.test(versionSpec) && !/[><=~^]/.test(versionSpec);
185
169
  const versionInfo = isPinned
@@ -266,7 +250,7 @@ function parsePipfile(manifest) {
266
250
  const match = line.trim().match(/^([a-zA-Z0-9_.-]+)\s*=\s*"([^"]*)"/);
267
251
  if (match) {
268
252
  const pkgName = match[1].toLowerCase();
269
- const framework = PYTHON_FRAMEWORKS.find((f) => f.pkg === pkgName);
253
+ const framework = constants_1.PYTHON_FRAMEWORKS.find((f) => f.pkg === pkgName);
270
254
  if (framework) {
271
255
  const versionSpec = match[2];
272
256
  const isExact = versionSpec === "*" ? false : /^\d+\.\d+/.test(versionSpec);
@@ -321,7 +305,7 @@ function parseSetupCfg(manifest) {
321
305
  const match = trimmed.match(/^([a-zA-Z0-9_.-]+)\s*([><=~!]+.*)?$/);
322
306
  if (match) {
323
307
  const pkgName = match[1].toLowerCase();
324
- const framework = PYTHON_FRAMEWORKS.find((f) => f.pkg === pkgName);
308
+ const framework = constants_1.PYTHON_FRAMEWORKS.find((f) => f.pkg === pkgName);
325
309
  if (framework) {
326
310
  const versionInfo = parsePythonVersion(match[2] || "", manifest.relativePath, pkgName);
327
311
  signals.push({
@@ -40,17 +40,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
40
40
  exports.parseCargoToml = parseCargoToml;
41
41
  const fs = __importStar(require("fs"));
42
42
  const path = __importStar(require("path"));
43
- /** Known Rust frameworks/libraries */
44
- const RUST_FRAMEWORKS = [
45
- { crate: "actix-web", frameworkId: "actix-web", frameworkName: "Actix Web" },
46
- { crate: "rocket", frameworkId: "rocket", frameworkName: "Rocket" },
47
- { crate: "axum", frameworkId: "axum", frameworkName: "Axum" },
48
- { crate: "tokio", frameworkId: "tokio", frameworkName: "Tokio" },
49
- { crate: "serde", frameworkId: "serde", frameworkName: "Serde" },
50
- { crate: "diesel", frameworkId: "diesel", frameworkName: "Diesel" },
51
- { crate: "sqlx", frameworkId: "sqlx", frameworkName: "SQLx" },
52
- { crate: "warp", frameworkId: "warp", frameworkName: "Warp" },
53
- ];
43
+ const constants_1 = require("../../constants");
54
44
  /**
55
45
  * Parse Cargo.toml
56
46
  */
@@ -117,7 +107,7 @@ function parseCargoToml(manifest) {
117
107
  }
118
108
  if (!crateName)
119
109
  continue;
120
- const framework = RUST_FRAMEWORKS.find((f) => f.crate === crateName);
110
+ const framework = constants_1.RUST_FRAMEWORKS.find((f) => f.crate === crateName);
121
111
  if (framework) {
122
112
  let versionInfo;
123
113
  if (versionStr) {
@@ -41,81 +41,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
41
41
  exports.scanManifests = scanManifests;
42
42
  const fs = __importStar(require("fs"));
43
43
  const path = __importStar(require("path"));
44
+ const constants_1 = require("../constants");
44
45
  /** Directories to skip during scanning */
45
- const SCAN_IGNORE_DIRS = new Set([
46
- ".git",
47
- "node_modules",
48
- "__pycache__",
49
- "venv",
50
- ".venv",
51
- "env",
52
- ".env",
53
- "dist",
54
- "build",
55
- "target",
56
- "vendor",
57
- "bin",
58
- "obj",
59
- "out",
60
- "coverage",
61
- "logs",
62
- "tmp",
63
- "temp",
64
- ".idea",
65
- ".vscode",
66
- ".next",
67
- ".nuxt",
68
- ".svelte-kit",
69
- ".angular",
70
- ".DS_Store",
71
- ]);
46
+ const IGNORE_DIRS_SET = new Set(constants_1.SCAN_IGNORE_DIRS);
72
47
  /** Exact filenames to match as manifests */
73
- const MANIFEST_EXACT_NAMES = new Set([
74
- "package.json",
75
- "package-lock.json",
76
- "yarn.lock",
77
- "pnpm-lock.yaml",
78
- "openclaw.json",
79
- ".openclaw.json",
80
- "angular.json",
81
- "workspace.json",
82
- "project.json",
83
- "pyproject.toml",
84
- "requirements.txt",
85
- "poetry.lock",
86
- "Pipfile",
87
- "Pipfile.lock",
88
- "setup.cfg",
89
- "setup.py",
90
- "pom.xml",
91
- "build.gradle",
92
- "build.gradle.kts",
93
- "settings.gradle",
94
- "settings.gradle.kts",
95
- "gradle.properties",
96
- "go.mod",
97
- "go.sum",
98
- "Cargo.toml",
99
- "Cargo.lock",
100
- "global.json",
101
- "packages.lock.json",
102
- "Dockerfile",
103
- "docker-compose.yml",
104
- "docker-compose.yaml",
105
- "Makefile",
106
- ".gitlab-ci.yml",
107
- ]);
108
- /** File extension patterns for manifests (e.g. *.csproj) */
109
- const MANIFEST_EXTENSION_PATTERNS = [".csproj", ".fsproj", ".vbproj"];
110
- /** Maximum file size in characters to read */
111
- const MAX_FILE_SIZE = 500_000;
48
+ const MANIFEST_EXACT_NAMES = new Set(constants_1.MANIFEST_EXACT_NAMES);
112
49
  /**
113
50
  * Check if a filename matches a known manifest pattern.
114
51
  */
115
52
  function isManifestFile(filename) {
116
53
  if (MANIFEST_EXACT_NAMES.has(filename))
117
54
  return true;
118
- for (const ext of MANIFEST_EXTENSION_PATTERNS) {
55
+ for (const ext of constants_1.MANIFEST_EXTENSION_PATTERNS) {
119
56
  if (filename.endsWith(ext))
120
57
  return true;
121
58
  }
@@ -142,7 +79,7 @@ function scanManifests(repoPath) {
142
79
  }
143
80
  for (const entry of entries) {
144
81
  // Skip ignored directories and hidden dirs (except specific manifest patterns)
145
- if (SCAN_IGNORE_DIRS.has(entry))
82
+ if (IGNORE_DIRS_SET.has(entry))
146
83
  continue;
147
84
  const fullPath = path.join(dir, entry);
148
85
  let stat;
@@ -160,7 +97,11 @@ function scanManifests(repoPath) {
160
97
  walk(fullPath, depth + 1);
161
98
  }
162
99
  else if (stat.isFile()) {
163
- if (isManifestFile(entry) && stat.size <= MAX_FILE_SIZE) {
100
+ if (isManifestFile(entry)) {
101
+ if (stat.size > constants_1.MAX_MANIFEST_FILE_SIZE) {
102
+ // File is too large, skip it
103
+ continue;
104
+ }
164
105
  results.push({
165
106
  absolutePath: fullPath,
166
107
  relativePath: path.relative(absoluteRoot, fullPath),
@@ -0,0 +1,5 @@
1
+ import { Signal } from "./types";
2
+ /**
3
+ * Scan source codebase for integrations.
4
+ */
5
+ export declare function scanSourceFiles(rootPath: string): Signal[];
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.scanSourceFiles = scanSourceFiles;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const ignore_1 = __importDefault(require("ignore"));
43
+ const constants_1 = require("../constants");
44
+ const MAX_SCAN_FILES = 200;
45
+ const MAX_LINES_PER_FILE = 500;
46
+ /**
47
+ * Loads .gitignore rules from the root if available
48
+ */
49
+ function loadGitIgnore(rootPath) {
50
+ const ig = (0, ignore_1.default)();
51
+ // Add hardcoded global ignores
52
+ for (const item of constants_1.SCAN_IGNORE_DIRS)
53
+ ig.add(`**/${item}/**`);
54
+ for (const item of constants_1.ALWAYS_IGNORE_FILES)
55
+ ig.add(`**/${item}`);
56
+ ig.add("**/*.env*"); // Cover all .env permutations globally
57
+ try {
58
+ const gitignorePath = path.join(rootPath, ".gitignore");
59
+ if (fs.existsSync(gitignorePath)) {
60
+ const content = fs.readFileSync(gitignorePath, "utf-8");
61
+ ig.add(content);
62
+ }
63
+ }
64
+ catch {
65
+ // Ignore errors reading .gitignore
66
+ }
67
+ return ig;
68
+ }
69
+ /**
70
+ * Collect source files sequentially via BFS
71
+ */
72
+ function collectSourceFiles(dir, ig, rootPath, files = []) {
73
+ if (files.length >= MAX_SCAN_FILES)
74
+ return files;
75
+ try {
76
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
77
+ for (const entry of entries) {
78
+ if (files.length >= MAX_SCAN_FILES)
79
+ break;
80
+ const fullPath = path.join(dir, entry.name);
81
+ // Ensure posix path for gitignore matching
82
+ const relPath = path.relative(rootPath, fullPath).split(path.sep).join(path.posix.sep);
83
+ // Skip ignored files/directories
84
+ // Note: ignore().ignores() requires directory paths to end with '/' to match properly sometimes,
85
+ // but relPath works fine for most rules.
86
+ if (ig.ignores(relPath))
87
+ continue;
88
+ if (entry.isDirectory()) {
89
+ if (!ig.ignores(relPath + "/")) {
90
+ collectSourceFiles(fullPath, ig, rootPath, files);
91
+ }
92
+ }
93
+ else if (entry.isFile()) {
94
+ const ext = path.extname(entry.name).toLowerCase();
95
+ if (constants_1.SOURCE_EXTENSIONS.includes(ext)) {
96
+ files.push(fullPath);
97
+ }
98
+ }
99
+ }
100
+ }
101
+ catch {
102
+ // access errors skipped
103
+ }
104
+ return files;
105
+ }
106
+ /**
107
+ * Heuristic: check if this phrase occurs in the text
108
+ */
109
+ function matchPatterns(content, patterns = []) {
110
+ for (const pat of patterns) {
111
+ if (content.includes(pat))
112
+ return pat;
113
+ }
114
+ return null;
115
+ }
116
+ /**
117
+ * Scan source codebase for integrations.
118
+ */
119
+ function scanSourceFiles(rootPath) {
120
+ const ig = loadGitIgnore(rootPath);
121
+ const targetFiles = collectSourceFiles(rootPath, ig, rootPath);
122
+ const signals = [];
123
+ const detectedIntegrationIds = new Set();
124
+ for (const file of targetFiles) {
125
+ try {
126
+ // Read file and limit to N lines to keep it fast
127
+ const contentRaw = fs.readFileSync(file, "utf-8");
128
+ let content = contentRaw;
129
+ const lines = contentRaw.split("\n");
130
+ if (lines.length > MAX_LINES_PER_FILE) {
131
+ content = lines.slice(0, MAX_LINES_PER_FILE).join("\n");
132
+ }
133
+ // Check all integrations against this chunk
134
+ for (const integration of constants_1.INTEGRATIONS) {
135
+ if (detectedIntegrationIds.has(integration.id))
136
+ continue; // Found it already somewhere
137
+ let reason = "";
138
+ let matchedPattern = "";
139
+ matchedPattern = matchPatterns(content, integration.urlPatterns) || "";
140
+ if (matchedPattern) {
141
+ reason = `Found API URL pattern "${matchedPattern}"`;
142
+ }
143
+ else {
144
+ matchedPattern = matchPatterns(content, integration.importPatterns) || "";
145
+ if (matchedPattern) {
146
+ reason = `Found SDK import pattern "${matchedPattern}"`;
147
+ }
148
+ else {
149
+ matchedPattern = matchPatterns(content, integration.envPatterns) || "";
150
+ if (matchedPattern) {
151
+ reason = `Found env var reference "${matchedPattern}"`;
152
+ }
153
+ }
154
+ }
155
+ if (reason) {
156
+ detectedIntegrationIds.add(integration.id);
157
+ signals.push({
158
+ kind: "integration",
159
+ frameworkId: integration.id,
160
+ frameworkName: integration.name,
161
+ version: { certainty: "unknown", value: undefined },
162
+ evidence: {
163
+ file: path.relative(rootPath, file),
164
+ reason: `Source code scanner detected ${integration.name}: ${reason}`,
165
+ },
166
+ scope: { pathRoot: rootPath },
167
+ });
168
+ }
169
+ }
170
+ // If we found everything, stop scanning
171
+ if (detectedIntegrationIds.size === constants_1.INTEGRATIONS.length)
172
+ break;
173
+ }
174
+ catch {
175
+ // Ignore unreadable files
176
+ }
177
+ }
178
+ return signals;
179
+ }
@@ -13,7 +13,7 @@ export interface VersionInfo {
13
13
  notes?: string;
14
14
  }
15
15
  /** Signal kinds emitted by manifest parsers */
16
- export type SignalKind = "framework" | "version" | "orchestrator" | "entrypoint" | "tooling" | "agent" | "subagent" | "heartbeat" | "cron" | "hook" | "skill" | "plugin";
16
+ export type SignalKind = "framework" | "version" | "orchestrator" | "entrypoint" | "tooling" | "agent" | "subagent" | "heartbeat" | "cron" | "hook" | "skill" | "plugin" | "integration";
17
17
  /** Evidence for a detected signal */
18
18
  export interface SignalEvidence {
19
19
  file: string;
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Shared programmatic constants and integration registries for Sylva.
3
+ */
1
4
  export interface ModelMetadata {
2
5
  provider: string;
3
6
  tier: "primary" | "mini";
@@ -16,3 +19,44 @@ export declare const IGNORED_DIRS: Set<string>;
16
19
  * source tree so the AI reads them FIRST, preventing framework hallucination.
17
20
  */
18
21
  export declare const DEPENDENCY_MANIFESTS: Set<string>;
22
+ export interface IntegrationDef {
23
+ id: string;
24
+ name: string;
25
+ urlPatterns?: string[];
26
+ importPatterns?: string[];
27
+ envPatterns?: string[];
28
+ }
29
+ export declare const INTEGRATIONS: IntegrationDef[];
30
+ export declare const SOURCE_EXTENSIONS: string[];
31
+ export declare const SCAN_IGNORE_DIRS: string[];
32
+ export declare const ALWAYS_IGNORE_FILES: string[];
33
+ export declare const MANIFEST_EXACT_NAMES: string[];
34
+ export declare const MANIFEST_EXTENSION_PATTERNS: string[];
35
+ export declare const MAX_MANIFEST_FILE_SIZE = 500000;
36
+ /** Confidence scoring rules mapped by framework ID */
37
+ export declare const CONFIDENCE_SCORES: Record<string, number>;
38
+ export declare const NPM_FRAMEWORKS: {
39
+ depPattern: string | RegExp;
40
+ frameworkId: string;
41
+ frameworkName: string;
42
+ }[];
43
+ export declare const PYTHON_FRAMEWORKS: {
44
+ pkg: string;
45
+ frameworkId: string;
46
+ frameworkName: string;
47
+ }[];
48
+ export declare const JAVA_FRAMEWORKS: {
49
+ groupArtifact: string;
50
+ frameworkId: string;
51
+ frameworkName: string;
52
+ }[];
53
+ export declare const GO_FRAMEWORKS: {
54
+ module: string;
55
+ frameworkId: string;
56
+ frameworkName: string;
57
+ }[];
58
+ export declare const RUST_FRAMEWORKS: {
59
+ crate: string;
60
+ frameworkId: string;
61
+ frameworkName: string;
62
+ }[];
package/dist/constants.js CHANGED
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
+ /**
3
+ * Shared programmatic constants and integration registries for Sylva.
4
+ */
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEPENDENCY_MANIFESTS = exports.IGNORED_DIRS = exports.ALLOWED_EXTENSIONS = exports.API_KEY_ENV_VARS = exports.DEFAULT_MINI_MODELS = exports.DEFAULT_MODELS = exports.MODEL_CATALOG = exports.PROVIDER_OPENAI = exports.PROVIDER_ANTHROPIC = exports.PROVIDER_GEMINI = void 0;
6
+ exports.RUST_FRAMEWORKS = exports.GO_FRAMEWORKS = exports.JAVA_FRAMEWORKS = exports.PYTHON_FRAMEWORKS = exports.NPM_FRAMEWORKS = exports.CONFIDENCE_SCORES = exports.MAX_MANIFEST_FILE_SIZE = exports.MANIFEST_EXTENSION_PATTERNS = exports.MANIFEST_EXACT_NAMES = exports.ALWAYS_IGNORE_FILES = exports.SCAN_IGNORE_DIRS = exports.SOURCE_EXTENSIONS = exports.INTEGRATIONS = exports.DEPENDENCY_MANIFESTS = exports.IGNORED_DIRS = exports.ALLOWED_EXTENSIONS = exports.API_KEY_ENV_VARS = exports.DEFAULT_MINI_MODELS = exports.DEFAULT_MODELS = exports.MODEL_CATALOG = exports.PROVIDER_OPENAI = exports.PROVIDER_ANTHROPIC = exports.PROVIDER_GEMINI = void 0;
4
7
  exports.PROVIDER_GEMINI = "gemini";
5
8
  exports.PROVIDER_ANTHROPIC = "anthropic";
6
9
  exports.PROVIDER_OPENAI = "openai";
@@ -131,3 +134,327 @@ exports.DEPENDENCY_MANIFESTS = new Set([
131
134
  "Cargo.lock",
132
135
  "go.mod",
133
136
  ]);
137
+ exports.INTEGRATIONS = [
138
+ // E-commerce & Headless
139
+ {
140
+ id: "wix",
141
+ name: "Wix Headless",
142
+ urlPatterns: ["wixapis.com", "wixstatic.com"],
143
+ envPatterns: ["WIX_API_KEY", "WIX_SITE_ID", "WIX_CLIENT_ID"],
144
+ },
145
+ {
146
+ id: "stripe",
147
+ name: "Stripe",
148
+ importPatterns: ["stripe", "@stripe/stripe-js"],
149
+ urlPatterns: ["api.stripe.com"],
150
+ envPatterns: ["STRIPE_SECRET_KEY", "STRIPE_PUBLISHABLE_KEY"],
151
+ },
152
+ // Cloud Providers
153
+ {
154
+ id: "aws",
155
+ name: "AWS",
156
+ importPatterns: ["boto3", "aws-sdk", "@aws-sdk"],
157
+ envPatterns: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION", "AWS_DEFAULT_REGION"],
158
+ },
159
+ {
160
+ id: "azure",
161
+ name: "Microsoft Azure",
162
+ importPatterns: ["azure", "@azure"],
163
+ urlPatterns: ["windows.net", "azure.com"],
164
+ envPatterns: ["AZURE_CLIENT_ID", "AZURE_TENANT_ID"],
165
+ },
166
+ {
167
+ id: "gcp",
168
+ name: "Google Cloud",
169
+ importPatterns: ["google-cloud", "@google-cloud"],
170
+ urlPatterns: ["googleapis.com"],
171
+ envPatterns: ["GOOGLE_APPLICATION_CREDENTIALS"],
172
+ },
173
+ // Hosting & Edge
174
+ {
175
+ id: "vercel",
176
+ name: "Vercel",
177
+ importPatterns: ["@vercel"],
178
+ envPatterns: ["VERCEL_URL", "VERCEL_PROJECT_ID"],
179
+ },
180
+ {
181
+ id: "netlify",
182
+ name: "Netlify",
183
+ importPatterns: ["@netlify"],
184
+ envPatterns: ["NETLIFY", "URL"],
185
+ },
186
+ {
187
+ id: "cloudflare",
188
+ name: "Cloudflare",
189
+ importPatterns: ["cloudflare", "@cloudflare"],
190
+ envPatterns: ["CLOUDFLARE_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID"],
191
+ },
192
+ // Firebase
193
+ {
194
+ id: "firebase",
195
+ name: "Firebase",
196
+ importPatterns: ["firebase", "firebase-admin"],
197
+ urlPatterns: ["firebaseio.com", "firebasestorage.googleapis.com"],
198
+ envPatterns: ["FIREBASE_API_KEY", "FIREBASE_PROJECT_ID"],
199
+ },
200
+ // Social & Graph
201
+ {
202
+ id: "instagram-api",
203
+ name: "Instagram Graph API",
204
+ urlPatterns: ["graph.instagram.com", "graph.facebook.com"],
205
+ envPatterns: ["INSTAGRAM_ACCESS_TOKEN", "INSTAGRAM_ACCOUNT_ID"],
206
+ },
207
+ // AI & LLMs
208
+ {
209
+ id: "openai",
210
+ name: "OpenAI",
211
+ importPatterns: ["openai"],
212
+ urlPatterns: ["api.openai.com"],
213
+ envPatterns: ["OPENAI_API_KEY"],
214
+ },
215
+ {
216
+ id: "anthropic",
217
+ name: "Anthropic",
218
+ importPatterns: ["@anthropic-ai", "anthropic"],
219
+ urlPatterns: ["api.anthropic.com"],
220
+ envPatterns: ["ANTHROPIC_API_KEY"],
221
+ },
222
+ // Comms
223
+ {
224
+ id: "twilio",
225
+ name: "Twilio",
226
+ importPatterns: ["twilio"],
227
+ urlPatterns: ["api.twilio.com"],
228
+ envPatterns: ["TWILIO_ACCOUNT_SID", "TWILIO_AUTH_TOKEN"],
229
+ },
230
+ {
231
+ id: "sendgrid",
232
+ name: "SendGrid",
233
+ importPatterns: ["sendgrid", "@sendgrid"],
234
+ envPatterns: ["SENDGRID_API_KEY"],
235
+ },
236
+ // Databases & BaaS
237
+ {
238
+ id: "mongodb",
239
+ name: "MongoDB",
240
+ importPatterns: ["mongoose", "pymongo", "mongodb"],
241
+ urlPatterns: ["mongodb.net", "mongodb+srv"],
242
+ envPatterns: ["MONGO_URI", "MONGODB_URI"],
243
+ },
244
+ {
245
+ id: "redis",
246
+ name: "Redis",
247
+ importPatterns: ["redis", "ioredis"],
248
+ urlPatterns: ["redis://", "rediss://"],
249
+ envPatterns: ["REDIS_URL"],
250
+ },
251
+ {
252
+ id: "supabase",
253
+ name: "Supabase",
254
+ importPatterns: ["supabase", "@supabase/supabase-js"],
255
+ urlPatterns: ["supabase.co"],
256
+ envPatterns: ["SUPABASE_URL", "SUPABASE_ANON_KEY"],
257
+ },
258
+ ];
259
+ // Reusable array of generic source file extensions to scan
260
+ exports.SOURCE_EXTENSIONS = [
261
+ ".py",
262
+ ".ts",
263
+ ".js",
264
+ ".go",
265
+ ".rs",
266
+ ".java",
267
+ ".rb",
268
+ ".php",
269
+ ".tsx",
270
+ ".jsx",
271
+ ".cs",
272
+ ".cpp",
273
+ ".c",
274
+ ".swift",
275
+ ".kt",
276
+ ];
277
+ // Shared directories to skip matching globally (used by manifest and source scanners)
278
+ exports.SCAN_IGNORE_DIRS = [
279
+ ".git",
280
+ "node_modules",
281
+ "__pycache__",
282
+ "venv",
283
+ ".venv",
284
+ "env",
285
+ ".env",
286
+ "dist",
287
+ "build",
288
+ "target",
289
+ "vendor",
290
+ "bin",
291
+ "obj",
292
+ "out",
293
+ ".output",
294
+ "coverage",
295
+ "logs",
296
+ "tmp",
297
+ "temp",
298
+ ".idea",
299
+ ".vscode",
300
+ ".next",
301
+ ".nuxt",
302
+ ".svelte-kit",
303
+ ".angular",
304
+ ".DS_Store",
305
+ "public",
306
+ ];
307
+ // NEVER extract .env files
308
+ exports.ALWAYS_IGNORE_FILES = [
309
+ ".env",
310
+ ".env.local",
311
+ ".env.development",
312
+ ".env.production",
313
+ ".env.test",
314
+ ];
315
+ // Exact filenames to match as manifests
316
+ exports.MANIFEST_EXACT_NAMES = [
317
+ "package.json",
318
+ "package-lock.json",
319
+ "yarn.lock",
320
+ "pnpm-lock.yaml",
321
+ "openclaw.json",
322
+ ".openclaw.json",
323
+ "angular.json",
324
+ "workspace.json",
325
+ "project.json",
326
+ "pyproject.toml",
327
+ "requirements.txt",
328
+ "poetry.lock",
329
+ "Pipfile",
330
+ "Pipfile.lock",
331
+ "setup.cfg",
332
+ "setup.py",
333
+ "pom.xml",
334
+ "build.gradle",
335
+ "build.gradle.kts",
336
+ "settings.gradle",
337
+ "settings.gradle.kts",
338
+ "gradle.properties",
339
+ "go.mod",
340
+ "go.sum",
341
+ "Cargo.toml",
342
+ "Cargo.lock",
343
+ "global.json",
344
+ "packages.lock.json",
345
+ "Dockerfile",
346
+ "docker-compose.yml",
347
+ "docker-compose.yaml",
348
+ "Makefile",
349
+ ".gitlab-ci.yml",
350
+ ];
351
+ // File extension patterns for manifests (e.g. *.csproj)
352
+ exports.MANIFEST_EXTENSION_PATTERNS = [".csproj", ".fsproj", ".vbproj"];
353
+ // Maximum file size in characters to read for manifests
354
+ exports.MAX_MANIFEST_FILE_SIZE = 500_000;
355
+ /** Confidence scoring rules mapped by framework ID */
356
+ exports.CONFIDENCE_SCORES = {
357
+ orchestrator: 95,
358
+ angular: 85,
359
+ react: 80,
360
+ nextjs: 85,
361
+ vue: 80,
362
+ nuxt: 85,
363
+ svelte: 80,
364
+ sveltekit: 85,
365
+ express: 75,
366
+ nestjs: 85,
367
+ fastify: 75,
368
+ django: 85,
369
+ flask: 75,
370
+ fastapi: 80,
371
+ "spring-boot": 90,
372
+ spring: 80,
373
+ "java-maven": 70,
374
+ "java-gradle": 70,
375
+ dotnet: 80,
376
+ "aspnet-core": 85,
377
+ go: 80,
378
+ rust: 80,
379
+ "actix-web": 85,
380
+ axum: 85,
381
+ nodejs: 60,
382
+ python: 60,
383
+ typescript: 65,
384
+ docker: 50,
385
+ };
386
+ exports.NPM_FRAMEWORKS = [
387
+ { depPattern: "@angular/core", frameworkId: "angular", frameworkName: "Angular" },
388
+ { depPattern: "react", frameworkId: "react", frameworkName: "React" },
389
+ { depPattern: "react-dom", frameworkId: "react-dom", frameworkName: "React DOM" },
390
+ { depPattern: "next", frameworkId: "nextjs", frameworkName: "Next.js" },
391
+ { depPattern: "vue", frameworkId: "vue", frameworkName: "Vue.js" },
392
+ { depPattern: "nuxt", frameworkId: "nuxt", frameworkName: "Nuxt" },
393
+ { depPattern: "@sveltejs/kit", frameworkId: "sveltekit", frameworkName: "SvelteKit" },
394
+ { depPattern: "svelte", frameworkId: "svelte", frameworkName: "Svelte" },
395
+ { depPattern: "express", frameworkId: "express", frameworkName: "Express" },
396
+ { depPattern: "@nestjs/core", frameworkId: "nestjs", frameworkName: "NestJS" },
397
+ { depPattern: "fastify", frameworkId: "fastify", frameworkName: "Fastify" },
398
+ { depPattern: "koa", frameworkId: "koa", frameworkName: "Koa" },
399
+ { depPattern: "typescript", frameworkId: "typescript", frameworkName: "TypeScript" },
400
+ { depPattern: "@ax-llm/ax", frameworkId: "ax-llm", frameworkName: "Ax-LLM" },
401
+ { depPattern: "electron", frameworkId: "electron", frameworkName: "Electron" },
402
+ { depPattern: "react-native", frameworkId: "react-native", frameworkName: "React Native" },
403
+ { depPattern: "tailwindcss", frameworkId: "tailwindcss", frameworkName: "Tailwind CSS" },
404
+ { depPattern: "vite", frameworkId: "vite", frameworkName: "Vite" },
405
+ { depPattern: "webpack", frameworkId: "webpack", frameworkName: "Webpack" },
406
+ { depPattern: "esbuild", frameworkId: "esbuild", frameworkName: "esbuild" },
407
+ ];
408
+ exports.PYTHON_FRAMEWORKS = [
409
+ { pkg: "django", frameworkId: "django", frameworkName: "Django" },
410
+ { pkg: "flask", frameworkId: "flask", frameworkName: "Flask" },
411
+ { pkg: "fastapi", frameworkId: "fastapi", frameworkName: "FastAPI" },
412
+ { pkg: "uvicorn", frameworkId: "uvicorn", frameworkName: "Uvicorn" },
413
+ { pkg: "starlette", frameworkId: "starlette", frameworkName: "Starlette" },
414
+ { pkg: "celery", frameworkId: "celery", frameworkName: "Celery" },
415
+ { pkg: "sqlalchemy", frameworkId: "sqlalchemy", frameworkName: "SQLAlchemy" },
416
+ { pkg: "pandas", frameworkId: "pandas", frameworkName: "Pandas" },
417
+ { pkg: "numpy", frameworkId: "numpy", frameworkName: "NumPy" },
418
+ { pkg: "tensorflow", frameworkId: "tensorflow", frameworkName: "TensorFlow" },
419
+ { pkg: "torch", frameworkId: "pytorch", frameworkName: "PyTorch" },
420
+ { pkg: "scikit-learn", frameworkId: "scikit-learn", frameworkName: "scikit-learn" },
421
+ { pkg: "pytest", frameworkId: "pytest", frameworkName: "pytest" },
422
+ { pkg: "gunicorn", frameworkId: "gunicorn", frameworkName: "Gunicorn" },
423
+ ];
424
+ exports.JAVA_FRAMEWORKS = [
425
+ {
426
+ groupArtifact: "org.springframework.boot",
427
+ frameworkId: "spring-boot",
428
+ frameworkName: "Spring Boot",
429
+ },
430
+ {
431
+ groupArtifact: "org.springframework",
432
+ frameworkId: "spring",
433
+ frameworkName: "Spring Framework",
434
+ },
435
+ { groupArtifact: "io.quarkus", frameworkId: "quarkus", frameworkName: "Quarkus" },
436
+ { groupArtifact: "io.micronaut", frameworkId: "micronaut", frameworkName: "Micronaut" },
437
+ { groupArtifact: "org.hibernate", frameworkId: "hibernate", frameworkName: "Hibernate" },
438
+ { groupArtifact: "junit", frameworkId: "junit", frameworkName: "JUnit" },
439
+ { groupArtifact: "org.junit", frameworkId: "junit5", frameworkName: "JUnit 5" },
440
+ { groupArtifact: "org.apache.kafka", frameworkId: "kafka", frameworkName: "Apache Kafka" },
441
+ ];
442
+ exports.GO_FRAMEWORKS = [
443
+ { module: "github.com/gin-gonic/gin", frameworkId: "gin", frameworkName: "Gin" },
444
+ { module: "github.com/labstack/echo", frameworkId: "echo", frameworkName: "Echo" },
445
+ { module: "github.com/gofiber/fiber", frameworkId: "fiber", frameworkName: "Fiber" },
446
+ { module: "github.com/gorilla/mux", frameworkId: "gorilla-mux", frameworkName: "Gorilla Mux" },
447
+ { module: "gorm.io/gorm", frameworkId: "gorm", frameworkName: "GORM" },
448
+ { module: "github.com/stretchr/testify", frameworkId: "testify", frameworkName: "Testify" },
449
+ { module: "google.golang.org/grpc", frameworkId: "grpc-go", frameworkName: "gRPC-Go" },
450
+ ];
451
+ exports.RUST_FRAMEWORKS = [
452
+ { crate: "actix-web", frameworkId: "actix-web", frameworkName: "Actix Web" },
453
+ { crate: "rocket", frameworkId: "rocket", frameworkName: "Rocket" },
454
+ { crate: "axum", frameworkId: "axum", frameworkName: "Axum" },
455
+ { crate: "tokio", frameworkId: "tokio", frameworkName: "Tokio" },
456
+ { crate: "serde", frameworkId: "serde", frameworkName: "Serde" },
457
+ { crate: "diesel", frameworkId: "diesel", frameworkName: "Diesel" },
458
+ { crate: "sqlx", frameworkId: "sqlx", frameworkName: "SQLx" },
459
+ { crate: "warp", frameworkId: "warp", frameworkName: "Warp" },
460
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thelogicatelier/sylva",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Auto-generate AGENTS.md for your repository using Ax-LLM. Analyze the structural backbone, data flow, and day-to-day coding conventions natively.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -50,6 +50,7 @@
50
50
  "@ax-llm/ax": "^19.0.2",
51
51
  "commander": "^14.0.3",
52
52
  "dotenv": "^17.3.1",
53
+ "ignore": "^7.0.5",
53
54
  "ts-node": "^10.9.2",
54
55
  "typescript": "^5.9.3",
55
56
  "vitest": "^4.0.18"
@@ -63,4 +64,4 @@
63
64
  "prettier": "^3.8.1",
64
65
  "typescript-eslint": "^8.56.1"
65
66
  }
66
- }
67
+ }