@shipispec/tsfix 0.1.0 → 0.2.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 ADDED
@@ -0,0 +1,86 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@shipispec/tsfix` are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
+
5
+ ## [Unreleased]
6
+
7
+ ### Added
8
+ - **Project-shape matrix** (`scripts/run-matrix.mjs`, `npm run matrix`) — pre-publish gate that builds the local tarball and exercises it cold against 6 distinct project shapes: `monorepo-refs` (project references — pinned as a documented limitation), `next-app` (App Router, `paths` alias, `jsx: preserve`), `plain-ts-bundler` (esnext + bundler), `plain-ts-commonjs` (legacy CJS + ES2015 + node10), `plain-ts-nodenext` (nodenext resolution), `react-vite` (TSX + `jsx: react-jsx`). Each sample has an `expected.json` asserting `errorsBefore`, `errorsAfterMax`, `lspFixesAppliedMin/Max`, `mustPass`, and `expectFileContains` post-fix. 6/6 pass on 2026-05-05. Dev-only — not shipped in the tarball.
9
+
10
+ ## [0.2.0] - 2026-05-04
11
+
12
+ Phase 1a complete. **Plain Node consumers can now `import` the package without a TypeScript loader, and `npx @shipispec/tsfix` works cold.** Folds in everything that was queued for v0.1.1 (which was never published — its commit is now part of v0.2.0).
13
+
14
+ ### Added
15
+ - **esbuild bundle** in `dist/`. Three artifacts: `dist/index.js` (library, ESM bundle), `dist/cli.js` (CLI, ESM with shebang, executable), `dist/index.d.ts` (public type declarations from `tsc --emitDeclarationOnly`). Per-file `.d.ts` files in `dist/types/` for callers wanting subpath types.
16
+ - `npm run build` → `node scripts/build.mjs`. Also runs as `prepublishOnly` so `npm publish` always ships fresh `dist/`.
17
+ - **`--dry-run` flag** on the CLI and `dryRun` option on `runValidationLoop` and `runLSPFixerPass`. Runs the full LSP fix loop in memory; reports what *would* be edited; no disk writes. Resolves the documented footgun where pointing tsfix at a fixture irreversibly mutated it. (Audit M-E4.)
18
+ - **Trust model section** in README: `tsfix` loads `typescript` from your workspace's `node_modules`. Only run on workspaces you trust. (Audit M-S1.)
19
+ - **Troubleshooting section** in README covering the most likely user errors (`ERR_MODULE_NOT_FOUND` for typescript; missing `tsconfig.json`).
20
+ - **Dev-vs-consumer guidance** in README. (Audit M-E3.)
21
+ - **3 dryRun unit tests** in `src/dryRun.test.ts`.
22
+
23
+ ### Changed
24
+ - **Package shape**: `main`/`types`/`exports` now point at `dist/`, not `src/`. `bin.tsfix` points at `dist/cli.js` directly. `files` array ships `dist/` only (no more `src/`, `cli/`, `bin/` in tarball). Tarball: 10 files, 16.8 KB packed.
25
+ - **Removed `bin/tsfix.mjs` wrapper** — replaced by the bundled `dist/cli.js`. The wrapper was a Phase 0c bridge that depended on local `tsx`; the bundle drops that dependency.
26
+ - **Dropped `./validation` and `./lsp-fixer` subpath exports** — unused; the only consumer (spectoship2 shims) imports from the main entry. Easy to re-add if needed.
27
+ - README CLI section rewritten to reflect Phase 0c standalone install (no longer references the old `cd spectoship2 && tsx ../tsc-defense-stack/...` flow).
28
+
29
+ ### Fixed
30
+ - **Plain Node `import { runValidationLoop } from "@shipispec/tsfix"` now works.** Was previously blocked by Node 22+ refusing to type-strip `.ts` files in `node_modules` (audit H-E1). Verified end-to-end via `npm install` from tarball + `node use-as-library.mjs`.
31
+ - **`npx @shipispec/tsfix --workspace ./project` now works cold.** Was previously blocked by the bin wrapper requiring `tsx` from the package's own `node_modules` (audit M-E2).
32
+ - `bin/tsfix.mjs` error message no longer references the old `tsc-defense` name (n/a in 0.2.0 — wrapper deleted entirely; audit M-E1).
33
+ - `cli/run-stack.ts` no longer ships with executable permission bits (the bundled `dist/cli.js` does, which is correct since it's the actual entry; audit L-S2).
34
+
35
+ ### Engines
36
+ - Node `>=20.9.0` (unchanged)
37
+ - TypeScript `>=5.0.0` peer (unchanged; npm 7+ auto-installs)
38
+
39
+ ### Outstanding from audit (deferred)
40
+ - L-S1 (npm `--provenance` for supply-chain attestation) — Phase 1b CI publish.
41
+
42
+ ## [0.1.1] - 2026-05-04
43
+
44
+ Patch release addressing the medium-severity findings from the post-publish audit (`docs/audit-2026-05-04.md`). No API breaks; consumers can upgrade with `npm install @shipispec/tsfix@latest`.
45
+
46
+ ### Added
47
+ - **`--dry-run` flag** on the CLI and a corresponding `dryRun` option on `runValidationLoop` and `runLSPFixerPass`. Runs the full LSP fix loop in memory and reports what *would* be edited, but does not write to disk. Resolves the documented footgun where running `tsfix` against a fixture directory irreversibly mutated the broken code. (Audit M-E4.)
48
+ - **Trust model section** in README: explicit disclosure that `tsfix` loads `typescript` from the workspace's `node_modules`, with the standard "only run on workspaces you trust" warning. (Audit M-S1.)
49
+ - **Dev-vs-consumer guidance** in README: clarifies that `npm scripts` shipped in the published `package.json` (benchmark/test/setup-fixtures) are for contributors only — consumer-side `node_modules/@shipispec/tsfix/` doesn't have `tsx`/`vitest`/`fixtures/`. (Audit M-E3.)
50
+
51
+ ### Fixed
52
+ - `bin/tsfix.mjs` error message no longer references the old `tsc-defense` name; now describes the correct `tsfix` flow when `tsx` cannot be resolved. (Audit M-E1.)
53
+ - `cli/run-stack.ts` no longer ships with executable permission bits (was `-rwxr-xr-x`, now `-rw-r--r--`). The file is loaded by `tsx`, never run directly. (Audit L-S2.)
54
+
55
+ ### Changed
56
+ - README CLI section rewritten to reflect Phase 0c standalone install (no longer references the old monorepo `cd spectoship2 && tsx ../tsc-defense-stack/...` flow).
57
+
58
+ ## [0.1.0] - 2026-05-04
59
+
60
+ Initial public release. **Layers 0–1 only** (deterministic detection + auto-fix). LLM-driven mend layers stay in `spectoship2/` until v0.2.
61
+
62
+ ### Added
63
+ - **`runValidationLoop(opts)`** — full deterministic loop (validate → auto-fix → re-validate). Recommended entry point.
64
+ - **`runInProcessTsc(opts)`** — in-process `tsc --noEmit` returning structured diagnostics. No subprocess spawn, no Node 23 startup-pause issue. Workspace lib-path override (uses the workspace's `node_modules/typescript` so globals resolve under esbuild bundling).
65
+ - **`runLSPFixerPass(opts)`** — Layer 0 deterministic auto-fixer using `ts.LanguageService.getCodeFixesAtPosition`. Strictly opt-in by error code and fix name:
66
+ - `SAFE_FIXABLE_CODES`: `TS2304`, `TS2305`, `TS2551`, `TS2552`, `TS2724`
67
+ - `SAFE_FIX_NAMES`: `import`, `fixImport`, `spelling`, `fixSpelling`
68
+ - 5-iteration cap with signature-set progress check (stops when the `(file, start, code)` set repeats)
69
+ - Multi-fix equivalence check abstains when candidate fixes produce different edits
70
+ - **`discoverTsFiles(workspaceRoot)`** — file-discovery helper. Includes `.ts`/`.tsx`; excludes `.d.ts` and `node_modules`/`.next`/`dist`/`build`/`out`/`coverage`/`.git`.
71
+ - **CLI** (`tsfix --workspace <path>`, after `npm link`). Flags: `--json`, `--no-lsp`, `--verbose`, `--files <comma-list>`, `--help`. Exit 0 = clean, 1 = errors remain, 2 = bad args.
72
+ - **MIT license**, no runtime deps except peer `typescript >=5.0.0`.
73
+
74
+ ### Known limitations
75
+ - **`npx @shipispec/tsfix ./project`** does not work for cold-start. The bin wrapper requires `tsx` to be resolvable from the package's own `node_modules`. Use `npm install @shipispec/tsfix && npm link` for now. Phase 1a (esbuild bundle) addresses this.
76
+ - **`export { X } from "./mod"`** — TS LanguageService returns zero code-fixes for typos in this syntactic position. Documented in `fixtures/synthetic-cross-file-typo-ts2305/`.
77
+ - **Footgun:** the CLI mutates files in place with no snapshot/restore. Don't point it at the package's own `fixtures/` directories during dev — use `npm run benchmark` instead, which snapshots and restores.
78
+
79
+ ### Engines
80
+ - Node `>=20.9.0` (matches VS Code Extension Host runtime)
81
+ - TypeScript `>=5.0.0` (peer dep, must be installed in the consuming workspace)
82
+
83
+ [Unreleased]: https://github.com/owgreen-dev/tsfix/compare/v0.2.0...HEAD
84
+ [0.2.0]: https://github.com/owgreen-dev/tsfix/compare/v0.1.1...v0.2.0
85
+ [0.1.1]: https://github.com/owgreen-dev/tsfix/compare/v0.1.0...v0.1.1
86
+ [0.1.0]: https://github.com/owgreen-dev/tsfix/releases/tag/v0.1.0
package/README.md CHANGED
@@ -91,25 +91,49 @@ fixtures/ # 14 hand-authored synthetic workspaces
91
91
  api-drift-*/ # 4 version-drift fixtures (Zod 3 vs 4, React 18 vs 19, etc.)
92
92
  ```
