configenvy 0.1.1 → 0.1.4

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/dist/index.d.ts CHANGED
@@ -1 +1,32 @@
1
1
  #!/usr/bin/env node
2
+ import { writeFile } from 'node:fs/promises';
3
+ import { resolve } from 'node:path';
4
+ import { Command } from 'commander';
5
+ import { buildMarkdownTable, explainVariable, scanProject, toJson, toSarif, Diagnostic } from '@configenvy/core';
6
+
7
+ type DoctorOptions = {
8
+ format?: "text" | "json" | "sarif";
9
+ strict?: boolean;
10
+ ci?: boolean;
11
+ };
12
+ type CliDependencies = {
13
+ buildMarkdownTable: typeof buildMarkdownTable;
14
+ error: (...values: unknown[]) => void;
15
+ exit: (code: number) => never | void;
16
+ explainVariable: typeof explainVariable;
17
+ log: (...values: unknown[]) => void;
18
+ resolvePath: typeof resolve;
19
+ scanProject: typeof scanProject;
20
+ toJson: typeof toJson;
21
+ toSarif: typeof toSarif;
22
+ writeFile: typeof writeFile;
23
+ };
24
+ declare function createProgram(dependencies?: CliDependencies): Command;
25
+ declare function runCli(argv: string[], dependencies?: CliDependencies): Promise<void>;
26
+ declare function runDoctor(projectPath: string, options: DoctorOptions, dependencies?: CliDependencies): Promise<void>;
27
+ declare function runInit(projectPath: string, dependencies?: CliDependencies): Promise<void>;
28
+ declare function resolveOutputPath(projectPath: string, outputPath: string, resolvePath?: typeof resolve): string;
29
+ declare function printHumanReport(diagnostics: Diagnostic[], log?: (...values: unknown[]) => void): void;
30
+ declare function printGitHubAnnotations(diagnostics: Diagnostic[], log?: (...values: unknown[]) => void): void;
31
+
32
+ export { type CliDependencies, createProgram, printGitHubAnnotations, printHumanReport, resolveOutputPath, runCli, runDoctor, runInit };
package/dist/index.js CHANGED
@@ -2,61 +2,151 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { writeFile } from "fs/promises";
5
- import { resolve } from "path";
5
+ import { isAbsolute, resolve } from "path";
6
+ import { pathToFileURL } from "url";
6
7
  import { Command } from "commander";
