@shipispec/tsfix 0.2.0 → 0.3.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 CHANGED
@@ -4,8 +4,25 @@ All notable changes to `@shipispec/tsfix` are documented here. Format follows [K
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.3.0] - 2026-05-07
8
+
9
+ Phase 2 contract release. **Establishes the public types `MendContext`, `LayerEvent`, and `Diagnostic` so a downstream LLM-mend package (e.g. `@shipispec/tsmend`) can consume tsfix's output without redefining the shape.** No behavior changes; purely additive types. Also collapses several dev-only improvements that landed since v0.2.0 into a single release.
10
+
7
11
  ### 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.
12
+ - **`MendContext` interface** — public type defining the input contract for a Layer 2–4 LLM-mend agent. Required fields: `workspaceRoot`, `diagnostics`, `erroredFiles`. Optional fields: `taskDescription`, `featureSpecText`, `acceptanceCriteria`, `siblingTasks`, `priorTaskExports`, `installedTypes`.
13
+ - **`LayerEvent` interface** — per-layer event shape for streaming telemetry. Designed for an `onLayerEvent` callback in a future minor release; the type is published now so downstream callers can construct events themselves.
14
+ - **`Diagnostic` type alias** — public re-export of `InProcessTscResult["diagnostics"][number]`. Convenience for consumers building `MendContext`.
15
+ - **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`). 6/6 pass. Dev-only — not shipped in the tarball.
16
+ - **Capture script** (`scripts/capture-fixture.mjs`, `npm run capture`) — Phase 3b tooling for snapshotting real broken workspaces into `fixtures/real-<name>/`. Awaits first real failure to produce fixtures.
17
+ - **GitHub Actions CI** (`.github/workflows/test.yml`) — runs check-types, vitest, benchmark, and the matrix on every PR + main push.
18
+
19
+ ### Changed
20
+ - **Repository moved.** `tsc-defense-stack/` was extracted from the `spectoship-meta` monorepo into its own repository at <https://github.com/owgreen-dev/tsfix>. All `repository.url`, `homepage`, `bugs.url` fields point at the new repo. Internal git history pre-2026-05-06 lives in the original monorepo; the CHANGELOG narrates v0.1.0–v0.2.0 in detail.
21
+ - **Public README rewritten** for an OSS audience — tagline, before/after, 30-second cold start, four-layer model, library API, trust model, contributing protocol. Previous internal-orientation README preserved at `docs/internal-orientation.md`.
22
+
23
+ ### Engines
24
+ - Node `>=20.9.0` (unchanged)
25
+ - TypeScript `>=5.0.0` peer (unchanged)
9
26
 
10
27
  ## [0.2.0] - 2026-05-04
11
28
 
@@ -80,7 +97,8 @@ Initial public release. **Layers 0–1 only** (deterministic detection + auto-fi
80
97
  - Node `>=20.9.0` (matches VS Code Extension Host runtime)
81
98
  - TypeScript `>=5.0.0` (peer dep, must be installed in the consuming workspace)
82
99
 
83
- [Unreleased]: https://github.com/owgreen-dev/tsfix/compare/v0.2.0...HEAD
100
+ [Unreleased]: https://github.com/owgreen-dev/tsfix/compare/v0.3.0...HEAD
101
+ [0.3.0]: https://github.com/owgreen-dev/tsfix/compare/v0.2.0...v0.3.0
84
102
  [0.2.0]: https://github.com/owgreen-dev/tsfix/compare/v0.1.1...v0.2.0
85
103
  [0.1.1]: https://github.com/owgreen-dev/tsfix/compare/v0.1.0...v0.1.1
86
104
  [0.1.0]: https://github.com/owgreen-dev/tsfix/releases/tag/v0.1.0
package/README.md CHANGED
@@ -1,170 +1,178 @@
1
- # TSC Defense Stack — `@shipispec/tsfix`
1
+ # tsfix
2
2
 
3
- Standalone npm package implementing **Layers 0–1** of the TypeScript error-recovery stack: in-process tsc validation + deterministic LSP auto-fix. Layers 2–4 (LLM mend) currently live in `spectoship2/src/pipeline/` and will move to a sister package `@shipispec/tsmend` per the roadmap.
3
+ > Headless TypeScript error recovery auto-resolve `TS2304`, `TS2305`, `TS2551`, `TS2552`, `TS2724` before they reach a human.
4
4
 
5
- Read first:
6
- - `STATUS.md` — what's working, what's planned, current gaps
7
- - `ARCHITECTURE.md` — why the package is shaped the way it is
8
- - `tsc-defense-roadmap.md` — phased plan with open decisions
9
- - `CLAUDE.md` — working principles (small allowlist, fixture-pinned trust model)
5
+ `@shipispec/tsfix` borrows the same TypeScript Language Service that powers VS Code's "Quick Fix" lightbulb and runs it as a CLI. Point it at a workspace, it fixes typos, missing imports, and did-you-mean errors deterministically — no LLM, no calls home, no config.
10
6
 
11
- ---
7
+ Built for the case where you've just generated a few hundred files of TypeScript with an LLM and `tsc --noEmit` is screaming at you.
12
8
 
13
- ## Source-of-truth map
9
+ ## Before / after
14
10
 
15
- This package owns its TypeScript-error handling code outright. The shims in `spectoship2/` re-export from here, not the reverse.
11
+ ```
12
+ $ tsc --noEmit
13
+ src/api.ts:5:2 - error TS2552: Cannot find name 'consol'. Did you mean 'console'?
14
+ src/api.ts:8:5 - error TS2305: Module '"react"' has no exported member 'ueState'.
15
+ src/api.ts:12:14 - error TS2551: Property 'lenght' does not exist on type 'string[]'. Did you mean 'length'?
16
16
 
