@alint-js/cli 0.0.10 → 0.0.11
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/README.md +446 -0
- package/package.json +3 -3
package/README.md
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# `alint`
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
`alint` is an [`eslint`](https://eslint.org/) inspired agentic code analysis tool for vibe-coded code that needs another look. It runs model-backed rules against source files, reports diagnostics in a familiar lint format, and lets rule authors use plain model calls or swappable tool-using agents when a rule needs deeper context.
|
|
6
|
+
|
|
7
|
+
While `alint` is inspired by `eslint`, we expect the concept that `alint` brings to the table to be a new paradigm for code analysis. It should not be limited to just JavaScript/TypeScript. You can extend this to other languages, non-code artifacts, generated files, or any content a plugin knows how to review.
|
|
8
|
+
|
|
9
|
+
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
|
10
|
+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
- [Installation and Usage](#installation-and-usage)
|
|
14
|
+
- [Concepts](#concepts)
|
|
15
|
+
- [Packages](#packages)
|
|
16
|
+
- [Documentation Automation](#documentation-automation)
|
|
17
|
+
- [Development](#development)
|
|
18
|
+
- [Status](#status)
|
|
19
|
+
- [License](#license)
|
|
20
|
+
|
|
21
|
+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
|
22
|
+
|
|
23
|
+
## Installation and Usage
|
|
24
|
+
|
|
25
|
+
### Prerequisites
|
|
26
|
+
|
|
27
|
+
`alint` is published as ESM packages and is intended for modern Node.js projects. Install Node.js and a package manager such as npm or pnpm before using the CLI.
|
|
28
|
+
|
|
29
|
+
You also need at least one OpenAI-compatible model provider. Local providers such as Ollama and LM Studio work well for repeated lint runs because they keep token cost predictable.
|
|
30
|
+
|
|
31
|
+
### Install the CLI
|
|
32
|
+
|
|
33
|
+
Install globally if you want an `alint` command available everywhere:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install -g @alint-js/cli
|
|
37
|
+
pnpm add -g @alint-js/cli
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or install it in a project and run it through your package manager:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install -D @alint-js/cli @alint-js/core
|
|
44
|
+
npx alint src
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pnpm add -D @alint-js/cli @alint-js/core
|
|
49
|
+
pnpm exec alint src
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Configure a Model Provider
|
|
53
|
+
|
|
54
|
+
Use `alint setup` to write provider configuration. The `-N` flag is short for `--no-interactive`, so setup can run in scripts or through coding agents without opening an interactive TUI.
|
|
55
|
+
|
|
56
|
+
Without `--local`, setup writes the global config at `~/.config/alint/config.toml`. With `--local`, it writes `.alint/config.toml` in the current project.
|
|
57
|
+
|
|
58
|
+
<details>
|
|
59
|
+
<summary>Ollama</summary>
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
alint setup -N \
|
|
63
|
+
--provider-endpoint http://localhost:11434/v1 \
|
|
64
|
+
--provider-model qwen:8b
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
</details>
|
|
68
|
+
|
|
69
|
+
Write provider setup into the current project when a repository should carry its own model mapping:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
alint setup -N \
|
|
73
|
+
--local \
|
|
74
|
+
--provider-endpoint http://localhost:11434/v1 \
|
|
75
|
+
--provider-model qwen:8b
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
<details>
|
|
79
|
+
<summary>LM Studio</summary>
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
alint setup -N \
|
|
83
|
+
--provider-endpoint http://localhost:1234/v1 \
|
|
84
|
+
--provider-model qwen:8b
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
</details>
|
|
88
|
+
|
|
89
|
+
<details>
|
|
90
|
+
<summary>OpenRouter</summary>
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
export OPENROUTER_API_KEY="sk-..."
|
|
94
|
+
|
|
95
|
+
alint setup -N \
|
|
96
|
+
--provider-endpoint https://openrouter.ai/api/v1 \
|
|
97
|
+
--provider-header "Authorization=Bearer $OPENROUTER_API_KEY" \
|
|
98
|
+
--provider-header "HTTP-Referer=http://localhost" \
|
|
99
|
+
--provider-header "X-OpenRouter-Title=alint" \
|
|
100
|
+
--provider-model openrouter:fusion
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
</details>
|
|
104
|
+
|
|
105
|
+
<details>
|
|
106
|
+
<summary>OpenAI</summary>
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
export OPENAI_API_KEY="sk-..."
|
|
110
|
+
|
|
111
|
+
alint setup -N \
|
|
112
|
+
--provider-endpoint https://api.openai.com/v1 \
|
|
113
|
+
--provider-header "Authorization=Bearer $OPENAI_API_KEY" \
|
|
114
|
+
--provider-model gpt-5.4-mini
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
</details>
|
|
118
|
+
|
|
119
|
+
### Run alint
|
|
120
|
+
|
|
121
|
+
Run the CLI against files or directories:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
alint src
|
|
125
|
+
alint demo.ts
|
|
126
|
+
alint --format json demo.ts
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Override the matched model for a one-off run:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
alint --model qwen:8b demo.ts
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Ask model-backed rules to write diagnostics in a specific language:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
alint --lang zh-CN src
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`alint` returns exit code `1` when diagnostics are reported and `0` when the run is clean.
|
|
142
|
+
|
|
143
|
+
### Inspect Configuration and Output
|
|
144
|
+
|
|
145
|
+
Useful CLI commands:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
alint config inspect src/index.ts
|
|
149
|
+
alint config providers list
|
|
150
|
+
alint config models list
|
|
151
|
+
alint config models probe
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Save machine-readable output and inspect it later without rerunning model calls:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
alint --format json src > alint-output.json
|
|
158
|
+
alint output inspect alint-output.json
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Concepts
|
|
162
|
+
|
|
163
|
+
`alint` keeps the familiar lint shape: select targets, apply named rules, report diagnostics, and return an exit code that CI can understand. The difference is that a rule can reach its judgment through model calls or a tool-using agent when syntax-only checks are not enough.
|
|
164
|
+
|
|
165
|
+
### `alint` User side
|
|
166
|
+
|
|
167
|
+
#### Configurations
|
|
168
|
+
|
|
169
|
+
In order to provision models and LLMs for `alint` while keeping it clean for contributors of your project without requiring them to set up their own LLMs, `alint` offers layers of configuration covering **Project Local**, **Global**, project config, and environment or CLI overrides.
|
|
170
|
+
|
|
171
|
+
The priorities follow:
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
~/.config/alint/config.toml < .alint/config.toml < alint.config.ts < environment and CLI overrides
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
- `~/.config/alint/config.toml` stores user-level provider setup.
|
|
178
|
+
- `.alint/config.toml` stores optional project-local provider setup.
|
|
179
|
+
- `alint.config.ts` stores project lint config, plugins, files, ignores, and rule settings.
|
|
180
|
+
- Environment variables and CLI flags are the highest-priority overrides.
|
|
181
|
+
|
|
182
|
+
Use setup TOML for machine or project provider definitions:
|
|
183
|
+
|
|
184
|
+
```toml
|
|
185
|
+
version = 1
|
|
186
|
+
|
|
187
|
+
[[providers]]
|
|
188
|
+
id = "http://localhost:11434/v1"
|
|
189
|
+
type = "openai-compatible"
|
|
190
|
+
endpoint = "http://localhost:11434/v1"
|
|
191
|
+
|
|
192
|
+
[[providers.models]]
|
|
193
|
+
id = "qwen:8b"
|
|
194
|
+
name = "qwen:8b"
|
|
195
|
+
size = "small"
|
|
196
|
+
capabilities = [ "tool-call" ]
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Note that `-N` stands for `--no-interactive`, which means this is not an interactive setup. TUI is not required, so you can ask Codex or Claude Code to run this command for you.
|
|
200
|
+
|
|
201
|
+
You can also use `--local` to write the config in the current project:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
alint setup -N \
|
|
205
|
+
--local \
|
|
206
|
+
--provider-endpoint http://localhost:11434/v1 \
|
|
207
|
+
--provider-model qwen:8b
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
- Without `--local`, `alint` writes the global config under `~/.config/alint/config.toml`.
|
|
211
|
+
- `--local` writes `.alint/config.toml` in the current project.
|
|
212
|
+
- You can inspect configs using the `alint config` command group.
|
|
213
|
+
|
|
214
|
+
#### Using Rules & Plugins
|
|
215
|
+
|
|
216
|
+
Similar to `eslint`, use `alint.config.ts` for files, ignores, plugins, and rules:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import { defineConfig } from '@alint-js/core'
|
|
220
|
+
import { examplePlugin } from '@alint-js/plugin-example'
|
|
221
|
+
|
|
222
|
+
export default defineConfig([
|
|
223
|
+
{
|
|
224
|
+
files: ['**/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}'],
|
|
225
|
+
ignore: {
|
|
226
|
+
// Reads applicable nested .gitignore files when selecting lint targets.
|
|
227
|
+
// This is powered by gitignore-fs.
|
|
228
|
+
gitignore: true,
|
|
229
|
+
},
|
|
230
|
+
plugins: {
|
|
231
|
+
example: examplePlugin,
|
|
232
|
+
},
|
|
233
|
+
rules: {
|
|
234
|
+
// The `example` prefix is the local alias configured above.
|
|
235
|
+
'example/inline-miniature-normalizer': 'warn',
|
|
236
|
+
'example/no-redundant-jsdoc': 'warn',
|
|
237
|
+
'example/no-trivial-wrapper-stack': 'warn',
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
])
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Rule severities follow the familiar lint convention:
|
|
244
|
+
|
|
245
|
+
- `"off"` or `0` disables a rule.
|
|
246
|
+
- `"warn"` or `1` reports a warning.
|
|
247
|
+
- `"error"` or `2` reports an error.
|
|
248
|
+
|
|
249
|
+
Flat configs can analyze non-JavaScript files by selecting `text/plain`:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
import docsPlugin from '@your-alint-config/docs-rules'
|
|
253
|
+
|
|
254
|
+
import { defineConfig } from '@alint-js/core'
|
|
255
|
+
|
|
256
|
+
export default defineConfig([
|
|
257
|
+
{
|
|
258
|
+
files: ['docs/**/*.md', '**/*.txt'],
|
|
259
|
+
language: 'text/plain',
|
|
260
|
+
plugins: {
|
|
261
|
+
docs: docsPlugin,
|
|
262
|
+
},
|
|
263
|
+
rules: {
|
|
264
|
+
'docs/review-copy': 'warn',
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
])
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### Cache and Stats
|
|
271
|
+
|
|
272
|
+
`alint` caches rule target results by default in `.alintcache` to avoid repeating LLM calls for unchanged source targets.
|
|
273
|
+
|
|
274
|
+
> [!NOTE]
|
|
275
|
+
> `.alintcache` should not be committed to Git. Add it to `.gitignore` before running repeated local analysis.
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
echo ".alintcache" >> .gitignore
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Disable cache for a single run:
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
alint --no-cache src
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Run stats are recorded by default. Use `--no-stats` to skip recording for a run, and use the `stats` command group to inspect saved usage over time.
|
|
288
|
+
|
|
289
|
+
### Rule Developer side
|
|
290
|
+
|
|
291
|
+
To reduce the token cost during analysis while allowing rule authors to specify model size and capabilities, `alint` allows rule authors to **Request & Match** models with *Capability Selector* and *Size Selector*, instead of hardening the entire `alint` run to use a single model for all rules.
|
|
292
|
+
|
|
293
|
+
In other words, you could set up your DeepSeek, OpenAI, Ollama, or other OpenAI-compatible model on your machine and let rule authors request a model with `tool-call` capability and `small` size. `alint` will match the best configured model for them.
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
const model = await ctx.model({
|
|
297
|
+
capabilities: ['tool-call'],
|
|
298
|
+
size: 'small',
|
|
299
|
+
})
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
You can also call `ctx.model()` without arguments when a rule does not need a specific size or capability.
|
|
303
|
+
|
|
304
|
+
#### About agent
|
|
305
|
+
|
|
306
|
+
In `alint`, we don't limit you to any specific agent SDK. You can use an exported client from a framework such as Eve, Strands, Pi, Claude Code SDK, Codex SDK, or another tool-using runtime to implement your own agent to analyze code.
|
|
307
|
+
|
|
308
|
+
Agentic rules use `ctx.agent` when they need a multi-step tool loop, such as reading related files before reporting findings. The rule stays framework-agnostic, and the user chooses the adapter:
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
import { createApeiraAdapter } from '@alint-js/agent-apeira'
|
|
312
|
+
import { createAgentExamplePlugin } from '@alint-js/plugin-example-agent'
|
|
313
|
+
|
|
314
|
+
export default [
|
|
315
|
+
{
|
|
316
|
+
agent: createApeiraAdapter(),
|
|
317
|
+
extends: ['agent-example/recommended'],
|
|
318
|
+
plugins: {
|
|
319
|
+
'agent-example': createAgentExamplePlugin(),
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
]
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Current adapter packages include:
|
|
326
|
+
|
|
327
|
+
- `@alint-js/agent-apeira` for Apeira on the xsai stack.
|
|
328
|
+
- `@alint-js/agent-pi` for Pi.
|
|
329
|
+
|
|
330
|
+
However, be careful with token cost. `alint` is designed to be a code analysis tool, where rapid and repeated calls to the model are expected. Local models, cheap small models, and cache-friendly prompts are usually better defaults than routing every rule target through a large hosted model.
|
|
331
|
+
|
|
332
|
+
#### BYOA, any agent works
|
|
333
|
+
|
|
334
|
+
Bring Your Own Agent means `alint` does not try to own the agent harness. A rule can depend on the `@alint-js/core` agent contract, while the actual runtime can be Apeira, Pi, your own in-house agent, or a small function that calls the tools you need.
|
|
335
|
+
|
|
336
|
+
If an adapter is missing, you can implement the missing function or package your own plugin to replace it. The important part is that the rule reports diagnostics back through `alint`; how the agent reads files, calls tools, plans steps, or talks to a model is intentionally left to the adapter or plugin author.
|
|
337
|
+
|
|
338
|
+
#### Example rule
|
|
339
|
+
|
|
340
|
+
Rules are ordinary JavaScript objects built with the public DSL from `@alint-js/core`. A rule receives source targets and reports diagnostics.
|
|
341
|
+
|
|
342
|
+
```ts
|
|
343
|
+
import { defineRule } from '@alint-js/core'
|
|
344
|
+
|
|
345
|
+
export const checkFunctionRule = defineRule({
|
|
346
|
+
create: ctx => ({
|
|
347
|
+
async onTarget(target) {
|
|
348
|
+
if (target.kind !== 'function') {
|
|
349
|
+
return
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const model = await ctx.model({ capabilities: ['tool-call'], size: 'small' })
|
|
353
|
+
|
|
354
|
+
ctx.report({
|
|
355
|
+
filePath: target.file.path,
|
|
356
|
+
loc: target.loc,
|
|
357
|
+
message: `checked ${target.name} with ${model.id}`,
|
|
358
|
+
})
|
|
359
|
+
},
|
|
360
|
+
}),
|
|
361
|
+
})
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Package rules as plugins:
|
|
365
|
+
|
|
366
|
+
```ts
|
|
367
|
+
import { definePlugin } from '@alint-js/core'
|
|
368
|
+
|
|
369
|
+
import { checkFunctionRule } from './rules/check-function'
|
|
370
|
+
|
|
371
|
+
export default definePlugin({
|
|
372
|
+
configs: {
|
|
373
|
+
recommended: [
|
|
374
|
+
{
|
|
375
|
+
rules: {
|
|
376
|
+
'my-plugin/check-function': 'warn',
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
],
|
|
380
|
+
},
|
|
381
|
+
rules: {
|
|
382
|
+
'check-function': checkFunctionRule,
|
|
383
|
+
},
|
|
384
|
+
})
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Rule authors can opt out of caching when a rule depends on external state:
|
|
388
|
+
|
|
389
|
+
```ts
|
|
390
|
+
defineRule({
|
|
391
|
+
cache: false,
|
|
392
|
+
create: ctx => ({
|
|
393
|
+
onTarget(target) {
|
|
394
|
+
// Always reruns.
|
|
395
|
+
},
|
|
396
|
+
}),
|
|
397
|
+
})
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
## Packages
|
|
401
|
+
|
|
402
|
+
| Package | Purpose |
|
|
403
|
+
| --- | --- |
|
|
404
|
+
| [`@alint-js/cli`](https://github.com/moeru-ai/alint/tree/main/packages/cli) | CLI entrypoint, setup commands, reporters, output inspection, and stats commands. |
|
|
405
|
+
| [`@alint-js/config`](https://github.com/moeru-ai/alint/tree/main/packages/config) | Config loading, setup TOML parsing, config paths, and ignore defaults. |
|
|
406
|
+
| [`@alint-js/core`](https://github.com/moeru-ai/alint/tree/main/packages/core) | Public DSL, run engine, source runtime, model resolution, diagnostics, cache, and agent contracts. |
|
|
407
|
+
| [`@alint-js/agent-apeira`](https://github.com/moeru-ai/alint/tree/main/packages/agent-apeira) | Apeira-backed `AgentAdapter`. |
|
|
408
|
+
| [`@alint-js/agent-pi`](https://github.com/moeru-ai/alint/tree/main/packages/agent-pi) | Pi-backed `AgentAdapter`. |
|
|
409
|
+
| [`@alint-js/plugin-example`](https://github.com/moeru-ai/alint/tree/main/packages/plugin-example) | Example TypeScript/JavaScript model-backed rules. |
|
|
410
|
+
| [`@alint-js/plugin-example-agent`](https://github.com/moeru-ai/alint/tree/main/packages/plugin-example-agent) | Example plugin for framework-agnostic agentic rules. |
|
|
411
|
+
| [`@alint-js/plugin-example-go`](https://github.com/moeru-ai/alint/tree/main/packages/plugin-example-go) | Example semantic Go review plugin using `text/plain`. |
|
|
412
|
+
|
|
413
|
+
## Documentation Automation
|
|
414
|
+
|
|
415
|
+
The table of contents above is generated with `doctoc` so README navigation is not hand-written. Run this after changing headings:
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
pnpm docs:update
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
`docs:update` refreshes the root README TOC and then copies the root README to `packages/cli/README.md`, keeping the npm README for `@alint-js/cli` in sync with the project overview.
|
|
422
|
+
|
|
423
|
+
## Development
|
|
424
|
+
|
|
425
|
+
This repository is a pnpm workspace.
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
pnpm install
|
|
429
|
+
pnpm -F @alint-js/cli build
|
|
430
|
+
pnpm -F @alint-js/core exec vitest run
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Before sending changes, run:
|
|
434
|
+
|
|
435
|
+
```bash
|
|
436
|
+
pnpm typecheck
|
|
437
|
+
pnpm lint
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
## Status
|
|
441
|
+
|
|
442
|
+
`alint` is early and APIs may change. The core direction is stable: lint-style diagnostics, model-backed rules, flat configs, provider setup, and optional agent adapters.
|
|
443
|
+
|
|
444
|
+
## License
|
|
445
|
+
|
|
446
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alint-js/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.11",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.mts",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"pathe": "^2.0.3",
|
|
26
26
|
"table": "^6.9.0",
|
|
27
27
|
"tinyrainbow": "^3.1.0",
|
|
28
|
-
"@alint-js/
|
|
29
|
-
"@alint-js/
|
|
28
|
+
"@alint-js/config": "0.0.11",
|
|
29
|
+
"@alint-js/core": "0.0.11"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^26.0.1",
|