@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 +20 -2
- package/README.md +128 -120
- package/dist/index.d.ts +78 -5
- package/dist/types/index.d.ts +78 -5
- package/package.json +2 -1
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
|
-
-
|
|
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.
|
|
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
|
-
#
|
|
1
|
+
# tsfix
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Headless TypeScript error recovery — auto-resolve `TS2304`, `TS2305`, `TS2551`, `TS2552`, `TS2724` before they reach a human.
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
##
|
|
9
|
+
## Before / after
|
|
14
10
|
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
22
|
+
$ tsc --noEmit
|
|
23
|
+
$ # 0 errors
|
|
24
|
+
```
|
|
31
25
|
|
|
32
|
-
|
|
26
|
+
## 30-second cold start
|
|
33
27
|
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
47
|
+
Machine-readable output for piping into other tools:
|
|
83
48
|
|
|
84
|
-
```
|
|
85
|
-
|
|
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
|
-
###
|
|
53
|
+
### All flags
|
|
95
54
|
|
|
96
|
-
|
|
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
|
-
|
|
99
|
-
npm install @shipispec/tsfix typescript
|
|
100
|
-
```
|
|
65
|
+
## What it fixes
|
|
101
66
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
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
|
-
|
|
112
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
106
|
+
```typescript
|
|
107
|
+
import { runValidationLoop } from '@shipispec/tsfix';
|
|
131
108
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
124
|
+
Other exports:
|
|
139
125
|
|
|
140
|
-
|
|
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
|
-
|
|
130
|
+
## Trust model
|
|
143
131
|
|
|
144
|
-
|
|
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
|
-
|
|
136
|
+
Other surface:
|
|
149
137
|
|
|
150
|
-
|
|
138
|
+
- No network calls.
|
|
139
|
+
- No telemetry.
|
|
140
|
+
- No background processes.
|
|
141
|
+
- No config files written or modified outside `--workspace`.
|
|
151
142
|
|
|
152
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
170
|
+
MIT.
|
|
167
171
|
|
|
168
|
-
|
|
172
|
+
## See also
|
|
169
173
|
|
|
170
|
-
|
|
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
|
-
* ##
|
|
34
|
+
* ## Public types for downstream LLM-mend integrations
|
|
35
35
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
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/dist/types/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
|
-
* ##
|
|
34
|
+
* ## Public types for downstream LLM-mend integrations
|
|
35
35
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
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.
|
|
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",
|