17
- | Path | Role |
18
- |---|---|
19
- | `src/index.ts` | Public API (`runValidationLoop`, `runInProcessTsc`, `runLSPFixerPass`, `discoverTsFiles`) |
20
- | `src/validatorInProcess.ts` | In-process tsc with lib-path workaround (Layer 0) |
21
- | `src/tsLanguageServiceFixer.ts` | LSP auto-fixer using `getCodeFixesAtPosition` (Layer 1) |
22
- | `cli/run-stack.ts` | CLI: `tsx cli/run-stack.ts --workspace <path>` |
23
- | `benchmark/run-benchmark.ts` | Fixture harness (auto-discovers `fixtures/*/`) |
24
- | `fixtures/` | 14 hand-authored synthetic fixtures across 3 tiers |
25
- | `spectoship2/src/pipeline/validatorInProcess.ts` | **Re-export shim** → `@shipispec/tsfix` |
26
- | `spectoship2/src/pipeline/tsLanguageServiceFixer.ts` | **Re-export shim** → `@shipispec/tsfix` |
17
+ Found 3 errors in 1 file.
27
18
 
28
- ---
19
+ $ npx @shipispec/tsfix --workspace .
20
+ [ts-lsp-fixer] applied 3 fixes across 1 file
29
21
 
30
- ## How the layers fit together
22
+ $ tsc --noEmit
23
+ $ # 0 errors
24
+ ```
31
25
 
32
- Per `ARCHITECTURE.md`, a TSC error has up to four chances to die before reaching a user. Layers -1 (prevention) and 2-4 (mend) live outside this package.
26
+ ## 30-second cold start
33
27
 
34
- ```
35
- ┌─────────────────────────────────────────────────┐
36
- Layer -1: PREVENTION (in spectoship2/, not here)│
37
- │ packageGotchas, installedExports, priorExports│
38
- │ codeGenPrompts (rules injected into prompt) │
39
- └────────────────────┬────────────────────────────┘
40
- │ files written to disk
41
-
42
- ┌────── @shipispec/tsfix ───────┴──────────────────────────┐
43
- │ │
44
- │ ┌─────────────────────────────────────────────┐ │
45
- │ │ Layer 0: src/validatorInProcess.ts │ │
46
- │ │ in-process tsc → structured diagnostics │ │
47
- │ │ workspace lib-path override │ │
48
- │ └─────────────────────┬───────────────────────┘ │
49
- │ │ if errors │
50
- │ ▼ │
51
- │ ┌─────────────────────────────────────────────┐ │
52
- │ │ Layer 1: src/tsLanguageServiceFixer.ts │ │
53
- │ │ getCodeFixesAtPosition (5 SAFE codes) │ │
54
- │ │ signature-set progress check, max 5 iters │ │
55
- │ └─────────────────────┬───────────────────────┘ │
56
- │ │ re-validate; if errors remain │
57
- └─────────────────────────┼─────────────────────────────────────────┘
58
-
59
- ┌─────────────────────────────────┐
60
- │ Layers 2-4: LLM MEND │
61
- │ mendAgent / mendArchitect / │
62
- │ multiFileMend / repairAgent │
63
- │ (in spectoship2/, not here; │
64
- │ moves to @shipispec/tsmend│
65
- │ in v0.2 per roadmap) │
66
- └─────────────────────────────────┘
28
+ ```bash
29
+ cd your-broken-project
30
+ npx @shipispec/tsfix --workspace .
67
31
  ```
