@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.
- package/dist/awareness/braveSearch.js +6 -3
- package/dist/awareness/detector.d.ts +1 -0
- package/dist/awareness/detector.js +4 -32
- package/dist/awareness/index.js +20 -2
- package/dist/awareness/manifestParsers/goParsers.js +2 -11
- package/dist/awareness/manifestParsers/javaParsers.js +4 -22
- package/dist/awareness/manifestParsers/packageJsonParser.js +2 -24
- package/dist/awareness/manifestParsers/pythonParsers.js +5 -21
- package/dist/awareness/manifestParsers/rustParsers.js +2 -12
- package/dist/awareness/manifestScanner.js +10 -69
- package/dist/awareness/sourceScanner.d.ts +5 -0
- package/dist/awareness/sourceScanner.js +179 -0
- package/dist/awareness/types.d.ts +1 -1
- package/dist/constants.d.ts +44 -0
- package/dist/constants.js +328 -1
- package/package.json +3 -2
|
@@ -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
|
-
|
|
129
|
+
throw error;
|
|
127
130
|
}
|
|
128
131
|
}
|
|
129
132
|
/**
|
|
@@ -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);
|
package/dist/awareness/index.js
CHANGED
|
@@ -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
|
|
315
|
-
console.log(` → Generated ${
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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)
|
|
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,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;
|
package/dist/constants.d.ts
CHANGED
|
@@ -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.
|
|
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
|
+
}
|