@pho9ubenaa/siro 0.5.1 → 0.6.0
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/CHANGELOG.md +62 -0
- package/README.md +55 -92
- package/dist/cli.mjs +24 -18
- package/dist/index.d.mts +87 -54
- package/dist/index.mjs +2 -2
- package/dist/{node-io-BDHg4J2w.mjs → node-io-CAszdmko.mjs} +757 -739
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,67 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0] — 2026-09-29
|
|
4
|
+
|
|
5
|
+
### Breaking changes and inspection scope
|
|
6
|
+
|
|
7
|
+
- Discover package.json and strict deno.json recursively by default, independently
|
|
8
|
+
of PM workspace declarations. Remove `--workspaces` / API `workspaces`, including
|
|
9
|
+
false; legacy calls receive migration errors. PM exclusions no longer hide
|
|
10
|
+
fixtures, vendor or dist. Use `exclude: ['test/fixtures', 'vendor', 'dist']`, or
|
|
11
|
+
`exclude: ['**']` to keep only cwd.
|
|
12
|
+
- Add common exclusions and explicit `installationRoots` (default `['.']`). Arrays
|
|
13
|
+
replace config values; `[]` disables installation checks, not publication checks.
|
|
14
|
+
Example: `siro lint . --installation-root . --installation-root tools/standalone`.
|
|
15
|
+
Additional independent installation projects are not automatically inferred.
|
|
16
|
+
- Resolve PM/version locally: root options stay at cwd, additional roots use their
|
|
17
|
+
entry/local detection, and other packages use manifest-local evidence. Unknown
|
|
18
|
+
PMs still receive generic publication checks; unknown availability is not safety.
|
|
19
|
+
- JSON schema 3 adds `inspection`, required finding `directory`, and optional `pm`.
|
|
20
|
+
Generic publication findings run once per manifest without a synthetic PM.
|
|
21
|
+
- Require injected `FileSystem.readDirectories`; remove `resolveDirectory`. Skip
|
|
22
|
+
directory symlinks, `.git`, node_modules and explicit exclusions before reads.
|
|
23
|
+
No implicit vendor/dist/fixture exclusions or native filesystem fallback.
|
|
24
|
+
- `requireConfigKey.defaultSafety` explicitly controls safe-default downgrades;
|
|
25
|
+
omitted safety is conservative. VersionNote has no policy effect.
|
|
26
|
+
- Reporter calls require scan cwd as a third argument:
|
|
27
|
+
`await reporter.format(result, io, { cwd })`. Await built-in reporters and direct
|
|
28
|
+
IO writes, which may now complete asynchronously; handle output rejections.
|
|
29
|
+
Two-argument custom reporter implementations can ignore the additional context.
|
|
30
|
+
|
|
31
|
+
### Fixes
|
|
32
|
+
|
|
33
|
+
- Validate consumed Deno publication metadata before applicability and check exact
|
|
34
|
+
registry pins in both inline imports and scopes. Reject unrepresentable npmrc age
|
|
35
|
+
cutoffs rather than treating any positive integer as protection.
|
|
36
|
+
- Respect known pre-12 npm targets when checking npm-shrinkwrap.json; explain removed
|
|
37
|
+
or unknown-version lockfiles instead of incorrectly reporting that no file exists.
|
|
38
|
+
- GitHub annotations reference the correct absolute file using the supplied scan cwd.
|
|
39
|
+
API/JSON paths and schema 3 retain their existing meaning.
|
|
40
|
+
- Escape untrusted display controls and workflow markers without changing API paths
|
|
41
|
+
or parsed JSON values. Observe actual stream writes and preserve exit 70 on output
|
|
42
|
+
failure. IO may complete asynchronously; synchronous return values remain ignored.
|
|
43
|
+
- Reject Promise/thenable config exports and check results without an unhandled
|
|
44
|
+
rejection overriding the configuration-error exit. Keep lint synchronous.
|
|
45
|
+
- Deno empty/age-null/exclude-only objects no longer falsely satisfy release age.
|
|
46
|
+
Valid omitted ages use active local npmrc fallback, retaining zero opt-out and
|
|
47
|
+
explicit-age precedence. Leaf remedies preserve valid exclusions.
|
|
48
|
+
- npm own publishConfig.provenance overrides npmrc, including false. Validate its
|
|
49
|
+
consumed boolean type; align finding/remedy with the responsible file and keep
|
|
50
|
+
both locations' old-target availability guards.
|
|
51
|
+
- Preserve legal POSIX backslash and colon directory names without confusing them
|
|
52
|
+
with separators or portable user input. Reject malformed/traversing adapter names.
|
|
53
|
+
- Make every remediation operation path relative to scan cwd, including multi-file
|
|
54
|
+
remedies. Findings without a responsible file remain file-less.
|
|
55
|
+
- Fix Windows package verification for paths with spaces and shell metacharacters.
|
|
56
|
+
- Make one-shot and locally installed usage explicit, restore rule configuration
|
|
57
|
+
examples, and update moved documentation anchors in findings and the rule reference.
|
|
58
|
+
|
|
59
|
+
### Inspection limits
|
|
60
|
+
|
|
61
|
+
Installation checks use local settings, not inherited effective policy. Manifest-only
|
|
62
|
+
children have no provenance-policy checks, and child executable configs are not loaded.
|
|
63
|
+
See [scope and migration](docs/configuration.md) and [schema 3](docs/json-output.md).
|
|
64
|
+
|
|
3
65
|
## [0.5.1]
|
|
4
66
|
|
|
5
67
|
### Refactoring
|
package/README.md
CHANGED
|
@@ -4,115 +4,78 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@pho9ubenaa/siro)
|
|
5
5
|
[](https://github.com/pHo9UBenaA/siro/blob/main/LICENSE)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
A security-configuration linter for npm, pnpm, Yarn, Bun, Deno, and Aube.
|
|
8
|
+
It reports supported dependency-installation and publication policy gaps, such as permissive
|
|
9
|
+
lifecycle scripts, unpinned versions, and missing publication safeguards. It does not install
|
|
10
|
+
packages or change your files.
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
| Approach | Primary question | Typical input |
|
|
13
|
+
| ----------------------------- | --------------------------------------------- | -------------------------------------------- |
|
|
14
|
+
| siro: configuration lint | Are supported install/publish settings risky? | Repository manifests and configuration files |
|
|
15
|
+
| Dependency vulnerability scan | Do dependencies match known advisories? | Dependency inventory and vulnerability data |
|
|
16
|
+
| Dependency update automation | Which dependencies can be updated? | Manifests, lockfiles, and package registries |
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
and turns those recommendations into something you can run: it **lints** repos for supply-chain risks,
|
|
16
|
-
graded `error` / `warn` / `info`, and emits machine-readable remediation so an editor or agent skill
|
|
17
|
-
can apply the fixes. The rule selection and severities reflect siro's own opinions; it is not
|
|
18
|
-
affiliated with the upstream doc.
|
|
18
|
+
These approaches complement one another; a clean result does not guarantee safety.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
npx @pho9ubenaa/siro lint # report best-practice violations in the current repo
|
|
22
|
-
npx @pho9ubenaa/siro lint --reporter json # machine-readable remediation (see docs/json-output.md)
|
|
23
|
-
```
|
|
20
|
+
## Try it
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
Requires Node.js `^22.18.0` or `^24.0.0`. From your repository:
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```diff
|
|
30
|
-
# .npmrc
|
|
31
|
-
-ignore-scripts=false
|
|
32
|
-
+ignore-scripts=true
|
|
24
|
+
```sh
|
|
25
|
+
npx @pho9ubenaa/siro lint
|
|
33
26
|
```
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
## Features
|
|
40
|
-
|
|
41
|
-
- **Rules across six managers.** 28 rules covering lifecycle scripts, version pinning, lockfiles
|
|
42
|
-
(`commit`/`frozen`), release age, publish provenance, `files`/`publishConfig`, SSL enforcement,
|
|
43
|
-
checksum verification, exotic subdependency blocking, audit suppression review, store integrity,
|
|
44
|
-
Bun's security scanner API, and Yarn 4's hardened-mode — each mapped to the right setting per
|
|
45
|
-
package manager (`.npmrc`, `pnpm-workspace.yaml`, `.yarnrc.yml`, `bunfig.toml`, `deno.json`,
|
|
46
|
-
`aube-workspace.yaml`, `package.json`).
|
|
47
|
-
- **PM-aware severities.** When a manager's documented default satisfies a rule across every
|
|
48
|
-
supported version and target environment, the finding is demoted to `info`. Installed versions
|
|
49
|
-
and CI conditions are not checked, so defaults that depend on either retain the rule's severity.
|
|
50
|
-
- **Machine-readable remediation.** A finding can carry automatic key operations or manual
|
|
51
|
-
instructions. Review proposed changes and rerun the linter after editing.
|
|
52
|
-
See [docs/json-output.md](docs/json-output.md).
|
|
53
|
-
- **Target PM versions.** Flag settings introduced after the declared or explicit stable PM
|
|
54
|
-
version. See [checked settings and sources](docs/rules.md#checked-introduction-versions)
|
|
55
|
-
for the npm, pnpm, Yarn, Bun, and Deno coverage.
|
|
56
|
-
- **Workspace members.** `--workspaces` adds publication-metadata checks for declared npm,
|
|
57
|
-
pnpm, Yarn, Bun, Deno, and Aube members, including public packages under a private root.
|
|
58
|
-
See [workspace inspection](docs/configuration.md#workspace-members) for scope and exclusions.
|
|
59
|
-
- **Lint with severities.** `error` fails CI by default; `--severity warn` tightens the gate.
|
|
60
|
-
- **Reporters.** `pretty` (default), `json` for CI, `github` for PR annotations; register your own.
|
|
61
|
-
- **Configurable.** Drop a `siro.config.ts` to disable rules, override severities, restrict PMs,
|
|
62
|
-
or plug in custom rules and reporters.
|
|
63
|
-
|
|
64
|
-
See the [rule reference](docs/rules.md) for what each check does and why, and the
|
|
65
|
-
[comparison matrix](docs/comparison.md) for per-manager support at a glance.
|
|
66
|
-
|
|
67
|
-
## Versioning policy
|
|
68
|
-
|
|
69
|
-
siro evaluates the recorded policy snapshot in [docs/policy-sources.md](docs/policy-sources.md).
|
|
70
|
-
It detects package-manager names and reads exact stable targets from `packageManager`,
|
|
71
|
-
`config.pmVersions`, or `--pm-version`. It does not inspect installed binaries. The
|
|
72
|
-
`unsupported-settings` rule checks recorded introduction versions; unlisted settings and
|
|
73
|
-
unknown targets are not evaluated for availability. A version-dependent safe-default annotation prevents an unverified
|
|
74
|
-
severity downgrade; it does not prove that the current version satisfies the rule. See
|
|
75
|
-
[configuration](docs/configuration.md) for defaults, applicability, and limits.
|
|
76
|
-
|
|
77
|
-
## Usage
|
|
28
|
+
siro recursively discovers package.json and strict deno.json below cwd, independently of PM
|
|
29
|
+
workspace declarations. It checks local installation policy at cwd by default; add independent
|
|
30
|
+
projects with `--installation-root`. Exclude intentional fixtures with `--exclude test/fixtures`.
|
|
31
|
+
Discovery does not imply that every package's installation settings were inspected.
|
|
78
32
|
|
|
79
|
-
|
|
80
|
-
siro
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
--workspaces Also inspect workspace members' publication metadata
|
|
85
|
-
--project-type <application|package> Select application or published-package policy (default auto)
|
|
86
|
-
--reporter <pretty|json|github> Output format (default pretty)
|
|
87
|
-
--severity <error|warn|info> Show and fail on findings at or above this level
|
|
88
|
-
--json Shortcut for --reporter json
|
|
89
|
-
--version, --help
|
|
90
|
-
```
|
|
33
|
+
siro detects managers from `packageManager`, lockfiles, and configuration files. If it cannot
|
|
34
|
+
detect one, choose it explicitly, for example `npx @pho9ubenaa/siro lint --pm npm`.
|
|
35
|
+
The CLI may download code through `npx` and imports a repository's `siro.config.*` as executable
|
|
36
|
+
code. Review configurations before running it on an unfamiliar project; see the
|
|
37
|
+
[threat model](docs/threat-model.md).
|
|
91
38
|
|
|
92
|
-
|
|
39
|
+
## Read findings and add CI
|
|
93
40
|
|
|
94
|
-
|
|
41
|
+
Findings have `error`, `warn`, or `info` severity. Exit `0` means no findings at or above the
|
|
42
|
+
selected threshold; exit `1` means there are findings. Usage/configuration errors exit `2`
|
|
43
|
+
without completing the check; unexpected failures exit `70`. Errors fail CI by default. siro
|
|
44
|
+
suggests fixes but **does not edit files**: review changes and rerun the linter.
|
|
95
45
|
|
|
96
|
-
|
|
46
|
+
For regular use, install it with `npm install --save-dev --save-exact @pho9ubenaa/siro`
|
|
47
|
+
and add a package script:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"scripts": { "lint:security": "siro lint" }
|
|
52
|
+
}
|
|
53
|
+
```
|
|
97
54
|
|
|
98
|
-
|
|
55
|
+
After installing dependencies in CI, run `npm run lint:security`. A local install
|
|
56
|
+
makes `siro` available to package scripts, not to every shell or Git hook.
|
|
57
|
+
For exclusions and rule overrides, see the [configuration examples](docs/configuration.md).
|
|
99
58
|
|
|
100
|
-
|
|
101
|
-
| -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
102
|
-
| `npm audit` · [osv-scanner](https://github.com/google/osv-scanner) · Snyk · Dependabot | **Known CVEs** in your installed dependency tree | GHSA / OSV.dev / vendor feeds |
|
|
103
|
-
| `siro` | **Your install pipeline's configuration** — postinstall scripts, version ranges, lockfile policy, publish provenance, files allow-list, etc. | Static analysis of `.npmrc`, `pnpm-workspace.yaml`, `.yarnrc.yml`, `bunfig.toml`, `deno.json`, `aube-workspace.yaml`, `package.json` |
|
|
59
|
+
## Common CLI options
|
|
104
60
|
|
|
105
|
-
`
|
|
61
|
+
`check` is an alias for `lint`. Run `npx @pho9ubenaa/siro lint --help` for the complete CLI syntax.
|
|
106
62
|
|
|
107
|
-
|
|
63
|
+
| Option | Use |
|
|
64
|
+
| ----------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
65
|
+
| `--pm <npm\|pnpm\|yarn\|bun\|deno\|aube>` | Select one manager at cwd; additional installation roots retain their own targets. |
|
|
66
|
+
| `--pm-version <x.y.z>` | Supply an exact stable target version (requires `--pm`); it does not run an installed PM. |
|
|
67
|
+
| `--project-type <application\|package>` | Choose whether publication safeguards apply; omitted means infer from publish metadata. |
|
|
68
|
+
| `--exclude <pattern>` | Prune directories from recursive discovery (repeatable). |
|
|
69
|
+
| `--installation-root <path>` | Replace the default cwd installation scope (repeatable; include `.` to retain cwd). |
|
|
70
|
+
| `--severity <error\|warn\|info>` | Set both the display and CI failure threshold; default failure threshold is `error`. |
|
|
71
|
+
| `--reporter <pretty\|json\|github>` | Choose terminal, JSON, or GitHub Actions output; `--json` is a JSON shortcut. |
|
|
108
72
|
|
|
109
|
-
|
|
110
|
-
[docs/contributing.md](docs/contributing.md).
|
|
73
|
+
For a walkthrough and deeper reference, use these guides:
|
|
111
74
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
[
|
|
75
|
+
- [Getting started](docs/getting-started.md) walks through findings and CI; [configuration](docs/configuration.md) covers local PM/version selection, discovery and explicit installation scope, executable config, exit codes, and migration from the removed `--workspaces` flag.
|
|
76
|
+
- The [rule reference](docs/rules.md) and [PM comparison](docs/comparison.md) show what is checked for each manager.
|
|
77
|
+
- [JSON output](docs/json-output.md) documents the machine-readable remediation contract.
|
|
78
|
+
- [Contributing](docs/contributing.md) covers development setup, the source map, and verification.
|
|
116
79
|
|
|
117
80
|
## License
|
|
118
81
|
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as
|
|
2
|
+
import { C as isSupportedNodeVersion, E as assertDirectory, M as SiroError, N as UsageError, O as isNodeError, S as isSeverity, T as version, _ as PROJECT_TYPES, a as DEFAULT_REPORTER_NAME, b as SEVERITIES, i as BUILTIN_REPORTER_NAMES, k as asAbsPath, l as safeText, m as loadConfig, o as JSON_REPORTER_NAME, r as lintCommand, t as nodeIO, v as isProjectType, w as SUPPORTED_NODE_RANGE, x as isPM, y as PMS } from "./node-io-CAszdmko.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { parseArgs } from "node:util";
|
|
@@ -31,18 +31,19 @@ const COMMANDS = ["lint", "check"];
|
|
|
31
31
|
const isCommandName = (value) => COMMANDS.some((cmd) => cmd === value);
|
|
32
32
|
//#endregion
|
|
33
33
|
//#region src/cli/parse-args.ts
|
|
34
|
+
const REPEATABLE_FLAGS = new Set(["exclude", "installation-root"]);
|
|
34
35
|
const VALUE_FLAGS = new Set([
|
|
35
36
|
"pm",
|
|
36
37
|
"pm-version",
|
|
37
38
|
"project-type",
|
|
38
39
|
"reporter",
|
|
39
|
-
"severity"
|
|
40
|
+
"severity",
|
|
41
|
+
...REPEATABLE_FLAGS
|
|
40
42
|
]);
|
|
41
43
|
const BOOLEAN_FLAGS = new Set([
|
|
42
44
|
"help",
|
|
43
45
|
"version",
|
|
44
|
-
"json"
|
|
45
|
-
"workspaces"
|
|
46
|
+
"json"
|
|
46
47
|
]);
|
|
47
48
|
const parseCommand = (argv) => {
|
|
48
49
|
const { tokens } = parseArgs({
|
|
@@ -61,6 +62,7 @@ const parseCommand = (argv) => {
|
|
|
61
62
|
tokens: true
|
|
62
63
|
});
|
|
63
64
|
const flags = /* @__PURE__ */ new Map();
|
|
65
|
+
const repeated = /* @__PURE__ */ new Map();
|
|
64
66
|
const positionals = [];
|
|
65
67
|
let error;
|
|
66
68
|
for (let index = 0; index < tokens.length; index += 1) {
|
|
@@ -87,11 +89,12 @@ const parseCommand = (argv) => {
|
|
|
87
89
|
index += 1;
|
|
88
90
|
}
|
|
89
91
|
if (value === void 0 || value === "") error ??= `${token.rawName} requires a value.`;
|
|
92
|
+
else if (REPEATABLE_FLAGS.has(token.name)) repeated.set(token.name, [...repeated.get(token.name) ?? [], value]);
|
|
90
93
|
else {
|
|
91
94
|
if (flags.has(token.name)) error ??= `${token.rawName} must be specified only once.`;
|
|
92
95
|
flags.set(token.name, value);
|
|
93
96
|
}
|
|
94
|
-
} else error ??= `Unknown flag: ${token.rawName}`;
|
|
97
|
+
} else error ??= token.name === "workspaces" ? "The --workspaces flag was removed in 0.6.0; discovery is recursive by default. Use --exclude and --installation-root." : `Unknown flag: ${token.rawName}`;
|
|
95
98
|
}
|
|
96
99
|
const [command, cwd, ...extra] = positionals;
|
|
97
100
|
if (flags.has("help")) return {
|
|
@@ -118,7 +121,8 @@ const parseCommand = (argv) => {
|
|
|
118
121
|
cwd: asAbsPath(path.resolve(cwd ?? process.cwd())),
|
|
119
122
|
pm: parsePmFlag(flags.get("pm")),
|
|
120
123
|
pmVersion: typeof pmVersion === "string" ? pmVersion : void 0,
|
|
121
|
-
|
|
124
|
+
exclude: repeated.get("exclude"),
|
|
125
|
+
installationRoots: repeated.get("installation-root"),
|
|
122
126
|
projectType: parseProjectTypeFlag(flags.get("project-type")),
|
|
123
127
|
severity: parseSeverityFlag(flags.get("severity")),
|
|
124
128
|
reporter: typeof reporter === "string" ? reporter : flags.has("json") ? JSON_REPORTER_NAME : DEFAULT_REPORTER_NAME
|
|
@@ -134,7 +138,7 @@ const FLAG_LINES = {
|
|
|
134
138
|
json: " --json Shortcut for --reporter json",
|
|
135
139
|
pm: ` --pm <name> Target a specific package manager (${PMS_LIST})`,
|
|
136
140
|
pmVersion: " --pm-version <x.y.z> Target an exact stable PM version (requires --pm)",
|
|
137
|
-
|
|
141
|
+
inspection: " --exclude <pattern> Exclude directories from recursive discovery (repeatable)\n --installation-root <path> Inspect local install policy here (repeatable; default .)",
|
|
138
142
|
projectType: ` --project-type <type> Project type (${PROJECT_TYPES_LIST}; default auto)`,
|
|
139
143
|
reporter: ` --reporter <name> Reporter (${REPORTERS_LIST}; additional reporters can be registered via siro.config.ts)`,
|
|
140
144
|
severity: ` --severity <level> Show + fail on findings at or above this level (${SEVERITIES_LIST})`
|
|
@@ -151,7 +155,7 @@ const HELP_ROOT = [
|
|
|
151
155
|
"GLOBAL FLAGS",
|
|
152
156
|
FLAG_LINES.pm,
|
|
153
157
|
FLAG_LINES.pmVersion,
|
|
154
|
-
FLAG_LINES.
|
|
158
|
+
FLAG_LINES.inspection,
|
|
155
159
|
FLAG_LINES.projectType,
|
|
156
160
|
" --version Print the siro version",
|
|
157
161
|
" --help Show help for siro or a command",
|
|
@@ -181,7 +185,7 @@ const HELP_LINT = [
|
|
|
181
185
|
"FLAGS",
|
|
182
186
|
FLAG_LINES.pm,
|
|
183
187
|
FLAG_LINES.pmVersion,
|
|
184
|
-
FLAG_LINES.
|
|
188
|
+
FLAG_LINES.inspection,
|
|
185
189
|
FLAG_LINES.projectType,
|
|
186
190
|
FLAG_LINES.reporter,
|
|
187
191
|
FLAG_LINES.json,
|
|
@@ -208,17 +212,17 @@ const renderHelp = (target) => {
|
|
|
208
212
|
const EXIT_SUCCESS = 0;
|
|
209
213
|
const EXIT_USAGE = 2;
|
|
210
214
|
const EXIT_CRASH = 70;
|
|
211
|
-
const dispatch = (cmd, io) => {
|
|
215
|
+
const dispatch = async (cmd, io) => {
|
|
212
216
|
switch (cmd.kind) {
|
|
213
217
|
case "version":
|
|
214
|
-
io.stdout(version);
|
|
218
|
+
await io.stdout(version);
|
|
215
219
|
return EXIT_SUCCESS;
|
|
216
220
|
case "help":
|
|
217
|
-
io.stdout(renderHelp(cmd.target));
|
|
221
|
+
await io.stdout(renderHelp(cmd.target));
|
|
218
222
|
return EXIT_SUCCESS;
|
|
219
223
|
case "usage":
|
|
220
|
-
if (cmd.reason) io.stderr(`${cmd.reason}\n`);
|
|
221
|
-
io.stderr(renderHelp());
|
|
224
|
+
if (cmd.reason) await io.stderr(`${safeText(cmd.reason)}\n`);
|
|
225
|
+
await io.stderr(renderHelp());
|
|
222
226
|
return EXIT_USAGE;
|
|
223
227
|
case "lint":
|
|
224
228
|
assertDirectory(cmd.cwd);
|
|
@@ -229,13 +233,13 @@ const dispatch = (cmd, io) => {
|
|
|
229
233
|
default: throw new Error(`Unhandled command kind: ${String(cmd)}`);
|
|
230
234
|
}
|
|
231
235
|
};
|
|
232
|
-
const handleError = (error, io) => {
|
|
236
|
+
const handleError = async (error, io) => {
|
|
233
237
|
if (error instanceof SiroError) {
|
|
234
|
-
io.stderr(error.message);
|
|
238
|
+
await io.stderr(safeText(error.message));
|
|
235
239
|
return error.exitCode;
|
|
236
240
|
}
|
|
237
241
|
if (isNodeError(error) && "errno" in error && typeof error.errno === "number") {
|
|
238
|
-
io.stderr(`File system error: ${error.message}`);
|
|
242
|
+
await io.stderr(safeText(`File system error: ${error.message}`));
|
|
239
243
|
return EXIT_USAGE;
|
|
240
244
|
}
|
|
241
245
|
throw error;
|
|
@@ -253,8 +257,10 @@ const runMain = async (argv) => {
|
|
|
253
257
|
process.exitCode = await run(argv);
|
|
254
258
|
} catch (error) {
|
|
255
259
|
const errStr = error instanceof Error ? error.stack ?? error.message : String(error);
|
|
256
|
-
process.stderr.write(`${errStr}\n`);
|
|
257
260
|
process.exitCode = EXIT_CRASH;
|
|
261
|
+
try {
|
|
262
|
+
await nodeIO.stderr(safeText(errStr));
|
|
263
|
+
} catch {}
|
|
258
264
|
}
|
|
259
265
|
};
|
|
260
266
|
const [, invokedPath] = process.argv;
|