68
32
 
69
- ---
33
+ No config file. Exit code conventions:
70
34
 
71
- ## What to read first
35
+ | Code | Meaning |
36
+ |---|---|
37
+ | 0 | Workspace is clean |
38
+ | 1 | Errors remain (printed to stderr) |
39
+ | 2 | Bad arguments / harness error |
72
40
 
73
- 1. **`STATUS.md`** current state, fixture catalog, recent fixes
74
- 2. **`ARCHITECTURE.md`** — why the package is shaped the way it is (12 sections)
75
- 3. **`tsc-defense-roadmap.md`** — phased plan with open decisions
76
- 4. **`src/index.ts`** — public API entry point (`runValidationLoop`)
77
- 5. **`src/tsLanguageServiceFixer.ts`** — Layer 1 fixer; understand `SAFE_FIXABLE_CODES`, the signature-set progress check, and the iteration loop
78
- 6. **`src/validatorInProcess.ts`** — in-process tsc with the lib-path workaround that makes the package work inside the VS Code Extension Host
41
+ Preview what *would* change without writing to disk:
79
42
 
80
- ---
43
+ ```bash
44
+ npx @shipispec/tsfix --workspace . --dry-run
45
+ ```
81
46
 
82
- ## Standalone harness
47
+ Machine-readable output for piping into other tools:
83
48
 
84
- ```
85
- cli/run-stack.ts # CLI: run stack on any workspace
86
- benchmark/run-benchmark.ts # benchmark across all fixtures
87
- fixtures/ # 14 hand-authored synthetic workspaces
88
- _shared/ # shared node_modules symlink target
89
- clean-baseline/ # regression check (must stay green)
90
- synthetic-*/ # 9 LSP-behavior fixtures (positive + negative)
91
- api-drift-*/ # 4 version-drift fixtures (Zod 3 vs 4, React 18 vs 19, etc.)
49
+ ```bash
50
+ npx @shipispec/tsfix --workspace . --json
92
51
  ```
93
52
 
94
- ### Use as a library (today's recommended path)
53
+ ### All flags
95
54
 
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.
55
+ | Flag | Meaning |
56
+ |---|---|
57
+ | `--workspace <path>` | Required. Directory containing your `tsconfig.json`. |
58
+ | `--dry-run` | Run the fixer in memory, report counts, write nothing. |
59
+ | `--no-lsp` | Validate only — skip auto-fix. |
60
+ | `--files <a.ts,b.ts>` | Restrict fixing to a comma-separated list. |
61
+ | `--json` | Machine-readable output. |
62
+ | `--verbose` | Per-fix logging. |
63
+ | `--help` | Print usage. |
97
64
 
98
- ```sh
99
- npm install @shipispec/tsfix typescript
100
- ```
65
+ ## What it fixes
101
66
 
102
- ```js
103
- // run-fix.mjs
104
- import { runValidationLoop } from "@shipispec/tsfix";
67
+ | TS code | Meaning | What tsfix does |
68
+ |---|---|---|
69
+ | `TS2304` | Cannot find name | Auto-imports |
70
+ | `TS2305` | Module has no exported member | Did-you-mean rename |
71
+ | `TS2551` | Property does not exist on T, did you mean Y | Spelling fix |
72
+ | `TS2552` | Cannot find name, did you mean Y | Spelling fix |
73
+ | `TS2724` | Module member did-you-mean | Import rename |
105
74
 
