@nepopsx/cli 0.0.2 → 0.0.4
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/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +113 -24
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/login.d.ts +7 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +108 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/scan.d.ts +2 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +405 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/sync.d.ts +2 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +68 -120
- package/dist/commands/sync.js.map +1 -1
- package/dist/generator/builtin-templates.d.ts +2 -1
- package/dist/generator/builtin-templates.d.ts.map +1 -1
- package/dist/generator/builtin-templates.js +161 -2
- package/dist/generator/builtin-templates.js.map +1 -1
- package/dist/generator/package-renderer.d.ts +37 -0
- package/dist/generator/package-renderer.d.ts.map +1 -0
- package/dist/generator/package-renderer.js +143 -0
- package/dist/generator/package-renderer.js.map +1 -0
- package/dist/generator/render.d.ts +11 -54
- package/dist/generator/render.d.ts.map +1 -1
- package/dist/generator/render.js +18 -174
- package/dist/generator/render.js.map +1 -1
- package/dist/index.js +32 -1
- package/dist/index.js.map +1 -1
- package/dist/licensing/fingerprint.test.d.ts +2 -0
- package/dist/licensing/fingerprint.test.d.ts.map +1 -0
- package/dist/licensing/fingerprint.test.js +41 -0
- package/dist/licensing/fingerprint.test.js.map +1 -0
- package/dist/licensing/installer.d.ts +43 -0
- package/dist/licensing/installer.d.ts.map +1 -0
- package/dist/licensing/installer.js +98 -0
- package/dist/licensing/installer.js.map +1 -0
- package/dist/scan/__tests__/context-gatherer.test.d.ts +2 -0
- package/dist/scan/__tests__/context-gatherer.test.d.ts.map +1 -0
- package/dist/scan/__tests__/context-gatherer.test.js +111 -0
- package/dist/scan/__tests__/context-gatherer.test.js.map +1 -0
- package/dist/scan/__tests__/merge.test.d.ts +2 -0
- package/dist/scan/__tests__/merge.test.d.ts.map +1 -0
- package/dist/scan/__tests__/merge.test.js +163 -0
- package/dist/scan/__tests__/merge.test.js.map +1 -0
- package/dist/scan/config.d.ts +24 -0
- package/dist/scan/config.d.ts.map +1 -0
- package/dist/scan/config.js +77 -0
- package/dist/scan/config.js.map +1 -0
- package/dist/scan/context/gatherer.d.ts +13 -0
- package/dist/scan/context/gatherer.d.ts.map +1 -0
- package/dist/scan/context/gatherer.js +97 -0
- package/dist/scan/context/gatherer.js.map +1 -0
- package/dist/scan/context/gitignore.d.ts +9 -0
- package/dist/scan/context/gitignore.d.ts.map +1 -0
- package/dist/scan/context/gitignore.js +50 -0
- package/dist/scan/context/gitignore.js.map +1 -0
- package/dist/scan/context/patterns.d.ts +14 -0
- package/dist/scan/context/patterns.d.ts.map +1 -0
- package/dist/scan/context/patterns.js +159 -0
- package/dist/scan/context/patterns.js.map +1 -0
- package/dist/scan/customs/writer.d.ts +6 -0
- package/dist/scan/customs/writer.d.ts.map +1 -0
- package/dist/scan/customs/writer.js +149 -0
- package/dist/scan/customs/writer.js.map +1 -0
- package/dist/scan/llm/anthropic.d.ts +11 -0
- package/dist/scan/llm/anthropic.d.ts.map +1 -0
- package/dist/scan/llm/anthropic.js +98 -0
- package/dist/scan/llm/anthropic.js.map +1 -0
- package/dist/scan/llm/factory.d.ts +4 -0
- package/dist/scan/llm/factory.d.ts.map +1 -0
- package/dist/scan/llm/factory.js +20 -0
- package/dist/scan/llm/factory.js.map +1 -0
- package/dist/scan/llm/ollama.d.ts +11 -0
- package/dist/scan/llm/ollama.d.ts.map +1 -0
- package/dist/scan/llm/ollama.js +73 -0
- package/dist/scan/llm/ollama.js.map +1 -0
- package/dist/scan/llm/openai.d.ts +12 -0
- package/dist/scan/llm/openai.d.ts.map +1 -0
- package/dist/scan/llm/openai.js +87 -0
- package/dist/scan/llm/openai.js.map +1 -0
- package/dist/scan/llm/types.d.ts +23 -0
- package/dist/scan/llm/types.d.ts.map +1 -0
- package/dist/scan/llm/types.js +3 -0
- package/dist/scan/llm/types.js.map +1 -0
- package/dist/scan/merge/diff-display.d.ts +11 -0
- package/dist/scan/merge/diff-display.d.ts.map +1 -0
- package/dist/scan/merge/diff-display.js +72 -0
- package/dist/scan/merge/diff-display.js.map +1 -0
- package/dist/scan/prompt/agent.d.ts +23 -0
- package/dist/scan/prompt/agent.d.ts.map +1 -0
- package/dist/scan/prompt/agent.js +95 -0
- package/dist/scan/prompt/agent.js.map +1 -0
- package/dist/scan/prompt/builder.d.ts +16 -0
- package/dist/scan/prompt/builder.d.ts.map +1 -0
- package/dist/scan/prompt/builder.js +64 -0
- package/dist/scan/prompt/builder.js.map +1 -0
- package/dist/scan/prompt/schema.d.ts +7 -0
- package/dist/scan/prompt/schema.d.ts.map +1 -0
- package/dist/scan/prompt/schema.js +52 -0
- package/dist/scan/prompt/schema.js.map +1 -0
- package/dist/security/scanner.d.ts +3 -40
- package/dist/security/scanner.d.ts.map +1 -1
- package/dist/security/scanner.js +3 -169
- package/dist/security/scanner.js.map +1 -1
- package/package.json +15 -12
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// @nepopsx/cli — Stat-first context gatherer with tiered budget enforcement
|
|
2
|
+
import { statSync } from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { glob } from 'glob';
|
|
6
|
+
import { getPatternsForFramework } from './patterns.js';
|
|
7
|
+
import { loadIgnoreFilter } from './gitignore.js';
|
|
8
|
+
/** Estimate tokens from file size before reading */
|
|
9
|
+
function estimateTokensFromSize(bytes) {
|
|
10
|
+
return Math.ceil(bytes / 3);
|
|
11
|
+
}
|
|
12
|
+
/** Count actual tokens after reading */
|
|
13
|
+
function countTokens(content) {
|
|
14
|
+
return Math.ceil(content.length / 3.5);
|
|
15
|
+
}
|
|
16
|
+
async function globSafe(pattern, cwd) {
|
|
17
|
+
try {
|
|
18
|
+
return await glob(pattern, { cwd, nodir: true, dot: false });
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Gather high-signal files from a service directory, respecting a token budget.
|
|
26
|
+
* Uses stat-first estimation to avoid reading files that would exceed budget.
|
|
27
|
+
*/
|
|
28
|
+
export async function gatherContext(servicePath, framework, budget, ignoreFilter) {
|
|
29
|
+
const filter = ignoreFilter ?? loadIgnoreFilter(servicePath);
|
|
30
|
+
const patterns = getPatternsForFramework(framework);
|
|
31
|
+
const files = new Map();
|
|
32
|
+
const skippedFiles = [];
|
|
33
|
+
let totalTokens = 0;
|
|
34
|
+
async function processPatterns(globs, maxFiles) {
|
|
35
|
+
// Collect all matching paths
|
|
36
|
+
const matchedPaths = new Set();
|
|
37
|
+
for (const pattern of globs) {
|
|
38
|
+
const matches = await globSafe(pattern, servicePath);
|
|
39
|
+
for (const m of matches) {
|
|
40
|
+
matchedPaths.add(m);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Stat-first: estimate tokens for all matched files before reading any
|
|
44
|
+
const candidates = [];
|
|
45
|
+
for (const relPath of matchedPaths) {
|
|
46
|
+
if (files.has(relPath))
|
|
47
|
+
continue; // already included
|
|
48
|
+
if (filter(relPath))
|
|
49
|
+
continue; // gitignored
|
|
50
|
+
const absPath = join(servicePath, relPath);
|
|
51
|
+
try {
|
|
52
|
+
const stats = statSync(absPath);
|
|
53
|
+
if (!stats.isFile())
|
|
54
|
+
continue;
|
|
55
|
+
const estimatedTokens = estimateTokensFromSize(stats.size);
|
|
56
|
+
candidates.push({ absPath, relPath, estimatedTokens });
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// File may have disappeared between glob and stat
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Sort by path depth ascending, then by estimated size ascending
|
|
63
|
+
candidates.sort((a, b) => {
|
|
64
|
+
const depthA = a.relPath.split('/').length;
|
|
65
|
+
const depthB = b.relPath.split('/').length;
|
|
66
|
+
return depthA !== depthB ? depthA - depthB : a.estimatedTokens - b.estimatedTokens;
|
|
67
|
+
});
|
|
68
|
+
// Apply maxFiles limit for tier3
|
|
69
|
+
const limited = maxFiles !== undefined ? candidates.slice(0, maxFiles) : candidates;
|
|
70
|
+
// Read files that fit within remaining budget
|
|
71
|
+
for (const candidate of limited) {
|
|
72
|
+
if (totalTokens + candidate.estimatedTokens > budget) {
|
|
73
|
+
skippedFiles.push(candidate.relPath);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const content = await readFile(candidate.absPath, 'utf-8');
|
|
78
|
+
const actualTokens = countTokens(content);
|
|
79
|
+
if (totalTokens + actualTokens > budget) {
|
|
80
|
+
skippedFiles.push(candidate.relPath);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
files.set(candidate.relPath, content);
|
|
84
|
+
totalTokens += actualTokens;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Skip unreadable files
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Process tiers in priority order
|
|
92
|
+
await processPatterns(patterns.tier1);
|
|
93
|
+
await processPatterns(patterns.tier2);
|
|
94
|
+
await processPatterns(patterns.tier3, 3);
|
|
95
|
+
return { files, totalTokens, skippedFiles };
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=gatherer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gatherer.js","sourceRoot":"","sources":["../../../src/scan/context/gatherer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a filter function for a service directory using .gitignore rules.
|
|
3
|
+
* Falls back to default exclusions if no .gitignore exists.
|
|
4
|
+
*
|
|
5
|
+
* @param serviceDir Absolute path to the service root directory
|
|
6
|
+
* @returns A function: (relativePath: string) => boolean — true if path should be ignored
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadIgnoreFilter(serviceDir: string): (path: string) => boolean;
|
|
9
|
+
//# sourceMappingURL=gitignore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../../src/scan/context/gitignore.ts"],"names":[],"mappings":"AAqBA;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAuB9E"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @nepopsx/cli — .gitignore parsing using the `ignore` package
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import ignore from 'ignore';
|
|
5
|
+
const DEFAULT_EXCLUDES = [
|
|
6
|
+
'node_modules',
|
|
7
|
+
'dist',
|
|
8
|
+
'.git',
|
|
9
|
+
'__pycache__',
|
|
10
|
+
'vendor',
|
|
11
|
+
'build',
|
|
12
|
+
'.next',
|
|
13
|
+
'.nuxt',
|
|
14
|
+
'coverage',
|
|
15
|
+
'target',
|
|
16
|
+
'.cache',
|
|
17
|
+
'.turbo',
|
|
18
|
+
'*.log',
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Create a filter function for a service directory using .gitignore rules.
|
|
22
|
+
* Falls back to default exclusions if no .gitignore exists.
|
|
23
|
+
*
|
|
24
|
+
* @param serviceDir Absolute path to the service root directory
|
|
25
|
+
* @returns A function: (relativePath: string) => boolean — true if path should be ignored
|
|
26
|
+
*/
|
|
27
|
+
export function loadIgnoreFilter(serviceDir) {
|
|
28
|
+
const ig = ignore();
|
|
29
|
+
// Add default exclusions
|
|
30
|
+
ig.add(DEFAULT_EXCLUDES);
|
|
31
|
+
// Add .gitignore if it exists
|
|
32
|
+
const gitignorePath = join(serviceDir, '.gitignore');
|
|
33
|
+
if (existsSync(gitignorePath)) {
|
|
34
|
+
try {
|
|
35
|
+
const content = readFileSync(gitignorePath, 'utf-8');
|
|
36
|
+
ig.add(content);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Silently ignore read errors
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return (relPath) => {
|
|
43
|
+
// The `ignore` package requires paths without leading slashes
|
|
44
|
+
const normalized = relPath.startsWith('/') ? relPath.slice(1) : relPath;
|
|
45
|
+
if (!normalized)
|
|
46
|
+
return false;
|
|
47
|
+
return ig.ignores(normalized);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=gitignore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignore.js","sourceRoot":"","sources":["../../../src/scan/context/gitignore.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,gBAAgB,GAAG;IACvB,cAAc;IACd,MAAM;IACN,MAAM;IACN,aAAa;IACb,QAAQ;IACR,OAAO;IACP,OAAO;IACP,OAAO;IACP,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,OAAO;CACR,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IAEpB,yBAAyB;IACzB,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAEzB,8BAA8B;IAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IACrD,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACrD,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,8BAA8B;QAChC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,OAAe,EAAE,EAAE;QACzB,8DAA8D;QAC9D,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACxE,IAAI,CAAC,UAAU;YAAE,OAAO,KAAK,CAAC;QAC9B,OAAO,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface TieredPatterns {
|
|
2
|
+
/** Always include — entry points, config files, manifests */
|
|
3
|
+
tier1: string[];
|
|
4
|
+
/** Include if budget allows — key modules, route definitions */
|
|
5
|
+
tier2: string[];
|
|
6
|
+
/** Sample if budget allows — representative implementation files (max 3) */
|
|
7
|
+
tier3: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Get tiered file patterns for a given framework.
|
|
11
|
+
* The returned patterns are merged with the base patterns.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getPatternsForFramework(framework: string | undefined): TieredPatterns;
|
|
14
|
+
//# sourceMappingURL=patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../../src/scan/context/patterns.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gEAAgE;IAChE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAoJD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CASrF"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// @nepopsx/cli — Framework-aware tiered file patterns for context gathering
|
|
2
|
+
const BASE_PATTERNS = {
|
|
3
|
+
tier1: [
|
|
4
|
+
'README.md',
|
|
5
|
+
'README.txt',
|
|
6
|
+
'.env.example',
|
|
7
|
+
'docker-compose.yml',
|
|
8
|
+
'docker-compose.yaml',
|
|
9
|
+
'Dockerfile',
|
|
10
|
+
],
|
|
11
|
+
tier2: [
|
|
12
|
+
'ARCHITECTURE.md',
|
|
13
|
+
'docs/**/*.md',
|
|
14
|
+
],
|
|
15
|
+
tier3: [],
|
|
16
|
+
};
|
|
17
|
+
const FRAMEWORK_PATTERNS = {
|
|
18
|
+
nestjs: {
|
|
19
|
+
tier1: [
|
|
20
|
+
'package.json',
|
|
21
|
+
'tsconfig.json',
|
|
22
|
+
'nest-cli.json',
|
|
23
|
+
'src/app.module.ts',
|
|
24
|
+
'src/main.ts',
|
|
25
|
+
'src/**/*.module.ts',
|
|
26
|
+
],
|
|
27
|
+
tier2: [
|
|
28
|
+
'src/**/*.controller.ts',
|
|
29
|
+
'src/**/*.service.ts',
|
|
30
|
+
'src/**/*.entity.ts',
|
|
31
|
+
'src/**/*.dto.ts',
|
|
32
|
+
'src/database/**/*.ts',
|
|
33
|
+
],
|
|
34
|
+
tier3: [
|
|
35
|
+
'src/**/*.guard.ts',
|
|
36
|
+
'src/**/*.decorator.ts',
|
|
37
|
+
'src/**/*.pipe.ts',
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
nextjs: {
|
|
41
|
+
tier1: [
|
|
42
|
+
'package.json',
|
|
43
|
+
'tsconfig.json',
|
|
44
|
+
'next.config.ts',
|
|
45
|
+
'next.config.js',
|
|
46
|
+
'next.config.mjs',
|
|
47
|
+
'src/app/layout.tsx',
|
|
48
|
+
'src/app/page.tsx',
|
|
49
|
+
'app/layout.tsx',
|
|
50
|
+
'app/page.tsx',
|
|
51
|
+
],
|
|
52
|
+
tier2: [
|
|
53
|
+
'src/app/**/page.tsx',
|
|
54
|
+
'src/app/**/layout.tsx',
|
|
55
|
+
'src/components/**/*.tsx',
|
|
56
|
+
'src/lib/**/*.ts',
|
|
57
|
+
'src/types/**/*.ts',
|
|
58
|
+
],
|
|
59
|
+
tier3: [
|
|
60
|
+
'src/hooks/**/*.ts',
|
|
61
|
+
'src/stores/**/*.ts',
|
|
62
|
+
'src/actions/**/*.ts',
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
react: {
|
|
66
|
+
tier1: [
|
|
67
|
+
'package.json',
|
|
68
|
+
'tsconfig.json',
|
|
69
|
+
'vite.config.ts',
|
|
70
|
+
'vite.config.js',
|
|
71
|
+
'src/App.tsx',
|
|
72
|
+
'src/App.jsx',
|
|
73
|
+
'src/main.tsx',
|
|
74
|
+
'src/index.tsx',
|
|
75
|
+
],
|
|
76
|
+
tier2: [
|
|
77
|
+
'src/components/**/*.tsx',
|
|
78
|
+
'src/pages/**/*.tsx',
|
|
79
|
+
],
|
|
80
|
+
tier3: [
|
|
81
|
+
'src/hooks/**/*.ts',
|
|
82
|
+
'src/store/**/*.ts',
|
|
83
|
+
'src/api/**/*.ts',
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
express: {
|
|
87
|
+
tier1: [
|
|
88
|
+
'package.json',
|
|
89
|
+
'tsconfig.json',
|
|
90
|
+
'src/app.ts',
|
|
91
|
+
'src/index.ts',
|
|
92
|
+
'src/server.ts',
|
|
93
|
+
'app.js',
|
|
94
|
+
'index.js',
|
|
95
|
+
'server.js',
|
|
96
|
+
],
|
|
97
|
+
tier2: [
|
|
98
|
+
'src/routes/**/*.ts',
|
|
99
|
+
'src/controllers/**/*.ts',
|
|
100
|
+
'src/middleware/**/*.ts',
|
|
101
|
+
'src/models/**/*.ts',
|
|
102
|
+
],
|
|
103
|
+
tier3: [
|
|
104
|
+
'src/services/**/*.ts',
|
|
105
|
+
'src/utils/**/*.ts',
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
go: {
|
|
109
|
+
tier1: [
|
|
110
|
+
'go.mod',
|
|
111
|
+
'go.sum',
|
|
112
|
+
'Makefile',
|
|
113
|
+
'main.go',
|
|
114
|
+
'cmd/*/main.go',
|
|
115
|
+
'cmd/**/*.go',
|
|
116
|
+
],
|
|
117
|
+
tier2: [
|
|
118
|
+
'internal/**/*.go',
|
|
119
|
+
'pkg/**/*.go',
|
|
120
|
+
'api/**/*.go',
|
|
121
|
+
],
|
|
122
|
+
tier3: [
|
|
123
|
+
'**/handler*.go',
|
|
124
|
+
'**/service*.go',
|
|
125
|
+
'**/store*.go',
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
python: {
|
|
129
|
+
tier1: [
|
|
130
|
+
'requirements.txt',
|
|
131
|
+
'pyproject.toml',
|
|
132
|
+
'setup.py',
|
|
133
|
+
'setup.cfg',
|
|
134
|
+
'Pipfile',
|
|
135
|
+
'main.py',
|
|
136
|
+
'app.py',
|
|
137
|
+
'src/**/__init__.py',
|
|
138
|
+
'src/**/main.py',
|
|
139
|
+
],
|
|
140
|
+
tier2: [
|
|
141
|
+
'src/**/*.py',
|
|
142
|
+
],
|
|
143
|
+
tier3: [],
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Get tiered file patterns for a given framework.
|
|
148
|
+
* The returned patterns are merged with the base patterns.
|
|
149
|
+
*/
|
|
150
|
+
export function getPatternsForFramework(framework) {
|
|
151
|
+
const fw = framework?.toLowerCase();
|
|
152
|
+
const specific = fw ? (FRAMEWORK_PATTERNS[fw] ?? null) : null;
|
|
153
|
+
return {
|
|
154
|
+
tier1: [...BASE_PATTERNS.tier1, ...(specific?.tier1 ?? [])],
|
|
155
|
+
tier2: [...BASE_PATTERNS.tier2, ...(specific?.tier2 ?? [])],
|
|
156
|
+
tier3: [...BASE_PATTERNS.tier3, ...(specific?.tier3 ?? [])],
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../../src/scan/context/patterns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ScanResponse } from '@nepopsx/core';
|
|
2
|
+
/**
|
|
3
|
+
* Write or update customs files with scan-managed sections.
|
|
4
|
+
*/
|
|
5
|
+
export declare function writeCustomsFiles(customsDir: string, scanResults: ScanResponse, dryRun: boolean): void;
|
|
6
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../../src/scan/customs/writer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAuIlD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,YAAY,EACzB,MAAM,EAAE,OAAO,GACd,IAAI,CAsBN"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// @nepopsx/cli — Customs file writer with marker-based merge
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const MARKER_START = '<!-- nepopsx-scan-managed:start -->';
|
|
5
|
+
const MARKER_END = '<!-- nepopsx-scan-managed:end -->';
|
|
6
|
+
const FILE_HEADER = `<!-- This file is partially managed by \`nepopsx scan\`.
|
|
7
|
+
Sections between ${MARKER_START} and ${MARKER_END} are auto-generated.
|
|
8
|
+
Content outside those markers is preserved across re-runs. -->
|
|
9
|
+
|
|
10
|
+
`;
|
|
11
|
+
/**
|
|
12
|
+
* Merge scan-managed content into an existing file while preserving user sections.
|
|
13
|
+
* If the file does not exist, create it with the managed block.
|
|
14
|
+
*/
|
|
15
|
+
function mergeCustomsFile(filePath, managedContent, dryRun) {
|
|
16
|
+
const newBlock = `${MARKER_START}\n${managedContent.trim()}\n${MARKER_END}`;
|
|
17
|
+
if (!existsSync(filePath)) {
|
|
18
|
+
if (!dryRun) {
|
|
19
|
+
writeFileSync(filePath, FILE_HEADER + newBlock + '\n', 'utf-8');
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
const existing = readFileSync(filePath, 'utf-8');
|
|
24
|
+
const startIdx = existing.indexOf(MARKER_START);
|
|
25
|
+
const endIdx = existing.indexOf(MARKER_END);
|
|
26
|
+
let updated;
|
|
27
|
+
if (startIdx === -1 || endIdx === -1) {
|
|
28
|
+
// No markers — append managed block
|
|
29
|
+
updated = existing.trimEnd() + '\n\n' + newBlock + '\n';
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Replace between markers
|
|
33
|
+
const before = existing.slice(0, startIdx);
|
|
34
|
+
const after = existing.slice(endIdx + MARKER_END.length);
|
|
35
|
+
updated = before + newBlock + after;
|
|
36
|
+
}
|
|
37
|
+
if (updated === existing)
|
|
38
|
+
return false;
|
|
39
|
+
if (!dryRun) {
|
|
40
|
+
writeFileSync(filePath, updated, 'utf-8');
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build the content for architecture-patterns.md from scan results.
|
|
46
|
+
*/
|
|
47
|
+
function buildArchitecturePatterns(scan) {
|
|
48
|
+
const lines = ['## Architecture Patterns', ''];
|
|
49
|
+
for (const svc of scan.services) {
|
|
50
|
+
if (!svc.patterns || svc.patterns.length === 0)
|
|
51
|
+
continue;
|
|
52
|
+
lines.push(`### ${svc.service_name}`);
|
|
53
|
+
for (const pattern of svc.patterns) {
|
|
54
|
+
lines.push(`- ${pattern}`);
|
|
55
|
+
}
|
|
56
|
+
lines.push('');
|
|
57
|
+
}
|
|
58
|
+
return lines.join('\n');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build the content for coding-conventions.md from scan results.
|
|
62
|
+
*/
|
|
63
|
+
function buildCodingConventions(scan) {
|
|
64
|
+
const lines = ['## Coding Conventions', ''];
|
|
65
|
+
for (const svc of scan.services) {
|
|
66
|
+
if (!svc.conventions || svc.conventions.length === 0)
|
|
67
|
+
continue;
|
|
68
|
+
lines.push(`### ${svc.service_name}`);
|
|
69
|
+
for (const conv of svc.conventions) {
|
|
70
|
+
lines.push(`- ${conv}`);
|
|
71
|
+
}
|
|
72
|
+
lines.push('');
|
|
73
|
+
}
|
|
74
|
+
if (scan.cross_service?.conventions) {
|
|
75
|
+
lines.push('### Workspace-wide');
|
|
76
|
+
const c = scan.cross_service.conventions;
|
|
77
|
+
if (c.commits)
|
|
78
|
+
lines.push(`- Commit style: ${c.commits}`);
|
|
79
|
+
if (c.branching)
|
|
80
|
+
lines.push(`- Branching: ${c.branching}`);
|
|
81
|
+
if (c.pr_required !== undefined)
|
|
82
|
+
lines.push(`- PR required: ${c.pr_required}`);
|
|
83
|
+
lines.push('');
|
|
84
|
+
}
|
|
85
|
+
return lines.join('\n');
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Build the content for service-communication.md from scan results.
|
|
89
|
+
*/
|
|
90
|
+
function buildServiceCommunication(scan) {
|
|
91
|
+
const lines = ['## Service Communication', ''];
|
|
92
|
+
if (scan.cross_service?.service_communication) {
|
|
93
|
+
for (const comm of scan.cross_service.service_communication) {
|
|
94
|
+
lines.push(`- **${comm.from}** → **${comm.to}** (${comm.protocol}): ${comm.description}`);
|
|
95
|
+
}
|
|
96
|
+
lines.push('');
|
|
97
|
+
}
|
|
98
|
+
for (const svc of scan.services) {
|
|
99
|
+
if (!svc.communication || svc.communication.length === 0)
|
|
100
|
+
continue;
|
|
101
|
+
lines.push(`### ${svc.service_name} outbound`);
|
|
102
|
+
for (const c of svc.communication) {
|
|
103
|
+
lines.push(`- → **${c.target}** via ${c.protocol}: ${c.description}`);
|
|
104
|
+
}
|
|
105
|
+
lines.push('');
|
|
106
|
+
}
|
|
107
|
+
return lines.join('\n');
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Build the content for gotchas.md from scan results.
|
|
111
|
+
*/
|
|
112
|
+
function buildGotchas(scan) {
|
|
113
|
+
const lines = ['## Known Gotchas', ''];
|
|
114
|
+
for (const svc of scan.services) {
|
|
115
|
+
if (!svc.gotchas || svc.gotchas.length === 0)
|
|
116
|
+
continue;
|
|
117
|
+
lines.push(`### ${svc.service_name}`);
|
|
118
|
+
for (const g of svc.gotchas) {
|
|
119
|
+
lines.push(`- ${g}`);
|
|
120
|
+
}
|
|
121
|
+
lines.push('');
|
|
122
|
+
}
|
|
123
|
+
return lines.join('\n');
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Write or update customs files with scan-managed sections.
|
|
127
|
+
*/
|
|
128
|
+
export function writeCustomsFiles(customsDir, scanResults, dryRun) {
|
|
129
|
+
if (!dryRun && !existsSync(customsDir)) {
|
|
130
|
+
mkdirSync(customsDir, { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
const files = [
|
|
133
|
+
{ name: 'architecture-patterns.md', content: buildArchitecturePatterns(scanResults) },
|
|
134
|
+
{ name: 'coding-conventions.md', content: buildCodingConventions(scanResults) },
|
|
135
|
+
{ name: 'service-communication.md', content: buildServiceCommunication(scanResults) },
|
|
136
|
+
{ name: 'gotchas.md', content: buildGotchas(scanResults) },
|
|
137
|
+
];
|
|
138
|
+
for (const { name, content } of files) {
|
|
139
|
+
if (content.trim().split('\n').length <= 2)
|
|
140
|
+
continue; // Skip empty sections
|
|
141
|
+
const filePath = join(customsDir, name);
|
|
142
|
+
const changed = mergeCustomsFile(filePath, content, dryRun);
|
|
143
|
+
const prefix = dryRun ? '[dry-run] ' : '';
|
|
144
|
+
if (changed) {
|
|
145
|
+
console.log(` ${prefix}${existsSync(filePath) && !dryRun ? 'updated' : 'created'}: customs/${name}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../../src/scan/customs/writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LlmProvider, LlmRequest, LlmResponse } from './types.js';
|
|
2
|
+
export declare class AnthropicProvider implements LlmProvider {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly model;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly supportsJsonMode = true;
|
|
7
|
+
constructor(apiKey: string, model?: string);
|
|
8
|
+
estimateTokens(text: string): number;
|
|
9
|
+
chat(request: LlmRequest): Promise<LlmResponse>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/scan/llm/anthropic.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAkBvE,qBAAa,iBAAkB,YAAW,WAAW;IAKjD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IALxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,QAAQ;gBAGd,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAsB;IAKhD,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI9B,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;CAkFtD"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const DEFAULT_MODEL = 'claude-3-5-sonnet-20241022';
|
|
2
|
+
const ENDPOINT = 'https://api.anthropic.com/v1/messages';
|
|
3
|
+
const TIMEOUT_MS = 120_000;
|
|
4
|
+
const MAX_RETRIES = 3;
|
|
5
|
+
const ANTHROPIC_VERSION = '2023-06-01';
|
|
6
|
+
async function fetchWithTimeout(url, init, ms) {
|
|
7
|
+
const controller = new AbortController();
|
|
8
|
+
const timer = setTimeout(() => controller.abort(), ms);
|
|
9
|
+
try {
|
|
10
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
11
|
+
}
|
|
12
|
+
finally {
|
|
13
|
+
clearTimeout(timer);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class AnthropicProvider {
|
|
17
|
+
apiKey;
|
|
18
|
+
model;
|
|
19
|
+
name;
|
|
20
|
+
supportsJsonMode = true;
|
|
21
|
+
constructor(apiKey, model = DEFAULT_MODEL) {
|
|
22
|
+
this.apiKey = apiKey;
|
|
23
|
+
this.model = model;
|
|
24
|
+
this.name = `anthropic:${model}`;
|
|
25
|
+
}
|
|
26
|
+
estimateTokens(text) {
|
|
27
|
+
return Math.ceil(text.length / 3.5);
|
|
28
|
+
}
|
|
29
|
+
async chat(request) {
|
|
30
|
+
// Use tool_use for structured output when a schema is provided
|
|
31
|
+
const tools = request.jsonSchema
|
|
32
|
+
? [
|
|
33
|
+
{
|
|
34
|
+
name: 'scan_response',
|
|
35
|
+
description: 'Return the structured scan analysis result',
|
|
36
|
+
input_schema: request.jsonSchema,
|
|
37
|
+
},
|
|
38
|
+
]
|
|
39
|
+
: undefined;
|
|
40
|
+
const body = {
|
|
41
|
+
model: this.model,
|
|
42
|
+
max_tokens: request.maxTokens,
|
|
43
|
+
system: request.systemPrompt,
|
|
44
|
+
messages: [{ role: 'user', content: request.userPrompt }],
|
|
45
|
+
};
|
|
46
|
+
if (tools) {
|
|
47
|
+
body.tools = tools;
|
|
48
|
+
body.tool_choice = { type: 'tool', name: 'scan_response' };
|
|
49
|
+
}
|
|
50
|
+
let lastError = null;
|
|
51
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
52
|
+
if (attempt > 0) {
|
|
53
|
+
await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, attempt - 1)));
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetchWithTimeout(ENDPOINT, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: {
|
|
59
|
+
'Content-Type': 'application/json',
|
|
60
|
+
'x-api-key': this.apiKey,
|
|
61
|
+
'anthropic-version': ANTHROPIC_VERSION,
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify(body),
|
|
64
|
+
}, TIMEOUT_MS);
|
|
65
|
+
if (!res.ok) {
|
|
66
|
+
const text = await res.text();
|
|
67
|
+
throw new Error(`Anthropic API error ${res.status}: ${text.slice(0, 200)}`);
|
|
68
|
+
}
|
|
69
|
+
const data = (await res.json());
|
|
70
|
+
// Extract content: tool_use returns input as JSON; text blocks return raw text
|
|
71
|
+
let content = '';
|
|
72
|
+
for (const block of data.content) {
|
|
73
|
+
if (block.type === 'tool_use' && block.input !== undefined) {
|
|
74
|
+
content = JSON.stringify(block.input);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
if (block.type === 'text' && block.text) {
|
|
78
|
+
content = block.text;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
content,
|
|
83
|
+
inputTokens: data.usage?.input_tokens ?? 0,
|
|
84
|
+
outputTokens: data.usage?.output_tokens ?? 0,
|
|
85
|
+
model: data.model,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
90
|
+
if (lastError.name === 'AbortError') {
|
|
91
|
+
throw new Error(`Anthropic request timed out after ${TIMEOUT_MS}ms`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
throw lastError ?? new Error('Anthropic request failed after retries');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/scan/llm/anthropic.ts"],"names":[],"mappings":"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"}
|