93
93
 
94
- ### Run the CLI
94
+ ### Use as a library (today's recommended path)
95
95
 
96
+ `@shipispec/tsfix` ships its source as `.ts`. Plain Node 22+ refuses to type-strip files in `node_modules`, so consumers need a TypeScript-aware loader (`tsx`, `ts-node`, or `jiti`) until v0.2 ships an esbuild bundle. Most LLM-tooling projects already use one of these.
97
+
98
+ ```sh
99
+ npm install @shipispec/tsfix typescript
96
100
  ```
97
- cd /Users/ogg/Documents/microservices/Meta/spectoship2
98
- ./node_modules/.bin/tsx ../tsc-defense-stack/cli/run-stack.ts --workspace <path>
101
+
102
+ ```js
103
+ // run-fix.mjs
104
+ import { runValidationLoop } from "@shipispec/tsfix";
105
+
106
+ const result = runValidationLoop({ workspaceRoot: "./my-project" });
107
+ console.log(result.errorsBefore, "→", result.errorsAfter);
108
+ console.log("LSP fixes:", result.lspFixer.fixesApplied);
99
109
  ```
100
110
 
101
- Flags: `--json`, `--no-lsp`, `--verbose`, `--files <comma-list>`. Exit 0 = clean, 1 = errors remain, 2 = bad args.
111
+ ```sh
112
+ npx tsx run-fix.mjs # tsx loads the package's .ts source
113
+ ```
102
114
 
