@technicalshree/auto-fix 1.1.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.
@@ -0,0 +1,118 @@
1
+ function nodeChecks(detection, selected) {
2
+ if (!detection.node.detected)
3
+ return [];
4
+ const scripts = detection.node.packageScripts;
5
+ const steps = [];
6
+ if (selected.includes("format") && scripts.includes("format")) {
7
+ steps.push({
8
+ id: "check-node-format",
9
+ title: "Run Node format check",
10
+ subsystem: "checks",
11
+ phase: "checks",
12
+ checkKind: "format",
13
+ rationale: "Configured formatting check for JS/TS project.",
14
+ commands: ["npm run format"],
15
+ destructive: false,
16
+ irreversible: false,
17
+ undoable: false,
18
+ status: "planned",
19
+ });
20
+ }
21
+ if (selected.includes("lint") && scripts.includes("lint")) {
22
+ steps.push({
23
+ id: "check-node-lint",
24
+ title: "Run Node lint check",
25
+ subsystem: "checks",
26
+ phase: "checks",
27
+ checkKind: "lint",
28
+ rationale: "Configured lint check for JS/TS project.",
29
+ commands: ["npm run lint"],
30
+ destructive: false,
31
+ irreversible: false,
32
+ undoable: false,
33
+ status: "planned",
34
+ });
35
+ }
36
+ if (selected.includes("test") && scripts.includes("test")) {
37
+ steps.push({
38
+ id: "check-node-test",
39
+ title: "Run Node tests",
40
+ subsystem: "checks",
41
+ phase: "checks",
42
+ checkKind: "test",
43
+ rationale: "Configured test script for JS/TS project.",
44
+ commands: ["npm test"],
45
+ destructive: false,
46
+ irreversible: false,
47
+ undoable: false,
48
+ status: "planned",
49
+ });
50
+ }
51
+ return steps;
52
+ }
53
+ function pythonChecks(detection, config, selected) {
54
+ if (!detection.python.detected)
55
+ return [];
56
+ const steps = [];
57
+ if (selected.includes("format")) {
58
+ for (const cmd of config.python.tools.format) {
59
+ steps.push({
60
+ id: `check-python-format-${cmd.replace(/[^a-z0-9]/gi, "-")}`,
61
+ title: `Run Python format: ${cmd}`,
62
+ subsystem: "checks",
63
+ phase: "checks",
64
+ checkKind: "format",
65
+ rationale: "Configured Python formatting check.",
66
+ commands: [cmd],
67
+ destructive: false,
68
+ irreversible: false,
69
+ undoable: false,
70
+ status: "planned",
71
+ });
72
+ }
73
+ }
74
+ if (selected.includes("lint")) {
75
+ for (const cmd of config.python.tools.lint) {
76
+ steps.push({
77
+ id: `check-python-lint-${cmd.replace(/[^a-z0-9]/gi, "-")}`,
78
+ title: `Run Python lint: ${cmd}`,
79
+ subsystem: "checks",
80
+ phase: "checks",
81
+ checkKind: "lint",
82
+ rationale: "Configured Python lint check.",
83
+ commands: [cmd],
84
+ destructive: false,
85
+ irreversible: false,
86
+ undoable: false,
87
+ status: "planned",
88
+ });
89
+ }
90
+ }
91
+ if (selected.includes("test")) {
92
+ for (const cmd of config.python.tools.test) {
93
+ steps.push({
94
+ id: `check-python-test-${cmd.replace(/[^a-z0-9]/gi, "-")}`,
95
+ title: `Run Python tests: ${cmd}`,
96
+ subsystem: "checks",
97
+ phase: "checks",
98
+ checkKind: "test",
99
+ rationale: "Configured Python test check.",
100
+ commands: [cmd],
101
+ destructive: false,
102
+ irreversible: false,
103
+ undoable: false,
104
+ status: "planned",
105
+ });
106
+ }
107
+ }
108
+ return steps;
109
+ }
110
+ export function buildCheckSteps(detection, config, flags, focusSubsystem) {
111
+ const selected = flags.checks ?? config.checks.default;
112
+ const steps = [];
113
+ if (!focusSubsystem || focusSubsystem === "node")
114
+ steps.push(...nodeChecks(detection, selected));
115
+ if (!focusSubsystem || focusSubsystem === "python")
116
+ steps.push(...pythonChecks(detection, config, selected));
117
+ return steps;
118
+ }
@@ -0,0 +1,56 @@
1
+ function composePrefix(detection) {
2
+ if (!detection.docker.composeFile)
3
+ return "docker compose";
4
+ return `docker compose -f ${detection.docker.composeFile}`;
5
+ }
6
+ export function buildDockerSteps(detection, config, flags) {
7
+ if (!detection.docker.detected)
8
+ return [];
9
+ const steps = [];
10
+ const prefix = composePrefix(detection);
11
+ if (config.docker.safe_down) {
12
+ steps.push({
13
+ id: "docker-compose-down",
14
+ title: "Run docker compose down",
15
+ subsystem: "docker",
16
+ phase: "docker",
17
+ rationale: "Reset stale compose state safely.",
18
+ commands: [`${prefix} down`],
19
+ destructive: false,
20
+ irreversible: false,
21
+ undoable: false,
22
+ status: "planned",
23
+ });
24
+ }
25
+ if (config.docker.rebuild) {
26
+ steps.push({
27
+ id: "docker-compose-rebuild",
28
+ title: "Rebuild docker compose services",
29
+ subsystem: "docker",
30
+ phase: "docker",
31
+ rationale: "Rebuild services to resolve dirty container/image state.",
32
+ commands: [`${prefix} up -d --build`],
33
+ destructive: false,
34
+ irreversible: false,
35
+ undoable: false,
36
+ status: "planned",
37
+ });
38
+ }
39
+ if (flags.deep || flags.approve || config.docker.prune) {
40
+ steps.push({
41
+ id: "docker-prune",
42
+ title: "IRREVERSIBLE: Prune docker system",
43
+ subsystem: "docker",
44
+ phase: "docker",
45
+ rationale: "Deep cleanup requested for stale docker artifacts.",
46
+ commands: ["docker system prune -f"],
47
+ destructive: true,
48
+ irreversible: true,
49
+ irreversibleReason: "cannot be snapshotted",
50
+ undoable: false,
51
+ undoHints: [{ action: "Rebuild services", command: `${prefix} up -d --build` }],
52
+ status: "planned",
53
+ });
54
+ }
55
+ return steps;
56
+ }
@@ -0,0 +1,124 @@
1
+ function choosePm(detected, configured) {
2
+ if (configured !== "auto")
3
+ return configured;
4
+ if (detected === "unknown")
5
+ return "npm";
6
+ return detected;
7
+ }
8
+ function frozenInstall(pm) {
9
+ if (pm === "pnpm")
10
+ return "pnpm install --frozen-lockfile";
11
+ if (pm === "yarn")
12
+ return "yarn install --frozen-lockfile";
13
+ return "npm ci";
14
+ }
15
+ export function buildNodeSteps(detection, config, flags) {
16
+ if (!detection.node.detected)
17
+ return [];
18
+ const pm = choosePm(detection.node.packageManager, config.node.package_manager);
19
+ const steps = [];
20
+ if (detection.node.lockfileCorrupted) {
21
+ steps.push({
22
+ id: "node-lockfile-corruption-detected",
23
+ title: "Lockfile corruption detected",
24
+ subsystem: "node",
25
+ phase: "node",
26
+ rationale: "Lockfile parse failure detected; frozen install strategy will likely fail.",
27
+ commands: [],
28
+ destructive: false,
29
+ irreversible: false,
30
+ undoable: false,
31
+ status: "proposed",
32
+ proposedReason: "Recommend fresh regeneration with --force-fresh and --deep/--approve",
33
+ });
34
+ if (flags.forceFresh && (flags.deep || flags.approve)) {
35
+ steps.push({
36
+ id: "node-remove-lockfiles-force-fresh",
37
+ title: "IRREVERSIBLE: Remove corrupted lockfiles and regenerate",
38
+ subsystem: "node",
39
+ phase: "node",
40
+ rationale: "Forced fresh recovery for corrupted lockfile.",
41
+ commands: ["rm -f package-lock.json pnpm-lock.yaml yarn.lock", `${pm} install`],
42
+ destructive: true,
43
+ irreversible: true,
44
+ irreversibleReason: "cannot be snapshotted reliably if unreadable/corrupt",
45
+ undoable: false,
46
+ undoHints: [{ action: "Regenerate lockfile", command: `${pm} install` }],
47
+ status: "planned",
48
+ });
49
+ }
50
+ }
51
+ if (!detection.node.hasNodeModules) {
52
+ steps.push({
53
+ id: "node-install-deps",
54
+ title: "Install Node dependencies",
55
+ subsystem: "node",
56
+ phase: "node",
57
+ rationale: "package.json found and node_modules appears missing.",
58
+ commands: [detection.node.lockfileCorrupted ? `${pm} install` : frozenInstall(pm)],
59
+ destructive: false,
60
+ irreversible: false,
61
+ undoable: false,
62
+ status: "planned",
63
+ });
64
+ }
65
+ if (detection.node.hasNext && config.node.caches.next) {
66
+ steps.push({
67
+ id: "node-clean-next-cache",
68
+ title: "Clean Next.js cache",
69
+ subsystem: "node",
70
+ phase: "node",
71
+ rationale: "Next.js cache can cause stale build/runtime state.",
72
+ commands: ["rm -rf .next"],
73
+ destructive: false,
74
+ irreversible: false,
75
+ undoable: false,
76
+ status: "planned",
77
+ });
78
+ }
79
+ if (detection.node.hasVite && config.node.caches.vite) {
80
+ steps.push({
81
+ id: "node-clean-vite-cache",
82
+ title: "Clean Vite cache",
83
+ subsystem: "node",
84
+ phase: "node",
85
+ rationale: "Vite cache corruption is a common local issue.",
86
+ commands: ["rm -rf node_modules/.vite"],
87
+ destructive: false,
88
+ irreversible: false,
89
+ undoable: false,
90
+ status: "planned",
91
+ });
92
+ }
93
+ for (const cacheDir of config.node.caches.directories) {
94
+ steps.push({
95
+ id: `node-clean-cache-${cacheDir.replace(/[^a-z0-9]/gi, "-")}`,
96
+ title: `Clean cache directory ${cacheDir}`,
97
+ subsystem: "node",
98
+ phase: "node",
99
+ rationale: "Configured cache directory cleanup.",
100
+ commands: [`rm -rf ${cacheDir}`],
101
+ destructive: false,
102
+ irreversible: false,
103
+ undoable: false,
104
+ status: "planned",
105
+ });
106
+ }
107
+ if (flags.deep && config.node.deep_cleanup.remove_node_modules) {
108
+ steps.push({
109
+ id: "node-remove-node-modules",
110
+ title: "IRREVERSIBLE: Remove node_modules for clean reinstall",
111
+ subsystem: "node",
112
+ phase: "node",
113
+ rationale: "Deep cleanup requested to resolve dependency drift.",
114
+ commands: ["rm -rf node_modules", `${pm} install`],
115
+ destructive: true,
116
+ irreversible: true,
117
+ irreversibleReason: "large folder not snapshotted in MVP",
118
+ undoable: false,
119
+ undoHints: [{ action: "Reinstall dependencies", command: `${pm} install` }],
120
+ status: "planned",
121
+ });
122
+ }
123
+ return steps;
124
+ }
@@ -0,0 +1,64 @@
1
+ function installCommand(prefer) {
2
+ switch (prefer) {
3
+ case "uv":
4
+ return "uv pip install -r requirements.txt";
5
+ case "poetry":
6
+ return "poetry install";
7
+ case "pipenv":
8
+ return "pipenv install";
9
+ case "pip":
10
+ return "pip install -r requirements.txt";
11
+ default:
12
+ return "pip install -r requirements.txt";
13
+ }
14
+ }
15
+ export function buildPythonSteps(detection, config, flags) {
16
+ if (!detection.python.detected)
17
+ return [];
18
+ const steps = [];
19
+ if (!detection.python.venvExists) {
20
+ steps.push({
21
+ id: "python-create-venv",
22
+ title: "Create Python virtual environment",
23
+ subsystem: "python",
24
+ phase: "python",
25
+ rationale: "Python project detected without configured virtual environment.",
26
+ commands: [`python3 -m venv ${config.python.venv_path}`],
27
+ destructive: false,
28
+ irreversible: false,
29
+ undoable: false,
30
+ status: "planned",
31
+ });
32
+ }
33
+ if (detection.python.hasRequirements || detection.python.hasPyproject) {
34
+ steps.push({
35
+ id: "python-install-deps",
36
+ title: "Install Python dependencies",
37
+ subsystem: "python",
38
+ phase: "python",
39
+ rationale: "Dependency refresh to resolve environment drift.",
40
+ commands: [installCommand(config.python.install.prefer)],
41
+ destructive: false,
42
+ irreversible: false,
43
+ undoable: false,
44
+ status: "planned",
45
+ });
46
+ }
47
+ if (flags.deep) {
48
+ steps.push({
49
+ id: "python-reset-venv",
50
+ title: "IRREVERSIBLE: Reset Python virtual environment",
51
+ subsystem: "python",
52
+ phase: "python",
53
+ rationale: "Deep cleanup for persistent Python environment drift.",
54
+ commands: [`rm -rf ${config.python.venv_path}`, `python3 -m venv ${config.python.venv_path}`],
55
+ destructive: true,
56
+ irreversible: true,
57
+ irreversibleReason: "cannot restore environment state fully",
58
+ undoable: false,
59
+ undoHints: [{ action: "Reinstall dependencies", command: installCommand(config.python.install.prefer) }],
60
+ status: "planned",
61
+ });
62
+ }
63
+ return steps;
64
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,161 @@
1
+ import * as p from "@clack/prompts";
2
+ const S = {
3
+ ok: "\u2714",
4
+ fail: "\u2717",
5
+ skip: "\u23ED",
6
+ warn: "\u25B2",
7
+ irr: "\u26A0",
8
+ dot: "\u25CF",
9
+ diamond: "\u25C6",
10
+ };
11
+ export function createRenderer(flags, interactive) {
12
+ const rich = interactive && !flags.quiet && !flags.json;
13
+ const spin = rich ? p.spinner() : null;
14
+ let spinRunning = false;
15
+ return {
16
+ isRich: rich,
17
+ intro(command) {
18
+ if (!rich)
19
+ return;
20
+ const tags = [];
21
+ if (flags.deep)
22
+ tags.push("deep");
23
+ if (flags.approve)
24
+ tags.push("approve");
25
+ if (flags.forceFresh)
26
+ tags.push("force-fresh");
27
+ if (flags.focus !== "all")
28
+ tags.push(`focus:${flags.focus}`);
29
+ if (flags.killPorts)
30
+ tags.push("kill-ports");
31
+ const extra = tags.length ? ` [${tags.join(", ")}]` : "";
32
+ p.intro(`auto-fix \u00B7 ${command}${extra}`);
33
+ },
34
+ showDetection(detection) {
35
+ if (!rich)
36
+ return;
37
+ const parts = [];
38
+ if (detection.node.detected)
39
+ parts.push(`Node (${detection.node.packageManager})`);
40
+ if (detection.python.detected)
41
+ parts.push("Python");
42
+ if (detection.docker.detected)
43
+ parts.push("Docker Compose");
44
+ p.log.info(`Detected: ${parts.join(", ") || "No supported project detected"}`);
45
+ for (const issue of detection.issues) {
46
+ p.log.warn(issue);
47
+ }
48
+ },
49
+ showPlan(steps, label) {
50
+ if (!rich)
51
+ return;
52
+ if (steps.length === 0) {
53
+ p.log.info("No actions to take.");
54
+ return;
55
+ }
56
+ const lines = steps.map((s) => {
57
+ const prefix = s.irreversible ? S.irr : s.destructive ? S.diamond : S.dot;
58
+ const irr = s.irreversible ? " [IRREVERSIBLE]" : "";
59
+ const reason = s.proposedReason ? ` \u2014 ${s.proposedReason}` : "";
60
+ return ` ${prefix} ${s.title}${irr}${reason}`;
61
+ });
62
+ p.note(lines.join("\n"), label ?? `Plan \u2014 ${steps.length} step(s)`);
63
+ },
64
+ createStepHooks() {
65
+ return {
66
+ onStepStart: (step) => {
67
+ if (!rich || !spin)
68
+ return;
69
+ spin.start(step.title);
70
+ spinRunning = true;
71
+ },
72
+ onStepEnd: (step) => {
73
+ if (!rich)
74
+ return;
75
+ if (spinRunning && spin) {
76
+ const msg = step.status === "success"
77
+ ? `${S.ok} ${step.title}`
78
+ : step.status === "failed"
79
+ ? `${S.fail} ${step.title}${step.error ? ` \u2014 ${step.error}` : ""}`
80
+ : `${S.skip} ${step.title}${step.proposedReason ? ` (${step.proposedReason})` : ""}`;
81
+ spin.stop(msg);
82
+ spinRunning = false;
83
+ }
84
+ else {
85
+ const symbol = step.status === "proposed" ? S.skip : S.dot;
86
+ const reason = step.proposedReason ? ` (${step.proposedReason})` : "";
87
+ p.log.warn(`${symbol} ${step.title}${reason}`);
88
+ }
89
+ },
90
+ onConfirm: async (question) => {
91
+ if (!rich)
92
+ return false;
93
+ if (spinRunning && spin) {
94
+ spin.stop();
95
+ spinRunning = false;
96
+ }
97
+ const result = await p.confirm({ message: question });
98
+ if (p.isCancel(result)) {
99
+ p.cancel("Operation cancelled.");
100
+ process.exit(0);
101
+ }
102
+ return result;
103
+ },
104
+ };
105
+ },
106
+ showResults(summary) {
107
+ if (!rich)
108
+ return;
109
+ const parts = [];
110
+ if (summary.succeeded > 0)
111
+ parts.push(`${S.ok} ${summary.succeeded} succeeded`);
112
+ if (summary.failed > 0)
113
+ parts.push(`${S.fail} ${summary.failed} failed`);
114
+ if (summary.skipped > 0)
115
+ parts.push(`${S.skip} ${summary.skipped} skipped/proposed`);
116
+ p.log.success(parts.join(" "));
117
+ if (summary.irreversibleStepIds.length > 0) {
118
+ p.log.warn(`Undo coverage: partial \u2014 ${summary.irreversibleStepIds.join(", ")} not undoable`);
119
+ }
120
+ for (const w of summary.warnings) {
121
+ p.log.warn(w);
122
+ }
123
+ },
124
+ showUndoResults(restored, skipped, missing, failed) {
125
+ if (!rich)
126
+ return;
127
+ const parts = [];
128
+ if (restored > 0)
129
+ parts.push(`${S.ok} ${restored} restored`);
130
+ if (skipped > 0)
131
+ parts.push(`${S.skip} ${skipped} skipped`);
132
+ if (missing > 0)
133
+ parts.push(`${S.warn} ${missing} missing snapshot`);
134
+ if (failed > 0)
135
+ parts.push(`${S.fail} ${failed} failed`);
136
+ p.log.success(parts.join(" "));
137
+ },
138
+ showReportInfo(msg) {
139
+ if (!rich)
140
+ return;
141
+ p.log.info(msg);
142
+ },
143
+ startTask(msg) {
144
+ if (!rich || !spin)
145
+ return;
146
+ spin.start(msg);
147
+ spinRunning = true;
148
+ },
149
+ stopTask(msg) {
150
+ if (!rich || !spin || !spinRunning)
151
+ return;
152
+ spin.stop(msg);
153
+ spinRunning = false;
154
+ },
155
+ outro(message) {
156
+ if (!rich)
157
+ return;
158
+ p.outro(`Next \u2192 ${message}`);
159
+ },
160
+ };
161
+ }
@@ -0,0 +1,20 @@
1
+ const reset = "\u001b[0m";
2
+ const bold = "\u001b[1m";
3
+ const dim = "\u001b[2m";
4
+ const green = "\u001b[32m";
5
+ const red = "\u001b[31m";
6
+ const yellow = "\u001b[33m";
7
+ const cyan = "\u001b[36m";
8
+ function wrap(enabled, code, value) {
9
+ return enabled ? `${code}${value}${reset}` : value;
10
+ }
11
+ export function style(enabled) {
12
+ return {
13
+ title: (v) => wrap(enabled, `${bold}${cyan}`, v),
14
+ ok: (v) => wrap(enabled, green, v),
15
+ warn: (v) => wrap(enabled, yellow, v),
16
+ err: (v) => wrap(enabled, red, v),
17
+ strong: (v) => wrap(enabled, bold, v),
18
+ dim: (v) => wrap(enabled, dim, v),
19
+ };
20
+ }
@@ -0,0 +1,60 @@
1
+ import { access, cp, mkdir, readFile, stat, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { constants } from "node:fs";
4
+ export async function fileExists(target) {
5
+ try {
6
+ await stat(target);
7
+ return true;
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ export async function ensureDir(dir) {
14
+ await mkdir(dir, { recursive: true });
15
+ }
16
+ export async function ensureWritableDir(dir) {
17
+ try {
18
+ await ensureDir(dir);
19
+ await access(dir, constants.W_OK);
20
+ return true;
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }
26
+ export async function readJsonFile(target) {
27
+ if (!(await fileExists(target)))
28
+ return null;
29
+ const content = await readFile(target, "utf8");
30
+ return JSON.parse(content);
31
+ }
32
+ export async function writeJsonFile(target, data) {
33
+ await ensureDir(path.dirname(target));
34
+ await writeFile(target, JSON.stringify(data, null, 2), "utf8");
35
+ }
36
+ export async function copyPath(src, dest) {
37
+ await ensureDir(path.dirname(dest));
38
+ await cp(src, dest, { recursive: true, force: true });
39
+ }
40
+ export async function ensureAutofixInGitignore(cwd) {
41
+ let current = cwd;
42
+ while (true) {
43
+ const gitDir = path.join(current, ".git");
44
+ if (await fileExists(gitDir)) {
45
+ const gitignore = path.join(current, ".gitignore");
46
+ const exists = await fileExists(gitignore);
47
+ const body = exists ? await readFile(gitignore, "utf8") : "";
48
+ if (!body.split(/\r?\n/).includes(".autofix/")) {
49
+ const next = `${body}${body.endsWith("\n") || body.length === 0 ? "" : "\n"}.autofix/\n`;
50
+ await writeFile(gitignore, next, "utf8");
51
+ return true;
52
+ }
53
+ return false;
54
+ }
55
+ const parent = path.dirname(current);
56
+ if (parent === current)
57
+ return false;
58
+ current = parent;
59
+ }
60
+ }
@@ -0,0 +1,17 @@
1
+ import { exec } from "node:child_process";
2
+ export function runShellCommand(command, cwd) {
3
+ return new Promise((resolve) => {
4
+ exec(command, { cwd, maxBuffer: 1024 * 1024 * 4 }, (error, stdout, stderr) => {
5
+ if (error) {
6
+ resolve({
7
+ success: false,
8
+ code: typeof error.code === "number" ? error.code : 1,
9
+ stdout: stdout ?? "",
10
+ stderr: stderr ?? error.message,
11
+ });
12
+ return;
13
+ }
14
+ resolve({ success: true, code: 0, stdout: stdout ?? "", stderr: stderr ?? "" });
15
+ });
16
+ });
17
+ }
@@ -0,0 +1,3 @@
1
+ export function isInteractive() {
2
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
3
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@technicalshree/auto-fix",
3
+ "version": "1.1.0",
4
+ "description": "Detect, diagnose, and safely fix common local dev environment issues",
5
+ "main": "dist/cli.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/TechnicalShree/ts-cli-tool.git"
9
+ },
10
+ "homepage": "https://github.com/TechnicalShree/ts-cli-tool#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/TechnicalShree/ts-cli-tool/issues"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "bin": {
19
+ "auto-fix": "dist/cli.js"
20
+ },
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.json",
23
+ "dev": "tsx src/cli.ts",
24
+ "start": "node dist/cli.js",
25
+ "test": "npm run build --silent && node --test",
26
+ "lint": "tsc --noEmit",
27
+ "prepack": "npm run build",
28
+ "prepublishOnly": "npm run lint && npm test"
29
+ },
30
+ "keywords": [
31
+ "cli",
32
+ "autofix",
33
+ "developer-tools"
34
+ ],
35
+ "author": "Krushna Raut",
36
+ "license": "ISC",
37
+ "type": "module",
38
+ "engines": {
39
+ "node": ">=18"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "dependencies": {
45
+ "@clack/prompts": "^1.0.1",
46
+ "yaml": "^2.8.1"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^24.3.0",
50
+ "tsx": "^4.20.4",
51
+ "typescript": "^5.9.2"
52
+ }
53
+ }