fidelizare-integrate 0.4.0 → 0.5.0
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/package.json +1 -1
- package/src/cli.js +9 -3
- package/src/core/detect.js +42 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fidelizare-integrate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Asistent de integrare Fidelizare pentru softuri de gestiune si case de marcat. Scaneaza codul, gaseste locul potrivit si propune integrarea API-ului, in siguranta.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/cli.js
CHANGED
|
@@ -87,9 +87,15 @@ async function main() {
|
|
|
87
87
|
|
|
88
88
|
const git = gitState(root);
|
|
89
89
|
|
|
90
|
-
// 5a. Agentic tool-loop (real coding agent)
|
|
91
|
-
// applies the integration itself,
|
|
92
|
-
|
|
90
|
+
// 5a. Agentic tool-loop (real coding agent) — the DEFAULT when an LLM key is
|
|
91
|
+
// available. The model finds the files and applies the integration itself,
|
|
92
|
+
// each write gated. `--no-agent` forces the basic deterministic proposer.
|
|
93
|
+
const llmKey = process.env.OPENROUTER_API_KEY || process.env.FIDELIZARE_LLM_KEY;
|
|
94
|
+
if (!has('--no-agent') && !llmKey) {
|
|
95
|
+
note('Pentru integrare cu AI (recomandat), seteaza OPENROUTER_API_KEY. Acum folosesc modul determinist de baza.', C.amber);
|
|
96
|
+
rule();
|
|
97
|
+
}
|
|
98
|
+
if (!has('--no-agent') && llmKey) {
|
|
93
99
|
out(' ' + paint('Agent ', C.ink) + bold(paint(val('--model') || 'Opus 4.8', C.red)) +
|
|
94
100
|
paint(' · scrierile cer confirmare (y / a / N)', C.dim) + '\n\n');
|
|
95
101
|
const r = await runAgentLoop({
|
package/src/core/detect.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Detect the vendor's stack from manifest/extension signals. Read-only.
|
|
2
|
-
import { readdirSync, existsSync, statSync } from 'fs';
|
|
3
|
-
import { join, extname } from 'path';
|
|
2
|
+
import { readdirSync, existsSync, statSync, readFileSync } from 'fs';
|
|
3
|
+
import { join, extname, basename } from 'path';
|
|
4
4
|
|
|
5
5
|
const MANIFESTS = [
|
|
6
6
|
{ file: 'composer.json', stack: 'php', label: 'PHP' },
|
|
@@ -28,10 +28,47 @@ const EXT_STACK = {
|
|
|
28
28
|
'.go': { stack: 'go', label: 'Go' },
|
|
29
29
|
'.rs': { stack: 'rust', label: 'Rust' },
|
|
30
30
|
};
|
|
31
|
-
|
|
31
|
+
// Build artifacts, dependencies and tooling dirs — never integration targets.
|
|
32
|
+
// Mirrors what ripgrep skips via .gitignore (opencode uses ripgrep).
|
|
33
|
+
const IGNORE = new Set([
|
|
34
|
+
'node_modules', '.git', '.next', '.nuxt', '.svelte-kit', '.parcel-cache', '.turbo', '.cache',
|
|
35
|
+
'dist', 'build', 'out', 'bin', 'obj', 'target', 'vendor', 'coverage', '__pycache__',
|
|
36
|
+
'.venv', 'venv', 'env', '.idea', '.vscode', '.gradle', 'static', 'tmp', '.expo',
|
|
37
|
+
]);
|
|
38
|
+
// Minified / generated bundles by filename.
|
|
39
|
+
const MINIFIED_NAME = /(\.min\.|\.bundle\.|\.chunk\.|[-_.]esm[-_.]|node_modules_|\.d\.ts$|\.map$)/i;
|
|
40
|
+
|
|
41
|
+
function loadGitignoreNames(dir) {
|
|
42
|
+
// Cheap .gitignore support: collect simple directory/file names to skip.
|
|
43
|
+
const names = new Set();
|
|
44
|
+
try {
|
|
45
|
+
for (const line of readFileSync(join(dir, '.gitignore'), 'utf8').split('\n')) {
|
|
46
|
+
const t = line.trim();
|
|
47
|
+
if (!t || t.startsWith('#') || t.startsWith('!')) continue;
|
|
48
|
+
const name = t.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
49
|
+
if (name && !name.includes('/') && !name.includes('*')) names.add(name);
|
|
50
|
+
}
|
|
51
|
+
} catch { /* no .gitignore */ }
|
|
52
|
+
return names;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// A real source file looks hand-written: not minified, not huge, sane line length.
|
|
56
|
+
function looksLikeSource(file) {
|
|
57
|
+
if (MINIFIED_NAME.test(basename(file))) return false;
|
|
58
|
+
try {
|
|
59
|
+
if (statSync(file).size > 200_000) return false;
|
|
60
|
+
const head = readFileSync(file, 'utf8').slice(0, 4000);
|
|
61
|
+
if (!head.includes('\n') && head.length > 1200) return false; // single huge line
|
|
62
|
+
const lines = head.split('\n').slice(0, 40);
|
|
63
|
+
const avg = lines.reduce((s, l) => s + l.length, 0) / Math.max(1, lines.length);
|
|
64
|
+
if (avg > 400) return false; // minified
|
|
65
|
+
} catch { return false; }
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
32
68
|
|
|
33
69
|
export function listSourceFiles(dir, max = 4000) {
|
|
34
70
|
const out = [];
|
|
71
|
+
const ignored = new Set([...IGNORE, ...loadGitignoreNames(dir)]);
|
|
35
72
|
const walk = (d) => {
|
|
36
73
|
if (out.length >= max) return;
|
|
37
74
|
let entries;
|
|
@@ -39,10 +76,10 @@ export function listSourceFiles(dir, max = 4000) {
|
|
|
39
76
|
for (const e of entries) {
|
|
40
77
|
if (out.length >= max) return;
|
|
41
78
|
if (e.name.startsWith('.') && e.name !== '.') continue;
|
|
42
|
-
if (
|
|
79
|
+
if (ignored.has(e.name)) continue;
|
|
43
80
|
const p = join(d, e.name);
|
|
44
81
|
if (e.isDirectory()) walk(p);
|
|
45
|
-
else if (EXT_STACK[extname(e.name).toLowerCase()]) out.push(p);
|
|
82
|
+
else if (EXT_STACK[extname(e.name).toLowerCase()] && looksLikeSource(p)) out.push(p);
|
|
46
83
|
}
|
|
47
84
|
};
|
|
48
85
|
walk(dir);
|