legacyver 2.1.1 → 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/.legacyverrc +5 -10
- package/legacyver-docs/SUMMARY.md +1 -1
- package/legacyver-docs/components.md +57 -0
- package/legacyver-docs/index.md +6 -204
- package/package.json +1 -1
- package/src/cli/commands/analyze.js +15 -4
- package/src/cli/commands/init.js +13 -6
- package/src/cli/commands/providers.js +5 -0
- package/src/llm/free-model.js +17 -2
- package/src/llm/index.js +4 -1
- package/src/llm/providers/gemini.js +94 -0
- package/src/llm/providers/groq.js +3 -1
- package/src/llm/queue.js +12 -1
- package/src/utils/config.js +9 -1
package/.legacyverrc
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"provider": "
|
|
2
|
+
"provider": "openrouter",
|
|
3
|
+
"model": "meta-llama/llama-3.3-70b-instruct:free",
|
|
3
4
|
"format": "markdown",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"ignore": [
|
|
8
|
-
"test/**",
|
|
9
|
-
"**/*.test.*",
|
|
10
|
-
"**/node_modules/**"
|
|
11
|
-
]
|
|
12
|
-
}
|
|
5
|
+
"out": "./legacyver-docs",
|
|
6
|
+
"apiKey": "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"
|
|
7
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
## Overview
|
|
2
|
+
This file contains React components and a utility function for formatting currency amounts.
|
|
3
|
+
|
|
4
|
+
## Functions
|
|
5
|
+
|
|
6
|
+
### formatCurrency
|
|
7
|
+
|
|
8
|
+
#### Description
|
|
9
|
+
Formats a given amount as a string in a specified currency.
|
|
10
|
+
|
|
11
|
+
#### Params Table
|
|
12
|
+
|
|
13
|
+
| Name | Type |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| `amount` | `number` |
|
|
16
|
+
| `currency` | `string`, defaults to `'USD'` |
|
|
17
|
+
|
|
18
|
+
#### Return Value
|
|
19
|
+
A formatted string representing the currency amount.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
export function formatCurrency(amount: number, currency: string = 'USD'): string {
|
|
23
|
+
return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Dependencies
|
|
28
|
+
|
|
29
|
+
* `react`
|
|
30
|
+
* `intl`
|
|
31
|
+
|
|
32
|
+
## Overview
|
|
33
|
+
This file appears to contain UI components, with buttons and cards used for user representation.
|
|
34
|
+
|
|
35
|
+
## Functions
|
|
36
|
+
|
|
37
|
+
### Button
|
|
38
|
+
#### Description
|
|
39
|
+
A button component that can trigger an action.
|
|
40
|
+
#### Params Table
|
|
41
|
+
| Param | Type | Required |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| - | - | No |
|
|
44
|
+
#### Return Value
|
|
45
|
+
N/A
|
|
46
|
+
|
|
47
|
+
### UserCard
|
|
48
|
+
#### Description
|
|
49
|
+
A card component representing a user.
|
|
50
|
+
#### Params Table
|
|
51
|
+
| Param | Type | Required |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| - | - | Yes |
|
|
54
|
+
|
|
55
|
+
## Dependencies
|
|
56
|
+
* `@ui-component/library` (UI components library)
|
|
57
|
+
* `@utils/typography` (Typography utilities)
|
package/legacyver-docs/index.md
CHANGED
|
@@ -1,213 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# src — Documentation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Primary language:** typescript
|
|
4
|
+
**Total files:** 1
|
|
5
|
+
**Analyzed at:** 2026-02-21T07:52:12.371Z
|
|
4
6
|
|
|
5
|
-
##
|
|
7
|
+
## Files
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|---|---|
|
|
9
|
-
| Primary Language | javascript |
|
|
10
|
-
| Total Files | 66 |
|
|
11
|
-
| Analyzed At | 2026-02-21T06:45:30.827Z |
|
|
12
|
-
|
|
13
|
-
## Entry Points
|
|
14
|
-
|
|
15
|
-
- [bin/legacyver.js](bin/legacyver.md)
|
|
16
|
-
- [src/cache/hash.js](src/cache/hash.md)
|
|
17
|
-
- [src/cli/commands/version.js](src/cli/commands/version.md)
|
|
18
|
-
- [src/parser/ast/generic.js](src/parser/ast/generic.md)
|
|
19
|
-
- [src/parser/ast/go.js](src/parser/ast/go.md)
|
|
20
|
-
- [src/parser/ast/java.js](src/parser/ast/java.md)
|
|
21
|
-
- [src/parser/ast/typescript.js](src/parser/ast/typescript.md)
|
|
22
|
-
- [src/renderer/html.js](src/renderer/html.md)
|
|
23
|
-
- [src/renderer/json.js](src/renderer/json.md)
|
|
24
|
-
- [src/renderer/markdown.js](src/renderer/markdown.md)
|
|
25
|
-
- [test/chunker.test.js](test/chunker.test.md)
|
|
26
|
-
- [test/complexity-scorer.test.js](test/complexity-scorer.test.md)
|
|
27
|
-
- [test/crawler.test.js](test/crawler.test.md)
|
|
28
|
-
- [test/fixtures/js-express/src/app.js](test/fixtures/js-express/src/app.md)
|
|
29
|
-
- [test/fixtures/python-flask/app.py](test/fixtures/python-flask/app.md)
|
|
30
|
-
- [test/fixtures/ts-react/src/components.tsx](test/fixtures/ts-react/src/components.md)
|
|
31
|
-
- [test/integration.laravel.test.js](test/integration.laravel.test.md)
|
|
32
|
-
- [test/integration.test.js](test/integration.test.md)
|
|
33
|
-
- [test/parser.laravel.test.js](test/parser.laravel.test.md)
|
|
34
|
-
- [test/parser.test.js](test/parser.test.md)
|
|
35
|
-
- [test/providers.openrouter.test.js](test/providers.openrouter.test.md)
|
|
36
|
-
- [test/validator.test.js](test/validator.test.md)
|
|
9
|
+
- [components.tsx](components.md)
|
|
37
10
|
|
|
38
11
|
## Dependency Graph
|
|
39
12
|
|
|
40
13
|
```mermaid
|
|
41
14
|
graph TD
|
|
42
|
-
N0["bin/legacyver.js"] --> N1["src/cli/commands/analyze.js"]
|
|
43
|
-
N0["bin/legacyver.js"] --> N2["src/cli/commands/init.js"]
|
|
44
|
-
N0["bin/legacyver.js"] --> N3["src/cli/commands/providers.js"]
|
|
45
|
-
N0["bin/legacyver.js"] --> N4["src/cli/commands/cache.js"]
|
|
46
|
-
N5["src/cache/index.js"] --> N6["src/utils/logger.js"]
|
|
47
|
-
N1["src/cli/commands/analyze.js"] --> N7["src/utils/config.js"]
|
|
48
|
-
N1["src/cli/commands/analyze.js"] --> N8["src/cli/ui.js"]
|
|
49
|
-
N1["src/cli/commands/analyze.js"] --> N6["src/utils/logger.js"]
|
|
50
|
-
N1["src/cli/commands/analyze.js"] --> N9["src/utils/errors.js"]
|
|
51
|
-
N1["src/cli/commands/analyze.js"] --> N10["src/crawler/index.js"]
|
|
52
|
-
N1["src/cli/commands/analyze.js"] --> N5["src/cache/index.js"]
|
|
53
|
-
N1["src/cli/commands/analyze.js"] --> N11["src/parser/index.js"]
|
|
54
|
-
N1["src/cli/commands/analyze.js"] --> N12["src/llm/cost-estimator.js"]
|
|
55
|
-
N1["src/cli/commands/analyze.js"] --> N13["src/llm/chunker.js"]
|
|
56
|
-
N1["src/cli/commands/analyze.js"] --> N14["src/llm/free-model.js"]
|
|
57
|
-
N1["src/cli/commands/analyze.js"] --> N15["src/llm/queue.js"]
|
|
58
|
-
N1["src/cli/commands/analyze.js"] --> N16["src/llm/index.js"]
|
|
59
|
-
N1["src/cli/commands/analyze.js"] --> N17["src/llm/validator.js"]
|
|
60
|
-
N1["src/cli/commands/analyze.js"] --> N18["src/llm/re-prompter.js"]
|
|
61
|
-
N1["src/cli/commands/analyze.js"] --> N19["src/renderer/index.js"]
|
|
62
|
-
N3["src/cli/commands/providers.js"] --> N6["src/utils/logger.js"]
|
|
63
|
-
N3["src/cli/commands/providers.js"] --> N7["src/utils/config.js"]
|
|
64
|
-
N10["src/crawler/index.js"] --> N20["src/crawler/walk.js"]
|
|
65
|
-
N10["src/crawler/index.js"] --> N21["src/crawler/manifest.js"]
|
|
66
|
-
N10["src/crawler/index.js"] --> N22["src/crawler/filters.js"]
|
|
67
|
-
N10["src/crawler/index.js"] --> N6["src/utils/logger.js"]
|
|
68
|
-
N21["src/crawler/manifest.js"] --> N22["src/crawler/filters.js"]
|
|
69
|
-
N20["src/crawler/walk.js"] --> N22["src/crawler/filters.js"]
|
|
70
|
-
N13["src/llm/chunker.js"] --> N23["src/llm/prompts.js"]
|
|
71
|
-
N13["src/llm/chunker.js"] --> N12["src/llm/cost-estimator.js"]
|
|
72
|
-
N13["src/llm/chunker.js"] --> N6["src/utils/logger.js"]
|
|
73
|
-
N12["src/llm/cost-estimator.js"] --> N6["src/utils/logger.js"]
|
|
74
|
-
N14["src/llm/free-model.js"] --> N6["src/utils/logger.js"]
|
|
75
|
-
N16["src/llm/index.js"] --> N24["src/llm/providers/openrouter.js"]
|
|
76
|
-
N16["src/llm/index.js"] --> N25["src/llm/providers/ollama.js"]
|
|
77
|
-
N16["src/llm/index.js"] --> N26["src/llm/providers/groq.js"]
|
|
78
|
-
N26["src/llm/providers/groq.js"] --> N9["src/utils/errors.js"]
|
|
79
|
-
N25["src/llm/providers/ollama.js"] --> N6["src/utils/logger.js"]
|
|
80
|
-
N24["src/llm/providers/openrouter.js"] --> N9["src/utils/errors.js"]
|
|
81
|
-
N24["src/llm/providers/openrouter.js"] --> N6["src/utils/logger.js"]
|
|
82
|
-
N15["src/llm/queue.js"] --> N6["src/utils/logger.js"]
|
|
83
|
-
N18["src/llm/re-prompter.js"] --> N23["src/llm/prompts.js"]
|
|
84
|
-
N18["src/llm/re-prompter.js"] --> N6["src/utils/logger.js"]
|
|
85
|
-
N17["src/llm/validator.js"] --> N6["src/utils/logger.js"]
|
|
86
|
-
N27["src/parser/ast/generic.js"] --> N6["src/utils/logger.js"]
|
|
87
|
-
N28["src/parser/ast/go.js"] --> N29["src/parser/complexity-scorer.js"]
|
|
88
|
-
N28["src/parser/ast/go.js"] --> N30["src/parser/body-extractor.js"]
|
|
89
|
-
N31["src/parser/ast/java.js"] --> N29["src/parser/complexity-scorer.js"]
|
|
90
|
-
N31["src/parser/ast/java.js"] --> N30["src/parser/body-extractor.js"]
|
|
91
|
-
N32["src/parser/ast/javascript.js"] --> N29["src/parser/complexity-scorer.js"]
|
|
92
|
-
N32["src/parser/ast/javascript.js"] --> N30["src/parser/body-extractor.js"]
|
|
93
|
-
N33["src/parser/ast/laravel/index.js"] --> N34["src/parser/ast/laravel/classifier.js"]
|
|
94
|
-
N33["src/parser/ast/laravel/index.js"] --> N35["src/parser/ast/laravel/controller.js"]
|
|
95
|
-
N33["src/parser/ast/laravel/index.js"] --> N36["src/parser/ast/laravel/model.js"]
|
|
96
|
-
N33["src/parser/ast/laravel/index.js"] --> N37["src/parser/ast/laravel/routes.js"]
|
|
97
|
-
N33["src/parser/ast/laravel/index.js"] --> N38["src/parser/ast/laravel/blade.js"]
|
|
98
|
-
N33["src/parser/ast/laravel/index.js"] --> N39["src/parser/ast/laravel/provider.js"]
|
|
99
|
-
N40["src/parser/ast/php.js"] --> N29["src/parser/complexity-scorer.js"]
|
|
100
|
-
N40["src/parser/ast/php.js"] --> N30["src/parser/body-extractor.js"]
|
|
101
|
-
N41["src/parser/ast/python.js"] --> N29["src/parser/complexity-scorer.js"]
|
|
102
|
-
N41["src/parser/ast/python.js"] --> N30["src/parser/body-extractor.js"]
|
|
103
|
-
N42["src/parser/ast/typescript.js"] --> N32["src/parser/ast/javascript.js"]
|
|
104
|
-
N29["src/parser/complexity-scorer.js"] --> N43["src/parser/pattern-detector.js"]
|
|
105
|
-
N11["src/parser/index.js"] --> N6["src/utils/logger.js"]
|
|
106
|
-
N11["src/parser/index.js"] --> N33["src/parser/ast/laravel/index.js"]
|
|
107
|
-
N11["src/parser/index.js"] --> N44["src/parser/call-graph.js"]
|
|
108
|
-
N11["src/parser/index.js"] --> N45["src/parser/pkg-builder.js"]
|
|
109
|
-
N19["src/renderer/index.js"] --> N9["src/utils/errors.js"]
|
|
110
|
-
N46["test/chunker.test.js"] --> N13["src/llm/chunker.js"]
|
|
111
|
-
N47["test/complexity-scorer.test.js"] --> N29["src/parser/complexity-scorer.js"]
|
|
112
|
-
N47["test/complexity-scorer.test.js"] --> N43["src/parser/pattern-detector.js"]
|
|
113
|
-
N47["test/complexity-scorer.test.js"] --> N30["src/parser/body-extractor.js"]
|
|
114
|
-
N48["test/crawler.test.js"] --> N10["src/crawler/index.js"]
|
|
115
|
-
N49["test/fixtures/js-express/src/app.js"] --> N50["test/fixtures/js-express/src/routes/users.js"]
|
|
116
|
-
N49["test/fixtures/js-express/src/app.js"] --> N51["test/fixtures/js-express/src/middleware/auth.js"]
|
|
117
|
-
N50["test/fixtures/js-express/src/routes/users.js"] --> N52["test/fixtures/js-express/src/utils/db.js"]
|
|
118
|
-
N53["test/integration.laravel.test.js"] --> N10["src/crawler/index.js"]
|
|
119
|
-
N53["test/integration.laravel.test.js"] --> N11["src/parser/index.js"]
|
|
120
|
-
N53["test/integration.laravel.test.js"] --> N13["src/llm/chunker.js"]
|
|
121
|
-
N53["test/integration.laravel.test.js"] --> N19["src/renderer/index.js"]
|
|
122
|
-
N54["test/integration.test.js"] --> N10["src/crawler/index.js"]
|
|
123
|
-
N54["test/integration.test.js"] --> N11["src/parser/index.js"]
|
|
124
|
-
N54["test/integration.test.js"] --> N13["src/llm/chunker.js"]
|
|
125
|
-
N54["test/integration.test.js"] --> N19["src/renderer/index.js"]
|
|
126
|
-
N55["test/parser.laravel.test.js"] --> N40["src/parser/ast/php.js"]
|
|
127
|
-
N55["test/parser.laravel.test.js"] --> N33["src/parser/ast/laravel/index.js"]
|
|
128
|
-
N55["test/parser.laravel.test.js"] --> N34["src/parser/ast/laravel/classifier.js"]
|
|
129
|
-
N55["test/parser.laravel.test.js"] --> N37["src/parser/ast/laravel/routes.js"]
|
|
130
|
-
N55["test/parser.laravel.test.js"] --> N36["src/parser/ast/laravel/model.js"]
|
|
131
|
-
N55["test/parser.laravel.test.js"] --> N35["src/parser/ast/laravel/controller.js"]
|
|
132
|
-
N56["test/parser.test.js"] --> N32["src/parser/ast/javascript.js"]
|
|
133
|
-
N56["test/parser.test.js"] --> N40["src/parser/ast/php.js"]
|
|
134
|
-
N56["test/parser.test.js"] --> N41["src/parser/ast/python.js"]
|
|
135
|
-
N56["test/parser.test.js"] --> N33["src/parser/ast/laravel/index.js"]
|
|
136
|
-
N57["test/providers.openrouter.test.js"] --> N24["src/llm/providers/openrouter.js"]
|
|
137
|
-
N57["test/providers.openrouter.test.js"] --> N9["src/utils/errors.js"]
|
|
138
|
-
N58["test/validator.test.js"] --> N17["src/llm/validator.js"]
|
|
139
15
|
```
|
|
140
|
-
|
|
141
|
-
## Module Index
|
|
142
|
-
|
|
143
|
-
| File | Language | Lines | Functions | Classes |
|
|
144
|
-
|---|---|---|---|---|
|
|
145
|
-
| [bin/legacyver.js](bin/legacyver.md) | javascript | 48 | 1 | 0 |
|
|
146
|
-
| [src/cache/hash.js](src/cache/hash.md) | javascript | 13 | 1 | 0 |
|
|
147
|
-
| [src/cache/index.js](src/cache/index.md) | javascript | 76 | 6 | 0 |
|
|
148
|
-
| [src/cli/commands/analyze.js](src/cli/commands/analyze.md) | javascript | 218 | 11 | 0 |
|
|
149
|
-
| [src/cli/commands/cache.js](src/cli/commands/cache.md) | javascript | 13 | 2 | 0 |
|
|
150
|
-
| [src/cli/commands/init.js](src/cli/commands/init.md) | javascript | 60 | 8 | 0 |
|
|
151
|
-
| [src/cli/commands/providers.js](src/cli/commands/providers.md) | javascript | 46 | 1 | 0 |
|
|
152
|
-
| [src/cli/commands/version.js](src/cli/commands/version.md) | javascript | 7 | 1 | 0 |
|
|
153
|
-
| [src/cli/ui.js](src/cli/ui.md) | javascript | 78 | 6 | 0 |
|
|
154
|
-
| [src/crawler/filters.js](src/crawler/filters.md) | javascript | 52 | 2 | 0 |
|
|
155
|
-
| [src/crawler/index.js](src/crawler/index.md) | javascript | 55 | 4 | 0 |
|
|
156
|
-
| [src/crawler/manifest.js](src/crawler/manifest.md) | javascript | 34 | 1 | 0 |
|
|
157
|
-
| [src/crawler/walk.js](src/crawler/walk.md) | javascript | 43 | 1 | 0 |
|
|
158
|
-
| [src/llm/chunker.js](src/llm/chunker.md) | javascript | 46 | 2 | 0 |
|
|
159
|
-
| [src/llm/cost-estimator.js](src/llm/cost-estimator.md) | javascript | 74 | 10 | 0 |
|
|
160
|
-
| [src/llm/free-model.js](src/llm/free-model.md) | javascript | 42 | 1 | 0 |
|
|
161
|
-
| [src/llm/index.js](src/llm/index.md) | javascript | 22 | 4 | 0 |
|
|
162
|
-
| [src/llm/prompts.js](src/llm/prompts.md) | javascript | 51 | 2 | 0 |
|
|
163
|
-
| [src/llm/providers/groq.js](src/llm/providers/groq.md) | javascript | 54 | 7 | 1 |
|
|
164
|
-
| [src/llm/providers/ollama.js](src/llm/providers/ollama.md) | javascript | 48 | 4 | 1 |
|
|
165
|
-
| [src/llm/providers/openrouter.js](src/llm/providers/openrouter.md) | javascript | 56 | 6 | 1 |
|
|
166
|
-
| [src/llm/queue.js](src/llm/queue.md) | javascript | 53 | 1 | 0 |
|
|
167
|
-
| [src/llm/re-prompter.js](src/llm/re-prompter.md) | javascript | 35 | 1 | 0 |
|
|
168
|
-
| [src/llm/validator.js](src/llm/validator.md) | javascript | 61 | 11 | 1 |
|
|
169
|
-
| [src/parser/ast/generic.js](src/parser/ast/generic.md) | javascript | 62 | 1 | 0 |
|
|
170
|
-
| [src/parser/ast/go.js](src/parser/ast/go.md) | javascript | 105 | 5 | 0 |
|
|
171
|
-
| [src/parser/ast/java.js](src/parser/ast/java.md) | javascript | 92 | 5 | 0 |
|
|
172
|
-
| [src/parser/ast/javascript.js](src/parser/ast/javascript.md) | javascript | 190 | 6 | 0 |
|
|
173
|
-
| [src/parser/ast/laravel/blade.js](src/parser/ast/laravel/blade.md) | javascript | 50 | 1 | 0 |
|
|
174
|
-
| [src/parser/ast/laravel/classifier.js](src/parser/ast/laravel/classifier.md) | javascript | 24 | 1 | 0 |
|
|
175
|
-
| [src/parser/ast/laravel/controller.js](src/parser/ast/laravel/controller.md) | javascript | 30 | 2 | 0 |
|
|
176
|
-
| [src/parser/ast/laravel/index.js](src/parser/ast/laravel/index.md) | javascript | 47 | 2 | 0 |
|
|
177
|
-
| [src/parser/ast/laravel/model.js](src/parser/ast/laravel/model.md) | javascript | 34 | 2 | 0 |
|
|
178
|
-
| [src/parser/ast/laravel/provider.js](src/parser/ast/laravel/provider.md) | javascript | 23 | 1 | 0 |
|
|
179
|
-
| [src/parser/ast/laravel/routes.js](src/parser/ast/laravel/routes.md) | javascript | 37 | 1 | 0 |
|
|
180
|
-
| [src/parser/ast/php.js](src/parser/ast/php.md) | javascript | 115 | 6 | 0 |
|
|
181
|
-
| [src/parser/ast/python.js](src/parser/ast/python.md) | javascript | 93 | 5 | 0 |
|
|
182
|
-
| [src/parser/ast/typescript.js](src/parser/ast/typescript.md) | javascript | 13 | 1 | 0 |
|
|
183
|
-
| [src/parser/body-extractor.js](src/parser/body-extractor.md) | javascript | 33 | 2 | 0 |
|
|
184
|
-
| [src/parser/call-graph.js](src/parser/call-graph.md) | javascript | 60 | 5 | 0 |
|
|
185
|
-
| [src/parser/complexity-scorer.js](src/parser/complexity-scorer.md) | javascript | 47 | 1 | 0 |
|
|
186
|
-
| [src/parser/index.js](src/parser/index.md) | javascript | 67 | 4 | 0 |
|
|
187
|
-
| [src/parser/pattern-detector.js](src/parser/pattern-detector.md) | javascript | 67 | 1 | 0 |
|
|
188
|
-
| [src/parser/pkg-builder.js](src/parser/pkg-builder.md) | javascript | 51 | 2 | 0 |
|
|
189
|
-
| [src/renderer/html.js](src/renderer/html.md) | javascript | 72 | 1 | 0 |
|
|
190
|
-
| [src/renderer/index.js](src/renderer/index.md) | javascript | 27 | 5 | 0 |
|
|
191
|
-
| [src/renderer/json.js](src/renderer/json.md) | javascript | 23 | 1 | 0 |
|
|
192
|
-
| [src/renderer/markdown.js](src/renderer/markdown.md) | javascript | 99 | 4 | 0 |
|
|
193
|
-
| [src/utils/config.js](src/utils/config.md) | javascript | 49 | 1 | 0 |
|
|
194
|
-
| [src/utils/errors.js](src/utils/errors.md) | javascript | 48 | 5 | 5 |
|
|
195
|
-
| [src/utils/logger.js](src/utils/logger.md) | javascript | 35 | 7 | 0 |
|
|
196
|
-
| [test/chunker.test.js](test/chunker.test.md) | javascript | 58 | 0 | 0 |
|
|
197
|
-
| [test/complexity-scorer.test.js](test/complexity-scorer.test.md) | javascript | 101 | 7 | 0 |
|
|
198
|
-
| [test/crawler.test.js](test/crawler.test.md) | javascript | 54 | 6 | 0 |
|
|
199
|
-
| [test/fixtures/js-express/src/app.js](test/fixtures/js-express/src/app.md) | javascript | 12 | 0 | 0 |
|
|
200
|
-
| [test/fixtures/js-express/src/middleware/auth.js](test/fixtures/js-express/src/middleware/auth.md) | javascript | 14 | 1 | 0 |
|
|
201
|
-
| [test/fixtures/js-express/src/routes/users.js](test/fixtures/js-express/src/routes/users.md) | javascript | 24 | 4 | 0 |
|
|
202
|
-
| [test/fixtures/js-express/src/utils/db.js](test/fixtures/js-express/src/utils/db.md) | javascript | 35 | 8 | 0 |
|
|
203
|
-
| [test/fixtures/python-flask/app.py](test/fixtures/python-flask/app.md) | python | 24 | 10 | 0 |
|
|
204
|
-
| [test/fixtures/ts-react/src/components.tsx](test/fixtures/ts-react/src/components.md) | typescript | 46 | 1 | 0 |
|
|
205
|
-
| [test/integration.laravel.test.js](test/integration.laravel.test.md) | javascript | 100 | 5 | 0 |
|
|
206
|
-
| [test/integration.test.js](test/integration.test.md) | javascript | 100 | 5 | 0 |
|
|
207
|
-
| [test/parser.laravel.test.js](test/parser.laravel.test.md) | javascript | 130 | 0 | 2 |
|
|
208
|
-
| [test/parser.test.js](test/parser.test.md) | javascript | 137 | 6 | 2 |
|
|
209
|
-
| [test/providers.openrouter.test.js](test/providers.openrouter.test.md) | javascript | 177 | 20 | 0 |
|
|
210
|
-
| [test/validator.test.js](test/validator.test.md) | javascript | 59 | 0 | 0 |
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
*Generated by [Legacyver](https://github.com/legacyver/legacyver)*
|
package/package.json
CHANGED
|
@@ -144,8 +144,11 @@ module.exports = async function analyzeCommand(target, flags) {
|
|
|
144
144
|
provider = createProvider(config);
|
|
145
145
|
} catch (e) {
|
|
146
146
|
if (e.code === 'NO_API_KEY') {
|
|
147
|
-
const
|
|
148
|
-
|
|
147
|
+
const providerName = (config.provider || '').toLowerCase();
|
|
148
|
+
const isGroq = providerName === 'groq';
|
|
149
|
+
const isGemini = providerName === 'gemini';
|
|
150
|
+
const label = isGemini ? 'Google Gemini' : isGroq ? 'Groq' : 'OpenRouter';
|
|
151
|
+
console.error(pc.red(`\n No API key found for ${label}.\n`));
|
|
149
152
|
console.error(' To fix, choose one of:\n');
|
|
150
153
|
if (isGroq) {
|
|
151
154
|
console.error(pc.cyan(' 1. Run the setup wizard:'));
|
|
@@ -153,14 +156,22 @@ module.exports = async function analyzeCommand(target, flags) {
|
|
|
153
156
|
console.error(pc.cyan(' 2. Set an environment variable:'));
|
|
154
157
|
console.error(' export GROQ_API_KEY=your_key_here\n');
|
|
155
158
|
console.error(' Get a free Groq key at: https://console.groq.com/keys\n');
|
|
159
|
+
} else if (isGemini) {
|
|
160
|
+
console.error(pc.cyan(' 1. Run the setup wizard:'));
|
|
161
|
+
console.error(' legacyver init\n');
|
|
162
|
+
console.error(pc.cyan(' 2. Set an environment variable:'));
|
|
163
|
+
console.error(' export GEMINI_API_KEY=your_key_here\n');
|
|
164
|
+
console.error(' Get a free key at: https://aistudio.google.com/apikey\n');
|
|
156
165
|
} else {
|
|
157
166
|
console.error(pc.cyan(' 1. Run the setup wizard:'));
|
|
158
167
|
console.error(' legacyver init\n');
|
|
159
168
|
console.error(pc.cyan(' 2. Set an environment variable:'));
|
|
160
169
|
console.error(' export OPENROUTER_API_KEY=your_key_here\n');
|
|
161
|
-
console.error(pc.cyan(' 3. Use
|
|
170
|
+
console.error(pc.cyan(' 3. Use Google Gemini instead (free, 15 req/min):'));
|
|
171
|
+
console.error(' legacyver analyze --provider gemini\n');
|
|
172
|
+
console.error(pc.cyan(' 4. Use Groq instead (fast & free):'));
|
|
162
173
|
console.error(' legacyver analyze --provider groq\n');
|
|
163
|
-
console.error(pc.cyan('
|
|
174
|
+
console.error(pc.cyan(' 5. Use local Ollama instead (no key needed):'));
|
|
164
175
|
console.error(' legacyver analyze --provider ollama\n');
|
|
165
176
|
console.error(' Get a free OpenRouter key at: https://openrouter.ai/keys\n');
|
|
166
177
|
}
|
package/src/cli/commands/init.js
CHANGED
|
@@ -24,21 +24,24 @@ module.exports = async function initCommand() {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const providerRaw = await ask(rl, `LLM provider [openrouter/groq/ollama] (default: openrouter): `);
|
|
27
|
+
const providerRaw = await ask(rl, `LLM provider [openrouter/gemini/groq/ollama] (default: openrouter): `);
|
|
28
28
|
const providerChoice = providerRaw.trim() || 'openrouter';
|
|
29
29
|
const isOllama = providerChoice === 'ollama';
|
|
30
30
|
const isGroq = providerChoice === 'groq';
|
|
31
|
+
const isGemini = providerChoice === 'gemini';
|
|
31
32
|
|
|
32
33
|
const defaultModel = isOllama
|
|
33
34
|
? 'llama3.2'
|
|
34
35
|
: isGroq
|
|
35
36
|
? 'llama-3.3-70b-versatile'
|
|
36
|
-
:
|
|
37
|
+
: isGemini
|
|
38
|
+
? 'gemini-2.0-flash'
|
|
39
|
+
: 'meta-llama/llama-3.3-70b-instruct:free';
|
|
37
40
|
|
|
38
41
|
let apiKey = '';
|
|
39
42
|
if (!isOllama) {
|
|
40
|
-
const keyLabel = isGroq ? 'Groq' : 'OpenRouter';
|
|
41
|
-
const keyHint = isGroq ? 'https://console.groq.com/keys' : 'https://openrouter.ai/keys';
|
|
43
|
+
const keyLabel = isGemini ? 'Google Gemini' : isGroq ? 'Groq' : 'OpenRouter';
|
|
44
|
+
const keyHint = isGemini ? 'https://aistudio.google.com/apikey' : isGroq ? 'https://console.groq.com/keys' : 'https://openrouter.ai/keys';
|
|
42
45
|
apiKey = await ask(rl, `${keyLabel} API key (leave blank to set via env var — see ${keyHint}): `);
|
|
43
46
|
}
|
|
44
47
|
|
|
@@ -55,7 +58,9 @@ module.exports = async function initCommand() {
|
|
|
55
58
|
};
|
|
56
59
|
|
|
57
60
|
if (apiKey.trim()) {
|
|
58
|
-
if (
|
|
61
|
+
if (isGemini) {
|
|
62
|
+
config.geminiApiKey = apiKey.trim();
|
|
63
|
+
} else if (isGroq) {
|
|
59
64
|
config.groqApiKey = apiKey.trim();
|
|
60
65
|
} else {
|
|
61
66
|
config.apiKey = apiKey.trim();
|
|
@@ -69,6 +74,8 @@ module.exports = async function initCommand() {
|
|
|
69
74
|
? 'legacyver analyze --provider ollama'
|
|
70
75
|
: isGroq
|
|
71
76
|
? 'legacyver analyze --provider groq'
|
|
72
|
-
:
|
|
77
|
+
: isGemini
|
|
78
|
+
? 'legacyver analyze --provider gemini'
|
|
79
|
+
: 'legacyver analyze';
|
|
73
80
|
console.log(pc.cyan(`\nRun \`${exampleCmd}\` to generate documentation.`));
|
|
74
81
|
};
|
|
@@ -30,6 +30,11 @@ module.exports = async function providersCommand() {
|
|
|
30
30
|
console.log(' Status: ' + (process.env.GROQ_API_KEY ? pc.green('API key detected') : pc.yellow('No API key found')));
|
|
31
31
|
console.log(' Get a free key at: https://console.groq.com/keys');
|
|
32
32
|
console.log('');
|
|
33
|
+
console.log(pc.bold('Google Gemini') + ' (https://ai.google.dev)');
|
|
34
|
+
console.log(' Free tier: 15 req/min, 1,500 req/day. Set GEMINI_API_KEY env variable.');
|
|
35
|
+
console.log(' Status: ' + (process.env.GEMINI_API_KEY ? pc.green('API key detected') : pc.yellow('No API key found')));
|
|
36
|
+
console.log(' Get a free key at: https://aistudio.google.com/apikey');
|
|
37
|
+
console.log('');
|
|
33
38
|
|
|
34
39
|
console.log(pc.bold('Recommended Models (via OpenRouter):'));
|
|
35
40
|
console.log('');
|
package/src/llm/free-model.js
CHANGED
|
@@ -11,12 +11,27 @@ const pc = require('picocolors');
|
|
|
11
11
|
function applyFreeModelPolicy(config) {
|
|
12
12
|
const provider = (config.provider || 'openrouter').toLowerCase();
|
|
13
13
|
|
|
14
|
-
// Ollama and
|
|
15
|
-
if (provider === 'ollama' || provider === 'groq') {
|
|
14
|
+
// Ollama, Groq, and Gemini are always free — skip openrouter-specific logic
|
|
15
|
+
if (provider === 'ollama' || provider === 'groq' || provider === 'gemini') {
|
|
16
16
|
config.isFreeModel = true;
|
|
17
17
|
config.skipCostEstimation = true;
|
|
18
18
|
if (provider === 'groq') {
|
|
19
19
|
console.log(pc.cyan('[info] Using Groq — free tier. Rate limit: 30 req/min, 14,400 req/day'));
|
|
20
|
+
// Cap concurrency to 1 for Groq to avoid rate limits (30 req/min)
|
|
21
|
+
const requested = parseInt(config.concurrency) || 1;
|
|
22
|
+
if (requested > 1) {
|
|
23
|
+
logger.warn(`Groq free tier: capping concurrency from ${requested} to 1.`);
|
|
24
|
+
config.concurrency = 1;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (provider === 'gemini') {
|
|
28
|
+
console.log(pc.cyan('[info] Using Gemini — free tier. Rate limit: 15 req/min, 1,500 req/day'));
|
|
29
|
+
// Cap concurrency to 2 for Gemini (15 req/min is more generous)
|
|
30
|
+
const requested = parseInt(config.concurrency) || 1;
|
|
31
|
+
if (requested > 2) {
|
|
32
|
+
logger.warn(`Gemini free tier: capping concurrency from ${requested} to 2.`);
|
|
33
|
+
config.concurrency = 2;
|
|
34
|
+
}
|
|
20
35
|
}
|
|
21
36
|
return config;
|
|
22
37
|
}
|
package/src/llm/index.js
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
const { OpenRouterProvider } = require('./providers/openrouter');
|
|
4
4
|
const { OllamaProvider } = require('./providers/ollama');
|
|
5
5
|
const { GroqProvider } = require('./providers/groq');
|
|
6
|
+
const { GeminiProvider } = require('./providers/gemini');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Provider factory — returns the appropriate LLM adapter.
|
|
9
10
|
* @param {Object} config
|
|
10
|
-
* @returns {OpenRouterProvider|OllamaProvider|GroqProvider}
|
|
11
|
+
* @returns {OpenRouterProvider|OllamaProvider|GroqProvider|GeminiProvider}
|
|
11
12
|
*/
|
|
12
13
|
function createProvider(config) {
|
|
13
14
|
const provider = (config.provider || 'openrouter').toLowerCase();
|
|
@@ -16,6 +17,8 @@ function createProvider(config) {
|
|
|
16
17
|
return new OllamaProvider(config);
|
|
17
18
|
case 'groq':
|
|
18
19
|
return new GroqProvider(config);
|
|
20
|
+
case 'gemini':
|
|
21
|
+
return new GeminiProvider(config);
|
|
19
22
|
case 'openrouter':
|
|
20
23
|
default:
|
|
21
24
|
return new OpenRouterProvider(config);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { NoApiKeyError } = require('../../utils/errors');
|
|
4
|
+
|
|
5
|
+
const GEMINI_BASE = 'https://generativelanguage.googleapis.com/v1beta';
|
|
6
|
+
const DEFAULT_MODEL = 'gemini-2.0-flash';
|
|
7
|
+
|
|
8
|
+
class GeminiProvider {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.apiKey = config.geminiApiKey || process.env.GEMINI_API_KEY;
|
|
11
|
+
if (!this.apiKey) throw new NoApiKeyError('gemini');
|
|
12
|
+
this.model = config.model || DEFAULT_MODEL;
|
|
13
|
+
this.name = 'gemini';
|
|
14
|
+
this.isFreeModel = true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async complete(chunk) {
|
|
18
|
+
const url = `${GEMINI_BASE}/models/${this.model}:generateContent?key=${this.apiKey}`;
|
|
19
|
+
|
|
20
|
+
const body = {
|
|
21
|
+
contents: [
|
|
22
|
+
{
|
|
23
|
+
parts: [
|
|
24
|
+
{ text: chunk.systemPrompt + '\n\n' + chunk.userMessage },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
generationConfig: {
|
|
29
|
+
temperature: 0.3,
|
|
30
|
+
maxOutputTokens: 4096,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
let response;
|
|
35
|
+
try {
|
|
36
|
+
response = await fetch(url, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: { 'Content-Type': 'application/json' },
|
|
39
|
+
body: JSON.stringify(body),
|
|
40
|
+
});
|
|
41
|
+
} catch (e) {
|
|
42
|
+
throw new Error(`Could not connect to Gemini API: ${e.message}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (response.status === 429) {
|
|
46
|
+
const body = await response.text();
|
|
47
|
+
const { RateLimitError } = require('../../utils/errors');
|
|
48
|
+
const headerVal = parseInt(response.headers.get('retry-after') || '0');
|
|
49
|
+
const retryAfter = Math.max(headerVal * 1000, 15000);
|
|
50
|
+
const err = new RateLimitError('gemini', retryAfter);
|
|
51
|
+
// Include Gemini's actual error detail so user can see what's wrong
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(body);
|
|
54
|
+
const detail = parsed.error && parsed.error.message ? parsed.error.message : body.substring(0, 200);
|
|
55
|
+
err.message = `Rate limit exceeded for provider "gemini": ${detail}`;
|
|
56
|
+
} catch (_) {
|
|
57
|
+
err.message = `Rate limit exceeded for provider "gemini": ${body.substring(0, 200)}`;
|
|
58
|
+
}
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
const text = await response.text();
|
|
64
|
+
throw new Error(`Gemini API error ${response.status}: ${text.substring(0, 500)}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
const text = await response.text();
|
|
69
|
+
throw new Error(`Gemini API error ${response.status}: ${text}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const data = await response.json();
|
|
73
|
+
|
|
74
|
+
// Extract content from Gemini response format
|
|
75
|
+
let content = '';
|
|
76
|
+
if (data.candidates && data.candidates[0] && data.candidates[0].content) {
|
|
77
|
+
const parts = data.candidates[0].content.parts || [];
|
|
78
|
+
content = parts.map((p) => p.text || '').join('');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Extract usage metadata
|
|
82
|
+
const usage = data.usageMetadata || {};
|
|
83
|
+
const tokensUsed = {
|
|
84
|
+
input: usage.promptTokenCount || 0,
|
|
85
|
+
output: usage.candidatesTokenCount || 0,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
return { content, tokensUsed };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
estimateCost() { return 0; }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = { GeminiProvider };
|
|
@@ -39,7 +39,9 @@ class GroqProvider {
|
|
|
39
39
|
|
|
40
40
|
if (response.status === 429) {
|
|
41
41
|
const { RateLimitError } = require('../../utils/errors');
|
|
42
|
-
const
|
|
42
|
+
const headerVal = parseInt(response.headers.get('retry-after') || '0');
|
|
43
|
+
// Minimum 15s wait — Groq free tier needs breathing room
|
|
44
|
+
const retryAfter = Math.max(headerVal * 1000, 15000);
|
|
43
45
|
throw new RateLimitError('groq', retryAfter);
|
|
44
46
|
}
|
|
45
47
|
|
package/src/llm/queue.js
CHANGED
|
@@ -21,7 +21,18 @@ async function createQueue(chunks, provider, config, callbacks = {}) {
|
|
|
21
21
|
limit(async () => {
|
|
22
22
|
try {
|
|
23
23
|
const result = await pRetry(
|
|
24
|
-
() =>
|
|
24
|
+
async () => {
|
|
25
|
+
try {
|
|
26
|
+
return await provider.complete(chunk);
|
|
27
|
+
} catch (err) {
|
|
28
|
+
// If it's a rate-limit error, wait for the retry-after period
|
|
29
|
+
// before letting p-retry schedule the next attempt.
|
|
30
|
+
if (err.code === 'RATE_LIMIT' && err.retryAfter) {
|
|
31
|
+
await new Promise((r) => setTimeout(r, err.retryAfter));
|
|
32
|
+
}
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
},
|
|
25
36
|
{
|
|
26
37
|
retries: 3,
|
|
27
38
|
minTimeout: config.isFreeModel ? 8000 : 1000,
|
package/src/utils/config.js
CHANGED
|
@@ -26,7 +26,7 @@ function loadConfig(cliFlags = {}) {
|
|
|
26
26
|
try {
|
|
27
27
|
const result = explorer.search();
|
|
28
28
|
if (result && result.config) {
|
|
29
|
-
fileConfig = result.config;
|
|
29
|
+
fileConfig = { ...result.config }; // shallow copy — never mutate the cached object
|
|
30
30
|
}
|
|
31
31
|
} catch (e) {
|
|
32
32
|
// no config file found — use defaults
|
|
@@ -50,6 +50,14 @@ function loadConfig(cliFlags = {}) {
|
|
|
50
50
|
Object.entries(cliFlags).filter(([, v]) => v !== undefined)
|
|
51
51
|
);
|
|
52
52
|
|
|
53
|
+
// If CLI specifies a different provider than what's in the config file,
|
|
54
|
+
// discard the file's model — it belongs to the old provider.
|
|
55
|
+
const effectiveProvider = cleanCli.provider || fileConfig.provider || defaults.provider;
|
|
56
|
+
const fileConfigProvider = fileConfig.provider || defaults.provider;
|
|
57
|
+
if (effectiveProvider !== fileConfigProvider && !cleanCli.model) {
|
|
58
|
+
delete fileConfig.model;
|
|
59
|
+
}
|
|
60
|
+
|
|
53
61
|
return { ...defaults, ...fileConfig, ...cleanCli };
|
|
54
62
|
}
|
|
55
63
|
|