@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 +86 -0
- package/README.md +60 -10
- package/dist/cli.js +724 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.js +576 -0
- package/dist/types/index.d.ts +103 -0
- package/dist/types/tsLanguageServiceFixer.d.ts +124 -0
- package/dist/types/validatorInProcess.d.ts +64 -0
- package/package.json +18 -16
- package/bin/tsfix.mjs +0 -49
- package/cli/run-stack.ts +0 -195
- package/src/index.ts +0 -202
- package/src/tsLanguageServiceFixer.ts +0 -486
- package/src/validatorInProcess.ts +0 -276
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
|
-
###
|
|
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
|
-
|
|
98
|
-
|
|
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
|
-
|
|
111
|
+
```sh
|
|
112
|
+
npx tsx run-fix.mjs # tsx loads the package's .ts source
|
|
113
|
+
```
|
|
102
114
|
|
|
103
|
-
|
|
115
|
+
### Use as a CLI (after `npm link` from a clone)
|
|
104
116
|
|
|
105
|
-
|
|
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
|
-
`--
|
|
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.
|