@alint-js/cli 0.0.19 → 0.0.21
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 +52 -10
- package/dist/bin/index.mjs +1 -1
- package/dist/{cli-B-E-qUMa.mjs → cli-Dey9TSc8.mjs} +87 -21
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +4 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -24,12 +24,14 @@ While `alint` is inspired by `eslint`, we expect the concept that `alint` brings
|
|
|
24
24
|
|
|
25
25
|
### Prerequisites
|
|
26
26
|
|
|
27
|
-
`alint` is published as ESM packages and
|
|
27
|
+
`alint` is written in TypeScript and published as ESM packages for JavaScript and TypeScript projects. Release builds also include standalone binaries, so teams working in Python, Go, Rust, and other non-Node.js projects can run the CLI without setting up Node.js, npm, or pnpm.
|
|
28
28
|
|
|
29
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
30
|
|
|
31
31
|
### Install the CLI
|
|
32
32
|
|
|
33
|
+
Download a standalone binary from the GitHub release assets when you want to use `alint` without a Node.js toolchain.
|
|
34
|
+
|
|
33
35
|
Install globally if you want an `alint` command available everywhere:
|
|
34
36
|
|
|
35
37
|
```bash
|
|
@@ -40,12 +42,12 @@ pnpm add -g @alint-js/cli
|
|
|
40
42
|
Or install it in a project and run it through your package manager:
|
|
41
43
|
|
|
42
44
|
```bash
|
|
43
|
-
npm install -D @alint-js/cli
|
|
45
|
+
npm install -D @alint-js/cli
|
|
44
46
|
npx alint src
|
|
45
47
|
```
|
|
46
48
|
|
|
47
49
|
```bash
|
|
48
|
-
pnpm add -D @alint-js/cli
|
|
50
|
+
pnpm add -D @alint-js/cli
|
|
49
51
|
pnpm exec alint src
|
|
50
52
|
```
|
|
51
53
|
|
|
@@ -171,12 +173,12 @@ In order to provision models and LLMs for `alint` while keeping it clean for con
|
|
|
171
173
|
The priorities follow:
|
|
172
174
|
|
|
173
175
|
```text
|
|
174
|
-
~/.config/alint/config.toml < .alint/config.toml < alint.config
|
|
176
|
+
~/.config/alint/config.toml < .alint/config.toml < alint.config.* < environment and CLI overrides
|
|
175
177
|
```
|
|
176
178
|
|
|
177
179
|
- `~/.config/alint/config.toml` stores user-level provider setup.
|
|
178
180
|
- `.alint/config.toml` stores optional project-local provider setup.
|
|
179
|
-
- `alint.config
|
|
181
|
+
- `alint.config.*` stores project lint config, plugins, files, ignores, and rule settings.
|
|
180
182
|
- Environment variables and CLI flags are the highest-priority overrides.
|
|
181
183
|
|
|
182
184
|
Use setup TOML for machine or project provider definitions:
|
|
@@ -216,7 +218,7 @@ alint setup -N \
|
|
|
216
218
|
Similar to `eslint`, use `alint.config.ts` for files, ignores, plugins, and rules:
|
|
217
219
|
|
|
218
220
|
```ts
|
|
219
|
-
import { defineConfig } from '@alint-js/
|
|
221
|
+
import { defineConfig } from '@alint-js/cli'
|
|
220
222
|
import { examplePlugin } from '@alint-js/plugin-example'
|
|
221
223
|
|
|
222
224
|
export default defineConfig([
|
|
@@ -240,6 +242,46 @@ export default defineConfig([
|
|
|
240
242
|
])
|
|
241
243
|
```
|
|
242
244
|
|
|
245
|
+
#### Executable and static configs
|
|
246
|
+
|
|
247
|
+
`alint` supports executable configs (`.js`, `.ts`, `.mjs`, `.cjs`, `.mts`, and `.cts`) and data-only static configs (`.toml`, `.yaml`, `.yml`, `.json`, `.jsonc`, and `.json5`).
|
|
248
|
+
|
|
249
|
+
- Executable configs export a flat config array and can import plugin definitions directly.
|
|
250
|
+
- Static configs use a `config.group` array and identify plugin sources with strings. They are useful for Python, Rust, Go, and other repositories that do not want to author a JavaScript config file or install a Node.js package manager just to run `alint`.
|
|
251
|
+
|
|
252
|
+
For example, a TOML static config can install an exact remote package or a local plugin directory:
|
|
253
|
+
|
|
254
|
+
```toml
|
|
255
|
+
[[config.group]]
|
|
256
|
+
|
|
257
|
+
[config.group.plugins]
|
|
258
|
+
plugin_1 = "@scope/alint-plugin-example1@1.2.3" # package
|
|
259
|
+
plugin_2 = "./plugins/relative-plugin-examplex" # relative directory
|
|
260
|
+
plugin_3 = "/opt/alint/plugins/absolute-plugin" # absolute directory
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Relative plugin paths are resolved from the directory containing the config file, including when `--config` points to a nested config. On Windows, use TOML literal strings to preserve native backslashes:
|
|
264
|
+
|
|
265
|
+
```toml
|
|
266
|
+
[[config.group]]
|
|
267
|
+
|
|
268
|
+
[config.group.plugins]
|
|
269
|
+
native = 'C:\alint\plugins\native-plugin'
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Use `alint plugin install` after adding or changing plugin sources.
|
|
273
|
+
|
|
274
|
+
- **Package:** `@scope/alint-plugin-example1@1.2.3` downloads that exact version into `.alint/plugins/store`, verifies its integrity, and loads its root export.
|
|
275
|
+
- **Local:** `./plugins/my-plugin` or an absolute directory loads the current package root export in place. `alint` checks that the package and entry exist and that the entry stays inside the package directory. It does not build the plugin or install the plugin's dependencies.
|
|
276
|
+
|
|
277
|
+
Run the install command again after changing a source string, moving a local directory, or changing its symlink target. Changes inside the same local directory are loaded by the next CLI process without reinstalling.
|
|
278
|
+
|
|
279
|
+
Local plugins execute as trusted Node.js code. Directory containment checks validate the installed source; they are not a sandbox.
|
|
280
|
+
|
|
281
|
+
#### Plugin lockfile
|
|
282
|
+
|
|
283
|
+
`alint plugin install` writes `.alint/plugins/lock.json`. Package entries lock the downloaded package and integrity metadata. Local entries lock the physical directory identity while loading its current contents at runtime.
|
|
284
|
+
|
|
243
285
|
Rule severities follow the familiar lint convention:
|
|
244
286
|
|
|
245
287
|
- `"off"` or `0` disables a rule.
|
|
@@ -251,7 +293,7 @@ Flat configs can analyze non-JavaScript files by selecting `text/plain`:
|
|
|
251
293
|
```ts
|
|
252
294
|
import docsPlugin from '@your-alint-config/docs-rules'
|
|
253
295
|
|
|
254
|
-
import { defineConfig } from '@alint-js/
|
|
296
|
+
import { defineConfig } from '@alint-js/cli'
|
|
255
297
|
|
|
256
298
|
export default defineConfig([
|
|
257
299
|
{
|
|
@@ -401,9 +443,9 @@ defineRule({
|
|
|
401
443
|
|
|
402
444
|
| Package | Purpose |
|
|
403
445
|
| --- | --- |
|
|
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) |
|
|
406
|
-
| [`@alint-js/core`](https://github.com/moeru-ai/alint/tree/main/packages/core) |
|
|
446
|
+
| [`@alint-js/cli`](https://github.com/moeru-ai/alint/tree/main/packages/cli) | CLI entrypoint, user-facing config facade, setup commands, reporters, output inspection, and stats commands. |
|
|
447
|
+
| [`@alint-js/config`](https://github.com/moeru-ai/alint/tree/main/packages/config) | Lower-level config loading, setup TOML parsing, config paths, and ignore defaults for tools. |
|
|
448
|
+
| [`@alint-js/core`](https://github.com/moeru-ai/alint/tree/main/packages/core) | SDK and run engine for plugins, rules, source runtime, model resolution, diagnostics, cache, and agent contracts. |
|
|
407
449
|
| [`@alint-js/agent-apeira`](https://github.com/moeru-ai/alint/tree/main/packages/agent-apeira) | Apeira-backed `AgentAdapter`. |
|
|
408
450
|
| [`@alint-js/agent-pi`](https://github.com/moeru-ai/alint/tree/main/packages/agent-pi) | Pi-backed `AgentAdapter`. |
|
|
409
451
|
| [`@alint-js/plugin-example`](https://github.com/moeru-ai/alint/tree/main/packages/plugin-example) | Example TypeScript/JavaScript model-backed rules. |
|
package/dist/bin/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
2
|
import { inspect } from "node:util";
|
|
3
3
|
import { cac } from "cac";
|
|
4
|
-
import { getGlobalSetupConfigPath, getProjectSetupConfigPath, getStatsDir, loadAlintConfig, loadSetupConfig, mergeSetupConfigs, writeSetupConfig } from "@alint-js/config";
|
|
4
|
+
import { getGlobalSetupConfigPath, getProjectSetupConfigPath, getStatsDir, installStaticPlugins, loadAlintConfig, loadSetupConfig, mergeSetupConfigs, writeSetupConfig } from "@alint-js/config";
|
|
5
5
|
import { AlintRunError, hasDiscoveryFilePatterns, matchesDiscoveryFile, normalizeConfig, resolveConfigForFile, runAlint } from "@alint-js/core";
|
|
6
6
|
import { isAbsolute, join, relative, resolve } from "pathe";
|
|
7
7
|
import { getBorderCharacters, table } from "table";
|
|
@@ -14,7 +14,7 @@ import Gitignore from "gitignore-fs";
|
|
|
14
14
|
import { Minimatch, minimatch } from "minimatch";
|
|
15
15
|
import { errorMessageFrom as errorMessageFrom$1 } from "@moeru/std";
|
|
16
16
|
//#region package.json
|
|
17
|
-
var version = "0.0.
|
|
17
|
+
var version = "0.0.21";
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/cli/commands/command.ts
|
|
20
20
|
function defineCommand(node) {
|
|
@@ -226,13 +226,39 @@ async function runConfigInspectCommand(file, configPath, io) {
|
|
|
226
226
|
}
|
|
227
227
|
//#endregion
|
|
228
228
|
//#region src/cli/provider-registry.ts
|
|
229
|
+
const providerSetupSources = [
|
|
230
|
+
{
|
|
231
|
+
defaultEndpoint: "http://127.0.0.1:8317/v1",
|
|
232
|
+
defaultProviderId: "CLIProxyAPI",
|
|
233
|
+
label: "CLIProxyAPI",
|
|
234
|
+
probeModels: true,
|
|
235
|
+
value: "cliProxyApi"
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
label: "Custom OpenAI-compatible provider",
|
|
239
|
+
probeModels: true,
|
|
240
|
+
value: "custom"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
defaultEndpoint: "http://localhost:11434/v1",
|
|
244
|
+
label: "Ollama",
|
|
245
|
+
probeModels: true,
|
|
246
|
+
value: "ollama"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
label: "Manual model entry",
|
|
250
|
+
probeModels: false,
|
|
251
|
+
value: "manual"
|
|
252
|
+
}
|
|
253
|
+
];
|
|
229
254
|
function buildModelsUrl(endpoint) {
|
|
230
255
|
return new URL("models", endpoint.endsWith("/") ? endpoint : `${endpoint}/`).toString();
|
|
231
256
|
}
|
|
232
257
|
function createProviderId(endpoint, existingIds) {
|
|
233
258
|
let base = "provider";
|
|
234
259
|
try {
|
|
235
|
-
|
|
260
|
+
const url = new URL(endpoint);
|
|
261
|
+
base = findProviderSetupSourceByEndpoint(url)?.defaultProviderId ?? (url.hostname.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "").toLowerCase() || "provider");
|
|
236
262
|
} catch {
|
|
237
263
|
base = "provider";
|
|
238
264
|
}
|
|
@@ -245,6 +271,13 @@ function createProviderId(endpoint, existingIds) {
|
|
|
245
271
|
function findModel(config, request) {
|
|
246
272
|
return flattenModels(config).find(({ model }) => model.id === request || model.name === request || (model.aliases ?? []).includes(request));
|
|
247
273
|
}
|
|
274
|
+
function findProviderSetupSource(value) {
|
|
275
|
+
return providerSetupSources.find((source) => source.value === value);
|
|
276
|
+
}
|
|
277
|
+
function findProviderSetupSourceByEndpoint(endpoint) {
|
|
278
|
+
const normalizedEndpoint = endpoint instanceof URL ? endpoint.toString() : new URL(endpoint).toString();
|
|
279
|
+
return providerSetupSources.find((source) => source.defaultEndpoint !== void 0 && new URL(source.defaultEndpoint).toString() === normalizedEndpoint);
|
|
280
|
+
}
|
|
248
281
|
function flattenModels(config) {
|
|
249
282
|
return config.providers.flatMap((provider) => provider.models.map((model) => ({
|
|
250
283
|
model,
|
|
@@ -1639,6 +1672,46 @@ const output = defineCommand({
|
|
|
1639
1672
|
name: "output"
|
|
1640
1673
|
});
|
|
1641
1674
|
//#endregion
|
|
1675
|
+
//#region src/cli/commands/plugin/index.ts
|
|
1676
|
+
const plugin = defineCommand({
|
|
1677
|
+
children: [defineCommand({
|
|
1678
|
+
action: async (context, options) => {
|
|
1679
|
+
const result = await installStaticPlugins({
|
|
1680
|
+
configFile: options.config,
|
|
1681
|
+
cwd: context.io.cwd,
|
|
1682
|
+
registry: options.registry
|
|
1683
|
+
});
|
|
1684
|
+
if (result.configuredPluginCount === 0) {
|
|
1685
|
+
context.io.stdout.write("No static plugins configured. Wrote empty plugin lock.\n");
|
|
1686
|
+
return 0;
|
|
1687
|
+
}
|
|
1688
|
+
context.io.stdout.write(`Installed packages: ${result.installedPackageCount}, local directories: ${result.installedLocalDirectoryCount}.\n`);
|
|
1689
|
+
return 0;
|
|
1690
|
+
},
|
|
1691
|
+
description: "Install plugins from static configs",
|
|
1692
|
+
examples: [
|
|
1693
|
+
["# Install plugins referenced by static configs", "alint plugin install"].join("\n"),
|
|
1694
|
+
["# Install using a custom registry", "alint plugin install --registry https://registry.npmjs.org/"].join("\n"),
|
|
1695
|
+
["# Install a local directory configured as ./plugins/local-plugin", "alint plugin install"].join("\n")
|
|
1696
|
+
],
|
|
1697
|
+
help: ["Install remote packages or local directories from static configs.", "Remote packages are extracted into the project plugin store. Local directories are installed in place. Both are recorded in `.alint/plugins/lock.json`."].join("\n\n"),
|
|
1698
|
+
name: "install",
|
|
1699
|
+
options: [{
|
|
1700
|
+
description: "Npm registry URL",
|
|
1701
|
+
flags: "--registry <url>"
|
|
1702
|
+
}]
|
|
1703
|
+
})],
|
|
1704
|
+
description: "Install remote packages or local directories from static configs",
|
|
1705
|
+
examples: [["# Install remote packages or local directories from static configs", "alint plugin install"].join("\n"), [
|
|
1706
|
+
"# Install a local plugin directory from alint.config.toml",
|
|
1707
|
+
"[[config.group]]",
|
|
1708
|
+
"[config.group.plugins]",
|
|
1709
|
+
"local = \"./plugins/local-plugin\""
|
|
1710
|
+
].join("\n")],
|
|
1711
|
+
help: ["Install remote packages or local directories from static configs.", "Use `plugin install` after adding or changing plugin sources."].join("\n\n"),
|
|
1712
|
+
name: "plugin"
|
|
1713
|
+
});
|
|
1714
|
+
//#endregion
|
|
1642
1715
|
//#region src/cli/commands/setup/interactive.ts
|
|
1643
1716
|
const nonTtyMessage = "interactive setup requires a TTY. Use -N/--no-interactive with --provider-id and --provider-endpoint.\n";
|
|
1644
1717
|
const backValue = "__alint_back__";
|
|
@@ -1682,20 +1755,10 @@ async function runInteractiveSetup(io) {
|
|
|
1682
1755
|
if (step === "source") {
|
|
1683
1756
|
const source = await prompts.select({
|
|
1684
1757
|
message: "Choose provider setup mode.",
|
|
1685
|
-
options: withBackOption(
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
},
|
|
1690
|
-
{
|
|
1691
|
-
label: "Ollama",
|
|
1692
|
-
value: "ollama"
|
|
1693
|
-
},
|
|
1694
|
-
{
|
|
1695
|
-
label: "Manual model entry",
|
|
1696
|
-
value: "manual"
|
|
1697
|
-
}
|
|
1698
|
-
])
|
|
1758
|
+
options: withBackOption(providerSetupSources.map(({ label, value }) => ({
|
|
1759
|
+
label,
|
|
1760
|
+
value
|
|
1761
|
+
})))
|
|
1699
1762
|
});
|
|
1700
1763
|
if (prompts.isCancel(source)) return cancelPrompt();
|
|
1701
1764
|
if (source === backValue) {
|
|
@@ -1707,7 +1770,9 @@ async function runInteractiveSetup(io) {
|
|
|
1707
1770
|
continue;
|
|
1708
1771
|
}
|
|
1709
1772
|
if (step === "endpoint") {
|
|
1710
|
-
const
|
|
1773
|
+
const setupSource = findProviderSetupSource(draft.source ?? "custom");
|
|
1774
|
+
if (setupSource === void 0) return cancelPrompt();
|
|
1775
|
+
const endpoint = await promptEndpoint(prompts, setupSource);
|
|
1711
1776
|
if (prompts.isCancel(endpoint)) return cancelPrompt();
|
|
1712
1777
|
if (typeof endpoint !== "string") return cancelPrompt();
|
|
1713
1778
|
if (isBackInput(endpoint)) {
|
|
@@ -1759,7 +1824,7 @@ async function runInteractiveSetup(io) {
|
|
|
1759
1824
|
}
|
|
1760
1825
|
draft.headerInput = headerInput;
|
|
1761
1826
|
draft.headers = parseHeaderList(splitHeaderInput(headerInput));
|
|
1762
|
-
draft.discoveredModels = draft.source
|
|
1827
|
+
draft.discoveredModels = findProviderSetupSource(draft.source ?? "custom")?.probeModels === false ? [] : await probeModelsWithSpinner(prompts, draft.endpoint ?? "", draft.headers);
|
|
1763
1828
|
step = "models";
|
|
1764
1829
|
continue;
|
|
1765
1830
|
}
|
|
@@ -1862,9 +1927,9 @@ async function probeModelsWithSpinner(prompts, endpoint, headers) {
|
|
|
1862
1927
|
}
|
|
1863
1928
|
async function promptEndpoint(prompts, source) {
|
|
1864
1929
|
return prompts.text({
|
|
1865
|
-
defaultValue: source
|
|
1930
|
+
defaultValue: source.defaultEndpoint,
|
|
1866
1931
|
message: "Provider endpoint",
|
|
1867
|
-
placeholder: source
|
|
1932
|
+
placeholder: `${source.defaultEndpoint ?? "https://example.test/v1"}; type .. to go back`,
|
|
1868
1933
|
validate: (value) => isBackInput(value ?? "") || (value ?? "").trim().length > 0 ? void 0 : "Provider endpoint is required."
|
|
1869
1934
|
});
|
|
1870
1935
|
}
|
|
@@ -2052,6 +2117,7 @@ function statsLocation(stats) {
|
|
|
2052
2117
|
const commandTree = [
|
|
2053
2118
|
setup,
|
|
2054
2119
|
config,
|
|
2120
|
+
plugin,
|
|
2055
2121
|
output,
|
|
2056
2122
|
defineCommand({
|
|
2057
2123
|
action: (context, options) => runStatsCommand(options, context.io),
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ignorePatternsAIAgents, ignorePatternsBuildOutputs, ignorePatternsCaches, ignorePatternsCommon, ignorePatternsEslintDefaults, ignorePatternsGenerated } from "@alint-js/config";
|
|
2
|
+
import { AlintConfig, AlintConfigItem, Diagnostic, RunResult, RunnerConfig, defineConfig } from "@alint-js/core";
|
|
2
3
|
|
|
3
4
|
//#region src/cli/types.d.ts
|
|
4
5
|
interface CliIo {
|
|
@@ -35,4 +36,4 @@ interface StylishReporterOptions {
|
|
|
35
36
|
}
|
|
36
37
|
declare function formatStylish(input: Diagnostic[] | RunResult, options?: StylishReporterOptions): string;
|
|
37
38
|
//#endregion
|
|
38
|
-
export { type CliIo, type ReporterName, executeCli, formatDiagnostics, formatJson, formatStylish };
|
|
39
|
+
export { type AlintConfig, type AlintConfigItem, type CliIo, type ReporterName, type RunnerConfig, defineConfig, executeCli, formatDiagnostics, formatJson, formatStylish, ignorePatternsAIAgents, ignorePatternsBuildOutputs, ignorePatternsCaches, ignorePatternsCommon, ignorePatternsEslintDefaults, ignorePatternsGenerated };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
import { i as formatJson, n as formatDiagnostics, r as formatStylish, t as executeCli } from "./cli-
|
|
2
|
-
|
|
1
|
+
import { i as formatJson, n as formatDiagnostics, r as formatStylish, t as executeCli } from "./cli-Dey9TSc8.mjs";
|
|
2
|
+
import { ignorePatternsAIAgents, ignorePatternsBuildOutputs, ignorePatternsCaches, ignorePatternsCommon, ignorePatternsEslintDefaults, ignorePatternsGenerated } from "@alint-js/config";
|
|
3
|
+
import { defineConfig } from "@alint-js/core";
|
|
4
|
+
export { defineConfig, executeCli, formatDiagnostics, formatJson, formatStylish, ignorePatternsAIAgents, ignorePatternsBuildOutputs, ignorePatternsCaches, ignorePatternsCommon, ignorePatternsEslintDefaults, ignorePatternsGenerated };
|
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.21",
|
|
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.21",
|
|
29
|
+
"@alint-js/core": "0.0.21"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@pnpm/find-workspace-dir": "^1000.1.5",
|