106
- const result = runValidationLoop({ workspaceRoot: "./my-project" });
107
- console.log(result.errorsBefore, "→", result.errorsAfter);
108
- console.log("LSP fixes:", result.lspFixer.fixesApplied);
109
- ```
75
+ Against a 14-fixture benchmark spanning typos, did-you-mean cases, multi-file ripples, and 4 API-drift scenarios: **14/14 fixtures pass and 14/25 errors are auto-fixed (56%).** The remaining errors are intentionally outside Layer 0's scope (see below).
110
76
 
111
- ```sh
112
- npx tsx run-fix.mjs # tsx loads the package's .ts source
113
- ```
77
+ ## What it does *not* fix
78
+
79
+ By design, tsfix only applies fixes that are **deterministic** and **non-structural**. It will refuse to:
114
80
 
115
- ### Use as a CLI (after `npm link` from a clone)
81
+ - Add or remove function declarations
82
+ - Insert type annotations or change types
83
+ - Modify control flow (`await` insertions, async propagation)
84
+ - Rewrite JSX trees
85
+ - Add object-literal stub properties
116
86
 
117
- The bin's `npx` cold-start is blocked on the v0.2 esbuild bundle (see roadmap § 1a). For now, clone-and-link works:
87
+ The internal allowlist is two-layered: error codes (`SAFE_FIXABLE_CODES`) and Quick Fix names (`SAFE_FIX_NAMES = ['import', 'fixImport', 'spelling', 'fixSpelling']`). When the language service offers anything outside that allowlist, tsfix abstains and surfaces the error in the result so a higher layer (LLM, human) can pick it up.
118
88
 
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
89
+ ## The four-layer model
124
90
 
125
- tsfix --workspace ./your-project
91
+ tsfix is **Layer 0–1** of a larger error-recovery stack. The other layers are LLM-driven and live elsewhere (in your own code, or in companion packages):
92
+
93
+ ```
94
+ Layer 0 — Prevention (prompt rules, exported-API injection — your problem)
95
+ Layer 1 — tsfix (this package: deterministic auto-fix)
96
+ ─────────────────────────────────────────────────────────────────────────
97
+ Layer 2 — Single-file LLM mend (architect + editor split)
98
+ Layer 3 — Multi-file LLM mend (blast-radius search/replace)
99
+ Layer 4 — Stub-and-continue (escape hatch)
126
100
  ```
127
101
 
128
- Flags: `--json`, `--no-lsp`, `--verbose`, `--files <comma-list>`. Exit codes: `0` = clean, `1` = errors remain, `2` = bad args / harness error.
102
+ The bet: roughly half of TypeScript errors in LLM output are deterministically fixable. By catching them in Layer 1, you dodge the LLM tax (latency, cost, nondeterminism) on the easy half.
103
+
104
+ ## Library API
129
105
 
130
- ### Run the benchmark (contributor-only)
106
+ ```typescript
107
+ import { runValidationLoop } from '@shipispec/tsfix';
131
108
 
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
109
+ const result = runValidationLoop({
110
+ workspaceRoot: '/path/to/your/project',
111
+ // Optional:
112
+ // targetFiles: ['src/api.ts'],
113
+ // dryRun: true,
114
+ // logger: { info: console.log, warn: console.warn, error: console.error },
115
+ });
116
+
117
+ result.errorsBefore; // number
118
+ result.errorsAfter; // number
119
+ result.lspFixer.fixesApplied; // number
120
+ result.lspFixer.filesEdited; // string[]
121
+ result.passed; // boolean — true if errorsAfter === 0
136
122
  ```
137
123
 
138
- ### Current baseline
124
+ Other exports:
139
125
 
140
- **14/14 synthetic fixtures pass. LSP fixer auto-resolves 14/25 errors (56%).** The remaining errors are intentional non-fixes TS7006 implicit-any, TS2741 missing prop, API-drift errors that need the mend layer. See `STATUS.md` § Fixture catalog for the full list.
126
+ - `runInProcessTsc(opts)`validation only, no fixer. Returns structured diagnostics.
127
+ - `runLSPFixerPass(opts)` — Layer 0 fixer alone, no validation loop wrapper.
128
+ - `discoverTsFiles(workspaceRoot)` — file-walking helper. Skips `node_modules`, `.next`, `dist`, `build`, `out`, `coverage`, `.git`.
141
129
 
142
- ### Capturing real-failure fixtures
130
+ ## Trust model
143
131
 
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.
132
+ tsfix loads `typescript` from your workspace's `node_modules` it does **not** bundle its own. This is intentional: it ensures the fixer behaves identically to the `tsc` your project actually compiles with.
145
133
 
146
- ---
134
+ > **Run tsfix only on workspaces you trust.** Loading `typescript` from an attacker-controlled `node_modules` is equivalent to running `node_modules/.bin/tsc` against it.
147
135
 
148
- ## Troubleshooting
136
+ Other surface:
149
137
 
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`.
138
+ - No network calls.
139
+ - No telemetry.
140
+ - No background processes.
141
+ - No config files written or modified outside `--workspace`.
151
142
 
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).
143
+ ## Engines
153
144
 
