legacyver 2.1.0 → 2.1.2
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/.agent/skills/openspec-apply-change/SKILL.md +156 -0
- package/.agent/skills/openspec-archive-change/SKILL.md +114 -0
- package/.agent/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.agent/skills/openspec-continue-change/SKILL.md +118 -0
- package/.agent/skills/openspec-explore/SKILL.md +290 -0
- package/.agent/skills/openspec-ff-change/SKILL.md +101 -0
- package/.agent/skills/openspec-new-change/SKILL.md +74 -0
- package/.agent/skills/openspec-onboard/SKILL.md +529 -0
- package/.agent/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.agent/skills/openspec-verify-change/SKILL.md +168 -0
- package/.agent/workflows/opsx-apply.md +149 -0
- package/.agent/workflows/opsx-archive.md +154 -0
- package/.agent/workflows/opsx-bulk-archive.md +239 -0
- package/.agent/workflows/opsx-continue.md +111 -0
- package/.agent/workflows/opsx-explore.md +171 -0
- package/.agent/workflows/opsx-ff.md +91 -0
- package/.agent/workflows/opsx-new.md +66 -0
- package/.agent/workflows/opsx-onboard.md +522 -0
- package/.agent/workflows/opsx-sync.md +131 -0
- package/.agent/workflows/opsx-verify.md +161 -0
- package/.github/prompts/opsx-apply.prompt.md +149 -0
- package/.github/prompts/opsx-archive.prompt.md +154 -0
- package/.github/prompts/opsx-bulk-archive.prompt.md +239 -0
- package/.github/prompts/opsx-continue.prompt.md +111 -0
- package/.github/prompts/opsx-explore.prompt.md +171 -0
- package/.github/prompts/opsx-ff.prompt.md +91 -0
- package/.github/prompts/opsx-new.prompt.md +66 -0
- package/.github/prompts/opsx-onboard.prompt.md +522 -0
- package/.github/prompts/opsx-sync.prompt.md +131 -0
- package/.github/prompts/opsx-verify.prompt.md +161 -0
- package/.github/skills/openspec-apply-change/SKILL.md +156 -0
- package/.github/skills/openspec-archive-change/SKILL.md +114 -0
- package/.github/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.github/skills/openspec-continue-change/SKILL.md +118 -0
- package/.github/skills/openspec-explore/SKILL.md +290 -0
- package/.github/skills/openspec-ff-change/SKILL.md +101 -0
- package/.github/skills/openspec-new-change/SKILL.md +74 -0
- package/.github/skills/openspec-onboard/SKILL.md +529 -0
- package/.github/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.github/skills/openspec-verify-change/SKILL.md +168 -0
- package/.legacyverignore.example +43 -0
- package/.legacyverrc +7 -0
- package/.opencode/command/opsx-apply.md +149 -0
- package/.opencode/command/opsx-archive.md +154 -0
- package/.opencode/command/opsx-bulk-archive.md +239 -0
- package/.opencode/command/opsx-continue.md +111 -0
- package/.opencode/command/opsx-explore.md +171 -0
- package/.opencode/command/opsx-ff.md +91 -0
- package/.opencode/command/opsx-new.md +66 -0
- package/.opencode/command/opsx-onboard.md +522 -0
- package/.opencode/command/opsx-sync.md +131 -0
- package/.opencode/command/opsx-verify.md +161 -0
- package/.opencode/skills/openspec-apply-change/SKILL.md +156 -0
- package/.opencode/skills/openspec-archive-change/SKILL.md +114 -0
- package/.opencode/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.opencode/skills/openspec-continue-change/SKILL.md +118 -0
- package/.opencode/skills/openspec-explore/SKILL.md +290 -0
- package/.opencode/skills/openspec-ff-change/SKILL.md +101 -0
- package/.opencode/skills/openspec-new-change/SKILL.md +74 -0
- package/.opencode/skills/openspec-onboard/SKILL.md +529 -0
- package/.opencode/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.opencode/skills/openspec-verify-change/SKILL.md +168 -0
- package/LICENSE +1 -1
- package/README.md +128 -83
- package/bin/legacyver.js +48 -25
- package/legacyver-docs/SUMMARY.md +3 -0
- package/legacyver-docs/components.md +57 -0
- package/legacyver-docs/index.md +15 -0
- package/nul +2 -0
- package/package.json +23 -25
- package/src/cache/hash.js +9 -10
- package/src/cache/index.js +43 -65
- package/src/cli/commands/analyze.js +212 -190
- package/src/cli/commands/cache.js +15 -35
- package/src/cli/commands/init.js +63 -107
- package/src/cli/commands/providers.js +56 -81
- package/src/cli/commands/version.js +7 -10
- package/src/cli/ui.js +58 -77
- package/src/crawler/filters.js +41 -40
- package/src/crawler/index.js +52 -36
- package/src/crawler/manifest.js +31 -43
- package/src/crawler/walk.js +32 -38
- package/src/llm/chunker.js +34 -56
- package/src/llm/cost-estimator.js +68 -51
- package/src/llm/free-model.js +67 -0
- package/src/llm/index.js +22 -43
- package/src/llm/prompts.js +45 -33
- package/src/llm/providers/gemini.js +94 -0
- package/src/llm/providers/groq.js +55 -40
- package/src/llm/providers/ollama.js +38 -65
- package/src/llm/providers/openrouter.js +67 -0
- package/src/llm/queue.js +59 -88
- package/src/llm/re-prompter.js +41 -0
- package/src/llm/validator.js +72 -0
- package/src/parser/ast/generic.js +45 -222
- package/src/parser/ast/go.js +86 -205
- package/src/parser/ast/java.js +76 -146
- package/src/parser/ast/javascript.js +173 -241
- package/src/parser/ast/laravel/blade.js +56 -0
- package/src/parser/ast/laravel/classifier.js +30 -0
- package/src/parser/ast/laravel/controller.js +35 -0
- package/src/parser/ast/laravel/index.js +54 -0
- package/src/parser/ast/laravel/model.js +41 -0
- package/src/parser/ast/laravel/provider.js +28 -0
- package/src/parser/ast/laravel/routes.js +45 -0
- package/src/parser/ast/php.js +129 -0
- package/src/parser/ast/python.js +76 -199
- package/src/parser/ast/typescript.js +10 -244
- package/src/parser/body-extractor.js +40 -0
- package/src/parser/call-graph.js +50 -67
- package/src/parser/complexity-scorer.js +59 -0
- package/src/parser/index.js +61 -86
- package/src/parser/pattern-detector.js +71 -0
- package/src/parser/pkg-builder.js +36 -83
- package/src/renderer/html.js +63 -135
- package/src/renderer/index.js +23 -35
- package/src/renderer/json.js +17 -35
- package/src/renderer/markdown.js +83 -117
- package/src/utils/config.js +52 -53
- package/src/utils/errors.js +26 -41
- package/src/utils/logger.js +32 -53
- package/src/cli/flags.js +0 -87
- package/src/llm/providers/anthropic.js +0 -57
- package/src/llm/providers/google.js +0 -65
- package/src/llm/providers/openai.js +0 -52
- package/src/parser/ast/tree-sitter-init.js +0 -80
package/package.json
CHANGED
|
@@ -1,51 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "legacyver",
|
|
3
|
-
"version": "2.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.1.2",
|
|
4
|
+
"description": "AI-powered CLI tool to auto-generate technical documentation from legacy/undocumented codebases",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"legacyver": "bin/legacyver.js"
|
|
8
8
|
},
|
|
9
|
+
"type": "commonjs",
|
|
9
10
|
"engines": {
|
|
10
11
|
"node": ">=18.0.0"
|
|
11
12
|
},
|
|
12
13
|
"scripts": {
|
|
13
14
|
"test": "vitest run",
|
|
14
15
|
"test:watch": "vitest",
|
|
15
|
-
"lint": "eslint src/
|
|
16
|
+
"lint": "eslint src/ bin/"
|
|
16
17
|
},
|
|
17
18
|
"keywords": [
|
|
18
19
|
"documentation",
|
|
19
|
-
"
|
|
20
|
-
"codebase",
|
|
20
|
+
"cli",
|
|
21
21
|
"ast",
|
|
22
22
|
"llm",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
23
|
+
"legacy",
|
|
24
|
+
"code-analysis",
|
|
25
|
+
"tree-sitter"
|
|
25
26
|
],
|
|
27
|
+
"author": "",
|
|
26
28
|
"license": "MIT",
|
|
27
|
-
"type": "module",
|
|
28
29
|
"dependencies": {
|
|
29
|
-
"
|
|
30
|
-
"@google/generative-ai": "^0.24.1",
|
|
31
|
-
"chalk": "^5.6.2",
|
|
30
|
+
"chalk": "^4.1.2",
|
|
32
31
|
"cli-progress": "^3.12.0",
|
|
33
|
-
"commander": "^
|
|
34
|
-
"conf": "^
|
|
32
|
+
"commander": "^11.1.0",
|
|
33
|
+
"conf": "^10.2.0",
|
|
35
34
|
"cosmiconfig": "^9.0.0",
|
|
36
|
-
"fast-glob": "^3.3.
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"web-tree-sitter": "^0.26.5"
|
|
35
|
+
"fast-glob": "^3.3.2",
|
|
36
|
+
"ignore": "^5.3.1",
|
|
37
|
+
"marked": "^11.1.1",
|
|
38
|
+
"ora": "^5.4.1",
|
|
39
|
+
"p-limit": "^3.1.0",
|
|
40
|
+
"p-retry": "^4.6.2",
|
|
41
|
+
"picocolors": "^1.0.0",
|
|
42
|
+
"tiktoken": "^1.0.15",
|
|
43
|
+
"web-tree-sitter": "^0.22.6"
|
|
46
44
|
},
|
|
47
45
|
"devDependencies": {
|
|
48
|
-
"eslint": "^
|
|
49
|
-
"vitest": "^
|
|
46
|
+
"eslint": "^8.57.0",
|
|
47
|
+
"vitest": "^1.2.2"
|
|
50
48
|
}
|
|
51
49
|
}
|
package/src/cache/hash.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
* File hash computation for incremental cache.
|
|
3
|
-
* Uses Node.js crypto SHA-256 to produce deterministic file fingerprints.
|
|
4
|
-
*/
|
|
1
|
+
'use strict';
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
const { createHash } = require('crypto');
|
|
4
|
+
const { readFileSync } = require('fs');
|
|
8
5
|
|
|
9
6
|
/**
|
|
10
|
-
* Compute SHA-256 hash of a file
|
|
11
|
-
* @param {string} filePath
|
|
12
|
-
* @returns {string}
|
|
7
|
+
* Compute SHA-256 hash of a file.
|
|
8
|
+
* @param {string} filePath
|
|
9
|
+
* @returns {string} hex string prefixed with 'sha256:'
|
|
13
10
|
*/
|
|
14
|
-
|
|
11
|
+
function computeHash(filePath) {
|
|
15
12
|
const content = readFileSync(filePath);
|
|
16
13
|
return 'sha256:' + createHash('sha256').update(content).digest('hex');
|
|
17
14
|
}
|
|
15
|
+
|
|
16
|
+
module.exports = { computeHash };
|
package/src/cache/index.js
CHANGED
|
@@ -1,56 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
* Incremental cache module.
|
|
3
|
-
* Persists file hashes to .legacyver-cache/hashes.json so that
|
|
4
|
-
* unchanged files can skip LLM re-analysis on subsequent runs.
|
|
5
|
-
*/
|
|
1
|
+
'use strict';
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
const { readFileSync, writeFileSync, mkdirSync, existsSync, appendFileSync } = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const logger = require('../utils/logger');
|
|
9
6
|
|
|
10
7
|
const CACHE_FILE = 'hashes.json';
|
|
11
8
|
|
|
12
9
|
/**
|
|
13
|
-
* Load
|
|
14
|
-
* @param {string} cacheDir
|
|
15
|
-
* @returns {
|
|
10
|
+
* Load cache from .legacyver-cache/hashes.json.
|
|
11
|
+
* @param {string} cacheDir
|
|
12
|
+
* @returns {Object} map of relativePath -> { hash, docFile, generatedAt }
|
|
16
13
|
*/
|
|
17
|
-
|
|
18
|
-
const cachePath = join(cacheDir, CACHE_FILE);
|
|
19
|
-
if (!existsSync(cachePath)) {
|
|
20
|
-
return {};
|
|
21
|
-
}
|
|
14
|
+
function loadCache(cacheDir) {
|
|
15
|
+
const cachePath = path.join(cacheDir, CACHE_FILE);
|
|
16
|
+
if (!existsSync(cachePath)) return {};
|
|
22
17
|
try {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// Corrupted cache — start fresh
|
|
18
|
+
return JSON.parse(readFileSync(cachePath, 'utf8'));
|
|
19
|
+
} catch (e) {
|
|
20
|
+
logger.warn(`Could not read cache: ${e.message}`);
|
|
27
21
|
return {};
|
|
28
22
|
}
|
|
29
23
|
}
|
|
30
24
|
|
|
31
25
|
/**
|
|
32
|
-
* Save
|
|
33
|
-
*
|
|
34
|
-
* @param {
|
|
35
|
-
* @param {Record<string, { hash: string, generatedAt: string }>} cacheMap - Cache map to persist
|
|
26
|
+
* Save cache to .legacyver-cache/hashes.json.
|
|
27
|
+
* @param {string} cacheDir
|
|
28
|
+
* @param {Object} map
|
|
36
29
|
*/
|
|
37
|
-
|
|
30
|
+
function saveCache(cacheDir, map) {
|
|
38
31
|
mkdirSync(cacheDir, { recursive: true });
|
|
39
|
-
const cachePath = join(cacheDir, CACHE_FILE);
|
|
40
|
-
writeFileSync(cachePath, JSON.stringify(
|
|
32
|
+
const cachePath = path.join(cacheDir, CACHE_FILE);
|
|
33
|
+
writeFileSync(cachePath, JSON.stringify(map, null, 2), 'utf8');
|
|
41
34
|
}
|
|
42
35
|
|
|
43
36
|
/**
|
|
44
|
-
* Separate
|
|
45
|
-
*
|
|
46
|
-
* @param {
|
|
47
|
-
* @
|
|
48
|
-
* @returns {{ hits: import('../crawler/manifest.js').FileManifest[], misses: import('../crawler/manifest.js').FileManifest[] }}
|
|
37
|
+
* Separate files into cache hits and misses.
|
|
38
|
+
* @param {Array} manifest FileManifest[]
|
|
39
|
+
* @param {Object} cacheMap
|
|
40
|
+
* @returns {{ hits: Array, misses: Array }}
|
|
49
41
|
*/
|
|
50
|
-
|
|
42
|
+
function getCacheHits(manifest, cacheMap) {
|
|
51
43
|
const hits = [];
|
|
52
44
|
const misses = [];
|
|
53
|
-
|
|
54
45
|
for (const file of manifest) {
|
|
55
46
|
const cached = cacheMap[file.relativePath];
|
|
56
47
|
if (cached && cached.hash === file.hash) {
|
|
@@ -59,48 +50,35 @@ export function getCacheHits(manifest, cacheMap) {
|
|
|
59
50
|
misses.push(file);
|
|
60
51
|
}
|
|
61
52
|
}
|
|
62
|
-
|
|
63
53
|
return { hits, misses };
|
|
64
54
|
}
|
|
65
55
|
|
|
66
56
|
/**
|
|
67
|
-
* Remove
|
|
68
|
-
* @param {
|
|
69
|
-
* @param {string[]} currentPaths
|
|
70
|
-
* @returns {Record<string, { hash: string }>} Cleaned cache map
|
|
57
|
+
* Remove entries for files that no longer exist on disk.
|
|
58
|
+
* @param {Object} cacheMap mutated in place
|
|
59
|
+
* @param {string[]} currentPaths relative paths currently on disk
|
|
71
60
|
*/
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
cleaned[key] = value;
|
|
61
|
+
function purgeDeleted(cacheMap, currentPaths) {
|
|
62
|
+
const current = new Set(currentPaths);
|
|
63
|
+
for (const key of Object.keys(cacheMap)) {
|
|
64
|
+
if (!current.has(key)) {
|
|
65
|
+
delete cacheMap[key];
|
|
78
66
|
}
|
|
79
67
|
}
|
|
80
|
-
return cleaned;
|
|
81
68
|
}
|
|
82
69
|
|
|
83
70
|
/**
|
|
84
|
-
* Auto-add .legacyver-cache/ to .gitignore if
|
|
85
|
-
*
|
|
86
|
-
* @param {string} projectRoot - Root directory of the project being analyzed
|
|
71
|
+
* Auto-add .legacyver-cache/ to .gitignore if it exists in projectRoot.
|
|
72
|
+
* @param {string} projectRoot
|
|
87
73
|
*/
|
|
88
|
-
|
|
89
|
-
const gitignorePath = join(projectRoot, '.gitignore');
|
|
90
|
-
if (!existsSync(gitignorePath))
|
|
91
|
-
|
|
74
|
+
function autoAddToGitignore(projectRoot) {
|
|
75
|
+
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
76
|
+
if (!existsSync(gitignorePath)) return;
|
|
77
|
+
const content = readFileSync(gitignorePath, 'utf8');
|
|
78
|
+
if (!content.includes('.legacyver-cache')) {
|
|
79
|
+
appendFileSync(gitignorePath, '\n.legacyver-cache/\n');
|
|
80
|
+
logger.info('Added .legacyver-cache/ to .gitignore');
|
|
92
81
|
}
|
|
93
|
-
|
|
94
|
-
const content = readFileSync(gitignorePath, 'utf-8');
|
|
95
|
-
const entry = '.legacyver-cache/';
|
|
96
|
-
|
|
97
|
-
// Check if already present (exact line match)
|
|
98
|
-
const lines = content.split('\n');
|
|
99
|
-
if (lines.some((line) => line.trim() === entry || line.trim() === '.legacyver-cache')) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Append entry with a newline separator
|
|
104
|
-
const separator = content.endsWith('\n') ? '' : '\n';
|
|
105
|
-
writeFileSync(gitignorePath, content + separator + entry + '\n', 'utf-8');
|
|
106
82
|
}
|
|
83
|
+
|
|
84
|
+
module.exports = { loadCache, saveCache, getCacheHits, purgeDeleted, autoAddToGitignore };
|