103
- > Note: per Phase 0c of `tsc-defense-roadmap.md`, this package will gain its own local `node_modules` so commands run from inside the package directory. Today it shares `spectoship2/node_modules`.
115
+ ### Use as a CLI (after `npm link` from a clone)
104
116
 
105
- ### Run the benchmark
117
+ The bin's `npx` cold-start is blocked on the v0.2 esbuild bundle (see roadmap § 1a). For now, clone-and-link works:
106
118
 
119
+ ```sh
120
+ git clone https://github.com/owgreen-dev/spectoship-meta
121
+ cd spectoship-meta/tsc-defense-stack
122
+ npm install
123
+ npm link
124
+
125
+ tsfix --workspace ./your-project
107
126
  ```
108
- cd /Users/ogg/Documents/microservices/Meta/spectoship2
109
- ./node_modules/.bin/tsx ../tsc-defense-stack/benchmark/run-benchmark.ts
110
- ```
111
127
 
112
- `--fixture <name>` to run a single fixture in isolation.
128
+ Flags: `--json`, `--no-lsp`, `--verbose`, `--files <comma-list>`. Exit codes: `0` = clean, `1` = errors remain, `2` = bad args / harness error.
129
+
130
+ ### Run the benchmark (contributor-only)
131
+
132
+ From inside the package directory after `npm install`:
133
+ ```sh
134
+ npm run benchmark # all 14 fixtures
135
+ npm run benchmark -- --fixture synthetic-typo-ts2552 # one fixture
136
+ ```
113
137
 
114
138
  ### Current baseline
115
139
 
@@ -118,3 +142,29 @@ cd /Users/ogg/Documents/microservices/Meta/spectoship2
118
142
  ### Capturing real-failure fixtures
119
143
 
120
144
  Phase 3b in the roadmap. When a real spec-pipeline run produces a TSC error Layer 0-1 doesn't fix, snapshot the broken `.ts(x)` files into `fixtures/real-<timestamp>-<hash>/` with an `expected.json`. The fixture set then grows from production failures, not just synthetic ones.
145
+
146
+ ---
147
+
148
+ ## Troubleshooting
149
+
150
+ **`ERR_MODULE_NOT_FOUND: Cannot find package 'typescript'`** — your package manager didn't install the peer dependency. Run `npm install typescript` (or yarn/pnpm equivalent). Modern npm (v7+) auto-installs peers, so you'll usually only see this with older npm or with `auto-install-peers=false`.
151
+
152
+ **`Cannot find module '<workspace>/tsconfig.json'`** — you pointed `--workspace` at a directory with no `tsconfig.json`. Pass a directory whose root has the project's tsconfig (typically the project root, not a sub-package).
153
+
154
+ ---
155
+
156
+ ## Trust model
157
+
158
+ `@shipispec/tsfix` loads `typescript` from your workspace's `node_modules` (this is required for the lib-path workaround that makes the package work inside esbuild bundles). That means a malicious workspace's `typescript` install can execute arbitrary code at validate time.
159
+
160
+ **Only run `tsfix` on workspaces you trust.** This is the same trust boundary as ESLint, Prettier, Vitest, and other tools that load the workspace's TypeScript.
161
+
162
+ There is no telemetry, no outbound HTTP, and no exec calls outside the local `node` ↔ `tsx` invocation in the bin wrapper. The only filesystem writes are LSP edits to files you pass in via `targetFiles` (or files discovered under `workspaceRoot`).
163
+
164
+ ---
165
+
166
+ ## What's in the package vs what's only for contributors
167
+
168
+ The published tarball ships `src/`, `cli/`, `bin/`, plus `README.md` / `LICENSE` / `CHANGELOG.md`. Everything else (`benchmark/`, `fixtures/`, `tsconfig.json`, the dev-only npm scripts in `package.json`, the design docs in `docs/`) is contributor-side and either excluded from the tarball via `package.json#files` or just not part of the consumer-facing surface.
169
+
170
+ **Heads-up for consumers:** the published `package.json` includes `scripts.benchmark`, `scripts.test`, and `scripts.setup-fixtures`. Those reference `tsx`, `vitest`, and `fixtures/_shared/` — none of which ship to consumers. Don't run them from your `node_modules/@shipispec/tsfix/` directory; clone the repo if you want to contribute.