7
- import { buildMarkdownTable, explainVariable, scanProject, toJson } from "@configenvy/core";
8
- var program = new Command();
9
- program.name("configenvy").description("Find missing, unused, undocumented, and risky environment variables.").version("0.1.1");
10
- program.command("doctor").argument("[path]", "project directory", ".").option("--format <format>", "output format: text or json", "text").option("--strict", "treat documentation warnings as errors").action(async (projectPath, options) => {
11
- await runDoctor(projectPath, options);
12
- });
13
- program.command("check").argument("[path]", "project directory", ".").option("--ci", "fail on warnings and errors").option("--format <format>", "output format: text or json", "text").action(async (projectPath, options) => {
14
- await runDoctor(projectPath, { ...options, strict: Boolean(options.ci), ci: Boolean(options.ci) });
15
- });
16
- program.command("table").argument("[path]", "project directory", ".").option("--out <file>", "write markdown table to a file").action(async (projectPath, options) => {
17
- const result = await scanProject({ rootDir: resolve(projectPath) });
18
- const table = buildMarkdownTable(result);
19
- if (options.out) {
20
- await writeFile(resolve(options.out), `${table}
8
+ import { buildMarkdownTable, explainVariable, scanProject, toJson, toSarif } from "@configenvy/core";
9
+ var defaultDependencies = {
10
+ buildMarkdownTable,
11
+ error: console.error,
12
+ exit: process.exit,
13
+ explainVariable,
14
+ log: console.log,
15
+ resolvePath: resolve,
16
+ scanProject,
17
+ toJson,
18
+ toSarif,
19
+ writeFile
20
+ };
21
+ function createProgram(dependencies = defaultDependencies) {
22
+ const program = new Command();
23
+ program.name("configenvy").description("Find missing, unused, undocumented, and risky environment variables.").version("0.1.4");
24
+ program.command("doctor").argument("[path]", "project directory", ".").option("--format <format>", "output format: text, json, or sarif", "text").option("--strict", "treat documentation warnings as errors").action(async (projectPath, options) => {
25
+ await runDoctor(projectPath, options, dependencies);
26
+ });
27
+ program.command("check").argument("[path]", "project directory", ".").option("--ci", "fail on warnings and errors").option("--format <format>", "output format: text, json, or sarif", "text").action(async (projectPath, options) => {
28
+ await runDoctor(projectPath, { ...options, strict: Boolean(options.ci), ci: Boolean(options.ci) }, dependencies);
29
+ });
30
+ program.command("table").argument("[path]", "project directory", ".").option("--out <file>", "write markdown table to a file").action(async (projectPath, options) => {
31
+ const rootDir = dependencies.resolvePath(projectPath);
32
+ const result = await dependencies.scanProject({ rootDir });
33
+ const table = dependencies.buildMarkdownTable(result);
34
+ if (options.out) {
35
+ await dependencies.writeFile(resolveOutputPath(rootDir, options.out, dependencies.resolvePath), `${table}
21
36
  `, "utf8");
22
- } else {
23
- console.log(table);
24
- }
25
- });
26
- program.command("explain").argument("<variable>", "environment variable name").argument("[path]", "project directory", ".").action(async (variable, projectPath) => {
27
- const result = await scanProject({ rootDir: resolve(projectPath) });
28
- console.log(explainVariable(result, variable));
29
- });
30
- program.parseAsync(process.argv).catch((error) => {
31
- console.error(error instanceof Error ? error.message : String(error));
32
- process.exit(3);
33
- });
34
- async function runDoctor(projectPath, options) {
35
- const result = await scanProject({ rootDir: resolve(projectPath), strict: Boolean(options.strict) });
37
+ } else {
38
+ dependencies.log(table);
39
+ }
40
+ });
41
+ program.command("init").argument("[path]", "project directory", ".").description("create a starter configenvy.config.json file").action(async (projectPath) => {
42
+ await runInit(projectPath, dependencies);
43
+ });
44
+ program.command("explain").argument("<variable>", "environment variable name").argument("[path]", "project directory", ".").action(async (variable, projectPath) => {
45
+ const result = await dependencies.scanProject({ rootDir: dependencies.resolvePath(projectPath) });
46
+ dependencies.log(dependencies.explainVariable(result, variable));
47
+ });
48
+ return program;
49
+ }
50
+ var starterConfig = {
51
+ required: [],
52
+ optional: [],
53
+ ignore: ["NODE_ENV"],
54
+ docs: ["README.md", "docs"]
55
+ };
56
+ async function runCli(argv, dependencies = defaultDependencies) {
57
+ const program = createProgram(dependencies);
58
+ await program.parseAsync(argv);
59
+ }
60
+ async function runDoctor(projectPath, options, dependencies = defaultDependencies) {
61
+ const result = await dependencies.scanProject({
62
+ rootDir: dependencies.resolvePath(projectPath),
63
+ strict: Boolean(options.strict)
64
+ });
36
65
  if (options.format === "json") {
37
- console.log(toJson(result));
66
+ dependencies.log(dependencies.toJson(result));
67
+ } else if (options.format === "sarif") {
68
+ dependencies.log(dependencies.toSarif(result));
38
69
  } else {
39
- printHumanReport(result.diagnostics);
70
+ printHumanReport(result.diagnostics, dependencies.log);
71
+ if (options.ci) {
72
+ printGitHubAnnotations(result.diagnostics, dependencies.log);
73
+ }
40
74
  }
41
75
  const hasError = result.diagnostics.some((diagnostic) => diagnostic.severity === "error");
42
76
  const hasWarning = result.diagnostics.some((diagnostic) => diagnostic.severity === "warning");
43
- if (hasError || options.ci && hasWarning) process.exit(2);
44
- if (hasWarning) process.exit(1);
77
+ if (hasError || options.ci && hasWarning) dependencies.exit(2);
78
+ if (hasWarning) dependencies.exit(1);
79
+ }
80
+ async function runInit(projectPath, dependencies = defaultDependencies) {
81
+ const rootDir = dependencies.resolvePath(projectPath);
82
+ const configPath = dependencies.resolvePath(rootDir, "configenvy.config.json");
83
+ const content = `${JSON.stringify(starterConfig, null, 2)}
84
+ `;
85
+ try {
86
+ await dependencies.writeFile(configPath, content, { encoding: "utf8", flag: "wx" });
87
+ } catch (error) {
88
+ if (isNodeError(error) && error.code === "EEXIST") {
89
+ dependencies.error("configenvy.config.json already exists.");
90
+ dependencies.exit(1);
91
+ return;
92
+ }
93
+ throw error;
94
+ }
95
+ dependencies.log(`Created ${configPath}`);
45
96
  }
46
- function printHumanReport(diagnostics) {
97
+ function resolveOutputPath(projectPath, outputPath, resolvePath = resolve) {
98
+ if (isAbsolute(outputPath)) return outputPath;
99
+ return resolvePath(projectPath, outputPath);
100
+ }
101
+ function printHumanReport(diagnostics, log = defaultDependencies.log) {
47
102
  if (diagnostics.length === 0) {
48
- console.log("PASS configenvy found no environment variable issues.");
103
+ log("PASS configenvy found no environment variable issues.");
49
104
  return;
50
105
  }
51
106
  for (const diagnostic of diagnostics) {
52
107
  const label = diagnostic.severity === "error" ? "FAIL" : "WARN";
53
- console.log(`${label} ${diagnostic.code} ${diagnostic.variable}`);
54
- console.log(` ${diagnostic.message}`);
108
+ log(`${label} ${diagnostic.code} ${diagnostic.variable}`);
109
+ log(` ${diagnostic.message}`);
55
110
  if (diagnostic.files.length > 0) {
56
- console.log(` files: ${diagnostic.files.join(", ")}`);
111
+ log(` files: ${diagnostic.files.join(", ")}`);
57
112
  }
58
113
  }
59
114
  const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error").length;
60
115
  const warnings = diagnostics.length - errors;
61
- console.log(`Summary: ${errors} error(s), ${warnings} warning(s).`);
116
+ log(`Summary: ${errors} error(s), ${warnings} warning(s).`);
117
+ }
118
+ function printGitHubAnnotations(diagnostics, log = defaultDependencies.log) {
119
+ for (const diagnostic of diagnostics) {
120
+ const command = diagnostic.severity === "error" ? "error" : "warning";
121
+ const properties = [
122
+ diagnostic.files[0] ? `file=${escapeAnnotationProperty(diagnostic.files[0])}` : void 0,
123
+ `title=${escapeAnnotationProperty(`${diagnostic.code} ${diagnostic.variable}`)}`
124
+ ].filter(Boolean);
125
+ log(`::${command} ${properties.join(",")}::${escapeAnnotationMessage(diagnostic.message)}`);
126
+ }
127
+ }
128
+ function escapeAnnotationProperty(value) {
129
+ return escapeAnnotationMessage(value).replace(/:/g, "%3A").replace(/,/g, "%2C");
130
+ }
131
+ function escapeAnnotationMessage(value) {
132
+ return value.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
133
+ }
134
+ function isNodeError(error) {
135
+ return error instanceof Error && "code" in error;
136
+ }
137
+ var invokedPath = process.argv[1];
138
+ if (invokedPath && import.meta.url === pathToFileURL(invokedPath).href) {
139
+ runCli(process.argv).catch((error) => {
140
+ defaultDependencies.error(error instanceof Error ? error.message : String(error));
141
+ defaultDependencies.exit(3);
142
+ });
62
143
  }
144
+ export {
145
+ createProgram,
146
+ printGitHubAnnotations,
147
+ printHumanReport,
148
+ resolveOutputPath,
149
+ runCli,
150
+ runDoctor,
151
+ runInit
152
+ };
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "configenvy",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "description": "Find missing, unused, undocumented, and risky environment variables before setup breaks.",
5
5
  "type": "module",
6
+ "engines": {
7
+ "node": ">=18"
8
+ },
6
9
  "repository": {
7
10
  "type": "git",
8
11
  "url": "git+https://github.com/sonsriver4815/configenvy.git",
@@ -32,7 +35,7 @@
32
35
  "build": "tsup src/index.ts --format esm --dts --clean"
33
36
  },
34
37
  "dependencies": {
35
- "@configenvy/core": "0.1.1",
38
+ "@configenvy/core": "0.1.4",
36
39
  "commander": "^12.1.0"
37
40
  },
38
41
  "keywords": [
package/src/index.ts CHANGED
@@ -1,99 +1,227 @@
1
1
  #!/usr/bin/env node
2
2
  import { writeFile } from "node:fs/promises";
3
- import { resolve } from "node:path";
3
+ import { isAbsolute, resolve } from "node:path";
4
+ import { pathToFileURL } from "node:url";
4
5
  import { Command } from "commander";
5
- import { buildMarkdownTable, explainVariable, scanProject, toJson, type Diagnostic } from "@configenvy/core";
6
+ import { buildMarkdownTable, explainVariable, scanProject, toJson, toSarif, type Diagnostic } from "@configenvy/core";
6
7
 
7
8
  type DoctorOptions = {
8
- format?: "text" | "json";
9
+ format?: "text" | "json" | "sarif";
9
10
  strict?: boolean;
10
11
  ci?: boolean;
11
12
  };
12
13
 
13
- const program = new Command();
14
+ export type CliDependencies = {
15
+ buildMarkdownTable: typeof buildMarkdownTable;
16
+ error: (...values: unknown[]) => void;
17
+ exit: (code: number) => never | void;
18
+ explainVariable: typeof explainVariable;
19
+ log: (...values: unknown[]) => void;
20
+ resolvePath: typeof resolve;
21
+ scanProject: typeof scanProject;
22
+ toJson: typeof toJson;
23
+ toSarif: typeof toSarif;
24
+ writeFile: typeof writeFile;
25
+ };
14
26
 
15
- program
16
- .name("configenvy")
17
- .description("Find missing, unused, undocumented, and risky environment variables.")
18
- .version("0.1.1");
27
+ const defaultDependencies: CliDependencies = {
28
+ buildMarkdownTable,
29
+ error: console.error,
30
+ exit: process.exit,
31
+ explainVariable,
32
+ log: console.log,
33
+ resolvePath: resolve,
34
+ scanProject,
35
+ toJson,
36
+ toSarif,
37
+ writeFile
38
+ };
19
39
 
20
- program
21
- .command("doctor")
22
- .argument("[path]", "project directory", ".")
23
- .option("--format <format>", "output format: text or json", "text")
24
- .option("--strict", "treat documentation warnings as errors")
25
- .action(async (projectPath: string, options: DoctorOptions) => {
26
- await runDoctor(projectPath, options);
27
- });
40
+ export function createProgram(dependencies: CliDependencies = defaultDependencies): Command {
41
+ const program = new Command();
28
42
 
29
- program
30
- .command("check")
31
- .argument("[path]", "project directory", ".")
32
- .option("--ci", "fail on warnings and errors")
33
- .option("--format <format>", "output format: text or json", "text")
34
- .action(async (projectPath: string, options: DoctorOptions) => {
35
- await runDoctor(projectPath, { ...options, strict: Boolean(options.ci), ci: Boolean(options.ci) });
36
- });
43
+ program
44
+ .name("configenvy")
45
+ .description("Find missing, unused, undocumented, and risky environment variables.")
46
+ .version("0.1.4");
37
47
 
38
- program
39
- .command("table")
40
- .argument("[path]", "project directory", ".")
41
- .option("--out <file>", "write markdown table to a file")
42
- .action(async (projectPath: string, options: { out?: string }) => {
43
- const result = await scanProject({ rootDir: resolve(projectPath) });
44
- const table = buildMarkdownTable(result);
45
- if (options.out) {
46
- await writeFile(resolve(options.out), `${table}\n`, "utf8");
47
- } else {
48
- console.log(table);
49
- }
50
- });
48
+ program
49
+ .command("doctor")
50
+ .argument("[path]", "project directory", ".")
51
+ .option("--format <format>", "output format: text, json, or sarif", "text")
52
+ .option("--strict", "treat documentation warnings as errors")
53
+ .action(async (projectPath: string, options: DoctorOptions) => {
54
+ await runDoctor(projectPath, options, dependencies);
55
+ });
51
56
 
52
- program
53
- .command("explain")
54
- .argument("<variable>", "environment variable name")
55
- .argument("[path]", "project directory", ".")
56
- .action(async (variable: string, projectPath: string) => {
57
- const result = await scanProject({ rootDir: resolve(projectPath) });
58
- console.log(explainVariable(result, variable));
59
- });
57
+ program
58
+ .command("check")
59
+ .argument("[path]", "project directory", ".")
60
+ .option("--ci", "fail on warnings and errors")
61
+ .option("--format <format>", "output format: text, json, or sarif", "text")
62
+ .action(async (projectPath: string, options: DoctorOptions) => {
63
+ await runDoctor(projectPath, { ...options, strict: Boolean(options.ci), ci: Boolean(options.ci) }, dependencies);
64
+ });
65
+
66
+ program
67
+ .command("table")
68
+ .argument("[path]", "project directory", ".")
69
+ .option("--out <file>", "write markdown table to a file")
70
+ .action(async (projectPath: string, options: { out?: string }) => {
71
+ const rootDir = dependencies.resolvePath(projectPath);
72
+ const result = await dependencies.scanProject({ rootDir });
73
+ const table = dependencies.buildMarkdownTable(result);
74
+ if (options.out) {
75
+ await dependencies.writeFile(resolveOutputPath(rootDir, options.out, dependencies.resolvePath), `${table}\n`, "utf8");
76
+ } else {
77
+ dependencies.log(table);
78
+ }
79
+ });
80
+
81
+ program
82
+ .command("init")
83
+ .argument("[path]", "project directory", ".")
84
+ .description("create a starter configenvy.config.json file")
85
+ .action(async (projectPath: string) => {
86
+ await runInit(projectPath, dependencies);
87
+ });
88
+
89
+ program
90
+ .command("explain")
91
+ .argument("<variable>", "environment variable name")
92
+ .argument("[path]", "project directory", ".")
93
+ .action(async (variable: string, projectPath: string) => {
94
+ const result = await dependencies.scanProject({ rootDir: dependencies.resolvePath(projectPath) });
95
+ dependencies.log(dependencies.explainVariable(result, variable));
96
+ });
60
97
 
61
- program.parseAsync(process.argv).catch((error: unknown) => {
62
- console.error(error instanceof Error ? error.message : String(error));
63
- process.exit(3);
64
- });
98
+ return program;
99
+ }
100
+
101
+ const starterConfig = {
102
+ required: [],
103
+ optional: [],
104
+ ignore: ["NODE_ENV"],
105
+ docs: ["README.md", "docs"]
106
+ };
107
+
108
+ export async function runCli(argv: string[], dependencies: CliDependencies = defaultDependencies): Promise<void> {
109
+ const program = createProgram(dependencies);
110
+ await program.parseAsync(argv);
111
+ }
65
112
 
66
- async function runDoctor(projectPath: string, options: DoctorOptions): Promise<void> {
67
- const result = await scanProject({ rootDir: resolve(projectPath), strict: Boolean(options.strict) });
113
+ export async function runDoctor(
114
+ projectPath: string,
115
+ options: DoctorOptions,
116
+ dependencies: CliDependencies = defaultDependencies
117
+ ): Promise<void> {
118
+ const result = await dependencies.scanProject({
119
+ rootDir: dependencies.resolvePath(projectPath),
120
+ strict: Boolean(options.strict)
121
+ });
68
122
 
69
123
  if (options.format === "json") {
70
- console.log(toJson(result));
124
+ dependencies.log(dependencies.toJson(result));
125
+ } else if (options.format === "sarif") {
126
+ dependencies.log(dependencies.toSarif(result));
71
127
  } else {
72
- printHumanReport(result.diagnostics);
128
+ printHumanReport(result.diagnostics, dependencies.log);
129
+ if (options.ci) {
130
+ printGitHubAnnotations(result.diagnostics, dependencies.log);
131
+ }
73
132
  }
74
133
 
75
134
  const hasError = result.diagnostics.some((diagnostic) => diagnostic.severity === "error");
76
135
  const hasWarning = result.diagnostics.some((diagnostic) => diagnostic.severity === "warning");
77
- if (hasError || (options.ci && hasWarning)) process.exit(2);
78
- if (hasWarning) process.exit(1);
136
+ if (hasError || (options.ci && hasWarning)) dependencies.exit(2);
137
+ if (hasWarning) dependencies.exit(1);
79
138
  }
80
139
 
81
- function printHumanReport(diagnostics: Diagnostic[]): void {
140
+ export async function runInit(
141
+ projectPath: string,
142
+ dependencies: CliDependencies = defaultDependencies
143
+ ): Promise<void> {
144
+ const rootDir = dependencies.resolvePath(projectPath);
145
+ const configPath = dependencies.resolvePath(rootDir, "configenvy.config.json");
146
+ const content = `${JSON.stringify(starterConfig, null, 2)}\n`;
147
+
148
+ try {
149
+ await dependencies.writeFile(configPath, content, { encoding: "utf8", flag: "wx" });
150
+ } catch (error) {
151
+ if (isNodeError(error) && error.code === "EEXIST") {
152
+ dependencies.error("configenvy.config.json already exists.");
153
+ dependencies.exit(1);
154
+ return;
155
+ }
156
+ throw error;
157
+ }
158
+
159
+ dependencies.log(`Created ${configPath}`);
160
+ }
161
+
162
+ export function resolveOutputPath(
163
+ projectPath: string,
164
+ outputPath: string,
165
+ resolvePath: typeof resolve = resolve
166
+ ): string {
167
+ if (isAbsolute(outputPath)) return outputPath;
168
+ return resolvePath(projectPath, outputPath);
169
+ }
170
+
171
+ export function printHumanReport(
172
+ diagnostics: Diagnostic[],
173
+ log: (...values: unknown[]) => void = defaultDependencies.log
174
+ ): void {
82
175
  if (diagnostics.length === 0) {
83
- console.log("PASS configenvy found no environment variable issues.");
176
+ log("PASS configenvy found no environment variable issues.");
84
177
  return;
85
178
  }
86
179
 
87
180
  for (const diagnostic of diagnostics) {
88
181
  const label = diagnostic.severity === "error" ? "FAIL" : "WARN";
89
- console.log(`${label} ${diagnostic.code} ${diagnostic.variable}`);
90
- console.log(` ${diagnostic.message}`);
182
+ log(`${label} ${diagnostic.code} ${diagnostic.variable}`);
183
+ log(` ${diagnostic.message}`);
91
184
  if (diagnostic.files.length > 0) {
92
- console.log(` files: ${diagnostic.files.join(", ")}`);
185
+ log(` files: ${diagnostic.files.join(", ")}`);
93
186
  }
94
187
  }
95
188
 
96
189
  const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error").length;
97
190
  const warnings = diagnostics.length - errors;
98
- console.log(`Summary: ${errors} error(s), ${warnings} warning(s).`);
191
+ log(`Summary: ${errors} error(s), ${warnings} warning(s).`);
192
+ }
193
+
194
+ export function printGitHubAnnotations(
195
+ diagnostics: Diagnostic[],
196
+ log: (...values: unknown[]) => void = defaultDependencies.log
197
+ ): void {
198
+ for (const diagnostic of diagnostics) {
199
+ const command = diagnostic.severity === "error" ? "error" : "warning";
200
+ const properties = [
201
+ diagnostic.files[0] ? `file=${escapeAnnotationProperty(diagnostic.files[0])}` : undefined,
202
+ `title=${escapeAnnotationProperty(`${diagnostic.code} ${diagnostic.variable}`)}`
203
+ ].filter(Boolean);
204
+
205
+ log(`::${command} ${properties.join(",")}::${escapeAnnotationMessage(diagnostic.message)}`);
206
+ }
207
+ }
208
+
209
+ function escapeAnnotationProperty(value: string): string {
210
+ return escapeAnnotationMessage(value).replace(/:/g, "%3A").replace(/,/g, "%2C");
211
+ }
212
+
213
+ function escapeAnnotationMessage(value: string): string {
214
+ return value.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
215
+ }
216
+
217
+ function isNodeError(error: unknown): error is NodeJS.ErrnoException {
218
+ return error instanceof Error && "code" in error;
219
+ }
220
+
221
+ const invokedPath = process.argv[1];
222
+ if (invokedPath && import.meta.url === pathToFileURL(invokedPath).href) {
223
+ runCli(process.argv).catch((error: unknown) => {
224
+ defaultDependencies.error(error instanceof Error ? error.message : String(error));
225
+ defaultDependencies.exit(3);
226
+ });
99
227
  }