154
- ---
145
+ - Node `>=20.9.0`
146
+ - TypeScript `>=5.0.0` (peer dep — must be installed in your workspace)
155
147
 
156
- ## Trust model
148
+ If your workspace has no `node_modules/typescript`, tsfix will fail with a clear error:
149
+
150
+ ```
151
+ error: this workspace has no TypeScript installed.
152
+ run: npm install --save-dev typescript
153
+ ```
154
+
155
+ ## Contributing
156
+
157
+ The contract for adding a fix:
157
158
 
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
+ 1. **Probe** write a tiny test workspace with the exact error you want fixable. Drop it under `fixtures/<descriptive-name>/` with an `expected.json` declaring `errorsBefore`, `errorsAfterMax`, `lspFixesAppliedMin/Max`, and `mustPass`.
160
+ 2. **Verify** — run `npm run benchmark -- --fixture <name>` and inspect what the language service offers (the `fix.fixName` field).
161
+ 3. **Allowlist change** — if `fixName` is unsafe (`fixMissingFunctionDeclaration`, `addMissingPropertyAndOptional`, etc.), document why we don't trust it. Otherwise, add the error code to `SAFE_FIXABLE_CODES` and the fix name to `SAFE_FIX_NAMES` in `src/tsLanguageServiceFixer.ts`.
162
+ 4. **Lock it in** — confirm all existing fixtures still pass (`npm run benchmark`). Open a PR.
159
163
 
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.
164
+ Each new code/fix-name pair gets its own fixture. We don't trust the language service blindly we trust it under specific, pinned conditions.
161
165
 
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`).
166
+ `npm run matrix` runs the same package against 6 distinct project shapes (Next.js, Vite + React, plain `nodenext`, plain `bundler`, plain CommonJS, monorepo with project references). It builds the local tarball and exercises it cold; pre-publish gate.
163
167
 
164
- ---
168
+ ## License
165
169
 
166
- ## What's in the package vs what's only for contributors
170
+ MIT.
167
171
 
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.
172
+ ## See also
169
173
 
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.
174
+ - `CHANGELOG.md` — release notes per version.
175
+ - `ARCHITECTURE.md` — internal design rationale (the four-layer model, the workspace lib-path workaround).
176
+ - `STATUS.md` — current snapshot, gaps, and roadmap state.
177
+ - `tsc-defense-roadmap.md` — phased plan.
178
+ - `docs/internal-orientation.md` — the original SpecToShip-context README, kept for contributors who want the design history.
package/dist/index.d.ts CHANGED
@@ -31,12 +31,15 @@
31
31
  * - `runInProcessTsc` — just type-check, returns structured diagnostics
32
32
  * - `runLSPFixerPass` — just the auto-fix pass, edits files in place
33
33
  *
34
- * ## What it doesn't do (yet)
34
+ * ## Public types for downstream LLM-mend integrations
35
35
  *
36
- * LLM-driven repair (the mend-agent layers from the spectoship pipeline) is
37
- * not exported here yet. They depend on internal types (ParsedTask) that need
38
- * to be redesigned as opaque interfaces before they can be moved into this
39
- * package. v0.2 target.
36
+ * - `Diagnostic` single tsc error (re-exported from `runInProcessTsc`)
37
+ * - `MendContext` input contract for a Layer 2–4 LLM-mend agent
38
+ * - `LayerEvent` per-layer event shape for streaming telemetry
39
+ *
40
+ * The mend agents themselves (`@shipispec/tsmend`, planned) consume these
41
+ * types but are not shipped from this package — `tsfix` stays Layer 0–1
42
+ * deterministic.
40
43
  */
41
44
  export { runInProcessTsc, isInProcessTscEnabled, resetInProcessTscCache } from "./validatorInProcess.js";
42
45
  export type { InProcessTscOptions, InProcessTscResult } from "./validatorInProcess.js";
@@ -101,3 +104,73 @@ export declare function discoverTsFiles(workspaceRoot: string): string[];
101
104
  * Throws on missing `tsconfig.json` or workspace path.
102
105
  */
103
106
  export declare function runValidationLoop(opts: ValidationLoopOptions): ValidationLoopResult;
107
+ /**
108
+ * Single tsc diagnostic. Re-exported from `runInProcessTsc`'s result type
109
+ * so consumers building a `MendContext` don't have to dig the shape out of
110
+ * `InProcessTscResult["diagnostics"][number]`.
111
+ */
112
+ export type Diagnostic = InProcessTscResult["diagnostics"][number];
113
+ /**
114
+ * Input contract for a Layer 2–4 LLM-mend agent.
115
+ *
116
+ * Pattern:
117
+ * 1. Run `runValidationLoop` (Layer 0/1).
118
+ * 2. If `result.errorsAfter > 0`, build a `MendContext` from the
119
+ * surviving diagnostics + whatever task/spec context your pipeline has.
120
+ * 3. Hand off to a mend agent (e.g. `@shipispec/tsmend`).
121
+ *
122
+ * Required fields: `workspaceRoot`, `diagnostics`, `erroredFiles`.
123
+ * Everything else is optional — leave fields out if your pipeline doesn't
124
+ * carry them.
125
+ */
126
+ export interface MendContext {
127
+ /** Absolute path to the workspace (must contain `tsconfig.json`). */
128
+ workspaceRoot: string;
129
+ /** Diagnostics that survived Layer 0/1 and need higher-layer repair. */
130
+ diagnostics: Diagnostic[];
131
+ /** Absolute paths of files containing the surviving diagnostics. */
132
+ erroredFiles: string[];
133
+ /** Optional one-line summary of what the failing code was supposed to do. */
134
+ taskDescription?: string;
135
+ /** Optional Markdown spec the code is implementing. Helps the LLM understand intent. */
136
+ featureSpecText?: string;
137
+ /** Optional testable acceptance criteria from the spec. */
138
+ acceptanceCriteria?: string;
139
+ /** Other tasks in the same feature, with their files and current status. */
140
+ siblingTasks?: Array<{
141
+ description: string;
142
+ files: string[];
143
+ status: "pending" | "completed" | "failed";
144
+ }>;
145
+ /** Public API surface from earlier completed tasks (helps prevent re-defining symbols). */
146
+ priorTaskExports?: string;
147
+ /** Compact type signatures of installed npm dependencies (helps prevent API hallucination). */
148
+ installedTypes?: string;
149
+ }
150
+ /**
151
+ * Per-layer event for streaming telemetry across the validate → fix → mend
152
+ * chain. Designed for an `onLayerEvent` callback (added in a future minor
153
+ * release) rather than accumulating in a result array — a workspace with
154
+ * 200 errors emits ~1000 events.
155
+ *
156
+ * Layer assignments:
157
+ * 0 = prevention (prompt rules, exported-API injection — caller's problem)
158
+ * 1 = tsfix LSP fixer (this package)
159
+ * 2 = single-file LLM mend
160
+ * 3 = multi-file LLM mend (blast-radius search/replace)
161
+ * 4 = stub-and-continue (escape hatch)
162
+ */
163
+ export interface LayerEvent {
164
+ /** Which layer ran. */
165
+ layer: 0 | 1 | 2 | 3 | 4;
166
+ /** TypeScript error code being acted on (e.g. 2304, 2339, 7006). */
167
+ errorCode: number;
168
+ /** True if the error was resolved by this layer. */
169
+ fixed: boolean;
170
+ /** Wall-clock time spent on this attempt. */
171
+ latencyMs: number;
172
+ /** USD cost (LLM tokens). Undefined for deterministic layers. */
173
+ costUsd?: number;
174
+ /** `Date.now()` at emission. */
175
+ ts: number;
176
+ }
@@ -31,12 +31,15 @@
31
31
  * - `runInProcessTsc` — just type-check, returns structured diagnostics
32
32
  * - `runLSPFixerPass` — just the auto-fix pass, edits files in place
33
33
  *
34
- * ## What it doesn't do (yet)
34
+ * ## Public types for downstream LLM-mend integrations
35
35
  *
36
- * LLM-driven repair (the mend-agent layers from the spectoship pipeline) is
37
- * not exported here yet. They depend on internal types (ParsedTask) that need
38
- * to be redesigned as opaque interfaces before they can be moved into this
39
- * package. v0.2 target.
36
+ * - `Diagnostic` single tsc error (re-exported from `runInProcessTsc`)
37
+ * - `MendContext` input contract for a Layer 2–4 LLM-mend agent
38
+ * - `LayerEvent` per-layer event shape for streaming telemetry
39
+ *
40
+ * The mend agents themselves (`@shipispec/tsmend`, planned) consume these
41
+ * types but are not shipped from this package — `tsfix` stays Layer 0–1
42
+ * deterministic.
40
43
  */
41
44
  export { runInProcessTsc, isInProcessTscEnabled, resetInProcessTscCache } from "./validatorInProcess.js";
42
45
  export type { InProcessTscOptions, InProcessTscResult } from "./validatorInProcess.js";
@@ -101,3 +104,73 @@ export declare function discoverTsFiles(workspaceRoot: string): string[];
101
104
  * Throws on missing `tsconfig.json` or workspace path.
102
105
  */
103
106
  export declare function runValidationLoop(opts: ValidationLoopOptions): ValidationLoopResult;
107
+ /**
108
+ * Single tsc diagnostic. Re-exported from `runInProcessTsc`'s result type
109
+ * so consumers building a `MendContext` don't have to dig the shape out of
110
+ * `InProcessTscResult["diagnostics"][number]`.
111
+ */
112
+ export type Diagnostic = InProcessTscResult["diagnostics"][number];
113
+ /**
114
+ * Input contract for a Layer 2–4 LLM-mend agent.
115
+ *
116
+ * Pattern:
117
+ * 1. Run `runValidationLoop` (Layer 0/1).
118
+ * 2. If `result.errorsAfter > 0`, build a `MendContext` from the
119
+ * surviving diagnostics + whatever task/spec context your pipeline has.
120
+ * 3. Hand off to a mend agent (e.g. `@shipispec/tsmend`).
121
+ *
122
+ * Required fields: `workspaceRoot`, `diagnostics`, `erroredFiles`.
123
+ * Everything else is optional — leave fields out if your pipeline doesn't
124
+ * carry them.
125
+ */
126
+ export interface MendContext {
127
+ /** Absolute path to the workspace (must contain `tsconfig.json`). */
128
+ workspaceRoot: string;
129
+ /** Diagnostics that survived Layer 0/1 and need higher-layer repair. */
130
+ diagnostics: Diagnostic[];
131
+ /** Absolute paths of files containing the surviving diagnostics. */
132
+ erroredFiles: string[];
133
+ /** Optional one-line summary of what the failing code was supposed to do. */
134
+ taskDescription?: string;
135
+ /** Optional Markdown spec the code is implementing. Helps the LLM understand intent. */
136
+ featureSpecText?: string;
137
+ /** Optional testable acceptance criteria from the spec. */
138
+ acceptanceCriteria?: string;
139
+ /** Other tasks in the same feature, with their files and current status. */
140
+ siblingTasks?: Array<{
141
+ description: string;
142
+ files: string[];
143
+ status: "pending" | "completed" | "failed";
144
+ }>;
145
+ /** Public API surface from earlier completed tasks (helps prevent re-defining symbols). */
146
+ priorTaskExports?: string;
147
+ /** Compact type signatures of installed npm dependencies (helps prevent API hallucination). */
148
+ installedTypes?: string;
149
+ }
150
+ /**
151
+ * Per-layer event for streaming telemetry across the validate → fix → mend
152
+ * chain. Designed for an `onLayerEvent` callback (added in a future minor
153
+ * release) rather than accumulating in a result array — a workspace with
154
+ * 200 errors emits ~1000 events.
155
+ *
156
+ * Layer assignments:
157
+ * 0 = prevention (prompt rules, exported-API injection — caller's problem)
158
+ * 1 = tsfix LSP fixer (this package)
159
+ * 2 = single-file LLM mend
160
+ * 3 = multi-file LLM mend (blast-radius search/replace)
161
+ * 4 = stub-and-continue (escape hatch)
162
+ */
163
+ export interface LayerEvent {
164
+ /** Which layer ran. */
165
+ layer: 0 | 1 | 2 | 3 | 4;
166
+ /** TypeScript error code being acted on (e.g. 2304, 2339, 7006). */
167
+ errorCode: number;
168
+ /** True if the error was resolved by this layer. */
169
+ fixed: boolean;
170
+ /** Wall-clock time spent on this attempt. */
171
+ latencyMs: number;
172
+ /** USD cost (LLM tokens). Undefined for deterministic layers. */
173
+ costUsd?: number;
174
+ /** `Date.now()` at emission. */
175
+ ts: number;
176
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipispec/tsfix",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Reusable TypeScript error-recovery agent. Validates LLM-generated TS code, auto-fixes deterministic error classes via the TS Language Service, and exposes hooks for LLM-driven repair.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -48,6 +48,7 @@
48
48
  "scripts": {
49
49
  "build": "node scripts/build.mjs",
50
50
  "matrix": "node scripts/run-matrix.mjs",
51
+ "capture": "node scripts/capture-fixture.mjs",
51
52
  "prepack": "npm run build",
52
53
  "setup-fixtures": "node -e \"require('fs').existsSync('fixtures/_shared/node_modules')||require('child_process').execSync('npm install --prefix fixtures/_shared',{stdio:'inherit'})\"",
53
54
  "prebenchmark": "npm run setup-fixtures",