@thelogicatelier/sylva 1.0.4 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +20 -0
  2. package/dist/awareness/braveSearch.d.ts +18 -0
  3. package/dist/awareness/braveSearch.js +134 -0
  4. package/dist/awareness/detector.d.ts +18 -0
  5. package/dist/awareness/detector.js +176 -0
  6. package/dist/awareness/index.d.ts +11 -0
  7. package/dist/awareness/index.js +259 -0
  8. package/dist/awareness/manifestParsers/dotnetParsers.d.ts +13 -0
  9. package/dist/awareness/manifestParsers/dotnetParsers.js +151 -0
  10. package/dist/awareness/manifestParsers/goParsers.d.ts +9 -0
  11. package/dist/awareness/manifestParsers/goParsers.js +137 -0
  12. package/dist/awareness/manifestParsers/index.d.ts +13 -0
  13. package/dist/awareness/manifestParsers/index.js +182 -0
  14. package/dist/awareness/manifestParsers/javaParsers.d.ts +13 -0
  15. package/dist/awareness/manifestParsers/javaParsers.js +243 -0
  16. package/dist/awareness/manifestParsers/openclawParser.d.ts +6 -0
  17. package/dist/awareness/manifestParsers/openclawParser.js +103 -0
  18. package/dist/awareness/manifestParsers/packageJsonParser.d.ts +7 -0
  19. package/dist/awareness/manifestParsers/packageJsonParser.js +209 -0
  20. package/dist/awareness/manifestParsers/pythonParsers.d.ts +21 -0
  21. package/dist/awareness/manifestParsers/pythonParsers.js +344 -0
  22. package/dist/awareness/manifestParsers/rustParsers.d.ts +9 -0
  23. package/dist/awareness/manifestParsers/rustParsers.js +153 -0
  24. package/dist/awareness/manifestScanner.d.ts +11 -0
  25. package/dist/awareness/manifestScanner.js +182 -0
  26. package/dist/awareness/types.d.ts +105 -0
  27. package/dist/awareness/types.js +6 -0
  28. package/dist/awareness/versionResolver.d.ts +17 -0
  29. package/dist/awareness/versionResolver.js +62 -0
  30. package/dist/awareness/webGrounding.d.ts +20 -0
  31. package/dist/awareness/webGrounding.js +102 -0
  32. package/dist/cli.js +19 -4
  33. package/dist/constants.js +11 -0
  34. package/dist/modules.d.ts +5 -2
  35. package/dist/modules.js +17 -4
  36. package/dist/prompts.d.ts +6 -0
  37. package/dist/prompts.js +5 -2
  38. package/dist/utils.js +12 -6
  39. package/package.json +2 -2
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ /**
3
+ * Full-repo manifest scanner.
4
+ * Recursively walks the entire repository to discover framework manifest files,
5
+ * regardless of nesting depth. Handles monorepos and nested subprojects.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.scanManifests = scanManifests;
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ /** 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
+ ]);
72
+ /** 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
+ "angular.json",
80
+ "workspace.json",
81
+ "project.json",
82
+ "pyproject.toml",
83
+ "requirements.txt",
84
+ "poetry.lock",
85
+ "Pipfile",
86
+ "Pipfile.lock",
87
+ "setup.cfg",
88
+ "setup.py",
89
+ "pom.xml",
90
+ "build.gradle",
91
+ "build.gradle.kts",
92
+ "settings.gradle",
93
+ "settings.gradle.kts",
94
+ "gradle.properties",
95
+ "go.mod",
96
+ "go.sum",
97
+ "Cargo.toml",
98
+ "Cargo.lock",
99
+ "global.json",
100
+ "packages.lock.json",
101
+ "Dockerfile",
102
+ "docker-compose.yml",
103
+ "docker-compose.yaml",
104
+ "Makefile",
105
+ ".gitlab-ci.yml",
106
+ ]);
107
+ /** File extension patterns for manifests (e.g. *.csproj) */
108
+ const MANIFEST_EXTENSION_PATTERNS = [".csproj", ".fsproj", ".vbproj"];
109
+ /** Maximum file size in characters to read */
110
+ const MAX_FILE_SIZE = 500_000;
111
+ /**
112
+ * Check if a filename matches a known manifest pattern.
113
+ */
114
+ function isManifestFile(filename) {
115
+ if (MANIFEST_EXACT_NAMES.has(filename))
116
+ return true;
117
+ for (const ext of MANIFEST_EXTENSION_PATTERNS) {
118
+ if (filename.endsWith(ext))
119
+ return true;
120
+ }
121
+ return false;
122
+ }
123
+ /**
124
+ * Recursively scan a repository for manifest files.
125
+ * Returns all discovered manifest files with metadata.
126
+ */
127
+ function scanManifests(repoPath) {
128
+ const results = [];
129
+ const absoluteRoot = path.resolve(repoPath);
130
+ function walk(dir, depth) {
131
+ let entries;
132
+ try {
133
+ entries = fs.readdirSync(dir);
134
+ }
135
+ catch (error) {
136
+ // Permission denied, broken symlink, or other OS-level issue
137
+ console.warn(`⚠️ Skipping unreadable directory: ${path.relative(absoluteRoot, dir) || "."}\n` +
138
+ ` Reason: ${error.message}\n` +
139
+ ` Manifests inside this directory will not be discovered.`);
140
+ return;
141
+ }
142
+ for (const entry of entries) {
143
+ // Skip ignored directories and hidden dirs (except specific manifest patterns)
144
+ if (SCAN_IGNORE_DIRS.has(entry))
145
+ continue;
146
+ const fullPath = path.join(dir, entry);
147
+ let stat;
148
+ try {
149
+ stat = fs.statSync(fullPath);
150
+ }
151
+ catch {
152
+ // Broken symlink or permission issue — skip silently (individual files are not noteworthy)
153
+ continue;
154
+ }
155
+ if (stat.isDirectory()) {
156
+ // Skip hidden directories (starting with .) except the repo root
157
+ if (entry.startsWith(".") && depth > 0)
158
+ continue;
159
+ walk(fullPath, depth + 1);
160
+ }
161
+ else if (stat.isFile()) {
162
+ if (isManifestFile(entry) && stat.size <= MAX_FILE_SIZE) {
163
+ results.push({
164
+ absolutePath: fullPath,
165
+ relativePath: path.relative(absoluteRoot, fullPath),
166
+ filename: entry,
167
+ depth,
168
+ size: stat.size,
169
+ });
170
+ }
171
+ }
172
+ }
173
+ }
174
+ walk(absoluteRoot, 0);
175
+ // Sort by depth (shallow first) then alphabetically for deterministic order
176
+ results.sort((a, b) => {
177
+ if (a.depth !== b.depth)
178
+ return a.depth - b.depth;
179
+ return a.relativePath.localeCompare(b.relativePath);
180
+ });
181
+ return results;
182
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Shared types for the Sylva awareness system.
3
+ * These types are used across manifest scanning, parsing, detection, and web grounding.
4
+ */
5
+ /** Version certainty levels — NEVER ASSUME */
6
+ export type VersionCertainty = "exact" | "unknown" | "ambiguous";
7
+ /** Version information extracted from a manifest file */
8
+ export interface VersionInfo {
9
+ value?: string;
10
+ certainty: VersionCertainty;
11
+ sourceFile?: string;
12
+ sourcePath?: string;
13
+ notes?: string;
14
+ }
15
+ /** Signal kinds emitted by manifest parsers */
16
+ export type SignalKind = "framework" | "version" | "orchestrator" | "entrypoint" | "tooling";
17
+ /** Evidence for a detected signal */
18
+ export interface SignalEvidence {
19
+ file: string;
20
+ reason: string;
21
+ excerpt?: string;
22
+ }
23
+ /** Scope of a signal — which subproject it belongs to */
24
+ export interface SignalScope {
25
+ pathRoot?: string;
26
+ }
27
+ /** A single signal emitted by a manifest parser */
28
+ export interface Signal {
29
+ kind: SignalKind;
30
+ frameworkId: string;
31
+ frameworkName: string;
32
+ version?: VersionInfo;
33
+ evidence: SignalEvidence;
34
+ scope: SignalScope;
35
+ }
36
+ /** A discovered manifest file */
37
+ export interface ManifestFile {
38
+ absolutePath: string;
39
+ relativePath: string;
40
+ filename: string;
41
+ depth: number;
42
+ size: number;
43
+ }
44
+ /** A detected stack with confidence and evidence */
45
+ export interface StackInfo {
46
+ frameworkId: string;
47
+ frameworkName: string;
48
+ confidence: number;
49
+ versions: VersionInfo[];
50
+ evidence: Signal[];
51
+ rootPath?: string;
52
+ }
53
+ /** A workload in the architecture model */
54
+ export interface Workload {
55
+ id: string;
56
+ name: string;
57
+ rootPath: string;
58
+ frameworks: string[];
59
+ entrypoints: string[];
60
+ buildTools: string[];
61
+ evidence: SignalEvidence[];
62
+ }
63
+ /** Orchestrator info (e.g., OpenClaw) */
64
+ export interface OrchestratorInfo {
65
+ id: string;
66
+ configPath: string;
67
+ details: Record<string, unknown>;
68
+ }
69
+ /** Architecture model derived from detection */
70
+ export interface ArchitectureModel {
71
+ primaryOrchestrator?: OrchestratorInfo;
72
+ workloads: Workload[];
73
+ repoType: "single" | "monorepo" | "unknown";
74
+ navigation: {
75
+ whatToReadFirst: string[];
76
+ whereThingsLive: string[];
77
+ };
78
+ }
79
+ /** Reference mode for web grounding */
80
+ export type ReferenceMode = "versioned" | "latest_fallback";
81
+ /** A single web search result */
82
+ export interface WebSearchResult {
83
+ title: string;
84
+ url: string;
85
+ snippet: string;
86
+ }
87
+ /** Grouped web references for a framework */
88
+ export interface WebReference {
89
+ frameworkId: string;
90
+ frameworkName: string;
91
+ versionInfo: VersionInfo;
92
+ referenceMode: ReferenceMode;
93
+ results: WebSearchResult[];
94
+ }
95
+ /** The complete output of the awareness pipeline */
96
+ export interface AwarenessResult {
97
+ manifests: ManifestFile[];
98
+ signals: Signal[];
99
+ stacks: StackInfo[];
100
+ architecture: ArchitectureModel;
101
+ webReferences: WebReference[];
102
+ constraintsBlock: string;
103
+ awarenessContext: string;
104
+ errors: string[];
105
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Shared types for the Sylva awareness system.
4
+ * These types are used across manifest scanning, parsing, detection, and web grounding.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Version resolver.
3
+ * Consolidates version signals per framework and determines version certainty.
4
+ * Core rule: NEVER ASSUME versions.
5
+ */
6
+ import { Signal, VersionInfo } from "./types";
7
+ /**
8
+ * Resolve the best version info for a given framework from its signals.
9
+ * Prioritizes exact > ambiguous > unknown.
10
+ * If multiple exact versions exist for different source files, picks the shallowest one.
11
+ */
12
+ export declare function resolveVersion(signals: Signal[]): VersionInfo;
13
+ /**
14
+ * Resolve versions for all detected frameworks.
15
+ * Groups signals by frameworkId and resolves each.
16
+ */
17
+ export declare function resolveAllVersions(signals: Signal[]): Map<string, VersionInfo>;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /**
3
+ * Version resolver.
4
+ * Consolidates version signals per framework and determines version certainty.
5
+ * Core rule: NEVER ASSUME versions.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.resolveVersion = resolveVersion;
9
+ exports.resolveAllVersions = resolveAllVersions;
10
+ /**
11
+ * Resolve the best version info for a given framework from its signals.
12
+ * Prioritizes exact > ambiguous > unknown.
13
+ * If multiple exact versions exist for different source files, picks the shallowest one.
14
+ */
15
+ function resolveVersion(signals) {
16
+ const versionSignals = signals.filter((s) => s.version);
17
+ if (versionSignals.length === 0) {
18
+ return { certainty: "unknown", notes: "No version information found" };
19
+ }
20
+ // Separate by certainty
21
+ const exact = versionSignals.filter((s) => s.version.certainty === "exact");
22
+ const ambiguous = versionSignals.filter((s) => s.version.certainty === "ambiguous");
23
+ if (exact.length === 1) {
24
+ return exact[0].version;
25
+ }
26
+ if (exact.length > 1) {
27
+ // Multiple exact versions — check if they agree
28
+ const uniqueValues = [...new Set(exact.map((s) => s.version.value))];
29
+ if (uniqueValues.length === 1) {
30
+ return exact[0].version;
31
+ }
32
+ // Conflicting exact versions — mark ambiguous
33
+ return {
34
+ value: uniqueValues[0],
35
+ certainty: "ambiguous",
36
+ sourceFile: exact[0].version.sourceFile,
37
+ notes: `Multiple exact versions found: ${uniqueValues.join(", ")}`,
38
+ };
39
+ }
40
+ if (ambiguous.length > 0) {
41
+ return ambiguous[0].version;
42
+ }
43
+ return { certainty: "unknown", notes: "No resolvable version" };
44
+ }
45
+ /**
46
+ * Resolve versions for all detected frameworks.
47
+ * Groups signals by frameworkId and resolves each.
48
+ */
49
+ function resolveAllVersions(signals) {
50
+ const grouped = new Map();
51
+ for (const signal of signals) {
52
+ if (!grouped.has(signal.frameworkId)) {
53
+ grouped.set(signal.frameworkId, []);
54
+ }
55
+ grouped.get(signal.frameworkId).push(signal);
56
+ }
57
+ const resolved = new Map();
58
+ for (const [frameworkId, frameworkSignals] of grouped) {
59
+ resolved.set(frameworkId, resolveVersion(frameworkSignals));
60
+ }
61
+ return resolved;
62
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Web grounding — version-aware query builder and reference gatherer.
3
+ * Uses Brave Search to fetch official docs for detected frameworks.
4
+ * NEVER ASSUMES — queries are version-specific only when exact version is known.
5
+ */
6
+ import { StackInfo, VersionInfo, WebReference } from "./types";
7
+ /**
8
+ * Build search queries for a framework based on version info.
9
+ */
10
+ export declare function buildQueries(frameworkName: string, versionInfo: VersionInfo): string[];
11
+ /**
12
+ * Gather web references for detected frameworks.
13
+ * @param stacks Detected stacks sorted by confidence
14
+ * @param limitPerFramework Max queries per framework
15
+ * @param cacheDir Optional cache directory
16
+ */
17
+ export declare function gatherReferences(stacks: StackInfo[], limitPerFramework?: number, cacheDir?: string): Promise<{
18
+ references: WebReference[];
19
+ errors: string[];
20
+ }>;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ /**
3
+ * Web grounding — version-aware query builder and reference gatherer.
4
+ * Uses Brave Search to fetch official docs for detected frameworks.
5
+ * NEVER ASSUMES — queries are version-specific only when exact version is known.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.buildQueries = buildQueries;
9
+ exports.gatherReferences = gatherReferences;
10
+ const braveSearch_1 = require("./braveSearch");
11
+ const versionResolver_1 = require("./versionResolver");
12
+ /**
13
+ * Build search queries for a framework based on version info.
14
+ */
15
+ function buildQueries(frameworkName, versionInfo) {
16
+ const queries = [];
17
+ if (versionInfo.certainty === "exact" && versionInfo.value) {
18
+ // Extract major.minor from version
19
+ const parts = versionInfo.value.replace(/^v/, "").split(".");
20
+ const major = parts[0];
21
+ const minor = parts.length > 1 ? parts[1] : undefined;
22
+ const majorMinor = minor ? `${major}.${minor}` : major;
23
+ queries.push(`${frameworkName} ${major} documentation official`);
24
+ if (minor) {
25
+ queries.push(`${frameworkName} ${majorMinor} reference documentation`);
26
+ }
27
+ queries.push(`${frameworkName} ${major} best practices`);
28
+ }
29
+ else {
30
+ // Unknown or ambiguous — use latest docs
31
+ queries.push(`${frameworkName} official documentation`);
32
+ queries.push(`${frameworkName} best practices`);
33
+ }
34
+ return queries;
35
+ }
36
+ /**
37
+ * Gather web references for detected frameworks.
38
+ * @param stacks Detected stacks sorted by confidence
39
+ * @param limitPerFramework Max queries per framework
40
+ * @param cacheDir Optional cache directory
41
+ */
42
+ async function gatherReferences(stacks, limitPerFramework = 3, cacheDir) {
43
+ const references = [];
44
+ const errors = [];
45
+ if (!(0, braveSearch_1.isBraveSearchAvailable)()) {
46
+ errors.push("BRAVE_API_KEY not set — web grounding is disabled.\n" +
47
+ " → Framework detection and version resolution still work perfectly.\n" +
48
+ " → To enable web-grounded documentation references, set BRAVE_API_KEY in your .env file.\n" +
49
+ " → Get a free API key at: https://brave.com/search/api/");
50
+ return { references, errors };
51
+ }
52
+ // Pick top frameworks by confidence (skip generic ones like "nodejs", "python")
53
+ const GENERIC_IDS = new Set([
54
+ "nodejs",
55
+ "python",
56
+ "java-maven",
57
+ "java-gradle",
58
+ "dotnet",
59
+ "docker",
60
+ ]);
61
+ const targetStacks = stacks
62
+ .filter((s) => !GENERIC_IDS.has(s.frameworkId) && s.confidence >= 60)
63
+ .slice(0, 6);
64
+ // Always include orchestrators
65
+ const orchestratorStacks = stacks.filter((s) => s.evidence.some((e) => e.kind === "orchestrator"));
66
+ for (const orc of orchestratorStacks) {
67
+ if (!targetStacks.some((t) => t.frameworkId === orc.frameworkId)) {
68
+ targetStacks.push(orc);
69
+ }
70
+ }
71
+ for (const stack of targetStacks) {
72
+ const versionInfo = (0, versionResolver_1.resolveVersion)(stack.evidence);
73
+ const queries = buildQueries(stack.frameworkName, versionInfo);
74
+ const referenceMode = versionInfo.certainty === "exact" ? "versioned" : "latest_fallback";
75
+ const allResults = [];
76
+ for (const query of queries.slice(0, limitPerFramework)) {
77
+ try {
78
+ const results = await (0, braveSearch_1.braveSearch)(query, { cacheDir });
79
+ allResults.push(...results);
80
+ }
81
+ catch (error) {
82
+ errors.push(`Web search failed for "${query}": ${error.message}`);
83
+ }
84
+ }
85
+ // Dedupe by URL
86
+ const seen = new Set();
87
+ const deduped = allResults.filter((r) => {
88
+ if (seen.has(r.url))
89
+ return false;
90
+ seen.add(r.url);
91
+ return true;
92
+ });
93
+ references.push({
94
+ frameworkId: stack.frameworkId,
95
+ frameworkName: stack.frameworkName,
96
+ versionInfo,
97
+ referenceMode: referenceMode,
98
+ results: deduped.slice(0, 5),
99
+ });
100
+ }
101
+ return { references, errors };
102
+ }
package/dist/cli.js CHANGED
@@ -43,6 +43,7 @@ const readline = __importStar(require("readline/promises"));
43
43
  const modelConfig_1 = require("./modelConfig");
44
44
  const utils_1 = require("./utils");
45
45
  const modules_1 = require("./modules");
46
+ const awareness_1 = require("./awareness");
46
47
  function initEnvironment() {
47
48
  const envPath = path.resolve(process.cwd(), ".env");
48
49
  if (fs.existsSync(envPath)) {
@@ -97,23 +98,32 @@ async function runPipeline(repoDir, repoName, llmPrimary, llmMini, maxIterations
97
98
  const sourceTree = (0, utils_1.loadSourceTree)(repoDir);
98
99
  const numFiles = Object.keys(sourceTree).length;
99
100
  if (numFiles === 0) {
100
- console.warn("\n⚠️ Warning: The loaded source tree is empty! Check IGNORED_DIRS or ensure the repository contains supported source files.");
101
+ console.warn("\n⚠️ The loaded source tree is empty no supported files found.\n" +
102
+ " Possible causes:\n" +
103
+ " • The repository directory doesn't exist or is empty\n" +
104
+ " • All files are filtered by IGNORED_DIRS (node_modules, dist, etc.)\n" +
105
+ " • No files match ALLOWED_EXTENSIONS (.ts, .py, .java, .go, etc.)\n" +
106
+ " Run with --help to check your --local-repository or --github-repository path.");
101
107
  }
102
108
  else {
103
109
  console.log(`✅ Extracted representation for ${numFiles} top-level file(s)/directory(ies).`);
104
110
  }
111
+ // Run Framework Awareness (deterministic, before LLM)
112
+ const awarenessResult = await (0, awareness_1.runAwareness)(repoDir, repoName);
113
+ const awarenessContext = awarenessResult.awarenessContext;
105
114
  const extractor = new modules_1.CodebaseConventionExtractor(maxIterations);
106
- const extractResult = await extractor.extract(sourceTree);
115
+ const extractResult = await extractor.extract(sourceTree, awarenessContext);
107
116
  // Use the PRIMARY model for RLM analysis (needs strong reasoning to avoid hallucination)
108
117
  console.log(`=> Running the Codebase Analyzer RLM workflow...`);
109
118
  const rlmResult = await extractResult.analyzer.forward(llmPrimary, {
110
119
  sourceContext: extractResult.contextString,
120
+ awarenessContext,
111
121
  });
112
122
  // Use the PRIMARY model for compiling conventions (needs to accurately synthesize)
113
123
  const conventionsMarkdown = await extractor.compileMarkdown(llmPrimary, rlmResult);
114
124
  // Use MINI model for section extraction (cheaper, deterministic task)
115
125
  const creator = new modules_1.AgentsMdCreator();
116
- const sections = await creator.extractAndCompileSections(llmMini, conventionsMarkdown, repoName);
126
+ const sections = await creator.extractAndCompileSections(llmMini, conventionsMarkdown, repoName, awarenessContext);
117
127
  const finalAgentsMd = (0, utils_1.compileAgentsMd)(sections, repoName);
118
128
  (0, utils_1.saveAgentsToDisk)(repoName, finalAgentsMd);
119
129
  console.log("\n======================================================");
@@ -166,7 +176,12 @@ async function main() {
166
176
  process.exit(0);
167
177
  }
168
178
  catch (err) {
169
- console.error(`\n❌ Error occurred: ${err.message}`);
179
+ console.error(`\n❌ Pipeline failed: ${err.message}\n` +
180
+ ` If this is an API error, check that your API key is valid and has sufficient quota.\n` +
181
+ ` If this is unexpected, report it at: https://github.com/achatt89/sylva/issues`);
182
+ if (err.stack) {
183
+ console.error(`\n Stack trace:\n ${err.stack.split("\n").slice(1, 5).join("\n ")}`);
184
+ }
170
185
  process.exit(1);
171
186
  }
172
187
  });
package/dist/constants.js CHANGED
@@ -75,6 +75,11 @@ exports.ALLOWED_EXTENSIONS = new Set([
75
75
  ".r",
76
76
  ".m",
77
77
  ".pl",
78
+ ".lock",
79
+ ".cfg",
80
+ ".csproj",
81
+ ".fsproj",
82
+ ".gradle",
78
83
  ]);
79
84
  exports.IGNORED_DIRS = new Set([
80
85
  "node_modules",
@@ -119,4 +124,10 @@ exports.DEPENDENCY_MANIFESTS = new Set([
119
124
  "docker-compose.yml",
120
125
  "docker-compose.yaml",
121
126
  "package.json",
127
+ "openclaw.json",
128
+ "angular.json",
129
+ "workspace.json",
130
+ "global.json",
131
+ "Cargo.lock",
132
+ "go.mod",
122
133
  ]);
package/dist/modules.d.ts CHANGED
@@ -1,12 +1,15 @@
1
1
  import { AgentsMdSections, TreeType } from "./utils";
2
2
  export declare class CodebaseConventionExtractor {
3
3
  private maxIterations;
4
+ private awarenessContext?;
4
5
  constructor(maxIterations?: number);
5
6
  extract(sourceTree: {
6
7
  [key: string]: TreeType;
7
- }): Promise<{
8
+ }, awarenessContext?: string): Promise<{
8
9
  analyzer: import("@ax-llm/ax").AxAgent<{
9
10
  readonly sourceContext: string;
11
+ } & {
12
+ readonly awarenessContext: string;
10
13
  }, {
11
14
  readonly projectOverview: string;
12
15
  } & {
@@ -49,5 +52,5 @@ export declare class CodebaseConventionExtractor {
49
52
  compileMarkdown(llm: any, extractResult: any): Promise<string>;
50
53
  }
51
54
  export declare class AgentsMdCreator {
52
- extractAndCompileSections(llm: any, conventionsMarkdown: string, repositoryName: string): Promise<AgentsMdSections>;
55
+ extractAndCompileSections(llm: any, conventionsMarkdown: string, repositoryName: string, awarenessContext?: string): Promise<AgentsMdSections>;
53
56
  }
package/dist/modules.js CHANGED
@@ -20,12 +20,19 @@ function serializeSourceTree(tree, indent = "") {
20
20
  }
21
21
  class CodebaseConventionExtractor {
22
22
  maxIterations;
23
+ awarenessContext;
23
24
  constructor(maxIterations = 35) {
24
25
  this.maxIterations = maxIterations;
25
26
  }
26
- async extract(sourceTree) {
27
+ async extract(sourceTree, awarenessContext) {
27
28
  console.log("=> Preparing and serializing Source Tree for RLM analysis...");
28
- const contextString = serializeSourceTree(sourceTree);
29
+ let contextString = serializeSourceTree(sourceTree);
30
+ // Store awareness context for use in subsequent pipeline steps
31
+ this.awarenessContext = awarenessContext;
32
+ // Prepend awareness context if available
33
+ if (awarenessContext) {
34
+ contextString = `${awarenessContext}\n\n---\n\nSOURCE TREE:\n${contextString}`;
35
+ }
29
36
  console.log(`=> Running AxAgent (RLM) for Codebase Analysis on ${Object.keys(sourceTree).length} root modules...`);
30
37
  // Use the f() builder for reliable type definition instead of long strings
31
38
  const agentSig = prompts_1.CODEBASE_ANALYSIS_SIGNATURE;
@@ -48,13 +55,18 @@ class CodebaseConventionExtractor {
48
55
  // Equivalent to dspy.ChainOfThought(CompileConventionsMarkdown)
49
56
  const compileSig = prompts_1.COMPILE_CONVENTIONS_SIGNATURE;
50
57
  const compiler = (0, ax_1.ax)(compileSig);
51
- const finalResult = await compiler.forward(llm, extractResult);
58
+ // Inject awarenessContext into the compilation step so constraints flow through
59
+ const inputWithAwareness = {
60
+ ...extractResult,
61
+ awarenessContext: this.awarenessContext || "No framework awareness context available.",
62
+ };
63
+ const finalResult = await compiler.forward(llm, inputWithAwareness);
52
64
  return finalResult.markdownDocument;
53
65
  }
54
66
  }
55
67
  exports.CodebaseConventionExtractor = CodebaseConventionExtractor;
56
68
  class AgentsMdCreator {
57
- async extractAndCompileSections(llm, conventionsMarkdown, repositoryName) {
69
+ async extractAndCompileSections(llm, conventionsMarkdown, repositoryName, awarenessContext) {
58
70
  console.log(`=> Extracting individual AGENTS.md sections for repository: ${repositoryName}...`);
59
71
  // Equivalent to ExtractAgentsSections via ChainOfThought
60
72
  const sectionSig = prompts_1.EXTRACT_AGENTS_SECTIONS_SIGNATURE;
@@ -62,6 +74,7 @@ class AgentsMdCreator {
62
74
  const sections = await sectionExtractor.forward(llm, {
63
75
  conventionsMarkdown,
64
76
  repositoryName,
77
+ awarenessContext: awarenessContext || "No framework awareness context available.",
65
78
  });
66
79
  return sections;
67
80
  }
package/dist/prompts.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export declare const CODEBASE_ANALYSIS_SIGNATURE: import("@ax-llm/ax").AxSignature<{
2
2
  readonly sourceContext: string;
3
+ } & {
4
+ readonly awarenessContext: string;
3
5
  }, {
4
6
  readonly projectOverview: string;
5
7
  } & {
@@ -77,6 +79,8 @@ export declare const COMPILE_CONVENTIONS_SIGNATURE: import("@ax-llm/ax").AxSigna
77
79
  readonly agentWorkflow: string;
78
80
  } & {
79
81
  readonly fewShotExamples: string;
82
+ } & {
83
+ readonly awarenessContext: string;
80
84
  }, {
81
85
  readonly markdownDocument: string;
82
86
  }>;
@@ -84,6 +88,8 @@ export declare const EXTRACT_AGENTS_SECTIONS_SIGNATURE: import("@ax-llm/ax").AxS
84
88
  readonly conventionsMarkdown: string;
85
89
  } & {
86
90
  readonly repositoryName: string;
91
+ } & {
92
+ readonly awarenessContext: string;
87
93
  }, {
88
94
  readonly projectOverview: string;
89
95
  } & {